diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2260343e7..609120a29 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,12 +1,32 @@ on: [push, pull_request] +env: + # Set this to "on" to enable integration tests and "off" to skip integration tests + RUN_INTEGRATION_TESTS: "on" name: Build jobs: + set-lib3mf-version: + runs-on: ubuntu-20.04 + outputs: + lib3mf-version: ${{ steps.set-version.outputs.LIB3MF_VERSION }} + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Run version extraction script and set environment variable + id: set-version + run: | + LIB3MF_VERSION=$(python CI/ci_cd_helper.py extract-version) + echo "LIB3MF_VERSION=$LIB3MF_VERSION" >> $GITHUB_OUTPUT + - name: Echo version for debug + run: echo "LIB3MF_VERSION=${{ steps.set-version.outputs.LIB3MF_VERSION }}" + build-linux-memtest: runs-on: ubuntu-20.04 + needs: [set-lib3mf-version] steps: - run: sudo apt update - run: sudo apt install -y valgrind uuid-dev - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - run: sh cmake/GenerateMake.sh @@ -15,22 +35,23 @@ jobs: build-linux-ubi8-gcc12: runs-on: ubuntu-20.04 + needs: [set-lib3mf-version] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} steps: - run: sudo apt update - run: sudo apt install -y uuid-dev - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - run: mkdir -p build + - run: mkdir -p build - run: zip -r build/bindings.zip Autogenerated/Bindings - - name: Archive bindings - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: bindings.zip path: build/bindings.zip - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Docker Build @@ -39,62 +60,108 @@ jobs: context: . file: ./CI/Dockerfile platforms: linux/amd64 - tags: lib3mf_ubi8:latest - load: true - - - name: Docker Extract + tags: lib3mf_ubi8:latest + load: true + - + name: Docker Extract uses: shrink/actions-docker-extract@v3.0.0 id: extract - with: + with: image: lib3mf_ubi8:latest path: out.zip destination: dist - + - run: unzip out.zip working-directory: ./dist - - - name: Upload Artifact - uses: actions/upload-artifact@v2 + - name: Upload Artifact + uses: actions/upload-artifact@v4 with: name: lib3mf.so - path: dist/lib3mf.so.2 + path: dist/lib3mf.so.2 + - name: Extract File Name (CPacked Archive) + run: | + ZIP_FILE=$(ls dist/lib3mf-*.zip) + echo "ARTIFACT_NAME_ZIP=$(basename ${ZIP_FILE})" >> $GITHUB_ENV + shell: bash + - name: Upload Artifact (CPacked Archive) + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME_ZIP }} + path: dist/${{ env.ARTIFACT_NAME_ZIP }} + - name: Extract File Name (Debian) + run: | + DEB_FILE=$(ls dist/lib3mf-*.deb) + echo "ARTIFACT_NAME_DEB=$(basename ${DEB_FILE})" >> $GITHUB_ENV + shell: bash + - name: Upload Artifact (Debian Archive) + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME_DEB }} + path: dist/${{ env.ARTIFACT_NAME_DEB }} + - name: Extract File Name (RPM) + run: | + RPM_FILE=$(ls dist/lib3mf-*.rpm) + echo "ARTIFACT_NAME_RPM=$(basename ${RPM_FILE})" >> $GITHUB_ENV + shell: bash + - name: Upload Artifact (RPM Archive) + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME_RPM }} + path: dist/${{ env.ARTIFACT_NAME_RPM }} build-macos: runs-on: macos-latest + needs: [set-lib3mf-version] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - run: sh cmake/GenerateMake.sh "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" + - run: sh cmake/GenerateMake.sh - run: cmake --build . working-directory: ./build - run: ctest -V working-directory: ./build + - run: cpack -G ZIP -C Release + working-directory: ./build + - name: Extract File Name + run: | + ZIP_FILE=$(ls build/lib3mf-*.zip) + echo "ARTIFACT_NAME=$(basename ${ZIP_FILE})" >> $GITHUB_ENV + shell: bash - name: Archive Mac binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: lib3mf.dylib path: build/lib3mf.dylib + - name: Upload Artifact (CPacked Archive) + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME }} + path: build/${{ env.ARTIFACT_NAME }} build-macos-debug: runs-on: macos-latest + needs: [set-lib3mf-version] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - run: sh cmake/GenerateMake.sh "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64 -DCMAKE_BUILD_TYPE=Debug" + - run: sh cmake/GenerateMake.sh "Debug" - run: cmake --build . working-directory: ./build - run: ctest -V working-directory: ./build - name: Archive Mac binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: lib3mf.debug.dylib path: build/lib3mf.dylib codecoverage-macos: runs-on: macos-latest + needs: [set-lib3mf-version] steps: - uses: actions/checkout@v4 with: @@ -108,7 +175,7 @@ jobs: working-directory: ./build - run: ./Tests/codecoverage/run_codecoverage.sh - name: Archive Code Coverage Results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: codecoverage.zip path: build/codecoverage.zip @@ -122,8 +189,11 @@ jobs: build-windows-release: runs-on: windows-2019 + needs: [set-lib3mf-version] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - run: ./cmake/GenerateVS2019.bat @@ -131,20 +201,34 @@ jobs: working-directory: ./build - run: ctest -V working-directory: ./build + - run: cpack -G ZIP -C Release + working-directory: ./build + - name: Extract File Name + run: | + $zipFile = Get-ChildItem build\lib3mf-*.zip -Name + echo "ARTIFACT_NAME=$zipFile" | Out-File -FilePath $env:GITHUB_ENV -Append + shell: pwsh - name: Archive Windows Release binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: lib3mf.dll path: build/Release/lib3mf.dll - name: Archive Windows Release lib - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: lib3mf.lib path: build/Release/lib3mf.lib + - name: Upload Artifact (CPacked Archive) + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME }} + path: build/${{ env.ARTIFACT_NAME }} + build-windows-debug: runs-on: windows-2019 + needs: [set-lib3mf-version] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - run: ./cmake/GenerateVS2019.bat @@ -153,22 +237,23 @@ jobs: - run: ctest -V working-directory: ./build - name: Archive Windows Debug binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: lib3mf.debug.dll path: build/Debug/lib3mf.dll - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: lib3mf.pdb path: build/Debug/lib3mf.pdb - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: - name: lib3mf.debug.lib - path: build/Debug/lib3mf.lib + name: lib3mf.debug.lib + path: build/Debug/lib3mf.lib build-windows-32bit: runs-on: windows-2019 + needs: [set-lib3mf-version] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - run: ./cmake/GenerateVS2019_32bit.bat @@ -177,20 +262,21 @@ jobs: - run: ctest -V working-directory: ./build_32bit - name: Archive Windows 32 bit Release binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: lib3mf_32bit.dll path: build_32bit/Release/lib3mf.dll - name: Archive Windows 32 bit Release lib - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: lib3mf_32bit.lib path: build_32bit/Release/lib3mf.lib build-mingw-w64: runs-on: windows-2019 + needs: [set-lib3mf-version] steps: - run: choco install mingw -y - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - run: ./cmake/GenerateMinGW.bat @@ -198,44 +284,52 @@ jobs: working-directory: ./build - run: ctest -V working-directory: ./build + + assemble-sdk: runs-on: ubuntu-20.04 - needs: [build-windows-release, build-macos, build-linux-ubi8-gcc12] + needs: [set-lib3mf-version, build-windows-release, build-macos, build-linux-ubi8-gcc12] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} steps: - run: sudo apt install -y zip unzip - run: mkdir build - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: false - name: Download all workflow run artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: path: ./build - run: ls -Rl ./build - run: unzip bindings.zip/bindings.zip working-directory: ./build - run: bash SDK/GenerateSDK_github.sh - - name: Archive SDK artifact - uses: actions/upload-artifact@v2 + - name: Archive SDK artifact (Comprehensive) + uses: actions/upload-artifact@v4 with: name: lib3mf_sdk.zip path: build/lib3mf_sdk.zip + + deploy-linux: runs-on: ubuntu-20.04 - needs: [assemble-sdk] + needs: [set-lib3mf-version, assemble-sdk] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} steps: - - run: sudo apt install -y zip unzip + - run: sudo apt install -y zip unzip file - run: pwd - run: ls -Rl . - name: Download lib3mf_sdk artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: lib3mf_sdk.zip path: lib3mf_sdk.zip - run: ls -Rl . - name: Unpack the SDK run: | - unzip lib3mf_sdk.zip/lib3mf_sdk.zip + unzip lib3mf_sdk.zip/lib3mf_sdk.zip - name: Build CppDynamic run: | sh Examples/CppDynamic/GenerateMake.sh @@ -248,18 +342,75 @@ jobs: cd Examples/Cpp/build cmake --build . ./Example_ExtractInfo ../../Files/Helix.3mf + - name: Python Bindings + run: | + python Examples/Python/extract_info.py Examples/Files/Helix.3mf + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + - run: ls -Rl + - name: Download lib3mf cpack (Linux) + uses: actions/download-artifact@v4 + with: + name: lib3mf-${{ env.LIB3MF_VERSION }}-Linux.zip + path: lib3mf-${{ env.LIB3MF_VERSION }}-Linux.zip + - name: Unpack the cpacked SDK + run: | + unzip lib3mf-${{ env.LIB3MF_VERSION }}-Linux.zip/lib3mf-${{ env.LIB3MF_VERSION }}-Linux.zip && ls -Rl + - name: Build CppDynamic - CPack (Linux) + run: | + sh SDK/CPackExamples/CppDynamic/GenerateMake.sh + cd SDK/CPackExamples/CppDynamic/build + cmake --build . + ./Example_ExtractInfo ../../../Examples/Files/Helix.3mf + - name: Build Cpp - CPack (Linux) + run: | + sh SDK/CPackExamples/Cpp/GenerateMake.sh + cd SDK/CPackExamples/Cpp/build + cmake --build . + ./Example_ExtractInfo ../../../Examples/Files/Helix.3mf + - name: Download lib3mf (Debian Linux) + uses: actions/download-artifact@v4 + with: + name: lib3mf-${{ env.LIB3MF_VERSION }}-Linux.deb + path: lib3mf-${{ env.LIB3MF_VERSION }}-Linux.deb + - name: Check the file type + run: | + file lib3mf-${{ env.LIB3MF_VERSION }}-Linux.deb + file lib3mf-${{ env.LIB3MF_VERSION }}-Linux.deb/lib3mf-${{ env.LIB3MF_VERSION }}-Linux.deb + - run: pwd + - run: ls -Rl . + - name: Install the debian package + run: | + sudo dpkg -i lib3mf-${{ env.LIB3MF_VERSION }}-Linux.deb/lib3mf-${{ env.LIB3MF_VERSION }}-Linux.deb + - name: Build CppDynamic - CPack (Debian) + run: | + sh SDK/CPackExamples/CppDynamic/GenerateMake.sh + cd SDK/CPackExamples/CppDynamic/build + cmake --build . + ./Example_ExtractInfo ../../../Examples/Files/Helix.3mf + - name: Build Cpp - CPack (Debian) + run: | + sh SDK/CPackExamples/Cpp/GenerateMake.sh + cd SDK/CPackExamples/Cpp/build + cmake --build . + ./Example_ExtractInfo ../../../Examples/Files/Helix.3mf + deploy-windows: runs-on: windows-2019 - needs: [assemble-sdk] + needs: [set-lib3mf-version, assemble-sdk] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} steps: - name: Download lib3mf_sdk artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: lib3mf_sdk.zip path: lib3mf_sdk.zip - name: Unpack the SDK run: | - unzip lib3mf_sdk.zip/lib3mf_sdk.zip + unzip lib3mf_sdk.zip/lib3mf_sdk.zip - name: Build CppDynamic run: | ./Examples/CppDynamic/GenerateVS2019.bat @@ -272,18 +423,48 @@ jobs: cd Examples/Cpp/build cmake --build . --config Release ./Release/Example_ExtractInfo.exe ../../Files/Helix.3mf + - name: Python Bindings + run: | + python Examples/Python/extract_info.py Examples/Files/Helix.3mf + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + - name: Download lib3mf cpack (Windows) + uses: actions/download-artifact@v4 + with: + name: lib3mf-${{ env.LIB3MF_VERSION }}-Windows.zip + path: lib3mf-${{ env.LIB3MF_VERSION }}-Windows.zip + - name: Unpack the cpacked SDK + run: | + unzip lib3mf-${{ env.LIB3MF_VERSION }}-Windows.zip/lib3mf-${{ env.LIB3MF_VERSION }}-Windows.zip + - name: Build CppDynamic - CPack (Windows) + run: | + ./SDK/CPackExamples/CppDynamic/GenerateVS2019.bat + cd SDK/CPackExamples/CppDynamic/build + cmake --build . --config Release + ./Release/Example_ExtractInfo.exe ../../../Examples/Files/Helix.3mf + - name: Build Cpp - CPack (Windows) + run: | + ./SDK/CPackExamples/Cpp/GenerateVS2019.bat + cd SDK/CPackExamples/Cpp/build + cmake --build . --config Release + ./Release/Example_ExtractInfo.exe ../../../Examples/Files/Helix.3mf + deploy-macos: runs-on: macos-latest - needs: [assemble-sdk] + needs: [set-lib3mf-version, assemble-sdk] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} steps: - name: Download lib3mf_sdk artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: lib3mf_sdk.zip path: lib3mf_sdk.zip - name: Unpack the SDK run: | - unzip lib3mf_sdk.zip/lib3mf_sdk.zip + unzip lib3mf_sdk.zip/lib3mf_sdk.zip - name: Build CppDynamic run: | sh Examples/CppDynamic/GenerateMake.sh @@ -295,4 +476,482 @@ jobs: sh Examples/Cpp/GenerateMake.sh cd Examples/Cpp/build cmake --build . - ./Example_ExtractInfo ../../Files/Helix.3mf \ No newline at end of file + ./Example_ExtractInfo ../../Files/Helix.3mf + - name: Python Bindings + run: | + python Examples/Python/extract_info.py Examples/Files/Helix.3mf + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + - name: Download lib3mf cpack (Darwin) + uses: actions/download-artifact@v4 + with: + name: lib3mf-${{ env.LIB3MF_VERSION }}-Darwin.zip + path: lib3mf-${{ env.LIB3MF_VERSION }}-Darwin.zip + - run: ls -Rl . + - name: Unpack the cpacked SDK (Darwin) + run: | + unzip lib3mf-${{ env.LIB3MF_VERSION }}-Darwin.zip/lib3mf-${{ env.LIB3MF_VERSION }}-Darwin.zip + - name: Build CppDynamic - CPack (Darwin) + run: | + sh SDK/CPackExamples/CppDynamic/GenerateMake.sh + cd SDK/CPackExamples/CppDynamic/build + cmake --build . + ./Example_ExtractInfo ../../../Examples/Files/Helix.3mf + - name: Build Cpp - CPack (Darwin) + run: | + sh SDK/CPackExamples/Cpp/GenerateMake.sh + cd SDK/CPackExamples/Cpp/build + cmake --build . + ./Example_ExtractInfo ../../../Examples/Files/Helix.3mf + + deploy-source-code-with-submodules: + runs-on: ubuntu-20.04 + needs: [ set-lib3mf-version, assemble-sdk ] + env: + LIB3MF_VERSION: ${{ needs.set-lib3mf-version.outputs.lib3mf-version }} + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - run: | + mkdir -p lib3mf-${{ env.LIB3MF_VERSION }}-source-with-submodules + rsync -av --progress . ./lib3mf-${{ env.LIB3MF_VERSION }}-source-with-submodules --exclude .git --exclude .gitignore --exclude .github --exclude .gitmodules --exclude *.yml --exclude lib3mf-${{ env.LIB3MF_VERSION }}-source-with-submodules + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: lib3mf-${{ env.LIB3MF_VERSION }}-source-with-submodules + path: lib3mf-${{ env.LIB3MF_VERSION }}-source-with-submodules + + + + set-integration-tests-status: + runs-on: ubuntu-20.04 + needs: [ deploy-linux, deploy-windows, deploy-macos, deploy-source-code-with-submodules ] + outputs: + run_integration_tests: ${{ steps.set-status.outputs.run_integration_tests }} + steps: + - name: Set status + id: set-status + run: | + if [ "${{ env.RUN_INTEGRATION_TESTS }}" == "on" ]; then + echo "run_integration_tests=true" >> $GITHUB_OUTPUT + else + echo "run_integration_tests=false" >> $GITHUB_OUTPUT + fi + + + integration-tests-latest-release: + runs-on: ubuntu-20.04 + needs: [set-integration-tests-status] + if: needs.set-integration-tests-status.outputs.run_integration_tests == 'true' # Single check before the job starts + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + + - name: Get latest lib3mf SDK release info from GitHub API + id: get_lib3mf_release + run: | + echo "LATEST_LIB3MF_URL=$(python CI/ci_cd_helper.py fetch-sdk-url 0 | xargs)" >> $GITHUB_ENV + + - name: Download latest lib3mf SDK zip + run: | + wget ${{ env.LATEST_LIB3MF_URL }} -O latest_lib3mf_sdk.zip + + - name: Unpack the SDK + run: | + unzip latest_lib3mf_sdk.zip -d lib3mf_sdk + mv lib3mf_sdk/lib3mf_sdk/* lib3mf_sdk/ + rmdir lib3mf_sdk/lib3mf_sdk + + - name: Build CppDynamic + run: | + sh lib3mf_sdk/Examples/CppDynamic/GenerateMake.sh + cd lib3mf_sdk/Examples/CppDynamic/build + cmake --build . + ./Example_ExtractInfo ../../Files/Helix.3mf + + - name: Download and unzip test suite + run: | + wget https://github.com/3MFConsortium/test_suites/releases/download/v2.0.0/3MF_Conformance_Test_Suites_v2.0.0.zip + unzip 3MF_Conformance_Test_Suites_v2.0.0.zip -d test_suites + + - name: List files + run: | + ls -al + + - name: Copy integration test script + run: | + cp CI/integration_test.py test_suites/ && cp -r lib3mf_sdk/Examples/CppDynamic/build/* test_suites/ + + - name: Run integration tests + run: | + cd test_suites && /usr/bin/time -v python integration_test.py 2>&1 | tee latest_sdk_test.log + + - name: Print results (Checks the total python script execution time) + run: | + LATEST_TIME=$(grep "Elapsed (wall clock) time" test_suites/latest_sdk_test.log | awk '{print $8}') + LATEST_TOTAL_SECONDS=$(echo $LATEST_TIME | awk -F: '{ print ($1 * 60) + $2 }') + echo "Latest SDK execution time in seconds: ${LATEST_TOTAL_SECONDS}" + + LATEST_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_sdk_test.log | awk '{print $3}' | tr -d '()') + LATEST_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_sdk_test.log | awk '{print $3}' | tr -d '()') + + + echo "MUSTPASS: ${LATEST_MUSTPASS} / ${LATEST_TOTAL_MUSTPASS}" + echo "MUSTFAIL: ${LATEST_MUSTFAIL} / ${LATEST_TOTAL_MUSTFAIL}" + + + integration-tests-last-two-releases: + runs-on: ubuntu-20.04 + needs: [set-integration-tests-status] + if: needs.set-integration-tests-status.outputs.run_integration_tests == 'true' # Single check before the job starts + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + + - name: Get latest lib3mf SDK release info from GitHub API + id: get_latest_release + run: | + echo "LATEST_LIB3MF_URL=$(python CI/ci_cd_helper.py fetch-sdk-url 0 | xargs)" >> $GITHUB_ENV + + - name: Get second latest lib3mf SDK release info from GitHub API + id: get_second_latest_release + run: | + echo "SECOND_LATEST_LIB3MF_URL=$(python CI/ci_cd_helper.py fetch-sdk-url 1 | xargs)" >> $GITHUB_ENV + + - name: Download latest lib3mf SDK zip + run: | + wget ${{ env.LATEST_LIB3MF_URL }} -O latest_lib3mf_sdk.zip + + - name: Download second latest lib3mf SDK zip + run: | + wget ${{ env.SECOND_LATEST_LIB3MF_URL }} -O second_latest_lib3mf_sdk.zip + + - name: Unpack the latest SDK + run: | + unzip latest_lib3mf_sdk.zip -d latest_lib3mf_sdk + mv latest_lib3mf_sdk/lib3mf_sdk/* latest_lib3mf_sdk + rmdir latest_lib3mf_sdk/lib3mf_sdk + + - name: Unpack the second latest SDK + run: | + unzip second_latest_lib3mf_sdk.zip -d second_latest_lib3mf_sdk + + - name: Download and unzip test suite + run: | + wget https://github.com/3MFConsortium/test_suites/releases/download/v2.0.0/3MF_Conformance_Test_Suites_v2.0.0.zip + unzip 3MF_Conformance_Test_Suites_v2.0.0.zip -d test_suites + + - name: Copy integration test script + run: | + cp CI/integration_test.py test_suites/ + + - name: Build and run CppDynamic with latest SDK + run: | + sh latest_lib3mf_sdk/Examples/CppDynamic/GenerateMake.sh + cd latest_lib3mf_sdk/Examples/CppDynamic/build + cmake --build . + cp -r * ../../../../test_suites/ + + - name: Run integration tests with latest SDK + run: | + cd test_suites + /usr/bin/time -v python integration_test.py 2>&1 | tee latest_sdk_test.log + + - name: Clean up latest SDK binaries + run: | + find test_suites -maxdepth 1 -type f ! -name 'integration_test.py' ! -name 'latest_sdk_test.log' ! -name 'second_latest_sdk_test.log' -exec rm -rf {} + + + - name: Build and run CppDynamic with second latest SDK + run: | + sh second_latest_lib3mf_sdk/Examples/CppDynamic/GenerateMake.sh + cd second_latest_lib3mf_sdk/Examples/CppDynamic/build + cmake --build . + echo "First debug" + ls -al ../../../../ + echo "This will fail" + cp -r * ../../../../test_suites/ + + - name: Run integration tests with second latest SDK + run: | + cd test_suites + /usr/bin/time -v python integration_test.py 2>&1 | tee second_latest_sdk_test.log + + - name: Compare results (Checks the total python script execution time and must pass/fail counts) + run: | + LATEST_TIME=$(grep "Elapsed (wall clock) time" test_suites/latest_sdk_test.log | awk '{print $8}') + SECOND_LATEST_TIME=$(grep "Elapsed (wall clock) time" test_suites/second_latest_sdk_test.log | awk '{print $8}') + LATEST_TOTAL_SECONDS=$(echo $LATEST_TIME | awk -F: '{ print ($1 * 60) + $2 }') + SECOND_LATEST_TOTAL_SECONDS=$(echo $SECOND_LATEST_TIME | awk -F: '{ print ($1 * 60) + $2 }') + echo "Latest SDK execution time in seconds: ${LATEST_TOTAL_SECONDS}" + echo "Second Latest SDK execution time in seconds: ${SECOND_LATEST_TOTAL_SECONDS}" + + LATEST_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_sdk_test.log | awk '{print $3}' | tr -d '()') + SECOND_LATEST_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/second_latest_sdk_test.log | awk '{print $1}') + SECOND_LATEST_TOTAL_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/second_latest_sdk_test.log | awk '{print $3}' | tr -d '()') + + LATEST_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_sdk_test.log | awk '{print $3}' | tr -d '()') + SECOND_LATEST_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/second_latest_sdk_test.log | awk '{print $1}') + SECOND_LATEST_TOTAL_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/second_latest_sdk_test.log | awk '{print $3}' | tr -d '()') + + echo "Latest MUSTPASS: ${LATEST_MUSTPASS} / ${LATEST_TOTAL_MUSTPASS}" + echo "Second Latest MUSTPASS: ${SECOND_LATEST_MUSTPASS} / ${SECOND_LATEST_TOTAL_MUSTPASS}" + echo "Latest MUSTFAIL: ${LATEST_MUSTFAIL} / ${LATEST_TOTAL_MUSTFAIL}" + echo "Second Latest MUSTFAIL: ${SECOND_LATEST_MUSTFAIL} / ${SECOND_LATEST_TOTAL_MUSTFAIL}" + + # Compare the total seconds + if (( $(echo "$LATEST_TOTAL_SECONDS < $SECOND_LATEST_TOTAL_SECONDS" | bc -l) )); then + echo "New release is better in execution time" + else + echo "New release is worse in execution time" + fi + + # Compare MUSTPASS and MUSTFAIL counts + if [ "$LATEST_MUSTPASS" != "$SECOND_LATEST_MUSTPASS" ] || [ "$LATEST_MUSTFAIL" != "$SECOND_LATEST_MUSTFAIL" ]; then + echo "MUSTPASS or MUSTFAIL counts have changed" + exit 1 + else + echo "MUSTPASS and MUSTFAIL counts are consistent" + fi + + + + integration-tests-latest-commit: + runs-on: ubuntu-20.04 + needs: [set-integration-tests-status] + if: needs.set-integration-tests-status.outputs.run_integration_tests == 'true' # Single check before the job starts + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + + - name: Download lib3mf_sdk artifact + uses: actions/download-artifact@v4 + with: + name: lib3mf_sdk.zip + path: lib3mf_sdk.zip + + - name: Unpack the SDK + run: | + unzip lib3mf_sdk.zip/lib3mf_sdk.zip -d lib3mf_sdk && ls -al + + - name: Build CppDynamic + run: | + sh lib3mf_sdk/Examples/CppDynamic/GenerateMake.sh + cd lib3mf_sdk/Examples/CppDynamic/build + cmake --build . + ./Example_ExtractInfo ../../Files/Helix.3mf + + - name: Download and unzip test suite + run: | + wget https://github.com/3MFConsortium/test_suites/releases/download/v2.0.0/3MF_Conformance_Test_Suites_v2.0.0.zip + unzip 3MF_Conformance_Test_Suites_v2.0.0.zip -d test_suites + + - name: Copy integration test script + run: | + cp CI/integration_test.py test_suites/ && cp -r lib3mf_sdk/Examples/CppDynamic/build/* test_suites/ + + - name: Run integration tests + run: | + cd test_suites && /usr/bin/time -v python integration_test.py 2>&1 | tee latest_sdk_test.log + + - name: Print results (Checks the total python script execution time) + run: | + LATEST_TIME=$(grep "Elapsed (wall clock) time" test_suites/latest_sdk_test.log | awk '{print $8}') + LATEST_TOTAL_SECONDS=$(echo $LATEST_TIME | awk -F: '{ print ($1 * 60) + $2 }') + echo "Latest SDK execution time in seconds: ${LATEST_TOTAL_SECONDS}" + + LATEST_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_sdk_test.log | awk '{print $3}' | tr -d '()') + LATEST_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_sdk_test.log | awk '{print $3}' | tr -d '()') + + echo "MUSTPASS: ${LATEST_MUSTPASS} / ${LATEST_TOTAL_MUSTPASS}" + echo "MUSTFAIL: ${LATEST_MUSTFAIL} / ${LATEST_TOTAL_MUSTFAIL}" + + # Save counts for comparison in other jobs + echo "LATEST_MUSTPASS=${LATEST_MUSTPASS}" >> $GITHUB_ENV + echo "LATEST_TOTAL_MUSTPASS=${LATEST_TOTAL_MUSTPASS}" >> $GITHUB_ENV + echo "LATEST_MUSTFAIL=${LATEST_MUSTFAIL}" >> $GITHUB_ENV + echo "LATEST_TOTAL_MUSTFAIL=${LATEST_TOTAL_MUSTFAIL}" >> $GITHUB_ENV + + integration-test-last-commit-and-last-release: + runs-on: ubuntu-20.04 + needs: [set-integration-tests-status] + if: needs.set-integration-tests-status.outputs.run_integration_tests == 'true' # Single check before the job starts + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + + - name: Download lib3mf_sdk artifact + uses: actions/download-artifact@v4 + with: + name: lib3mf_sdk.zip + path: lib3mf_sdk.zip + + - name: Unpack the SDK + run: | + unzip lib3mf_sdk.zip/lib3mf_sdk.zip -d latest_commit_lib3mf_sdk && ls -al + + + - name: Build CppDynamic with latest commit SDK + run: | + sh latest_commit_lib3mf_sdk/Examples/CppDynamic/GenerateMake.sh + cd latest_commit_lib3mf_sdk/Examples/CppDynamic/build + cmake --build . + ./Example_ExtractInfo ../../Files/Helix.3mf + + - name: Download and unzip test suite + run: | + wget https://github.com/3MFConsortium/test_suites/releases/download/v2.0.0/3MF_Conformance_Test_Suites_v2.0.0.zip + unzip 3MF_Conformance_Test_Suites_v2.0.0.zip -d test_suites + + - name: Copy integration test script + run: | + cp CI/integration_test.py test_suites/ + + - name: Copy latest commit SDK to test suite + run: | + cp -r latest_commit_lib3mf_sdk/Examples/CppDynamic/build/* test_suites/ + + - name: Run integration tests with latest commit SDK + run: | + cd test_suites && /usr/bin/time -v python integration_test.py 2>&1 | tee latest_commit_sdk_test.log + + - name: Clean up latest SDK binaries + run: | + find test_suites -maxdepth 1 -type f ! -name 'integration_test.py' ! -name '*.log' -exec rm -rf {} + + + - name: Get latest lib3mf SDK release info from GitHub API + id: get_latest_release + run: | + echo "LATEST_LIB3MF_URL=$(python CI/ci_cd_helper.py fetch-sdk-url 0 | xargs)" >> $GITHUB_ENV + LATEST_RELEASE_NAME=$(curl -s https://api.github.com/repos/3MFConsortium/lib3mf/releases/latest | grep '"tag_name"' | cut -d '"' -f 4) + echo "LATEST_RELEASE_NAME=${LATEST_RELEASE_NAME}" >> $GITHUB_ENV + + - name: Download latest lib3mf SDK release zip + run: | + wget ${{ env.LATEST_LIB3MF_URL }} -O latest_release_lib3mf_sdk.zip + + - name: Unpack the SDK from latest release + run: | + unzip latest_release_lib3mf_sdk.zip -d latest_release_lib3mf_sdk + mv latest_release_lib3mf_sdk/lib3mf_sdk/* latest_release_lib3mf_sdk/ + rmdir latest_release_lib3mf_sdk/lib3mf_sdk/ + + - name: Build CppDynamic with latest release SDK + run: | + sh latest_release_lib3mf_sdk/Examples/CppDynamic/GenerateMake.sh + cd latest_release_lib3mf_sdk/Examples/CppDynamic/build + cmake --build . + ./Example_ExtractInfo ../../Files/Helix.3mf + + - name: Copy latest release SDK to test suite + run: | + cp -r latest_release_lib3mf_sdk/Examples/CppDynamic/build/* test_suites/ + + - name: Run integration tests with latest release SDK + run: | + cd test_suites && /usr/bin/time -v python integration_test.py 2>&1 | tee latest_release_sdk_test.log + + - name: Compare results (Checks the total python script execution time) + id: compare_results + run: | + LATEST_COMMIT_TIME=$(grep "Elapsed (wall clock) time" test_suites/latest_commit_sdk_test.log | awk '{print $8}') + LATEST_RELEASE_TIME=$(grep "Elapsed (wall clock) time" test_suites/latest_release_sdk_test.log | awk '{print $8}') + LATEST_COMMIT_TOTAL_SECONDS=$(echo $LATEST_COMMIT_TIME | awk -F: '{ print ($1 * 60) + $2 }') + LATEST_RELEASE_TOTAL_SECONDS=$(echo $LATEST_RELEASE_TIME | awk -F: '{ print ($1 * 60) + $2 }') + echo "Latest commit SDK execution time in seconds: ${LATEST_COMMIT_TOTAL_SECONDS}" + echo "Latest release SDK execution time in seconds: ${LATEST_RELEASE_TOTAL_SECONDS}" + + LATEST_COMMIT_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_commit_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_COMMIT_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_commit_sdk_test.log | awk '{print $3}' | tr -d '()') + LATEST_RELEASE_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_release_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_RELEASE_MUSTPASS=$(grep "MUSTPASS files passed" test_suites/latest_release_sdk_test.log | awk '{print $3}' | tr -d '()') + + LATEST_COMMIT_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_commit_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_COMMIT_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_commit_sdk_test.log | awk '{print $3}' | tr -d '()') + LATEST_RELEASE_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_release_sdk_test.log | awk '{print $1}') + LATEST_TOTAL_RELEASE_MUSTFAIL=$(grep "MUSTFAIL files failed" test_suites/latest_release_sdk_test.log | awk '{print $3}' | tr -d '()') + + echo "Latest commit MUSTPASS: ${LATEST_COMMIT_MUSTPASS} / ${LATEST_TOTAL_COMMIT_MUSTPASS}" + echo "Latest release MUSTPASS: ${LATEST_RELEASE_MUSTPASS} / ${LATEST_TOTAL_RELEASE_MUSTPASS}" + echo "Latest commit MUSTFAIL: ${LATEST_COMMIT_MUSTFAIL} / ${LATEST_TOTAL_COMMIT_MUSTFAIL}" + echo "Latest release MUSTFAIL: ${LATEST_RELEASE_MUSTFAIL} / ${LATEST_TOTAL_RELEASE_MUSTFAIL}" + + # Compare MUSTPASS and MUSTFAIL counts + if [ "$LATEST_COMMIT_MUSTPASS" != "$LATEST_RELEASE_MUSTPASS" ] || [ "$LATEST_COMMIT_MUSTFAIL" != "$LATEST_RELEASE_MUSTFAIL" ]; then + echo "MUSTPASS or MUSTFAIL counts have changed" + exit 1 + else + echo "MUSTPASS and MUSTFAIL counts are consistent" + fi + + # Compare the total seconds + if (( $(echo "$LATEST_COMMIT_TOTAL_SECONDS < $LATEST_RELEASE_TOTAL_SECONDS" | bc -l) )); then + echo "Latest commit is better" + else + echo "Latest release is better" + fi + + echo "Latest commit with SHA ${{ github.sha }} ran in ${LATEST_COMMIT_TOTAL_SECONDS} seconds" > results.txt + echo "Latest release with tag ${{ env.LATEST_RELEASE_NAME }} ran in ${LATEST_RELEASE_TOTAL_SECONDS} seconds" >> results.txt + echo "Latest commit MUSTPASS: ${LATEST_COMMIT_MUSTPASS} / ${LATEST_TOTAL_COMMIT_MUSTPASS}" >> results.txt + echo "Latest release MUSTPASS: ${LATEST_RELEASE_MUSTPASS} / ${LATEST_TOTAL_RELEASE_MUSTPASS}" >> results.txt + echo "Latest commit MUSTFAIL: ${LATEST_COMMIT_MUSTFAIL} / ${LATEST_TOTAL_COMMIT_MUSTFAIL}" >> results.txt + echo "Latest release MUSTFAIL: ${LATEST_RELEASE_MUSTFAIL} / ${LATEST_TOTAL_RELEASE_MUSTFAIL}" >> results.txt + + - name: Upload results artifact + uses: actions/upload-artifact@v4 + with: + name: integration-test-results + path: results.txt \ No newline at end of file diff --git a/.gitignore b/.gitignore index a41019361..87ee8d189 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ Include/Model/COM/NMR_COMVersion.h debug .DS_Store .vscode +.idea +cmake-build-* \ No newline at end of file diff --git a/Autogenerated/Bindings/C/lib3mf.h b/Autogenerated/Bindings/C/lib3mf.h index d22a9aac1..80ba9cd19 100644 --- a/Autogenerated/Bindings/C/lib3mf.h +++ b/Autogenerated/Bindings/C/lib3mf.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/C/lib3mf_types.h b/Autogenerated/Bindings/C/lib3mf_types.h index a0c6149a6..6f2dcf6a4 100644 --- a/Autogenerated/Bindings/C/lib3mf_types.h +++ b/Autogenerated/Bindings/C/lib3mf_types.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file with basic types in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -85,7 +85,7 @@ typedef void * Lib3MF_pvoid; #define LIB3MF_VERSION_MAJOR 2 #define LIB3MF_VERSION_MINOR 3 -#define LIB3MF_VERSION_MICRO 1 +#define LIB3MF_VERSION_MICRO 2 #define LIB3MF_VERSION_PRERELEASEINFO "" #define LIB3MF_VERSION_BUILDINFO "" diff --git a/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.cc b/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.cc index 937582f41..e1cec341d 100644 --- a/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.cc +++ b/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.cc @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.h b/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.h index c524c7583..044c754bb 100644 --- a/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.h +++ b/Autogenerated/Bindings/CDynamic/lib3mf_dynamic.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/CDynamic/lib3mf_types.h b/Autogenerated/Bindings/CDynamic/lib3mf_types.h index a0c6149a6..6f2dcf6a4 100644 --- a/Autogenerated/Bindings/CDynamic/lib3mf_types.h +++ b/Autogenerated/Bindings/CDynamic/lib3mf_types.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file with basic types in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -85,7 +85,7 @@ typedef void * Lib3MF_pvoid; #define LIB3MF_VERSION_MAJOR 2 #define LIB3MF_VERSION_MINOR 3 -#define LIB3MF_VERSION_MICRO 1 +#define LIB3MF_VERSION_MICRO 2 #define LIB3MF_VERSION_PRERELEASEINFO "" #define LIB3MF_VERSION_BUILDINFO "" diff --git a/Autogenerated/Bindings/CSharp/Lib3MF.cs b/Autogenerated/Bindings/CSharp/Lib3MF.cs index fab65add3..9caaa404a 100644 --- a/Autogenerated/Bindings/CSharp/Lib3MF.cs +++ b/Autogenerated/Bindings/CSharp/Lib3MF.cs @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated CSharp file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Cpp/lib3mf_abi.hpp b/Autogenerated/Bindings/Cpp/lib3mf_abi.hpp index 864f8704d..44b8273b8 100644 --- a/Autogenerated/Bindings/Cpp/lib3mf_abi.hpp +++ b/Autogenerated/Bindings/Cpp/lib3mf_abi.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp b/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp index c5718c58f..c69787d70 100644 --- a/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp +++ b/Autogenerated/Bindings/Cpp/lib3mf_implicit.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Cpp/lib3mf_types.hpp b/Autogenerated/Bindings/Cpp/lib3mf_types.hpp index bc584e7b5..705f02718 100644 --- a/Autogenerated/Bindings/Cpp/lib3mf_types.hpp +++ b/Autogenerated/Bindings/Cpp/lib3mf_types.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file with basic types in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -84,7 +84,7 @@ typedef void * Lib3MF_pvoid; #define LIB3MF_VERSION_MAJOR 2 #define LIB3MF_VERSION_MINOR 3 -#define LIB3MF_VERSION_MICRO 1 +#define LIB3MF_VERSION_MICRO 2 #define LIB3MF_VERSION_PRERELEASEINFO "" #define LIB3MF_VERSION_BUILDINFO "" diff --git a/Autogenerated/Bindings/CppDynamic/lib3mf_abi.hpp b/Autogenerated/Bindings/CppDynamic/lib3mf_abi.hpp index 255061d89..4efde3a1a 100644 --- a/Autogenerated/Bindings/CppDynamic/lib3mf_abi.hpp +++ b/Autogenerated/Bindings/CppDynamic/lib3mf_abi.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.h b/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.h index 5aef62409..bfe996afe 100644 --- a/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.h +++ b/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.hpp b/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.hpp index 3411be9e3..a374db4eb 100644 --- a/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.hpp +++ b/Autogenerated/Bindings/CppDynamic/lib3mf_dynamic.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/CppDynamic/lib3mf_types.hpp b/Autogenerated/Bindings/CppDynamic/lib3mf_types.hpp index bc584e7b5..705f02718 100644 --- a/Autogenerated/Bindings/CppDynamic/lib3mf_types.hpp +++ b/Autogenerated/Bindings/CppDynamic/lib3mf_types.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file with basic types in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -84,7 +84,7 @@ typedef void * Lib3MF_pvoid; #define LIB3MF_VERSION_MAJOR 2 #define LIB3MF_VERSION_MINOR 3 -#define LIB3MF_VERSION_MICRO 1 +#define LIB3MF_VERSION_MICRO 2 #define LIB3MF_VERSION_PRERELEASEINFO "" #define LIB3MF_VERSION_BUILDINFO "" diff --git a/Autogenerated/Bindings/Go/cfunc.go b/Autogenerated/Bindings/Go/cfunc.go index 66d256455..0256de1e0 100644 --- a/Autogenerated/Bindings/Go/cfunc.go +++ b/Autogenerated/Bindings/Go/cfunc.go @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated Go wrapper file in order to allow an easy use of the 3MF Library. -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Go/lib3mf.go b/Autogenerated/Bindings/Go/lib3mf.go index c454d5b63..705bad104 100644 --- a/Autogenerated/Bindings/Go/lib3mf.go +++ b/Autogenerated/Bindings/Go/lib3mf.go @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated Go wrapper file in order to allow an easy use of the 3MF Library. -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Go/lib3mf_dynamic.cc b/Autogenerated/Bindings/Go/lib3mf_dynamic.cc index 937582f41..e1cec341d 100644 --- a/Autogenerated/Bindings/Go/lib3mf_dynamic.cc +++ b/Autogenerated/Bindings/Go/lib3mf_dynamic.cc @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Go/lib3mf_dynamic.h b/Autogenerated/Bindings/Go/lib3mf_dynamic.h index c524c7583..044c754bb 100644 --- a/Autogenerated/Bindings/Go/lib3mf_dynamic.h +++ b/Autogenerated/Bindings/Go/lib3mf_dynamic.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Go/lib3mf_impl.go b/Autogenerated/Bindings/Go/lib3mf_impl.go index 8fc4c8d1c..f91e68c3b 100644 --- a/Autogenerated/Bindings/Go/lib3mf_impl.go +++ b/Autogenerated/Bindings/Go/lib3mf_impl.go @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated Go implementation file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/Go/lib3mf_types.h b/Autogenerated/Bindings/Go/lib3mf_types.h index a0c6149a6..6f2dcf6a4 100644 --- a/Autogenerated/Bindings/Go/lib3mf_types.h +++ b/Autogenerated/Bindings/Go/lib3mf_types.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file with basic types in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -85,7 +85,7 @@ typedef void * Lib3MF_pvoid; #define LIB3MF_VERSION_MAJOR 2 #define LIB3MF_VERSION_MINOR 3 -#define LIB3MF_VERSION_MICRO 1 +#define LIB3MF_VERSION_MICRO 2 #define LIB3MF_VERSION_PRERELEASEINFO "" #define LIB3MF_VERSION_BUILDINFO "" diff --git a/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.cc b/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.cc index 937582f41..e1cec341d 100644 --- a/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.cc +++ b/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.cc @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.h b/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.h index c524c7583..044c754bb 100644 --- a/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.h +++ b/Autogenerated/Bindings/NodeJS/lib3mf_dynamic.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/NodeJS/lib3mf_nodeaddon.cc b/Autogenerated/Bindings/NodeJS/lib3mf_nodeaddon.cc index 983c79636..96e56c3d9 100644 --- a/Autogenerated/Bindings/NodeJS/lib3mf_nodeaddon.cc +++ b/Autogenerated/Bindings/NodeJS/lib3mf_nodeaddon.cc @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ Implementation file for the Node addon class of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.cc b/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.cc index c4bedb2a2..36b978e15 100644 --- a/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.cc +++ b/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.cc @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ Implementation file for the Node wrapper class of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.h b/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.h index 66c489824..49ce0ade5 100644 --- a/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.h +++ b/Autogenerated/Bindings/NodeJS/lib3mf_nodewrapper.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ Header file for the Node wrapper class of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Bindings/NodeJS/lib3mf_types.h b/Autogenerated/Bindings/NodeJS/lib3mf_types.h index a0c6149a6..6f2dcf6a4 100644 --- a/Autogenerated/Bindings/NodeJS/lib3mf_types.h +++ b/Autogenerated/Bindings/NodeJS/lib3mf_types.h @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated plain C Header file with basic types in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -85,7 +85,7 @@ typedef void * Lib3MF_pvoid; #define LIB3MF_VERSION_MAJOR 2 #define LIB3MF_VERSION_MINOR 3 -#define LIB3MF_VERSION_MICRO 1 +#define LIB3MF_VERSION_MICRO 2 #define LIB3MF_VERSION_PRERELEASEINFO "" #define LIB3MF_VERSION_BUILDINFO "" diff --git a/Autogenerated/Bindings/Pascal/Unit_Lib3MF.pas b/Autogenerated/Bindings/Pascal/Unit_Lib3MF.pas index 6b5ff029d..8271fb01c 100644 --- a/Autogenerated/Bindings/Pascal/Unit_Lib3MF.pas +++ b/Autogenerated/Bindings/Pascal/Unit_Lib3MF.pas @@ -30,7 +30,7 @@ Abstract: This is an autogenerated Pascal Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 *) @@ -55,7 +55,7 @@ interface const LIB3MF_VERSION_MAJOR = 2; LIB3MF_VERSION_MINOR = 3; - LIB3MF_VERSION_MICRO = 1; + LIB3MF_VERSION_MICRO = 2; LIB3MF_VERSION_PRERELEASEINFO = ''; LIB3MF_VERSION_BUILDINFO = ''; diff --git a/Autogenerated/Bindings/Python/Lib3MF.py b/Autogenerated/Bindings/Python/Lib3MF.py index 54e233c8d..1b5e6d2fd 100644 --- a/Autogenerated/Bindings/Python/Lib3MF.py +++ b/Autogenerated/Bindings/Python/Lib3MF.py @@ -29,7 +29,7 @@ Abstract: This is an autogenerated Python file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 ''' @@ -58,7 +58,7 @@ def __str__(self): class BindingVersion(enum.IntEnum): MAJOR = 2 MINOR = 3 - MICRO = 1 + MICRO = 2 '''Definition Error Codes ''' diff --git a/Autogenerated/Source/lib3mf_abi.hpp b/Autogenerated/Source/lib3mf_abi.hpp index 864f8704d..44b8273b8 100644 --- a/Autogenerated/Source/lib3mf_abi.hpp +++ b/Autogenerated/Source/lib3mf_abi.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Source/lib3mf_interfaceexception.cpp b/Autogenerated/Source/lib3mf_interfaceexception.cpp index b484bd6a8..5f10f6f2f 100644 --- a/Autogenerated/Source/lib3mf_interfaceexception.cpp +++ b/Autogenerated/Source/lib3mf_interfaceexception.cpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ Implementation file with the basic internal exception type in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Source/lib3mf_interfaceexception.hpp b/Autogenerated/Source/lib3mf_interfaceexception.hpp index 1df317ec2..38891fe7e 100644 --- a/Autogenerated/Source/lib3mf_interfaceexception.hpp +++ b/Autogenerated/Source/lib3mf_interfaceexception.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ Header file with the basic internal exception type in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Source/lib3mf_interfacejournal.cpp b/Autogenerated/Source/lib3mf_interfacejournal.cpp index 106908b7f..5a94fcddf 100644 --- a/Autogenerated/Source/lib3mf_interfacejournal.cpp +++ b/Autogenerated/Source/lib3mf_interfacejournal.cpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ implementation file in order to allow easy development of the 3MF Library. It provides an automatic Journaling mechanism for the library implementation. -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -286,7 +286,7 @@ CLib3MFInterfaceJournal::CLib3MFInterfaceJournal (const std::string & sFileName) m_StartTime = std::chrono::high_resolution_clock::now(); m_Stream.open (sFileName, std::ios::out); m_Stream << "\n"; - m_Stream << "\n"; + m_Stream << "\n"; m_Stream << "\n"; } diff --git a/Autogenerated/Source/lib3mf_interfacejournal.hpp b/Autogenerated/Source/lib3mf_interfacejournal.hpp index f12f333d1..361b67bc0 100644 --- a/Autogenerated/Source/lib3mf_interfacejournal.hpp +++ b/Autogenerated/Source/lib3mf_interfacejournal.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ header file in order to allow easy development of the 3MF Library. It provides an automatic Journaling mechanism for the library implementation. -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Source/lib3mf_interfaces.hpp b/Autogenerated/Source/lib3mf_interfaces.hpp index 9a479767f..906ffae2d 100644 --- a/Autogenerated/Source/lib3mf_interfaces.hpp +++ b/Autogenerated/Source/lib3mf_interfaces.hpp @@ -30,7 +30,7 @@ Abstract: This is an autogenerated C++ header file in order to allow easy development of the 3MF Library. The implementer of the 3MF Library needs to derive concrete classes from the abstract classes in this header. -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Source/lib3mf_interfacewrapper.cpp b/Autogenerated/Source/lib3mf_interfacewrapper.cpp index 8eddf9ce8..92633dbbd 100644 --- a/Autogenerated/Source/lib3mf_interfacewrapper.cpp +++ b/Autogenerated/Source/lib3mf_interfacewrapper.cpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ implementation file in order to allow easy development of the 3MF Library. The functions in this file need to be implemented. It needs to be generated only once. -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Autogenerated/Source/lib3mf_types.hpp b/Autogenerated/Source/lib3mf_types.hpp index bc584e7b5..705f02718 100644 --- a/Autogenerated/Source/lib3mf_types.hpp +++ b/Autogenerated/Source/lib3mf_types.hpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++-Header file with basic types in order to allow an easy use of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ @@ -84,7 +84,7 @@ typedef void * Lib3MF_pvoid; #define LIB3MF_VERSION_MAJOR 2 #define LIB3MF_VERSION_MINOR 3 -#define LIB3MF_VERSION_MICRO 1 +#define LIB3MF_VERSION_MICRO 2 #define LIB3MF_VERSION_PRERELEASEINFO "" #define LIB3MF_VERSION_BUILDINFO "" diff --git a/AutomaticComponentToolkit/lib3mf.xml b/AutomaticComponentToolkit/lib3mf.xml index 273d1792f..078cdc4b4 100644 --- a/AutomaticComponentToolkit/lib3mf.xml +++ b/AutomaticComponentToolkit/lib3mf.xml @@ -1,5 +1,5 @@ - + diff --git a/CI/Dockerfile b/CI/Dockerfile index 846332f66..efedb0943 100644 --- a/CI/Dockerfile +++ b/CI/Dockerfile @@ -14,6 +14,7 @@ RUN \ tar \ gzip \ zip \ + rpm-build \ ${GCCTOOLSET} \ && microdnf clean all @@ -53,14 +54,28 @@ RUN cmake --build . RUN ctest -V . +# Add this line to generate a ZIP package with cpack +RUN cpack -G ZIP -C Release + +# Generate a debian package +RUN cpack -G DEB -C Release + +# Generate a RPM package +RUN cpack -G RPM -C Release + WORKDIR "/../../" RUN mkdir -p out RUN cp ./lib3mf-repo/build/lib3mf.so.2 ./out/ -RUN cd out && zip -r ../out.zip . +RUN cp ./lib3mf-repo/build/lib3mf-*-Linux.zip ./out/ +RUN cp ./lib3mf-repo/build/lib3mf-*-Linux.deb ./out/ + +RUN cp ./lib3mf-repo/build/lib3mf-*-Linux.rpm ./out/ + +RUN cd out && zip -r ../out.zip . diff --git a/CI/ci_cd_helper.py b/CI/ci_cd_helper.py new file mode 100644 index 000000000..675880103 --- /dev/null +++ b/CI/ci_cd_helper.py @@ -0,0 +1,106 @@ +import argparse +import urllib.request +import json +import os +import re + +def extract_version_from_cmake(): + cmake_file = 'CMakeLists.txt' + + if not os.path.exists(cmake_file): + raise FileNotFoundError(f"{cmake_file} not found in the current directory") + + with open(cmake_file, 'r') as file: + content = file.read() + + major = re.search(r'set\(LIB3MF_VERSION_MAJOR\s+([0-9]+)\)', content) + minor = re.search(r'set\(LIB3MF_VERSION_MINOR\s+([0-9]+)\)', content) + micro = re.search(r'set\(LIB3MF_VERSION_MICRO\s+([0-9]+)\)', content) + prerelease = re.search(r'set\(LIB3MF_VERSION_PRERELEASE\s+"([^"]*)"\)', content) + + if not major or not minor or not micro: + raise ValueError("Could not find version components in CMakeLists.txt") + + version = f"{major.group(1)}.{minor.group(1)}.{micro.group(1)}" + if prerelease and prerelease.group(1): + version += f"-{prerelease.group(1)}" + + return version + +def get_integration_sdk_url(index): + url = "https://api.github.com/repos/3MFConsortium/test_suites/releases" + + try: + with urllib.request.urlopen(url) as response: + data = response.read().decode('utf-8') + + releases = json.loads(data) + selected_release = releases[index] # Select the release by index + for asset in selected_release['assets']: + asset_name = str(asset['name']) + if asset_name.startswith("3MF_Conformance_Test_Suites") and asset_name.endswith(".zip"): + return asset['browser_download_url'] + return None + except Exception as e: + print(f"Error fetching the SDK URL: {e}") + return None + +def get_sdk_url(index): + url = "https://api.github.com/repos/3MFConsortium/lib3mf/releases" + + try: + with urllib.request.urlopen(url) as response: + data = response.read().decode('utf-8') + + releases = json.loads(data) + selected_release = releases[index] # Select the release by index + for asset in selected_release['assets']: + asset_name = str(asset['name']) + if asset_name.startswith("lib3mf_sdk") and asset_name.endswith(".zip"): + return asset['browser_download_url'] + return None + except Exception as e: + print(f"Error fetching the SDK URL: {e}") + return None + +def main(): + parser = argparse.ArgumentParser(description="Multi-utility script for CI/CD.") + + subparsers = parser.add_subparsers(dest='command') + + # Subparser for the fetch-integration-test-sdk-url command + parser_fetch_sdk_url = subparsers.add_parser('fetch-integration-test-sdk-url', help='Fetch the SDK URL for a specific integration test release index.') + parser_fetch_sdk_url.add_argument('index', type=int, help='Index of the release (0 for latest, 1 for second latest, etc.)') + + # Subparser for the fetch-sdk-url command + parser_fetch_sdk_url = subparsers.add_parser('fetch-sdk-url', help='Fetch the SDK URL for a specific release index.') + parser_fetch_sdk_url.add_argument('index', type=int, help='Index of the release (0 for latest, 1 for second latest, etc.)') + + # Subparser for the extract-version command + parser_extract_version = subparsers.add_parser('extract-version', help='Extract the version from CMakeLists.txt.') + + args = parser.parse_args() + + if args.command == 'fetch-sdk-url': + url = get_sdk_url(args.index) + if url: + print(url) + else: + print("FAIL") + elif args.command == 'fetch-integration-test-sdk-url': + url = get_integration_sdk_url(args.index) + if url: + print(url) + else: + print("FAIL") + elif args.command == 'extract-version': + try: + version = extract_version_from_cmake() + print(version) + except Exception as e: + print("FAIL") + else: + parser.print_help() + +if __name__ == "__main__": + main() diff --git a/CI/integration_test.py b/CI/integration_test.py new file mode 100644 index 000000000..dbfb7bb3f --- /dev/null +++ b/CI/integration_test.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +""" +@original author: weismam + +lib3mf_integration: + tests whether a large number of 3MF files is parsed correctly by lib3MF / + the Example_ExtractInfo from the SDK + +""" + +import datetime, time +import subprocess +import os + + +def listFiles(root, extension): + lFiles = [] + for path, _, files in os.walk(root): + for name in files: + [_, fileextension] = os.path.splitext(name) + if extension == fileextension: + lFiles.append(os.path.join(path, name)) + return lFiles + + +# returns a list of files of the following pattern: $root/{*}/$inbetweenFolder/{*}/*.$extension +def listFilesIn(root, inbetweenFolder, extension): + lFiles = [] + for path, subdirs, _ in os.walk(root): + for subdir in subdirs: + if subdir == inbetweenFolder: + lFiles += listFiles(os.path.join(path, subdir), extension) + lFiles = list(set(lFiles)) + lFiles.sort() + return lFiles + + +def ExtractInfo(execCommand, fileName): + tStart = time.time() + proc = subprocess.Popen([execCommand, fileName], stdout=subprocess.PIPE) + pOut = "" + errLines = [] + for line in proc.stdout: + utf8line = line.decode("utf-8") + if "error" in utf8line: + errLines.append(utf8line) + if "warning" in utf8line: + errLines.append(utf8line) + pOut += utf8line + + proc.wait() + info = dict.fromkeys({'success', 'time', 'stdout'}) + info['time'] = time.time() - tStart + info['returncode'] = proc.returncode + info['success'] = len(errLines) == 0 + info['errLines'] = errLines + info['stdout'] = str(pOut) + return info + + +if __name__ == "__main__": + tStart = datetime.datetime.now() + + root = os.path.dirname(os.path.realpath(__file__)) + + execCommand = os.path.join(root, "Example_ExtractInfo") + + print("Execute once for testing") + os.system(execCommand) + print("Execution done") + + positives = [] + negatives = [] + + for suite in os.listdir(root): + suite_path = os.path.join(root, suite) + if os.path.isdir(suite_path) and suite.startswith("suite"): + positives += listFilesIn(suite_path, "positive_test_cases", ".3mf") + negatives += listFilesIn(suite_path, "negative_test_cases", ".3mf") + + nPos = len(positives) + nNeg = len(negatives) + nFiles = nPos + nNeg + + print(execCommand) + + brokenPositives = [] + iFile = 0 + for fileName in positives: + iFile += 1 + print("{:3.0f}%: {:s}".format(100 * (iFile / nFiles), fileName), flush=True) + info = ExtractInfo(execCommand, fileName) + if not info['returncode'] == 0: + print("Fatal Error: MUSTPASS file \"{:s}\" does not work with returncode {:d}:".format(fileName, + info['returncode'])) + brokenPositives.append(info) + if not info['success']: + print("Error: MUSTPASS file \"{:s}\" does not work:".format(fileName)) + print('Contains {:d} problem{:s}:'.format(len(info['errLines']), ['s', ''][len(info['errLines']) == 0])) + for errLine in info['errLines']: + print(errLine, end='') + print('=== Output === ') + print(info['stdout']) + print('=== /Output === ') + brokenPositives.append(info) + + runningNegatives = [] + for fileName in negatives: + iFile += 1 + print("{:3.0f}%: {:s}".format(100 * (iFile / nFiles), fileName), flush=True) + info = ExtractInfo(execCommand, fileName) + if not info['returncode'] >= 0: + print("Fatal Error: MUSTFAIL file \"{:s}\" does not work with returncode {:d}:".format(fileName, + info['returncode'])) + if info['success'] and info['returncode'] == 0: + print("Error: MUSTFAIL file \"{:s}\" works".format(fileName)) + runningNegatives.append(info) + + duration = datetime.datetime.now() - tStart + print("Tested a total of {:d} = ({:d} positive + {:d} negative) files in {:s}.".format( + nFiles, nPos, nNeg, str(duration).split('.')[0])) + + if nPos > 0: + print(" {:3d} / {:3d} MUSTPASS files passed ({:6.2f}%)".format(nPos - len(brokenPositives), nPos, + 100 * (1 - len(brokenPositives) / nPos))) + if len(negatives) > 0: + print(" {:3d} / {:3d} MUSTFAIL files failed ({:6.2f}%)".format(nNeg - len(runningNegatives), nNeg, + 100 * (1 - len(runningNegatives) / nNeg))) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30a31120a..aaca07d2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required (VERSION 3.0) cmake_policy(SET CMP0054 NEW) cmake_policy(SET CMP0048 NEW) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) include(GNUInstallDirs) @@ -10,9 +11,9 @@ include(GNUInstallDirs) # Define Version set(LIB3MF_VERSION_MAJOR 2) # increase on every backward-compatibility breaking change of the API set(LIB3MF_VERSION_MINOR 3) # increase on every backward compatible change of the API -set(LIB3MF_VERSION_MICRO 1) # increase on on every change that does not alter the API +set(LIB3MF_VERSION_MICRO 2) # increase on on every change that does not alter the API set(LIB3MF_VERSION_PRERELEASE "") # denotes pre-release information of a version of lib3mf - +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") project(lib3mf VERSION ${LIB3MF_VERSION_MAJOR}.${LIB3MF_VERSION_MINOR}.${LIB3MF_VERSION_MICRO} DESCRIPTION "An implementation of the 3D Manufacturing Format file standard" @@ -46,10 +47,10 @@ if (${MSVC}) # using Visual Studio C++ # this ensures that the min/max macros of minwindef.h are not used - add_definitions(-DNOMINMAX /W3) + add_definitions(-DNOMINMAX) + + #add_definitions(/W3) - add_definitions(/W3) - # add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS) # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") # set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") @@ -131,6 +132,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/I target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Include) if (USE_INCLUDED_LIBZIP) + # Something goes here to check if submodules exist and initialize the submodules if it does not target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/libzip/Include) if(MSVC) target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) @@ -226,6 +228,8 @@ endif(WIN32) configure_file(lib3mf.pc.in lib3mf.pc @ONLY) install(FILES ${CMAKE_BINARY_DIR}/lib3mf.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +install(FILES cmake/lib3mfConfig.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/lib3mf) install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" @@ -237,10 +241,6 @@ option(LIB3MF_TESTS "Switch whether the tests of lib3mf should be build" ON) message("LIB3MF_TESTS ... " ${LIB3MF_TESTS}) if(LIB3MF_TESTS) - if(APPLE) - # libressl only compiles on arm64 - SET(CMAKE_OSX_ARCHITECTURES "x86_64") - endif() enable_testing() add_subdirectory(Tests) endif() @@ -253,3 +253,21 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${STARTUPPROJECT}) ENDIF() endif() + + +######################################################### +set(CPACK_PACKAGE_NAME "lib3mf") +set(CPACK_PACKAGE_VENDOR "3MF Consortium") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "lib3mf - An implementation of the 3D Manufacturing Format file standard") +set(CPACK_PACKAGE_VERSION "${LIB3MF_VERSION_MAJOR}.${LIB3MF_VERSION_MINOR}.${LIB3MF_VERSION_MICRO}") +set(CPACK_PACKAGE_VERSION_MAJOR "${LIB3MF_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${LIB3MF_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${LIB3MF_VERSION_MICRO}") +set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") +set(CPACK_PACKAGE_CONTACT "lib3mf@3mf.io") +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "3MF Consortium") +set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}") +set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-Source") + +######################################################### +include(CPack) diff --git a/Documentation/conf.py b/Documentation/conf.py index 3b05e0b61..70c28f068 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -22,7 +22,7 @@ author = '3MF Consortium' # The full version, including alpha/beta/rc tags -release = 'v2.3.1' +release = 'v2.3.2' master_doc = 'index' diff --git a/Documentation/index.rst b/Documentation/index.rst index ad31b3b56..4eb80031d 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -1,7 +1,7 @@ .. lib3mf documentation master file ********************************************* -lib3mf v2.3.1 documentation +lib3mf v2.3.2 documentation ********************************************* .. image:: https://github.com/3MFConsortium/lib3mf/workflows/Build/badge.svg?branch=master @@ -12,7 +12,7 @@ lib3mf v2.3.1 documentation :target: https://readthedocs.org/projects/lib3mf/ :alt: Documentation Status -.. image:: https://img.shields.io/static/v1.svg?label=lib3mf&message=v2.3.1&color=green +.. image:: https://img.shields.io/static/v1.svg?label=lib3mf&message=v2.3.2&color=green :alt: Version .. image:: https://img.shields.io/static/v1.svg?label=platform&message=windows%20%7C%20macos%20%7C%20linux&color=lightgrey @@ -27,7 +27,7 @@ lib3mf v2.3.1 documentation :language: bash -Welcome! This is the documentation for lib3mf v2.3.1. +Welcome! This is the documentation for lib3mf v2.3.2. lib3mf is an implementation of the 3D Manufacturing Format file standard. diff --git a/Include/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.h b/Include/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.h index 6a6954ba5..74a5b832d 100644 --- a/Include/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.h +++ b/Include/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.h @@ -84,7 +84,7 @@ namespace NMR { nfUint32 m_nBallRefBufferPos; private: const int m_nPosAfterDecPoint; - const int m_nPutDoubleFactor; + const nfInt64 m_nPutDoubleFactor; __NMR_INLINE void putFloat(_In_ const nfFloat fValue, _In_ std::array & line, _In_ nfUint32 & nBufferPos); __NMR_INLINE void putDouble(_In_ const nfDouble dValue, _In_ std::array & line, _In_ nfUint32 & nBufferPos); diff --git a/Libraries/zlib/Include/deflate.h b/Libraries/zlib/Include/deflate.h index 869679142..300c6ada6 100644 --- a/Libraries/zlib/Include/deflate.h +++ b/Libraries/zlib/Include/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2018 Jean-loup Gailly + * Copyright (C) 1995-2024 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -23,6 +23,10 @@ # define GZIP #endif +/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at + the cost of a larger memory footprint */ +/* #define LIT_MEM */ + /* =========================================================================== * Internal compression state. */ @@ -217,7 +221,14 @@ typedef struct internal_state { /* Depth of each subtree used as tie breaker for trees of equal frequency */ +#ifdef LIT_MEM +# define LIT_BUFS 5 + ushf *d_buf; /* buffer for distances */ + uchf *l_buf; /* buffer for literals/lengths */ +#else +# define LIT_BUFS 4 uchf *sym_buf; /* buffer for distances and literals/lengths */ +#endif uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for @@ -239,7 +250,7 @@ typedef struct internal_state { * - I can't count above 4 */ - uInt sym_next; /* running index in sym_buf */ + uInt sym_next; /* running index in symbol buffer */ uInt sym_end; /* symbol table full when sym_next reaches this */ ulg opt_len; /* bit length of current block with optimal trees */ @@ -318,6 +329,25 @@ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, extern const uch ZLIB_INTERNAL _dist_code[]; #endif +#ifdef LIT_MEM +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->sym_next] = 0; \ + s->l_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->d_buf[s->sym_next] = dist; \ + s->l_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#else # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->sym_buf[s->sym_next++] = 0; \ @@ -337,6 +367,7 @@ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->sym_next == s->sym_end); \ } +#endif #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ diff --git a/Libraries/zlib/Include/gzguts.h b/Libraries/zlib/Include/gzguts.h index f9375047e..eba72085b 100644 --- a/Libraries/zlib/Include/gzguts.h +++ b/Libraries/zlib/Include/gzguts.h @@ -1,5 +1,5 @@ /* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004-2019 Mark Adler + * Copyright (C) 2004-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -210,9 +210,5 @@ char ZLIB_INTERNAL *gz_strwinerror(DWORD error); /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ -#ifdef INT_MAX -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) -#else unsigned ZLIB_INTERNAL gz_intmax(void); -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) -#endif +#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) diff --git a/Libraries/zlib/Include/inftrees.h b/Libraries/zlib/Include/inftrees.h index a10712d8c..396f74b5d 100644 --- a/Libraries/zlib/Include/inftrees.h +++ b/Libraries/zlib/Include/inftrees.h @@ -41,8 +41,8 @@ typedef struct { examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes - returns returns 852, and "enough 30 6 15" for distance codes returns 592. - The initial root table size (9 or 6) is found in the fifth argument of the + returns 852, and "enough 30 6 15" for distance codes returns 592. The + initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ diff --git a/Libraries/zlib/Include/zconf.h b/Libraries/zlib/Include/zconf.h index fb76ffe31..62adc8d84 100644 --- a/Libraries/zlib/Include/zconf.h +++ b/Libraries/zlib/Include/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -300,14 +300,6 @@ # endif #endif -#ifndef Z_ARG /* function prototypes for stdarg */ -# if defined(STDC) || defined(Z_HAVE_STDARG_H) -# define Z_ARG(args) args -# else -# define Z_ARG(args) () -# endif -#endif - /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have diff --git a/Libraries/zlib/Include/zlib.h b/Libraries/zlib/Include/zlib.h index 6b7244f99..8d4b932ea 100644 --- a/Libraries/zlib/Include/zlib.h +++ b/Libraries/zlib/Include/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.3, August 18th, 2023 + version 1.3.1, January 22nd, 2024 - Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.3" -#define ZLIB_VERNUM 0x1300 +#define ZLIB_VERSION "1.3.1" +#define ZLIB_VERNUM 0x1310 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 3 -#define ZLIB_VER_REVISION 0 +#define ZLIB_VER_REVISION 1 #define ZLIB_VER_SUBREVISION 0 /* @@ -936,10 +936,10 @@ ZEXTERN int ZEXPORT inflateSync(z_streamp strm); inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. - In the success case, the application may save the current current value of - total_in which indicates where valid compressed data was found. In the - error case, the application may repeatedly call inflateSync, providing more - input each time, until success or end of the input data. + In the success case, the application may save the current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, @@ -1758,14 +1758,14 @@ ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. + len2. len2 must be non-negative. */ /* ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); Return the operator corresponding to length len2, to be used with - crc32_combine_op(). + crc32_combine_op(). len2 must be non-negative. */ ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); diff --git a/Libraries/zlib/Include/zutil.h b/Libraries/zlib/Include/zutil.h index 902a304cc..48dd7feba 100644 --- a/Libraries/zlib/Include/zutil.h +++ b/Libraries/zlib/Include/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -56,7 +56,7 @@ typedef unsigned long ulg; extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] +#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) @@ -137,17 +137,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif #endif -#if defined(MACOS) || defined(TARGET_OS_MAC) +#if defined(MACOS) # define OS_CODE 7 -# ifndef Z_SOLO -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -# endif #endif #ifdef __acorn @@ -170,18 +161,6 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define OS_CODE 19 #endif -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 diff --git a/Libraries/zlib/Source/deflate.c b/Libraries/zlib/Source/deflate.c index bd0117519..012ea8148 100644 --- a/Libraries/zlib/Source/deflate.c +++ b/Libraries/zlib/Source/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler "; + " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -493,7 +493,7 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, * symbols from which it is being constructed. */ - s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4); + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS); s->pending_buf_size = (ulg)s->lit_bufsize * 4; if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || @@ -503,8 +503,14 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, deflateEnd (strm); return Z_MEM_ERROR; } +#ifdef LIT_MEM + s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1)); + s->l_buf = s->pending_buf + (s->lit_bufsize << 2); + s->sym_end = s->lit_bufsize - 1; +#else s->sym_buf = s->pending_buf + s->lit_bufsize; s->sym_end = (s->lit_bufsize - 1) * 3; +#endif /* We avoid equality with lit_bufsize*3 because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. @@ -720,9 +726,15 @@ int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; +#ifdef LIT_MEM + if (bits < 0 || bits > 16 || + (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#else if (bits < 0 || bits > 16 || s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; +#endif do { put = Buf_size - s->bi_valid; if (put > bits) @@ -1294,7 +1306,7 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS); if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { @@ -1305,10 +1317,15 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); +#ifdef LIT_MEM + ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1)); + ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); +#else ds->sym_buf = ds->pending_buf + ds->lit_bufsize; +#endif ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; @@ -1539,13 +1556,21 @@ local uInt longest_match(deflate_state *s, IPos cur_match) { */ local void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); + Bytef *back = s->window + (int)match, *here = s->window + start; + IPos len = length; + if (match == (IPos)-1) { + /* match starts one byte before the current window -- just compare the + subsequent length-1 bytes */ + back++; + here++; + len--; + } + if (zmemcmp(back, here, len) != EQUAL) { + fprintf(stderr, " start %u, match %d, length %d\n", + start, (int)match, length); do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); + fprintf(stderr, "(%02x %02x)", *back++, *here++); + } while (--len != 0); z_error("invalid match"); } if (z_verbose > 1) { diff --git a/Libraries/zlib/Source/gzlib.c b/Libraries/zlib/Source/gzlib.c index 29fc4486f..983153cc8 100644 --- a/Libraries/zlib/Source/gzlib.c +++ b/Libraries/zlib/Source/gzlib.c @@ -1,5 +1,5 @@ /* gzlib.c -- zlib functions common to reading and writing gzip files - * Copyright (C) 2004-2019 Mark Adler + * Copyright (C) 2004-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -563,20 +563,20 @@ void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) { #endif } -#ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax(void) { - unsigned p, q; - - p = 1; +#ifdef INT_MAX + return INT_MAX; +#else + unsigned p = 1, q; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; -} #endif +} diff --git a/Libraries/zlib/Source/inflate.c b/Libraries/zlib/Source/inflate.c index b0757a9b2..94ecff015 100644 --- a/Libraries/zlib/Source/inflate.c +++ b/Libraries/zlib/Source/inflate.c @@ -1387,7 +1387,7 @@ int ZEXPORT inflateSync(z_streamp strm) { /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; - state->hold <<= state->bits & 7; + state->hold >>= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { diff --git a/Libraries/zlib/Source/inftrees.c b/Libraries/zlib/Source/inftrees.c index 8a208c2da..98cfe1644 100644 --- a/Libraries/zlib/Source/inftrees.c +++ b/Libraries/zlib/Source/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2023 Mark Adler + * Copyright (C) 1995-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.3 Copyright 1995-2023 Mark Adler "; + " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -57,7 +57,7 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/Libraries/zlib/Source/trees.c b/Libraries/zlib/Source/trees.c index 8dbdc40ba..6a523ef34 100644 --- a/Libraries/zlib/Source/trees.c +++ b/Libraries/zlib/Source/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2021 Jean-loup Gailly + * Copyright (C) 1995-2024 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -899,14 +899,19 @@ local void compress_block(deflate_state *s, const ct_data *ltree, const ct_data *dtree) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ - unsigned sx = 0; /* running index in sym_buf */ + unsigned sx = 0; /* running index in symbol buffers */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->sym_next != 0) do { +#ifdef LIT_MEM + dist = s->d_buf[sx]; + lc = s->l_buf[sx++]; +#else dist = s->sym_buf[sx++] & 0xff; dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; lc = s->sym_buf[sx++]; +#endif if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); @@ -931,8 +936,12 @@ local void compress_block(deflate_state *s, const ct_data *ltree, } } /* literal or match pair ? */ - /* Check that the overlay between pending_buf and sym_buf is ok: */ + /* Check for no overlay of pending_buf on needed symbols */ +#ifdef LIT_MEM + Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow"); +#else Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); +#endif } while (sx < s->sym_next); @@ -1082,9 +1091,14 @@ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { +#ifdef LIT_MEM + s->d_buf[s->sym_next] = (ush)dist; + s->l_buf[s->sym_next++] = (uch)lc; +#else s->sym_buf[s->sym_next++] = (uch)dist; s->sym_buf[s->sym_next++] = (uch)(dist >> 8); s->sym_buf[s->sym_next++] = (uch)lc; +#endif if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; diff --git a/Libraries/zlib/zlib_v1.3.1^0.txt b/Libraries/zlib/zlib_v1.3.1^0.txt new file mode 100644 index 000000000..bd2d16a9b --- /dev/null +++ b/Libraries/zlib/zlib_v1.3.1^0.txt @@ -0,0 +1 @@ +"v1.3.1^0" diff --git a/Libraries/zlib/zlib_v1.3^0.txt b/Libraries/zlib/zlib_v1.3^0.txt deleted file mode 100644 index acd062169..000000000 --- a/Libraries/zlib/zlib_v1.3^0.txt +++ /dev/null @@ -1 +0,0 @@ -"v1.3^0" diff --git a/README.md b/README.md index 910d569a7..c0b164bcf 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # lib3mf -[![Build Status]](https://github.com/3MFConsortium/lib3mf/workflows/Build/badge.svg?branch=release%2F2.3.1) +[![Build Status]](https://github.com/3MFConsortium/lib3mf/workflows/Build/badge.svg?branch=release%2F2.3.2) [![Documentation Status](https://readthedocs.org/projects/lib3mf/badge/?version=master)](https://readthedocs.org/projects/lib3mf) -[![Version 2.3.1](https://img.shields.io/static/v1.svg?label=lib3mf&message=v2.3.1&color=green)]() +[![Version 2.3.2](https://img.shields.io/static/v1.svg?label=lib3mf&message=v2.3.2&color=green)]() [![Supported platforms](https://img.shields.io/static/v1.svg?label=platform&message=windows%20%7C%20macos%20%7C%20linux&color=lightgrey)]() [![Simplified BSD License](https://img.shields.io/static/v1.svg?label=license&message=BSD&color=green)](LICENSE) [![codecov](https://codecov.io/gh/3MFConsortium/lib3mf/branch/develop/graph/badge.svg?token=3ARnBye33c)](https://codecov.io/gh/3MFConsortium/lib3mf) @@ -43,7 +43,7 @@ This page also contains a section about building lib3mf from source or obtaining ## Licenses and third party code lib3mf is released under the [BSD license](LICENSE). The library contains code of the following [third parties](SDK/Credits.txt): 1. libzip 1.10.1, https://libzip.org/license/ -2. zlib 1.3.0, http://www.zlib.net/zlib_license.html +2. zlib 1.3.1, http://www.zlib.net/zlib_license.html 3. cpp-base64 2.rc.08, https://github.com/ReneNyffenegger/cpp-base64/blob/master/LICENSE 4. fast-float v6.0.0, https://github.com/fastfloat/fast_float/tree/v6.0.0?tab=License-3-ov-file diff --git a/SDK/.gitignore b/SDK/.gitignore index cfab9db9a..ffe319c10 100644 --- a/SDK/.gitignore +++ b/SDK/.gitignore @@ -5,3 +5,5 @@ Bin Bindings Examples/*/*.dll Examples/*/*.stl +.idea +cmake-build-* \ No newline at end of file diff --git a/SDK/CPackExamples/Cpp/CMakeLists.txt b/SDK/CPackExamples/Cpp/CMakeLists.txt new file mode 100644 index 000000000..64e493284 --- /dev/null +++ b/SDK/CPackExamples/Cpp/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required (VERSION 3.5) +project(Examples) +set(CMAKE_CXX_STANDARD 11) + +# Determine the platform and set lib3mf_DIR accordingly +if(WIN32) + # Path for Windows + set(lib3mf_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib3mf-2.3.2-Windows/lib/cmake/lib3mf") + find_package(lib3mf REQUIRED COMPONENTS Cpp) +elseif(APPLE) + # Path for macOS (Darwin) + set(lib3mf_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib3mf-2.3.2-Darwin/lib/cmake/lib3mf") + find_package(lib3mf REQUIRED COMPONENTS Cpp) +else() + # Path for Linux (Here we check twice to test for Debian / RPM packages properly) + find_package(lib3mf QUIET COMPONENTS Cpp) + # Check if the package was not found + if(NOT lib3mf_FOUND) + # lib3mf not found, so set lib3mf_DIR to the fallback directory + set(lib3mf_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib3mf-2.3.2-Linux/lib/cmake/lib3mf") + # Find package (lib3mf) + find_package(lib3mf REQUIRED COMPONENTS Cpp) + endif() +endif() + +add_definitions(-DTEXTURESPATH="${CMAKE_CURRENT_SOURCE_DIR}/../Files/Textures/") + +add_executable(Example_ColorCube Source/ColorCube.cpp) +target_link_libraries(Example_ColorCube lib3mf::lib3mf) +copy_lib3mf_libraries(Example_ColorCube) + +add_executable(Example_Components Source/Components.cpp) +target_link_libraries(Example_Components lib3mf::lib3mf) +copy_lib3mf_libraries(Example_Components) + +add_executable(Example_Converter Source/Converter.cpp) +target_link_libraries(Example_Converter lib3mf::lib3mf) +copy_lib3mf_libraries(Example_Converter) + +add_executable(Example_Cube Source/Cube.cpp) +target_link_libraries(Example_Cube lib3mf::lib3mf) +copy_lib3mf_libraries(Example_Cube) + +add_executable(Example_SecureCube Source/SecureCube.cpp) +target_link_libraries(Example_SecureCube lib3mf::lib3mf) +copy_lib3mf_libraries(Example_SecureCube) + +add_executable(Example_ExtractInfo Source/ExtractInfo.cpp) +target_link_libraries(Example_ExtractInfo lib3mf::lib3mf) +copy_lib3mf_libraries(Example_ExtractInfo) + +add_executable(Example_TextureCube Source/TextureCube.cpp) +target_link_libraries(Example_TextureCube lib3mf::lib3mf) +copy_lib3mf_libraries(Example_TextureCube) + +add_executable(Example_Slice Source/Slice.cpp) +target_link_libraries(Example_Slice lib3mf::lib3mf) +copy_lib3mf_libraries(Example_Slice) + +add_executable(Example_BeamLattice Source/BeamLattice.cpp) +target_link_libraries(Example_BeamLattice lib3mf::lib3mf) +copy_lib3mf_libraries(Example_BeamLattice) + +if (${MSVC}) + IF(${CMAKE_VERSION} VERSION_LESS 3.6.3) + MESSAGE ("Note: You need to manually select a StartUp-project in Visual Studio.") + ELSE() + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Example_Cube) + ENDIF() +endif() diff --git a/SDK/CPackExamples/Cpp/GenerateMake.sh b/SDK/CPackExamples/Cpp/GenerateMake.sh new file mode 100644 index 000000000..16fe9cf2b --- /dev/null +++ b/SDK/CPackExamples/Cpp/GenerateMake.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +basepath="$(cd "$(dirname "$0")" && pwd)" +builddir="$basepath/build" +mkdir -p $builddir +cd $builddir +cmake .. -G "Unix Makefiles" "$@" \ No newline at end of file diff --git a/SDK/CPackExamples/Cpp/GenerateVS2015.bat b/SDK/CPackExamples/Cpp/GenerateVS2015.bat new file mode 100644 index 000000000..e6933cdeb --- /dev/null +++ b/SDK/CPackExamples/Cpp/GenerateVS2015.bat @@ -0,0 +1,10 @@ +@echo off +set startingDir=%CD% + +set basepath=%~dp0 +set builddir=%basepath%\build +if not exist %builddir% (mkdir %builddir%) +cd %builddir% +cmake -G "Visual Studio 14 2015 Win64" .. %* + +cd %startingDir% diff --git a/SDK/CPackExamples/Cpp/GenerateVS2017.bat b/SDK/CPackExamples/Cpp/GenerateVS2017.bat new file mode 100644 index 000000000..4014d2f99 --- /dev/null +++ b/SDK/CPackExamples/Cpp/GenerateVS2017.bat @@ -0,0 +1,10 @@ +@echo off +set startingDir=%CD% + +set basepath=%~dp0 +set builddir=%basepath%\build +if not exist %builddir% (mkdir %builddir%) +cd %builddir% +cmake -G "Visual Studio 15 2017 Win64" .. %* + +cd %startingDir% diff --git a/SDK/CPackExamples/Cpp/GenerateVS2019.bat b/SDK/CPackExamples/Cpp/GenerateVS2019.bat new file mode 100644 index 000000000..efa4f308f --- /dev/null +++ b/SDK/CPackExamples/Cpp/GenerateVS2019.bat @@ -0,0 +1,10 @@ +@echo off +set startingDir=%CD% + +set basepath=%~dp0 +set builddir=%basepath%\build +if not exist %builddir% (mkdir %builddir%) +cd %builddir% +cmake -G "Visual Studio 16 2019" .. %* + +cd %startingDir% diff --git a/SDK/CPackExamples/Cpp/Source/BeamLattice.cpp b/SDK/CPackExamples/Cpp/Source/BeamLattice.cpp new file mode 100644 index 000000000..c1509cc88 --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/BeamLattice.cpp @@ -0,0 +1,159 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +BeamLattice.cpp : 3MF beamlattice creation example + +--*/ + +#include +#include +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +// Utility functions to create vertices and beams +sLib3MFPosition fnCreateVertex(float x, float y, float z) +{ + sLib3MFPosition result; + result.m_Coordinates[0] = x; + result.m_Coordinates[1] = y; + result.m_Coordinates[2] = z; + return result; +} + +sLib3MFBeam fnCreateBeam(int v0, int v1, double r0, double r1, eLib3MFBeamLatticeCapMode c0, eLib3MFBeamLatticeCapMode c1) +{ + sLib3MFBeam result; + result.m_Indices[0] = v0; + result.m_Indices[1] = v1; + result.m_Radii[0] = r0; + result.m_Radii[1] = r1; + result.m_CapModes[0] = c0; + result.m_CapModes[1] = c1; + return result; +} + + +void BeamLatticeExample() { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Beamlattice example" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + PMeshObject meshObject = model->AddMeshObject(); + meshObject->SetName("Beamlattice"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(0); + std::vector beams(12); + + float fSizeX = 100.0f; + float fSizeY = 200.0f; + float fSizeZ = 300.0f; + + // Manually create vertices + vertices[0] = fnCreateVertex(0.0f, 0.0f, 0.0f); + vertices[1] = fnCreateVertex(fSizeX, 0.0f, 0.0f); + vertices[2] = fnCreateVertex(fSizeX, fSizeY, 0.0f); + vertices[3] = fnCreateVertex(0.0f, fSizeY, 0.0f); + vertices[4] = fnCreateVertex(0.0f, 0.0f, fSizeZ); + vertices[5] = fnCreateVertex(fSizeX, 0.0f, fSizeZ); + vertices[6] = fnCreateVertex(fSizeX, fSizeY, fSizeZ); + vertices[7] = fnCreateVertex(0.0f, fSizeY, fSizeZ); + + // Manually create beams + double r0 = 1.0; + double r1 = 1.5; + double r2 = 2.0; + double r3 = 2.5; + beams[0] = fnCreateBeam(2, 1, r0, r0, eBeamLatticeCapMode::Butt, eBeamLatticeCapMode::Butt); + beams[1] = fnCreateBeam(0, 3, r0, r1, eBeamLatticeCapMode::Sphere, eBeamLatticeCapMode::Butt); + beams[2] = fnCreateBeam(4, 5, r0, r2, eBeamLatticeCapMode::Sphere, eBeamLatticeCapMode::Butt); + beams[3] = fnCreateBeam(6, 7, r0, r3, eBeamLatticeCapMode::HemiSphere, eBeamLatticeCapMode::Butt); + beams[4] = fnCreateBeam(0, 1, r1, r0, eBeamLatticeCapMode::HemiSphere, eBeamLatticeCapMode::Butt); + beams[5] = fnCreateBeam(5, 4, r1, r1, eBeamLatticeCapMode::Sphere, eBeamLatticeCapMode::HemiSphere); + beams[6] = fnCreateBeam(2, 3, r1, r2, eBeamLatticeCapMode::Sphere, eBeamLatticeCapMode::Sphere); + beams[7] = fnCreateBeam(7, 6, r1, r3, eBeamLatticeCapMode::Butt, eBeamLatticeCapMode::Butt); + beams[8] = fnCreateBeam(1, 2, r2, r2, eBeamLatticeCapMode::Butt, eBeamLatticeCapMode::Butt); + beams[9] = fnCreateBeam(6, 5, r2, r3, eBeamLatticeCapMode::HemiSphere, eBeamLatticeCapMode::Butt); + beams[10] = fnCreateBeam(3, 0, r3, r0, eBeamLatticeCapMode::Butt, eBeamLatticeCapMode::Sphere); + beams[11] = fnCreateBeam(4, 7, r3, r1, eBeamLatticeCapMode::HemiSphere, eBeamLatticeCapMode::HemiSphere); + meshObject->SetGeometry(vertices, triangles); + + // Set beamlattice geometry and metadata + PBeamLattice beamLattice = meshObject->BeamLattice(); + beamLattice->SetBeams(beams); + beamLattice->SetMinLength(0.005); + + PBeamSet set = beamLattice->AddBeamSet(); + set->SetName("Special Beams"); + set->SetIdentifier("bs1"); + std::vector references = { 2,0,5 }; + set->SetReferences(references); + + // Add build item + model->AddBuildItem(meshObject.get(), wrapper->GetIdentityTransform()); + + // Write file + PWriter writer = model->QueryWriter("3mf"); + writer->WriteToFile("beamlattice.3mf"); + + std::cout << "done" << std::endl; +} + +int main() { + try { + BeamLatticeExample(); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/CPackExamples/Cpp/Source/ColorCube.cpp b/SDK/CPackExamples/Cpp/Source/ColorCube.cpp new file mode 100644 index 000000000..f1c46baca --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/ColorCube.cpp @@ -0,0 +1,183 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +ColorCube.cpp : 3MF Color Cube creation example + +--*/ + +#include +#include +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +// Utility functions to create vertices and triangles +sLib3MFPosition fnCreateVertex(float x, float y, float z) +{ + sLib3MFPosition result; + result.m_Coordinates[0] = x; + result.m_Coordinates[1] = y; + result.m_Coordinates[2] = z; + return result; +} + +sLib3MFTriangle fnCreateTriangle(int v0, int v1, int v2) +{ + sLib3MFTriangle result; + result.m_Indices[0] = v0; + result.m_Indices[1] = v1; + result.m_Indices[2] = v2; + return result; +} + +sLib3MFTriangleProperties fnCreateTriangleColor(PColorGroup colorGroup, Lib3MF_uint32 colorID1, Lib3MF_uint32 colorID2, Lib3MF_uint32 colorID3) +{ + sLib3MFTriangleProperties sTriangleProperty; + sTriangleProperty.m_ResourceID = colorGroup->GetResourceID(); + sTriangleProperty.m_PropertyIDs[0] = colorID1; + sTriangleProperty.m_PropertyIDs[1] = colorID2; + sTriangleProperty.m_PropertyIDs[2] = colorID3; + return sTriangleProperty; +} + + +void CubeExample() { + PWrapper wrapper = wrapper->loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Color Cube example" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + PMeshObject meshObject = model->AddMeshObject(); + meshObject->SetName("Colored Box"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(12); + + float fSizeX = 100.0f; + float fSizeY = 200.0f; + float fSizeZ = 300.0f; + + // Manually create vertices + vertices[0] = fnCreateVertex(0.0f, 0.0f, 0.0f); + vertices[1] = fnCreateVertex(fSizeX, 0.0f, 0.0f); + vertices[2] = fnCreateVertex(fSizeX, fSizeY, 0.0f); + vertices[3] = fnCreateVertex(0.0f, fSizeY, 0.0f); + vertices[4] = fnCreateVertex(0.0f, 0.0f, fSizeZ); + vertices[5] = fnCreateVertex(fSizeX, 0.0f, fSizeZ); + vertices[6] = fnCreateVertex(fSizeX, fSizeY, fSizeZ); + vertices[7] = fnCreateVertex(0.0f, fSizeY, fSizeZ); + + // Manually create triangles + triangles[0] = fnCreateTriangle(2, 1, 0); + triangles[1] = fnCreateTriangle(0, 3, 2); + triangles[2] = fnCreateTriangle(4, 5, 6); + triangles[3] = fnCreateTriangle(6, 7, 4); + triangles[4] = fnCreateTriangle(0, 1, 5); + triangles[5] = fnCreateTriangle(5, 4, 0); + triangles[6] = fnCreateTriangle(2, 3, 7); + triangles[7] = fnCreateTriangle(7, 6, 2); + triangles[8] = fnCreateTriangle(1, 2, 6); + triangles[9] = fnCreateTriangle(6, 5, 1); + triangles[10] = fnCreateTriangle(3, 0, 4); + triangles[11] = fnCreateTriangle(4, 7, 3); + + meshObject->SetGeometry(vertices, triangles); + + // define colors + PColorGroup colorGroup = model->AddColorGroup(); + Lib3MF_uint32 idRed = colorGroup->AddColor(wrapper->RGBAToColor(255, 0, 0, 255)); + Lib3MF_uint32 idGreen = colorGroup->AddColor(wrapper->RGBAToColor(0, 255, 0, 255)); + Lib3MF_uint32 idBlue = colorGroup->AddColor(wrapper->RGBAToColor(0, 0, 255, 255)); + Lib3MF_uint32 idOrange = colorGroup->AddColor(wrapper->RGBAToColor(255, 128, 0, 255)); + Lib3MF_uint32 idYellow = colorGroup->AddColor(wrapper->RGBAToColor(255, 255, 0, 255)); + + sLib3MFTriangleProperties sTriangleColorRed = fnCreateTriangleColor(colorGroup, idRed, idRed, idRed); + sLib3MFTriangleProperties sTriangleColorGreen = fnCreateTriangleColor(colorGroup, idGreen, idGreen, idGreen); + sLib3MFTriangleProperties sTriangleColorBlue = fnCreateTriangleColor(colorGroup, idBlue, idBlue, idBlue); + + sLib3MFTriangleProperties sTriangleColor1 = fnCreateTriangleColor(colorGroup, idOrange, idRed, idYellow); + sLib3MFTriangleProperties sTriangleColor2 = fnCreateTriangleColor(colorGroup, idYellow, idGreen, idOrange); + + // One-colored Triangles + meshObject->SetTriangleProperties(0, sTriangleColorRed); + meshObject->SetTriangleProperties(1, sTriangleColorRed); + meshObject->SetTriangleProperties(2, sTriangleColorGreen); + meshObject->SetTriangleProperties(3, sTriangleColorGreen); + meshObject->SetTriangleProperties(4, sTriangleColorBlue); + meshObject->SetTriangleProperties(5, sTriangleColorBlue); + // Gradient-colored Triangles + meshObject->SetTriangleProperties(6, sTriangleColor1); + meshObject->SetTriangleProperties(7, sTriangleColor2); + meshObject->SetTriangleProperties(8, sTriangleColor1); + meshObject->SetTriangleProperties(9, sTriangleColor2); + meshObject->SetTriangleProperties(10, sTriangleColor1); + meshObject->SetTriangleProperties(11, sTriangleColor2); + + // Object Level Property + meshObject->SetObjectLevelProperty(sTriangleColorRed.m_ResourceID, sTriangleColorRed.m_PropertyIDs[0]); + + // Add build item + model->AddBuildItem(meshObject.get(), wrapper->GetIdentityTransform()); + + PWriter writer = model->QueryWriter("3mf"); + writer->WriteToFile("colorcube.3mf"); + + std::cout << "done" << std::endl; +} + +int main() { + try { + CubeExample(); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/CPackExamples/Cpp/Source/Components.cpp b/SDK/CPackExamples/Cpp/Source/Components.cpp new file mode 100644 index 000000000..f91499024 --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/Components.cpp @@ -0,0 +1,183 @@ + +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +Components.cpp : 3MF Components example + +--*/ + +#include +#include +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +// Utility functions to create vertices and triangles +sLib3MFPosition fnCreateVertex(float x, float y, float z) +{ + sLib3MFPosition result; + result.m_Coordinates[0] = x; + result.m_Coordinates[1] = y; + result.m_Coordinates[2] = z; + return result; +} + +sLib3MFTriangle fnCreateTriangle(int v0, int v1, int v2) +{ + sLib3MFTriangle result; + result.m_Indices[0] = v0; + result.m_Indices[1] = v1; + result.m_Indices[2] = v2; + return result; +} + +sLib3MFTransform createTranslationMatrix(float x, float y, float z) +{ + sLib3MFTransform mMatrix; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 3; j++) { + mMatrix.m_Fields[i][j] = (i == j) ? 1.0f : 0.0f; + } + } + + mMatrix.m_Fields[3][0] = x; + mMatrix.m_Fields[3][1] = y; + mMatrix.m_Fields[3][2] = z; + + return mMatrix; +} + + +void ComponentsExample() { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Components example" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + PMeshObject meshObject = model->AddMeshObject(); + meshObject->SetName("Box"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(12); + + float fSizeX = 10.0f; + float fSizeY = 20.0f; + float fSizeZ = 30.0f; + + // Manually create vertices + vertices[0] = fnCreateVertex(0.0f, 0.0f, 0.0f); + vertices[1] = fnCreateVertex(fSizeX, 0.0f, 0.0f); + vertices[2] = fnCreateVertex(fSizeX, fSizeY, 0.0f); + vertices[3] = fnCreateVertex(0.0f, fSizeY, 0.0f); + vertices[4] = fnCreateVertex(0.0f, 0.0f, fSizeZ); + vertices[5] = fnCreateVertex(fSizeX, 0.0f, fSizeZ); + vertices[6] = fnCreateVertex(fSizeX, fSizeY, fSizeZ); + vertices[7] = fnCreateVertex(0.0f, fSizeY, fSizeZ); + + // Manually create triangles + triangles[0] = fnCreateTriangle(2, 1, 0); + triangles[1] = fnCreateTriangle(0, 3, 2); + triangles[2] = fnCreateTriangle(4, 5, 6); + triangles[3] = fnCreateTriangle(6, 7, 4); + triangles[4] = fnCreateTriangle(0, 1, 5); + triangles[5] = fnCreateTriangle(5, 4, 0); + triangles[6] = fnCreateTriangle(2, 3, 7); + triangles[7] = fnCreateTriangle(7, 6, 2); + triangles[8] = fnCreateTriangle(1, 2, 6); + triangles[9] = fnCreateTriangle(6, 5, 1); + triangles[10] = fnCreateTriangle(3, 0, 4); + triangles[11] = fnCreateTriangle(4, 7, 3); + + meshObject->SetGeometry(vertices, triangles); + + // Create Component Object + PComponentsObject componentsObject = model->AddComponentsObject(); + + // Add first component + componentsObject->AddComponent(meshObject.get(), createTranslationMatrix(0.0f, 0.0f, 0.0f)); + + // Add second component + componentsObject->AddComponent(meshObject.get(), createTranslationMatrix(40.0f, 60.0f, 80.0f)); + + // Add third component + componentsObject->AddComponent(meshObject.get(), createTranslationMatrix(120.0f, 30.0f, 70.0f)); + + + // Add componentsobject as build item + model->AddBuildItem(componentsObject.get(), createTranslationMatrix(0.0f, 0.0f, 0.0f)); + + // Add translated componentsobject as build item + model->AddBuildItem(componentsObject.get(), createTranslationMatrix(200.0f, 40.0f, 10.0f)); + + // Add translated meshobject as build item + model->AddBuildItem(meshObject.get(), createTranslationMatrix(-40.0f, 0.0f, 20.0f)); + + // Output scene as STL and 3MF + PWriter _3mfWriter = model->QueryWriter("3mf"); + std::cout << "writing components.3mf..." << std::endl; + _3mfWriter->WriteToFile("components.3mf"); + + PWriter stlWriter = model->QueryWriter("stl"); + std::cout << "writing components.stl..." << std::endl; + stlWriter->WriteToFile("components.stl"); + + std::cout << "done" << std::endl; +} + +int main() { + try { + ComponentsExample(); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} + diff --git a/SDK/CPackExamples/Cpp/Source/Converter.cpp b/SDK/CPackExamples/Cpp/Source/Converter.cpp new file mode 100644 index 000000000..2fefdbc56 --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/Converter.cpp @@ -0,0 +1,154 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +Converter.cpp : Can convert 3MFs to STL and back + +--*/ + +#include +#include +#include + +#ifndef __GNUC__ +#include +#endif + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +std::string FindExtension(std::string filename) { + // this emulates Windows' PathFindExtension + std::string::size_type idx; + idx = filename.rfind('.'); + + if (idx != std::string::npos) + { + return filename.substr(idx); + } + else + { + return ""; + } +} + + +int convert(std::string sFilename) { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Model Converter" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + // Extract Extension of filename + std::string sReaderName; + std::string sWriterName; + std::string sNewExtension; + std::string sExtension = FindExtension(sFilename); + std::transform(sExtension.begin(), sExtension.end(), sExtension.begin(), ::tolower); + + // Which Reader and Writer classes do we need? + if (sExtension == ".stl") { + sReaderName = "stl"; + sWriterName = "3mf"; + sNewExtension = ".3mf"; + } + if (sExtension == ".3mf") { + sReaderName = "3mf"; + sWriterName = "stl"; + sNewExtension = ".stl"; + } + if (sReaderName.length() == 0) { + std::cout << "unknown input file extension:" << sExtension << std::endl; + return -1; + } + + // Create new filename + std::string sOutputFilename = sFilename; + sOutputFilename.erase(sOutputFilename.length() - sExtension.length()); + sOutputFilename += sNewExtension; + + PModel model = wrapper->CreateModel(); + PReader reader = model->QueryReader(sReaderName); + + // Import Model from File + std::cout << "reading " << sFilename << "..." << std::endl; +#ifndef __GNUC__ + ULONGLONG nStartTicks = GetTickCount64(); +#endif + reader->ReadFromFile(sFilename); +#ifndef __GNUC__ + std::cout << "elapsed time: " << (GetTickCount64() - nStartTicks) << "ms" << std::endl; +#endif + + PWriter writer = model->QueryWriter(sWriterName); + std::cout << "writing " << sOutputFilename << "..." << std::endl; +#ifndef __GNUC__ + nStartTicks = GetTickCount64(); +#endif + writer->WriteToFile(sOutputFilename); +#ifndef __GNUC__ + std::cout << "elapsed time: " << (GetTickCount64() - nStartTicks) << "ms" << std::endl; +#endif + std::cout << "done" << std::endl; + return 0; +} + +int main(int argc, char** argv) { + // Parse Arguments + if (argc != 2) { + std::cout << "Usage: " << std::endl; + std::cout << "Convert 3MF to STL: Converter.exe model.3mf" << std::endl; + std::cout << "Convert STL to 3MF: Converter.exe model.stl" << std::endl; + return 0; + } + + try { + return convert(argv[1]); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/CPackExamples/Cpp/Source/Cube.cpp b/SDK/CPackExamples/Cpp/Source/Cube.cpp new file mode 100644 index 000000000..18e99cb51 --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/Cube.cpp @@ -0,0 +1,140 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +Cube.cpp : 3MF Cube creation example + +--*/ + +#include +#include +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +// Utility functions to create vertices and triangles +sLib3MFPosition fnCreateVertex(float x, float y, float z) +{ + sLib3MFPosition result; + result.m_Coordinates[0] = x; + result.m_Coordinates[1] = y; + result.m_Coordinates[2] = z; + return result; +} + +sLib3MFTriangle fnCreateTriangle(int v0, int v1, int v2) +{ + sLib3MFTriangle result; + result.m_Indices[0] = v0; + result.m_Indices[1] = v1; + result.m_Indices[2] = v2; + return result; +} + + +void CubeExample() { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Cube example" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + PMeshObject meshObject = model->AddMeshObject(); + meshObject->SetName("Box"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(12); + + float fSizeX = 100.0f; + float fSizeY = 200.0f; + float fSizeZ = 300.0f; + + // Manually create vertices + vertices[0] = fnCreateVertex(0.0f, 0.0f, 0.0f); + vertices[1] = fnCreateVertex(fSizeX, 0.0f, 0.0f); + vertices[2] = fnCreateVertex(fSizeX, fSizeY, 0.0f); + vertices[3] = fnCreateVertex(0.0f, fSizeY, 0.0f); + vertices[4] = fnCreateVertex(0.0f, 0.0f, fSizeZ); + vertices[5] = fnCreateVertex(fSizeX, 0.0f, fSizeZ); + vertices[6] = fnCreateVertex(fSizeX, fSizeY, fSizeZ); + vertices[7] = fnCreateVertex(0.0f, fSizeY, fSizeZ); + + // Manually create triangles + triangles[0] = fnCreateTriangle(2, 1, 0); + triangles[1] = fnCreateTriangle(0, 3, 2); + triangles[2] = fnCreateTriangle(4, 5, 6); + triangles[3] = fnCreateTriangle(6, 7, 4); + triangles[4] = fnCreateTriangle(0, 1, 5); + triangles[5] = fnCreateTriangle(5, 4, 0); + triangles[6] = fnCreateTriangle(2, 3, 7); + triangles[7] = fnCreateTriangle(7, 6, 2); + triangles[8] = fnCreateTriangle(1, 2, 6); + triangles[9] = fnCreateTriangle(6, 5, 1); + triangles[10] = fnCreateTriangle(3, 0, 4); + triangles[11] = fnCreateTriangle(4, 7, 3); + + meshObject->SetGeometry(vertices, triangles); + + // Add build item + model->AddBuildItem(meshObject.get(), wrapper->GetIdentityTransform()); + + PWriter writer = model->QueryWriter("3mf"); + writer->WriteToFile("cube.3mf"); + + std::cout << "done" << std::endl; +} + +int main() { + try { + CubeExample(); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/CPackExamples/Cpp/Source/ExtractInfo.cpp b/SDK/CPackExamples/Cpp/Source/ExtractInfo.cpp new file mode 100644 index 000000000..661cd30f2 --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/ExtractInfo.cpp @@ -0,0 +1,269 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +ExtractInfo.cpp : 3MF Read Example + +--*/ + +#include +#include +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +void ShowThumbnailInformation(PModel model) +{ + /* + // TODO: this is not yet implemented in Lib3MF + */ +} + + +void ShowMetaDataInformation(PMetaDataGroup metaDataGroup) +{ + Lib3MF_uint32 nMetaDataCount = metaDataGroup->GetMetaDataCount(); + + for (Lib3MF_uint32 iMeta = 0; iMeta < nMetaDataCount; iMeta++) { + + PMetaData metaData = metaDataGroup->GetMetaData(iMeta); + std::string sMetaDataValue = metaData->GetValue(); + std::string sMetaDataName = metaData->GetName(); + std::cout << "Metadatum: " << iMeta << ":" << std::endl; + std::cout << "Name = \"" << sMetaDataName << "\"" << std::endl; + std::cout << "Value = \"" << sMetaDataValue << "\"" << std::endl; + } +} + +void ShowSliceStack(PSliceStack sliceStack, std::string indent) +{ + std::cout << indent << "SliceStackID: " << sliceStack->GetResourceID() << std::endl; + if (sliceStack->GetSliceCount() > 0) { + std::cout << indent << " Slice count: " << sliceStack->GetSliceCount() << std::endl; + } + if (sliceStack->GetSliceRefCount() > 0) { + std::cout << indent << " Slice ref count: " << sliceStack->GetSliceRefCount() << std::endl; + for (Lib3MF_uint64 iSliceRef = 0; iSliceRef < sliceStack->GetSliceRefCount(); iSliceRef++) { + std::cout << indent << " Slice ref : " << sliceStack->GetSliceStackReference(iSliceRef)->GetResourceID() << std::endl; + } + } +} + +void ShowObjectProperties(PObject object) +{ + std::cout << " Name: \"" << object->GetName() << "\"" << std::endl; + std::cout << " PartNumber: \"" << object->GetPartNumber() << "\"" << std::endl; + + switch (object->GetType()) { + case eObjectType::Model: + std::cout << " Object type: model" << std::endl; + break; + case eObjectType::Support: + std::cout << " Object type: support" << std::endl; + break; + case eObjectType::SolidSupport: + std::cout << " Object type: solidsupport" << std::endl; + break; + case eObjectType::Other: + std::cout << " Object type: other" << std::endl; + break; + default: + std::cout << " Object type: invalid" << std::endl; + break; + } + + if (object->HasSlices(false)) { + PSliceStack sliceStack = object->GetSliceStack(); + ShowSliceStack(sliceStack, " "); + } + + if (object->GetMetaDataGroup()->GetMetaDataCount() > 0) { + ShowMetaDataInformation(object->GetMetaDataGroup()); + } +} + +void ShowMeshObjectInformation(PMeshObject meshObject) +{ + std::cout << "mesh object #" << meshObject->GetResourceID() << ": " << std::endl; + + ShowObjectProperties(meshObject); + + Lib3MF_uint64 nVertexCount = meshObject->GetVertexCount(); + Lib3MF_uint64 nTriangleCount = meshObject->GetTriangleCount(); + PBeamLattice beamLattice = meshObject->BeamLattice(); + + // Output data + std::cout << " Vertex count: " << nVertexCount << std::endl; + std::cout << " Triangle count: " << nTriangleCount << std::endl; + + Lib3MF_uint64 nBeamCount = beamLattice->GetBeamCount(); + if (nBeamCount > 0) { + std::cout << " Beam count: " << nBeamCount << std::endl; + Lib3MF_uint32 nRepresentationMesh; + if (beamLattice->GetRepresentation(nRepresentationMesh)) + std::cout << " |_Representation Mesh ID: " << nRepresentationMesh << std::endl; + eLib3MFBeamLatticeClipMode eClipMode; + Lib3MF_uint32 nClippingMesh; + beamLattice->GetClipping(eClipMode, nClippingMesh); + if (eClipMode != eBeamLatticeClipMode::NoClipMode) + std::cout << " |_Clipping Mesh ID: " << nClippingMesh << "(mode=" << (int)eClipMode << ")" << std::endl; + if (beamLattice->GetBeamSetCount() > 0) { + std::cout << " |_BeamSet count: " << beamLattice->GetBeamSetCount() << std::endl; + } + } + +} + +void ShowTransform(sLib3MFTransform transform, std::string indent) { + std::cout << indent << "Transformation: [ " << transform.m_Fields[0][0] << " " << transform.m_Fields[1][0] << " " << transform.m_Fields[2][0] << " " << transform.m_Fields[3][0] << " ]" << std::endl; + std::cout << indent << " [ " << transform.m_Fields[0][1] << " " << transform.m_Fields[1][1] << " " << transform.m_Fields[2][1] << " " << transform.m_Fields[3][1] << " ]" << std::endl; + std::cout << indent << " [ " << transform.m_Fields[0][2] << " " << transform.m_Fields[1][2] << " " << transform.m_Fields[2][2] << " " << transform.m_Fields[3][2] << " ]" << std::endl; +} + +void ShowComponentsObjectInformation(PComponentsObject componentsObject) +{ + std::cout << "components object #" << componentsObject->GetResourceID() << ": " << std::endl; + + ShowObjectProperties(componentsObject); + std::cout << " Component count: " << componentsObject->GetComponentCount() << std::endl; + for (Lib3MF_uint32 nIndex = 0; nIndex < componentsObject->GetComponentCount(); nIndex++) { + PComponent component = componentsObject->GetComponent(nIndex); + + std::cout << " Component " << nIndex << ": Object ID: " << component->GetObjectResourceID() << std::endl; + if (component->HasTransform()) { + ShowTransform(component->GetTransform(), " "); + } + else { + std::cout << " Transformation: none" << std::endl; + } + } +} + + +void ExtractInfoExample(std::string sFileName) { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Read example" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + // Import Model from 3MF File + { + PReader reader = model->QueryReader("3mf"); + // And deactivate the strict mode (default is "false", anyway. This just demonstrates where/how to use it). + reader->SetStrictModeActive(false); + reader->ReadFromFile(sFileName); + + for (Lib3MF_uint32 iWarning = 0; iWarning < reader->GetWarningCount(); iWarning++) { + Lib3MF_uint32 nErrorCode; + std::string sWarningMessage = reader->GetWarning(iWarning, nErrorCode); + std::cout << "Encountered warning #" << nErrorCode << " : " << sWarningMessage << std::endl; + } + } + ShowThumbnailInformation(model); + + ShowMetaDataInformation(model->GetMetaDataGroup()); + + PSliceStackIterator sliceStacks = model->GetSliceStacks(); + while (sliceStacks->MoveNext()) { + PSliceStack sliceStack = sliceStacks->GetCurrentSliceStack(); + ShowSliceStack(sliceStack, ""); + } + + PObjectIterator objectIterator = model->GetObjects(); + while (objectIterator->MoveNext()) { + PObject object = objectIterator->GetCurrentObject(); + if (object->IsMeshObject()) { + ShowMeshObjectInformation(model->GetMeshObjectByID(object->GetResourceID())); + } + else if (object->IsComponentsObject()) { + ShowComponentsObjectInformation(model->GetComponentsObjectByID(object->GetResourceID())); + } + else { + std::cout << "unknown object #" << object->GetResourceID() << ": " << std::endl; + } + } + + + PBuildItemIterator buildItemIterator = model->GetBuildItems(); + while (buildItemIterator->MoveNext()) { + PBuildItem buildItem = buildItemIterator->GetCurrent(); + + std::cout << "Build item (Object #" << buildItem->GetObjectResourceID() << "): " << std::endl; + + if (buildItem->HasObjectTransform()) { + ShowTransform(buildItem->GetObjectTransform(), " "); + } + else { + std::cout << " Transformation: none" << std::endl; + } + std::cout << " Part number: \"" << buildItem->GetPartNumber() << "\"" << std::endl; + if (buildItem->GetMetaDataGroup()->GetMetaDataCount() > 0) { + ShowMetaDataInformation(buildItem->GetMetaDataGroup()); + } + } + + std::cout << "done" << std::endl; +} + + +int main(int argc, char** argv) { + // Parse Arguments + if (argc != 2) { + std::cout << "Usage: " << std::endl; + std::cout << "ExtractInfo.exe model.3mf" << std::endl; + return 0; + } + + try { + ExtractInfoExample(argv[1]); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/CPackExamples/Cpp/Source/SecureCube.cpp b/SDK/CPackExamples/Cpp/Source/SecureCube.cpp new file mode 100644 index 000000000..de966b61f --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/SecureCube.cpp @@ -0,0 +1,487 @@ +/*++ + +Copyright (C) 2020 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +SecureCube.cpp : 3MF encrypted Cube creation and read example. This is a sample +skeleton code provided to guide you to the process of reading and writing a 3MF +file using the Secure Content spec. Encryption and decryption processes are abstracted +so to avoid binding this sample to any particular implementation. If you would like +to check a working version of the process, there's a unit tests available on the 3MF code +base that implements the entire workflow using LibreSSL: EncryptionMethods.cpp +Tip: you could also copy buffers around - file won't be valid but you will be able +to run the entire process. +--*/ + +#include +#include +#include +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +namespace SecureContentCallbacks { + // Sample random number generation callback. Do not use this beyond the scope of this example as it is not really a random number generation function. + static void NotRandomBytesAtAll(Lib3MF_uint64 byteData, Lib3MF_uint64 size, Lib3MF_pvoid userData, Lib3MF_uint64 * bytesWritten) { + static Lib3MF_uint8 random = 0; + Lib3MF_uint8 * buffer = (Lib3MF_uint8 *)byteData; + *bytesWritten = size; + while (size > 0) + *(buffer + (--size)) = ++random; + } + + // Structure to hold encryption context for keys + struct KeyWrappingCbData { + CWrapper * wrapper; + }; + + + // Structure to hold encryption context for resources + struct ContentEncryptionCbData { + CWrapper * wrapper; + std::map context; + }; + + // Sample callback to wrap the key of an encryption process + static void WriteKeyWrappingCbSample( + Lib3MF_AccessRight access, + Lib3MF_uint64 inSize, + const Lib3MF_uint8 * inBuffer, + const Lib3MF_uint64 outSize, + Lib3MF_uint64 * outNeeded, + Lib3MF_uint8 * outBuffer, + Lib3MF_pvoid userData, + Lib3MF_uint64 * status) { + + KeyWrappingCbData * cp = (KeyWrappingCbData *)userData; + + // Since we're using CAccessRight constructure, we have to account for + // the use of 'access' by calling Acquire on the CWrapper + CAccessRight accessRight(cp->wrapper, access); + cp->wrapper->Acquire(&accessRight); + + // This is going to be called for each consumer you've registered to + PConsumer consumer = accessRight.GetConsumer(); + std::string consumerId = consumer->GetConsumerID(); + std::cout << "ConsumerID " << consumer->GetConsumerID() << std::endl; + // You can also check for keyid and keyvalue + + // A call could be made to first identify what the output buffer size should be. + // In that case, outSize will be 0 or outBuffer will be null, and the proper size must be placed in outNeeded. + if (nullptr == outBuffer || outSize == 0) { + *outNeeded = inSize; + *status = inSize; + return; + } + + // Query the data about the encryption process to be done + eWrappingAlgorithm algorithm = accessRight.GetWrappingAlgorithm(); + eMgfAlgorithm mask = accessRight.GetMgfAlgorithm(); + eDigestMethod diges = accessRight.GetDigestMethod(); + + // You should deal with the encryption process of the key. + // Use the encryption process to wrap inBuffer (plain) into outBuffer (cipher) using details above. + // Use KeyWrappingCbData to hold any information you'll be needing at this point. + throw std::runtime_error("TODO: Add your encryption wrapping process here"); + //std::copy(inBuffer, inBuffer + outSize, outBuffer); + + // Finally, this function should use status to return the number of bytes needed, + // encrypted - or zero to indicate a failure. + *status = outSize; + } + + // Sample callback to encrypt contents of a resource + static void WriteContentEncryptionCbSample( + Lib3MF_ContentEncryptionParams params, + Lib3MF_uint64 inSize, + const Lib3MF_uint8 * inBuffer, + const Lib3MF_uint64 outSize, + Lib3MF_uint64 * outNeededSize, + Lib3MF_uint8 * outBuffer, + Lib3MF_pvoid userData, + Lib3MF_uint64 * status) { + + ContentEncryptionCbData * cb = (ContentEncryptionCbData *)userData; + + // Since we're using CAccessRight constructure, we have to account for + // the use of 'access' by calling Acquire on the CWrapper + CContentEncryptionParams cd(cb->wrapper, params); + cb->wrapper->Acquire(&cd); + + // A descriptor uniquely identifies the encryption process for a resource + Lib3MF_uint64 descriptor = cd.GetDescriptor(); + + // You can map the descriptor in use as you'll probably keep several + // contexts initialized at same time + auto localDescriptor = cb->context.find(cd.GetDescriptor()); + if (localDescriptor != cb->context.end()) + // Use an existing context + localDescriptor->second++; + else { + // Initialize a new context + + // Retrieve the encryption key, if there is one + std::vector key; + cd.GetKey(key); + + // You can also use keyuuid to look up a key externally + std::string keyUUID = cd.GetKeyUUID(); + + // Retrieve the additional authenticaton data, if it has been used to encrypt + std::vector aad; + cd.GetAdditionalAuthenticationData(aad); + + // TODO: Initialize the encryption context + cb->context[cd.GetDescriptor()] = 0; + } + + // Attention to the order in which params are tested, it matters + if (0 == inSize || nullptr == inBuffer) { + // When input buffer is null or input size is 0, this is a request + // to finalize this encryption process and generating the authentication tag + // TODO: generate proper tag + std::vector tag = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + cd.SetAuthenticationTag(tag); + //add tag verification status here + *status = tag.size(); + } else if (0 == outSize || nullptr == outBuffer) { + // If outSize is zero or outBuffer is null (but inSize and inBuffer are not), + // this is a call to figure out the output buffer size. + // Put the respective value in outNeededSize. + *outNeededSize = inSize; + *status = inSize; + } else { + // Else, perform the encryption process + throw std::runtime_error("TODO: Add your encryption process here"); + //std::copy(inBuffer, inBuffer + outSize, outBuffer); + *status = outSize; + } + //This function should use status to return the number of bytes needed, encrypted + // or verified - or zero to indicate a failure. + } + + static void ReadKeyWrappingCbSample( + Lib3MF_AccessRight access, + Lib3MF_uint64 inSize, + const Lib3MF_uint8 * inBuffer, + const Lib3MF_uint64 outSize, + Lib3MF_uint64 * outNeeded, + Lib3MF_uint8 * outBuffer, + Lib3MF_pvoid userData, + Lib3MF_uint64 * status) { + + // A call could be made to first identify what the output buffer size should be. + // In that case, outSize will be 0 or outBuffer will be null, and the proper size must be placed in outNeeded. + if (nullptr == outBuffer || outSize == 0) { + *outNeeded = inSize; + *status = inSize; + return; + } + + KeyWrappingCbData * cp = (KeyWrappingCbData *)userData; + + // Since we're using CAccessRight constructure, we have to account for + // the use of 'access' by calling Acquire on the CWrapper + CAccessRight accessRight(cp->wrapper, access); + cp->wrapper->Acquire(&accessRight); + + // This is going to be called for each consumer you've registered to + PConsumer consumer = accessRight.GetConsumer(); + std::string consumerId = consumer->GetConsumerID(); + std::cout << "ConsumerID " << consumer->GetConsumerID() << std::endl; + // You can also check for keyid and keyvalue + + // Query the data about the encryption process to be done + eWrappingAlgorithm algorithm = accessRight.GetWrappingAlgorithm(); + eMgfAlgorithm mask = accessRight.GetMgfAlgorithm(); + eDigestMethod diges = accessRight.GetDigestMethod(); + + // You should deal with the encryption process of the key. + // Use the encryption process to wrap inBuffer (cipher) into outBuffer (plain) using details above. + // Use KeyWrappingCbData to hold any information you'll be needing at this point. + throw std::runtime_error("TODO: Add your decryption wrapping process here"); + //std::copy(inBuffer, inBuffer + outSize, outBuffer); + + // Finally, this function should use status to return the number of bytes needed, + // decrypted - or zero to indicate a failure. + *status = outSize; + } + + static void ReadContentEncryptionCbSample( + Lib3MF_ContentEncryptionParams params, + Lib3MF_uint64 inSize, + const Lib3MF_uint8 * inBuffer, + const Lib3MF_uint64 outSize, + Lib3MF_uint64 * outNeededSize, + Lib3MF_uint8 * outBuffer, + Lib3MF_pvoid userData, + Lib3MF_uint64 * status) { + + ContentEncryptionCbData * cb = (ContentEncryptionCbData *)userData; + + // Since we're using CAccessRight constructure, we have to account for + // the use of 'access' by calling Acquire on the CWrapper + CContentEncryptionParams cd(cb->wrapper, params); + cb->wrapper->Acquire(&cd); + + // A descriptor uniquely identifies the encryption process for a resource + Lib3MF_uint64 descriptor = cd.GetDescriptor(); + + // You can map the descriptor in use as you'll probably keep several + // contexts initialized at same time + auto localDescriptor = cb->context.find(cd.GetDescriptor()); + if (localDescriptor != cb->context.end()) + // Use an existing context + localDescriptor->second++; + else { + // Initialize a new context + + // Retrieve the encryption key, if there is one + std::vector key; + cd.GetKey(key); + + // You can also use keyuuid to look up a key externally + std::string keyUUID = cd.GetKeyUUID(); + + // Retrieve the additional authenticaton data, if it has been used to encrypt + std::vector aad; + cd.GetAdditionalAuthenticationData(aad); + + // TODO: Initialize the encryption context + cb->context[cd.GetDescriptor()] = 0; + } + + // Attention to the order in which params are tested, it matters + if (0 == inSize || nullptr == inBuffer) { + // When input buffer is null or input size is 0, this is a request + // to finalize this encryption process and verify the authentication tag + std::vector tag; + cd.GetAuthenticationTag(tag); + // TODO: verify tag + *status = tag.size(); + } else if (0 == outSize || nullptr == outBuffer) { + // If outSize is zero or outBuffer is null (but inSize and inBuffer are not), + // this is a call to figure out the output buffer size. + // Put the respective value in outNeededSize. + *outNeededSize = inSize; + *status = inSize; + return; + } else { + // Else, perform the descryption process + throw std::runtime_error("TODO: Add your encryption process here"); + //std::copy(inBuffer, inBuffer + outSize, outBuffer); + *status = outSize; + } + //This function should use status to return the number of bytes needed, decrypted + // or verified - or zero to indicate a failure. + } +}; + +void printVersion(CWrapper & wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper.GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper.GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper.GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +// Utility functions to create vertices and triangles +sLib3MFPosition fnCreateVertex(float x, float y, float z) { + sLib3MFPosition result; + result.m_Coordinates[0] = x; + result.m_Coordinates[1] = y; + result.m_Coordinates[2] = z; + return result; +} + +sLib3MFTriangle fnCreateTriangle(int v0, int v1, int v2) { + sLib3MFTriangle result; + result.m_Indices[0] = v0; + result.m_Indices[1] = v1; + result.m_Indices[2] = v2; + return result; +} + +void WriteSecureContentExample(CWrapper & wrapper) { + + PModel model = wrapper.CreateModel(); + + // After initializing the model, set the random number generation callback + // A default one will be used if you don't, current implementation uses std::mt19937 + model->SetRandomNumberCallback(SecureContentCallbacks::NotRandomBytesAtAll, nullptr); + + PMeshObject meshObject = model->AddMeshObject(); + meshObject->SetName("Box"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(12); + + float fSizeX = 100.0f; + float fSizeY = 200.0f; + float fSizeZ = 300.0f; + + // Manually create vertices + vertices[0] = fnCreateVertex(0.0f, 0.0f, 0.0f); + vertices[1] = fnCreateVertex(fSizeX, 0.0f, 0.0f); + vertices[2] = fnCreateVertex(fSizeX, fSizeY, 0.0f); + vertices[3] = fnCreateVertex(0.0f, fSizeY, 0.0f); + vertices[4] = fnCreateVertex(0.0f, 0.0f, fSizeZ); + vertices[5] = fnCreateVertex(fSizeX, 0.0f, fSizeZ); + vertices[6] = fnCreateVertex(fSizeX, fSizeY, fSizeZ); + vertices[7] = fnCreateVertex(0.0f, fSizeY, fSizeZ); + + // Manually create triangles + triangles[0] = fnCreateTriangle(2, 1, 0); + triangles[1] = fnCreateTriangle(0, 3, 2); + triangles[2] = fnCreateTriangle(4, 5, 6); + triangles[3] = fnCreateTriangle(6, 7, 4); + triangles[4] = fnCreateTriangle(0, 1, 5); + triangles[5] = fnCreateTriangle(5, 4, 0); + triangles[6] = fnCreateTriangle(2, 3, 7); + triangles[7] = fnCreateTriangle(7, 6, 2); + triangles[8] = fnCreateTriangle(1, 2, 6); + triangles[9] = fnCreateTriangle(6, 5, 1); + triangles[10] = fnCreateTriangle(3, 0, 4); + triangles[11] = fnCreateTriangle(4, 7, 3); + + meshObject->SetGeometry(vertices, triangles); + + // Add build item + model->AddBuildItem(meshObject.get(), wrapper.GetIdentityTransform()); + + // Move this mesh out of the root model file into another model + PPackagePart nonRootModel = model->FindOrCreatePackagePart("/3D/securecube.model"); + meshObject->SetPackagePart(nonRootModel.get()); + + // Locate the keystore and setup the resource as a secure content + PKeyStore keystore = model->GetKeyStore(); + + // Add you (client) as consumer of the resource. You'll need to do this + // to be able to have a chance to wrap the content key + // You can set optional public key and an optional key id + PConsumer consumer = keystore->AddConsumer("MyConsumerID", std::string(), std::string()); + + // Add a container for your secured resources. Resources within the same container will have a shared key. + PResourceDataGroup dataGroup = keystore->AddResourceDataGroup(); + + // Add access rights for your consumer into the datagroup + PAccessRight accessRight = dataGroup->AddAccessRight(consumer.get(), eWrappingAlgorithm::RSA_OAEP, eMgfAlgorithm::MGF1_SHA1, eDigestMethod::SHA1); + + // Specify additional authentication data that you could use to further validate your encryption process + std::vector aad = { '3','M','F','C','o','n','s','o','r','t','i','u','m',' ','S','a','m','p','l','e' }; + + // This will effectively add your nonRootModel as a secure content + PResourceData resourceData = keystore->AddResourceData(dataGroup.get(), nonRootModel.get(), eEncryptionAlgorithm::AES256_GCM, eCompression::Deflate, aad); + + // Query the writer and setup the encryption before saving results + PWriter writer = model->QueryWriter("3mf"); + + // Setup Key Wrapping process + SecureContentCallbacks::KeyWrappingCbData keyData; + keyData.wrapper = &wrapper; + writer->AddKeyWrappingCallback(consumer->GetConsumerID(), SecureContentCallbacks::WriteKeyWrappingCbSample, &keyData); + + // Content Encryption process + SecureContentCallbacks::ContentEncryptionCbData contentData; + contentData.wrapper = &wrapper; + writer->SetContentEncryptionCallback(SecureContentCallbacks::WriteContentEncryptionCbSample, &contentData); + + // You'll need to complete the callback code for this call to work properly. + writer->WriteToFile("secureCube.3mf"); + + std::cout << "Writing Done." << std::endl; +} + +void ReadSecureContentExample(CWrapper & wrapper) { + PModel model = wrapper.CreateModel(); + + // After initializing the model, set the random number generation callback + // A default one will be used if you don't, current implementation uses std::mt19937 + model->SetRandomNumberCallback(SecureContentCallbacks::NotRandomBytesAtAll, nullptr); + + // Query the reader and setup the encryption before saving results + PReader reader = model->QueryReader("3mf"); + + // Setup Key Wrapping process + SecureContentCallbacks::KeyWrappingCbData keyData; + keyData.wrapper = &wrapper; + reader->AddKeyWrappingCallback("MyConsumerID", SecureContentCallbacks::ReadKeyWrappingCbSample, &keyData); + + // Content Encryption process + SecureContentCallbacks::ContentEncryptionCbData contentData; + contentData.wrapper = &wrapper; + reader->SetContentEncryptionCallback(SecureContentCallbacks::ReadContentEncryptionCbSample, &contentData); + + // You'll need to complete the callback code for this call to work properly. + reader->ReadFromFile("secureCube.3mf"); + + PKeyStore keystore = model->GetKeyStore(); + + // If you know the part you're interested in, look for its resource data + PPackagePart partPath = model->FindOrCreatePackagePart("/3D/securecube.model"); + PResourceData resourceData = keystore->FindResourceData(partPath.get()); + + // You can retrieve additional authenticated data using in the encryption + // to further verify the consistency of the process. At this time, it is + // already verified. + std::vector aad; + resourceData->GetAdditionalAuthenticationData(aad); + std::cout << "Additional Authenticated Data: "; + for (auto it = aad.begin(); it != aad.end(); ++it) { + std::cout << (char)*it; + } + std::cout << std::endl; + + std::cout << "Reading Done." << std::endl; + +} + +int main() { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF SecureContent example" << std::endl; + printVersion(*wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + try { + WriteSecureContentExample(*wrapper); + ReadSecureContentExample(*wrapper); + } catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/CPackExamples/Cpp/Source/Slice.cpp b/SDK/CPackExamples/Cpp/Source/Slice.cpp new file mode 100644 index 000000000..5b8a3828e --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/Slice.cpp @@ -0,0 +1,191 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +Slice.cpp : 3MF slice extension example + +--*/ + +#include +#include +#include +double const_pi() { return std::atan(1) * 4; } +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +// Utility functions to create vertices and beams +sLib3MFPosition fnCreateVertex(float x, float y, float z) +{ + sLib3MFPosition result; + result.m_Coordinates[0] = x; + result.m_Coordinates[1] = y; + result.m_Coordinates[2] = z; + return result; +} + +sLib3MFTriangle fnCreateTriangle(int v0, int v1, int v2) +{ + sLib3MFTriangle result; + result.m_Indices[0] = v0; + result.m_Indices[1] = v1; + result.m_Indices[2] = v2; + return result; +} + + +void SliceExample() { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Slice example" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + PMeshObject meshObject = model->AddMeshObject(); + meshObject->SetName("Sliced Object [outbox]"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(12); + + float fSizeX = 100.0f; + float fSizeY = 100.0f; + float fSizeZ = 300.0f; + + // Manually create vertices + vertices[0] = fnCreateVertex(-fSizeX, -fSizeY, 0.0f); + vertices[1] = fnCreateVertex(fSizeX, -fSizeY, 0.0f); + vertices[2] = fnCreateVertex(fSizeX, fSizeY, 0.0f); + vertices[3] = fnCreateVertex(-fSizeX, fSizeY, 0.0f); + vertices[4] = fnCreateVertex(-fSizeX, -fSizeY, fSizeZ); + vertices[5] = fnCreateVertex(fSizeX, -fSizeY, fSizeZ); + vertices[6] = fnCreateVertex(fSizeX, fSizeY, fSizeZ); + vertices[7] = fnCreateVertex(-fSizeX, fSizeY, fSizeZ); + + // Manually create triangles + triangles[0] = fnCreateTriangle(2, 1, 0); + triangles[1] = fnCreateTriangle(0, 3, 2); + triangles[2] = fnCreateTriangle(4, 5, 6); + triangles[3] = fnCreateTriangle(6, 7, 4); + triangles[4] = fnCreateTriangle(0, 1, 5); + triangles[5] = fnCreateTriangle(5, 4, 0); + triangles[6] = fnCreateTriangle(2, 3, 7); + triangles[7] = fnCreateTriangle(7, 6, 2); + triangles[8] = fnCreateTriangle(1, 2, 6); + triangles[9] = fnCreateTriangle(6, 5, 1); + triangles[10] = fnCreateTriangle(3, 0, 4); + triangles[11] = fnCreateTriangle(4, 7, 3); + + // Set Geometry + meshObject->SetGeometry(vertices, triangles); + + + PSliceStack sliceStack = model->AddSliceStack(0.0); + + + + + + // Define an ellipse + Lib3MF_uint32 nSliceVertices = 20; + std::vector origSliceVertices(nSliceVertices); + for (Lib3MF_uint32 iSliceVertex = 0; iSliceVertex < nSliceVertices; iSliceVertex++) { + double angle = 2 * (const_pi()* iSliceVertex) / nSliceVertices; + origSliceVertices[iSliceVertex].m_Coordinates[0] = (Lib3MF_single)(fSizeX / 2 * std::cos(angle)); + origSliceVertices[iSliceVertex].m_Coordinates[1] = (Lib3MF_single)(fSizeY *std::sin(angle)); + } + + std::vector polygonIndices(nSliceVertices + 1); + for (Lib3MF_uint32 iPolygonIndex = 0; iPolygonIndex < polygonIndices.size(); iPolygonIndex++) { + polygonIndices[iPolygonIndex] = iPolygonIndex % nSliceVertices; + } + + Lib3MF_uint32 nSlices = 10; + + for (Lib3MF_uint32 iSlice = 0; iSlice < nSlices; iSlice++) { + PSlice slice = sliceStack->AddSlice((iSlice + 1.0)*fSizeZ / nSlices); + + // Rotate the ellpise as we move up z + double angle = 2 * (const_pi()*iSlice) / nSlices; + std::vector sliceVertices(nSliceVertices); + for (Lib3MF_uint32 iSliceVertex = 0; iSliceVertex < nSliceVertices; iSliceVertex++) { + double x = origSliceVertices[iSliceVertex].m_Coordinates[0]; + double y = origSliceVertices[iSliceVertex].m_Coordinates[1]; + sliceVertices[iSliceVertex].m_Coordinates[0] = (Lib3MF_single)(std::cos(angle)*x - std::sin(angle)*y); + sliceVertices[iSliceVertex].m_Coordinates[1] = (Lib3MF_single)(std::sin(angle)*x + std::cos(angle)*y); + } + + slice->SetVertices(sliceVertices); + slice->AddPolygon(polygonIndices); + } + + + // Assign this slice stack to mesh..., the exact geometry of the part + meshObject->AssignSliceStack(sliceStack.get()); + // which is not an exact representation of the sliced geometry + meshObject->SetSlicesMeshResolution(eSlicesMeshResolution::Lowres); + + + // Add build item + model->AddBuildItem(meshObject.get(), wrapper->GetIdentityTransform()); + + // Write file + PWriter writer = model->QueryWriter("3mf"); + writer->WriteToFile("slice.3mf"); + + std::cout << "done" << std::endl; +} + +int main() { + try { + SliceExample(); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/CPackExamples/Cpp/Source/TextureCube.cpp b/SDK/CPackExamples/Cpp/Source/TextureCube.cpp new file mode 100644 index 000000000..a8cd51d76 --- /dev/null +++ b/SDK/CPackExamples/Cpp/Source/TextureCube.cpp @@ -0,0 +1,205 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +TextureCube.cpp : 3MF Texture Cube creation example. + +--*/ + +#include +#include +#include + +#include "lib3mf_implicit.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +// Utility functions to create vertices and triangles +sLib3MFPosition fnCreateVertex(float x, float y, float z) +{ + sLib3MFPosition result; + result.m_Coordinates[0] = x; + result.m_Coordinates[1] = y; + result.m_Coordinates[2] = z; + return result; +} + +sLib3MFTriangle fnCreateTriangle(int v0, int v1, int v2) +{ + sLib3MFTriangle result; + result.m_Indices[0] = v0; + result.m_Indices[1] = v1; + result.m_Indices[2] = v2; + return result; +} + +PTexture2DGroup fnLoadModelTexture(PModel model, const std::string sOPCPath, const std::string sFilePath, eLib3MFTextureType eType, eLib3MFTextureTileStyle eTileStyleU, eLib3MFTextureTileStyle eTileStyleV) +{ + std::string sRelationshipType_Texture = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture"; + PAttachment attachment = model->AddAttachment(sOPCPath, sRelationshipType_Texture); + attachment->ReadFromFile(sFilePath); + + PTexture2D texture2D = model->AddTexture2DFromAttachment(attachment.get()); + + texture2D->SetContentType(eType); + texture2D->SetTileStyleUV(eTileStyleU, eTileStyleV); + + PTexture2DGroup textureGroup = model->AddTexture2DGroup(texture2D.get()); + return textureGroup; +} + + +sLib3MFTriangleProperties fnCreateTexture(PTexture2DGroup textureGroup, double u1, double v1, double u2, double v2, double u3, double v3) +{ + sLib3MFTriangleProperties property; + property.m_ResourceID = textureGroup->GetResourceID(); + property.m_PropertyIDs[0] = textureGroup->AddTex2Coord(sLib3MFTex2Coord({ u1, v1 })); + property.m_PropertyIDs[1] = textureGroup->AddTex2Coord(sLib3MFTex2Coord({ u2, v2 })); + property.m_PropertyIDs[2] = textureGroup->AddTex2Coord(sLib3MFTex2Coord({ u3, v3 })); + return property; +} + +void TextureExample() { + PWrapper wrapper = CWrapper::loadLibrary(); + + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Texture Cube example" << std::endl; + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + PMeshObject meshObject = model->AddMeshObject(); + meshObject->SetName("Textured Box"); + + // Create mesh structure of a cube + std::vector vertices(8); + std::vector triangles(12); + + float fSizeX = 100.0f; + float fSizeY = 100.0f; + float fSizeZ = 100.0f; + + // Manually create vertices + vertices[0] = fnCreateVertex(0.0f, 0.0f, 0.0f); + vertices[1] = fnCreateVertex(fSizeX, 0.0f, 0.0f); + vertices[2] = fnCreateVertex(fSizeX, fSizeY, 0.0f); + vertices[3] = fnCreateVertex(0.0f, fSizeY, 0.0f); + vertices[4] = fnCreateVertex(0.0f, 0.0f, fSizeZ); + vertices[5] = fnCreateVertex(fSizeX, 0.0f, fSizeZ); + vertices[6] = fnCreateVertex(fSizeX, fSizeY, fSizeZ); + vertices[7] = fnCreateVertex(0.0f, fSizeY, fSizeZ); + + // Manually create triangles + triangles[0] = fnCreateTriangle(2, 1, 0); + triangles[1] = fnCreateTriangle(0, 3, 2); + triangles[2] = fnCreateTriangle(4, 5, 6); + triangles[3] = fnCreateTriangle(6, 7, 4); + triangles[4] = fnCreateTriangle(0, 1, 5); + triangles[5] = fnCreateTriangle(5, 4, 0); + triangles[6] = fnCreateTriangle(2, 3, 7); + triangles[7] = fnCreateTriangle(7, 6, 2); + triangles[8] = fnCreateTriangle(1, 2, 6); + triangles[9] = fnCreateTriangle(6, 5, 1); + triangles[10] = fnCreateTriangle(3, 0, 4); + triangles[11] = fnCreateTriangle(4, 7, 3); + + meshObject->SetGeometry(vertices, triangles); + + std::string sTextureFolder = TEXTURESPATH; + // add textures to 3mf package + std::cout << "sTextureFolder=\"" << sTextureFolder << "\"\n"; + auto textureGroup1 = fnLoadModelTexture(model, "/3D/Textures/tex1.png", sTextureFolder + "tex1.png", eTextureType::PNG, eTextureTileStyle::Wrap, eTextureTileStyle::Wrap); + auto textureGroup2 = fnLoadModelTexture(model, "/3D/Textures/tex2.png", sTextureFolder + "tex2.png", eTextureType::PNG, eTextureTileStyle::Mirror, eTextureTileStyle::Wrap); + auto textureGroup3 = fnLoadModelTexture(model, "/3D/Textures/tex3.png", sTextureFolder + "tex3.png", eTextureType::PNG, eTextureTileStyle::Wrap, eTextureTileStyle::Mirror); + auto textureGroup4 = fnLoadModelTexture(model, "/3D/Textures/tex4.png", sTextureFolder + "tex4.png", eTextureType::PNG, eTextureTileStyle::Clamp, eTextureTileStyle::Wrap); + auto textureGroup5 = fnLoadModelTexture(model, "/3D/Textures/tex5.png", sTextureFolder + "tex5.png", eTextureType::PNG, eTextureTileStyle::Wrap, eTextureTileStyle::Clamp); + auto textureGroup6 = fnLoadModelTexture(model, "/3D/Textures/tex6.png", sTextureFolder + "tex6.png", eTextureType::PNG, eTextureTileStyle::Clamp, eTextureTileStyle::Mirror); + + // Side 1 + meshObject->SetTriangleProperties(0, fnCreateTexture(textureGroup1, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0)); + meshObject->SetTriangleProperties(1, fnCreateTexture(textureGroup1, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0)); + + // Side 2 + meshObject->SetTriangleProperties(2, fnCreateTexture(textureGroup2, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0)); + meshObject->SetTriangleProperties(3, fnCreateTexture(textureGroup2, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0)); + + // Side 3 + // Go outside of bounds on this side + meshObject->SetTriangleProperties(4, fnCreateTexture(textureGroup3, -1.0, -1.0, 2.0, -1.0, 2.0, 2.0)); + meshObject->SetTriangleProperties(5, fnCreateTexture(textureGroup3, 2.0, 2.0, -1.0, 2.0, -1.0, -1.0)); + + // Side 4 + meshObject->SetTriangleProperties(6, fnCreateTexture(textureGroup4, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0)); + meshObject->SetTriangleProperties(7, fnCreateTexture(textureGroup4, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0)); + + // Side 5 + meshObject->SetTriangleProperties(8, fnCreateTexture(textureGroup5, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0)); + meshObject->SetTriangleProperties(9, fnCreateTexture(textureGroup5, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0)); + + // Side 6 + meshObject->SetTriangleProperties(10, fnCreateTexture(textureGroup6, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0)); + meshObject->SetTriangleProperties(11, fnCreateTexture(textureGroup6, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0)); + + // Object Level Property + meshObject->SetObjectLevelProperty(textureGroup1->GetResourceID(), 1); + + // Add build item + model->AddBuildItem(meshObject.get(), wrapper->GetIdentityTransform()); + + PWriter writer = model->QueryWriter("3mf"); + writer->WriteToFile("texturegroup.3mf"); + + std::cout << "done" << std::endl; +} + +int main() { + try { + TextureExample(); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} + + diff --git a/SDK/CPackExamples/CppDynamic/CMakeLists.txt b/SDK/CPackExamples/CppDynamic/CMakeLists.txt new file mode 100644 index 000000000..0e1a52a69 --- /dev/null +++ b/SDK/CPackExamples/CppDynamic/CMakeLists.txt @@ -0,0 +1,75 @@ +#[[++ + +Copyright (C) 2019 3MF Consortium (Original Author) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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 file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0-develop3. + +Abstract: This is an autogenerated CMake Project that demonstrates the + usage of the Dynamic C++ bindings of the 3MF Library + +Interface version: 2.2.0 + + +]] + +cmake_minimum_required(VERSION 3.5) + +project(Example_ExtractInfo) +set(CMAKE_CXX_STANDARD 11) + +# Determine the platform and set lib3mf_DIR accordingly +if(WIN32) + # Path for Windows + set(lib3mf_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib3mf-2.3.2-Windows/lib/cmake/lib3mf") + find_package(lib3mf REQUIRED COMPONENTS CppDynamic) +elseif(APPLE) + # Path for macOS (Darwin) + set(lib3mf_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib3mf-2.3.2-Darwin/lib/cmake/lib3mf") + find_package(lib3mf REQUIRED COMPONENTS CppDynamic) +else() + # Path for Linux (Here we check twice to test for Debian / RPM packages properly) + find_package(lib3mf QUIET COMPONENTS CppDynamic) + # Check if the package was not found + if(NOT lib3mf_FOUND) + # lib3mf not found, so set lib3mf_DIR to the fallback directory + set(lib3mf_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib3mf-2.3.2-Linux/lib/cmake/lib3mf") + # Find package (lib3mf) + find_package(lib3mf REQUIRED COMPONENTS CppDynamic) + endif() +endif() + +add_executable(Example_ExtractInfo "${CMAKE_CURRENT_SOURCE_DIR}/Source/ExtractInfo.cpp") + +# In case of CDynamic and CppDynamic, the lib3mf::lib3mf is simply an alias to an interface +target_link_libraries(Example_ExtractInfo lib3mf::lib3mf ${CMAKE_DL_LIBS}) + +if (${MSVC}) + IF(${CMAKE_VERSION} VERSION_LESS 3.6.3) + MESSAGE ("Note: You need to manually select a StartUp-project in Visual Studio.") + ELSE() + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Example_ExtractInfo) + ENDIF() +endif() + diff --git a/SDK/CPackExamples/CppDynamic/GenerateMake.sh b/SDK/CPackExamples/CppDynamic/GenerateMake.sh new file mode 100644 index 000000000..16fe9cf2b --- /dev/null +++ b/SDK/CPackExamples/CppDynamic/GenerateMake.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +basepath="$(cd "$(dirname "$0")" && pwd)" +builddir="$basepath/build" +mkdir -p $builddir +cd $builddir +cmake .. -G "Unix Makefiles" "$@" \ No newline at end of file diff --git a/SDK/CPackExamples/CppDynamic/GenerateVS2015.bat b/SDK/CPackExamples/CppDynamic/GenerateVS2015.bat new file mode 100644 index 000000000..e6933cdeb --- /dev/null +++ b/SDK/CPackExamples/CppDynamic/GenerateVS2015.bat @@ -0,0 +1,10 @@ +@echo off +set startingDir=%CD% + +set basepath=%~dp0 +set builddir=%basepath%\build +if not exist %builddir% (mkdir %builddir%) +cd %builddir% +cmake -G "Visual Studio 14 2015 Win64" .. %* + +cd %startingDir% diff --git a/SDK/CPackExamples/CppDynamic/GenerateVS2017.bat b/SDK/CPackExamples/CppDynamic/GenerateVS2017.bat new file mode 100644 index 000000000..4014d2f99 --- /dev/null +++ b/SDK/CPackExamples/CppDynamic/GenerateVS2017.bat @@ -0,0 +1,10 @@ +@echo off +set startingDir=%CD% + +set basepath=%~dp0 +set builddir=%basepath%\build +if not exist %builddir% (mkdir %builddir%) +cd %builddir% +cmake -G "Visual Studio 15 2017 Win64" .. %* + +cd %startingDir% diff --git a/SDK/CPackExamples/CppDynamic/GenerateVS2019.bat b/SDK/CPackExamples/CppDynamic/GenerateVS2019.bat new file mode 100644 index 000000000..efa4f308f --- /dev/null +++ b/SDK/CPackExamples/CppDynamic/GenerateVS2019.bat @@ -0,0 +1,10 @@ +@echo off +set startingDir=%CD% + +set basepath=%~dp0 +set builddir=%basepath%\build +if not exist %builddir% (mkdir %builddir%) +cd %builddir% +cmake -G "Visual Studio 16 2019" .. %* + +cd %startingDir% diff --git a/SDK/CPackExamples/CppDynamic/Source/ExtractInfo.cpp b/SDK/CPackExamples/CppDynamic/Source/ExtractInfo.cpp new file mode 100644 index 000000000..0a96b29f4 --- /dev/null +++ b/SDK/CPackExamples/CppDynamic/Source/ExtractInfo.cpp @@ -0,0 +1,271 @@ +/*++ + +Copyright (C) 2019 3MF Consortium + +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 MICROSOFT AND/OR NETFABB 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. + +Abstract: + +ExtractInfo.cpp : 3MF Read Example + +--*/ + +#include +#include +#include + +#include "lib3mf_dynamic.hpp" + +using namespace Lib3MF; + + +void printVersion(PWrapper wrapper) { + Lib3MF_uint32 nMajor, nMinor, nMicro; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + std::cout << "lib3mf version = " << nMajor << "." << nMinor << "." << nMicro; + std::string sReleaseInfo, sBuildInfo; + if (wrapper->GetPrereleaseInformation(sReleaseInfo)) { + std::cout << "-" << sReleaseInfo; + } + if (wrapper->GetBuildInformation(sBuildInfo)) { + std::cout << "+" << sBuildInfo; + } + std::cout << std::endl; +} + +void ShowThumbnailInformation(PModel model) +{ + /* + // TODO: this is not yet implemented in lib3mf + */ +} + + +void ShowMetaDataInformation(PMetaDataGroup metaDataGroup) +{ + Lib3MF_uint32 nMetaDataCount = metaDataGroup->GetMetaDataCount(); + + for (Lib3MF_uint32 iMeta = 0; iMeta < nMetaDataCount; iMeta++) { + + PMetaData metaData = metaDataGroup->GetMetaData(iMeta); + std::string sMetaDataValue = metaData->GetValue(); + std::string sMetaDataName = metaData->GetName(); + std::cout << "Metadatum: " << iMeta << ":" << std::endl; + std::cout << "Name = \"" << sMetaDataName << "\"" << std::endl; + std::cout << "Value = \"" << sMetaDataValue << "\"" << std::endl; + } +} + +void ShowSliceStack(PSliceStack sliceStack, std::string indent) +{ + std::cout << indent << "SliceStackID: " << sliceStack->GetResourceID() << std::endl; + if (sliceStack->GetSliceCount() > 0) { + std::cout << indent << " Slice count: " << sliceStack->GetSliceCount() << std::endl; + } + if (sliceStack->GetSliceRefCount() > 0) { + std::cout << indent << " Slice ref count: " << sliceStack->GetSliceRefCount() << std::endl; + for (Lib3MF_uint64 iSliceRef = 0; iSliceRef < sliceStack->GetSliceRefCount(); iSliceRef++) { + std::cout << indent << " Slice ref : " << sliceStack->GetSliceStackReference(iSliceRef)->GetResourceID() << std::endl; + } + } +} + +void ShowObjectProperties(PObject object) +{ + std::cout << " Name: \"" << object->GetName() << "\"" << std::endl; + std::cout << " PartNumber: \"" << object->GetPartNumber() << "\"" << std::endl; + + switch (object->GetType()) { + case eObjectType::Model: + std::cout << " Object type: model" << std::endl; + break; + case eObjectType::Support: + std::cout << " Object type: support" << std::endl; + break; + case eObjectType::SolidSupport: + std::cout << " Object type: solidsupport" << std::endl; + break; + case eObjectType::Other: + std::cout << " Object type: other" << std::endl; + break; + default: + std::cout << " Object type: invalid" << std::endl; + break; + } + + if (object->HasSlices(false)) { + PSliceStack sliceStack = object->GetSliceStack(); + ShowSliceStack(sliceStack, " "); + } + + if (object->GetMetaDataGroup()->GetMetaDataCount() > 0) { + ShowMetaDataInformation(object->GetMetaDataGroup()); + } +} + +void ShowMeshObjectInformation(PMeshObject meshObject) +{ + std::cout << "mesh object #" << meshObject->GetResourceID() << ": " << std::endl; + + ShowObjectProperties(meshObject); + + Lib3MF_uint64 nVertexCount = meshObject->GetVertexCount(); + Lib3MF_uint64 nTriangleCount = meshObject->GetTriangleCount(); + PBeamLattice beamLattice = meshObject->BeamLattice(); + + // Output data + std::cout << " Vertex count: " << nVertexCount << std::endl; + std::cout << " Triangle count: " << nTriangleCount << std::endl; + + Lib3MF_uint64 nBeamCount = beamLattice->GetBeamCount(); + if (nBeamCount > 0) { + std::cout << " Beam count: " << nBeamCount << std::endl; + Lib3MF_uint32 nRepresentationMesh; + if (beamLattice->GetRepresentation(nRepresentationMesh)) + std::cout << " |_Representation Mesh ID: " << nRepresentationMesh << std::endl; + eLib3MFBeamLatticeClipMode eClipMode; + Lib3MF_uint32 nClippingMesh; + beamLattice->GetClipping(eClipMode, nClippingMesh); + if (eClipMode != eBeamLatticeClipMode::NoClipMode) + std::cout << " |_Clipping Mesh ID: " << nClippingMesh << "(mode=" << (int)eClipMode << ")" << std::endl; + if (beamLattice->GetBeamSetCount() > 0) { + std::cout << " |_BeamSet count: " << beamLattice->GetBeamSetCount() << std::endl; + } + } + +} + +void ShowTransform(sLib3MFTransform transform, std::string indent) { + std::cout << indent << "Transformation: [ " << transform.m_Fields[0][0] << " " << transform.m_Fields[1][0] << " " << transform.m_Fields[2][0] << " " << transform.m_Fields[3][0] << " ]" << std::endl; + std::cout << indent << " [ " << transform.m_Fields[0][1] << " " << transform.m_Fields[1][1] << " " << transform.m_Fields[2][1] << " " << transform.m_Fields[3][1] << " ]" << std::endl; + std::cout << indent << " [ " << transform.m_Fields[0][2] << " " << transform.m_Fields[1][2] << " " << transform.m_Fields[2][2] << " " << transform.m_Fields[3][2] << " ]" << std::endl; +} + +void ShowComponentsObjectInformation(PComponentsObject componentsObject) +{ + std::cout << "components object #" << componentsObject->GetResourceID() << ": " << std::endl; + + ShowObjectProperties(componentsObject); + std::cout << " Component count: " << componentsObject->GetComponentCount() << std::endl; + for (Lib3MF_uint32 nIndex = 0; nIndex < componentsObject->GetComponentCount(); nIndex++) { + PComponent component = componentsObject->GetComponent(nIndex); + + std::cout << " Component " << nIndex << ": Object ID: " << component->GetObjectResourceID() << std::endl; + if (component->HasTransform()) { + ShowTransform(component->GetTransform(), " "); + } + else { + std::cout << " Transformation: none" << std::endl; + } + } +} + + +void ExtractInfoExample(std::string sFileName) { + std::cout << "------------------------------------------------------------------" << std::endl; + std::cout << "3MF Read example" << std::endl; + + std::string libpath = ("."); // TODO: put the location of the Lib3MF-library file here. + auto wrapper = Lib3MF::CWrapper::loadLibrary(LIB3MF_LIBRARY_LOCATION); // TODO: add correct suffix of the library + + printVersion(wrapper); + std::cout << "------------------------------------------------------------------" << std::endl; + + PModel model = wrapper->CreateModel(); + + // Import Model from 3MF File + { + PReader reader = model->QueryReader("3mf"); + // And deactivate the strict mode (default is "false", anyway. This just demonstrates where/how to use it). + reader->SetStrictModeActive(false); + reader->ReadFromFile(sFileName); + + for (Lib3MF_uint32 iWarning = 0; iWarning < reader->GetWarningCount(); iWarning++) { + Lib3MF_uint32 nErrorCode; + std::string sWarningMessage = reader->GetWarning(iWarning, nErrorCode); + std::cout << "Encountered warning #" << nErrorCode << " : " << sWarningMessage << std::endl; + } + } + ShowThumbnailInformation(model); + + ShowMetaDataInformation(model->GetMetaDataGroup()); + + PSliceStackIterator sliceStacks = model->GetSliceStacks(); + while (sliceStacks->MoveNext()) { + PSliceStack sliceStack = sliceStacks->GetCurrentSliceStack(); + ShowSliceStack(sliceStack, ""); + } + + PObjectIterator objectIterator = model->GetObjects(); + while (objectIterator->MoveNext()) { + PObject object = objectIterator->GetCurrentObject(); + if (object->IsMeshObject()) { + ShowMeshObjectInformation(model->GetMeshObjectByID(object->GetResourceID())); + } + else if (object->IsComponentsObject()) { + ShowComponentsObjectInformation(model->GetComponentsObjectByID(object->GetResourceID())); + } + else { + std::cout << "unknown object #" << object->GetResourceID() << ": " << std::endl; + } + } + + + PBuildItemIterator buildItemIterator = model->GetBuildItems(); + while (buildItemIterator->MoveNext()) { + PBuildItem buildItem = buildItemIterator->GetCurrent(); + + std::cout << "Build item (Object #" << buildItem->GetObjectResourceID() << "): " << std::endl; + + if (buildItem->HasObjectTransform()) { + ShowTransform(buildItem->GetObjectTransform(), " "); + } + else { + std::cout << " Transformation: none" << std::endl; + } + std::cout << " Part number: \"" << buildItem->GetPartNumber() << "\"" << std::endl; + if (buildItem->GetMetaDataGroup()->GetMetaDataCount() > 0) { + ShowMetaDataInformation(buildItem->GetMetaDataGroup()); + } + } + + std::cout << "done" << std::endl; +} + + +int main(int argc, char** argv) { + // Parse Arguments + if (argc != 2) { + std::cout << "Usage: " << std::endl; + std::cout << "ExtractInfo.exe model.3mf" << std::endl; + return 0; + } + + try { + ExtractInfoExample(argv[1]); + } + catch (ELib3MFException &e) { + std::cout << e.what() << std::endl; + return e.getErrorCode(); + } + return 0; +} diff --git a/SDK/Examples/CSharp/Lib3MF_Example.cs b/SDK/Examples/CSharp/Lib3MF_Example.cs index 53c85dff8..a5b5b9dcc 100644 --- a/SDK/Examples/CSharp/Lib3MF_Example.cs +++ b/SDK/Examples/CSharp/Lib3MF_Example.cs @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated CSharp application that demonstrates the usage of the CSharp bindings of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/SDK/Examples/Pascal/Lib3MF_Example.lpr b/SDK/Examples/Pascal/Lib3MF_Example.lpr index 6a564d7dd..22d95d28e 100644 --- a/SDK/Examples/Pascal/Lib3MF_Example.lpr +++ b/SDK/Examples/Pascal/Lib3MF_Example.lpr @@ -29,7 +29,7 @@ Abstract: This is an autogenerated Pascal application that demonstrates the usage of the Pascal bindings of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 *) diff --git a/SDK/Examples/Python/3mf_convert.py b/SDK/Examples/Python/3mf_convert.py new file mode 100644 index 000000000..10e10e264 --- /dev/null +++ b/SDK/Examples/Python/3mf_convert.py @@ -0,0 +1,93 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: An example to convert between 3MF and STL + +Interface version: 2.3.2 + +''' + + +import sys +from lib3mf_common import * + + +def find_extension(filename): + idx = filename.rfind('.') + if idx != -1: + return filename[idx:] + return "" + + +def convert(filename): + # Get a wrapper object + wrapper = get_wrapper() + + # Check version always + get_version(wrapper) + + extension = find_extension(filename).lower() + reader_name, writer_name, new_extension = "", "", "" + + if extension == ".stl": + reader_name = "stl" + writer_name = "3mf" + new_extension = ".3mf" + elif extension == ".3mf": + reader_name = "3mf" + writer_name = "stl" + new_extension = ".stl" + + if not reader_name: + print(f"Unknown input file extension: {extension}") + return -1 + + output_filename = filename[:-len(extension)] + new_extension + + model = wrapper.CreateModel() + reader = model.QueryReader(reader_name) + print(f"Reading {filename}...") + reader.ReadFromFile(filename) + + writer = model.QueryWriter(writer_name) + print(f"Writing {output_filename}...") + writer.WriteToFile(output_filename) + print("Done") + return 0 + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage:") + print("Convert 3MF to STL: python3 3mf_convert.py model.3mf") + print("Convert STL to 3MF: python3 3mf_convert.py model.stl") + else: + try: + result = convert(sys.argv[1]) + sys.exit(result) + except Exception as e: + print(str(e)) + sys.exit(1) \ No newline at end of file diff --git a/SDK/Examples/Python/Lib3MF_Example.py b/SDK/Examples/Python/Lib3MF_Example.py index 22220afd2..b656b5ac3 100644 --- a/SDK/Examples/Python/Lib3MF_Example.py +++ b/SDK/Examples/Python/Lib3MF_Example.py @@ -29,7 +29,7 @@ Abstract: This is an autogenerated Python application that demonstrates the usage of the Python bindings of the 3MF Library -Interface version: 2.3.1 +Interface version: 2.3.2 ''' diff --git a/SDK/Examples/Python/add_triangle.py b/SDK/Examples/Python/add_triangle.py new file mode 100644 index 000000000..80e335d32 --- /dev/null +++ b/SDK/Examples/Python/add_triangle.py @@ -0,0 +1,57 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: Simplest 3mf example that just includes a single triangle + +Interface version: 2.3.2 + +''' + +from lib3mf_common import * + +# Get wrapper +wrapper = get_wrapper() + +# Get version +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() + +# Initialize a mesh object +meshObject = model.AddMeshObject() + +# Now create 3 vertices +p1 = create_vertex_and_return_index(meshObject, 0, 0, 0) +p2 = create_vertex_and_return_index(meshObject, 0, 1, 0) +p3 = create_vertex_and_return_index(meshObject, 0, 0, 1) + +# Create a triangle with 3 positions +add_triangle(meshObject, p1, p2, p3) + +# Get a 3MF writer and write the single triangle +writer = model.QueryWriter("3mf") +writer.WriteToFile("triangle.3mf") diff --git a/SDK/Examples/Python/beam_lattice.py b/SDK/Examples/Python/beam_lattice.py new file mode 100644 index 000000000..c2fbce2d6 --- /dev/null +++ b/SDK/Examples/Python/beam_lattice.py @@ -0,0 +1,97 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: Beam Lattice example + +Interface version: 2.3.2 + +''' + + +from lib3mf_common import * + +# Get a wrapper object +wrapper = get_wrapper() + +# Check version always +get_version(wrapper) + +# Create a model and set name +model = wrapper.CreateModel() +mesh_object = model.AddMeshObject() +mesh_object.SetName("Beamlattice") + +# Modifiable size +fSizeX = 100.0 +fSizeY = 200.0 +fSizeZ = 300.0 + +# Define vertices (creates an array of lib3mf position objects) +vertices = [ + create_vertex(mesh_object, 0.0, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0.0, fSizeY, fSizeZ) +] + +# Define beam variables +r0 = 1.0 +r1 = 1.5 +r2 = 2.0 +r3 = 2.5 + +# Create a list of beams (strings are automatically converted to enums) +beams = [ + create_beam(2, 1, r0, r0, 'Butt', 'Butt'), + create_beam(0, 3, r0, r1, 'Sphere', 'Butt'), + create_beam(4, 5, r0, r2, 'Sphere', 'Butt'), + create_beam(6, 7, r0, r3, 'HemiSphere', 'Butt'), + create_beam(0, 1, r1, r0, 'HemiSphere', 'Butt'), + create_beam(5, 4, r1, r1, 'Sphere', 'HemiSphere'), + create_beam(2, 3, r1, r2, 'Sphere', 'Sphere'), + create_beam(7, 6, r1, r3, 'Butt', 'Butt'), + create_beam(1, 2, r2, r2, 'Butt', 'Butt'), + create_beam(6, 5, r2, r3, 'HemiSphere', 'Butt'), + create_beam(3, 0, r3, r0, 'Butt', 'Sphere'), + create_beam(4, 7, r3, r1, 'HemiSphere', 'HemiSphere') +] + +# Set geometry and beams +mesh_object.SetGeometry(vertices, []) +beam_lattice = mesh_object.BeamLattice() +beam_lattice.SetBeams(beams) +beam_lattice.SetMinLength(0.005) + +# Add mesh object to the model +model.AddBuildItem(mesh_object, wrapper.GetIdentityTransform()) + +# Write it out +writer = model.QueryWriter("3mf") +writer.WriteToFile("beamlattice.3mf") diff --git a/SDK/Examples/Python/color_cube.py b/SDK/Examples/Python/color_cube.py new file mode 100644 index 000000000..704b15248 --- /dev/null +++ b/SDK/Examples/Python/color_cube.py @@ -0,0 +1,121 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: Color cube example + +Interface version: 2.3.2 + +''' + + +from lib3mf_common import * + +# Get wrapper +wrapper = get_wrapper() + +# Get version +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() + +# Initialize a mesh object +mesh_object = model.AddMeshObject() +mesh_object.SetName("Colored Box") + +# Define cube size +fSizeX, fSizeY, fSizeZ = 100.0, 200.0, 300.0 + +# Create vertices +vertices = [ + create_vertex(mesh_object, 0.0, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, 0.0, 0.0), + create_vertex(mesh_object, fSizeX, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, fSizeY, 0.0), + create_vertex(mesh_object, 0.0, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0.0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0.0, fSizeY, fSizeZ) +] + +# Define triangles +triangles = [ + add_triangle(mesh_object, 2, 1, 0), + add_triangle(mesh_object, 0, 3, 2), + add_triangle(mesh_object, 4, 5, 6), + add_triangle(mesh_object, 6, 7, 4), + add_triangle(mesh_object, 0, 1, 5), + add_triangle(mesh_object, 5, 4, 0), + add_triangle(mesh_object, 2, 3, 7), + add_triangle(mesh_object, 7, 6, 2), + add_triangle(mesh_object, 1, 2, 6), + add_triangle(mesh_object, 6, 5, 1), + add_triangle(mesh_object, 3, 0, 4), + add_triangle(mesh_object, 4, 7, 3) +] + +# Set geometry +mesh_object.SetGeometry(vertices, triangles) + +# Define colors +color_group = model.AddColorGroup() +id_red = color_group.AddColor(wrapper.RGBAToColor(255, 0, 0, 255)) +id_green = color_group.AddColor(wrapper.RGBAToColor(0, 255, 0, 255)) +id_blue = color_group.AddColor(wrapper.RGBAToColor(0, 0, 255, 255)) +id_orange = color_group.AddColor(wrapper.RGBAToColor(255, 128, 0, 255)) +id_yellow = color_group.AddColor(wrapper.RGBAToColor(255, 255, 0, 255)) + +# Set triangle colors +sTriangleColorRed = create_triangle_color(color_group, id_red, id_red, id_red) +sTriangleColorGreen = create_triangle_color(color_group, id_green, id_green, id_green) +sTriangleColorBlue = create_triangle_color(color_group, id_blue, id_blue, id_blue) +sTriangleColor1 = create_triangle_color(color_group, id_orange, id_red, id_yellow) +sTriangleColor2 = create_triangle_color(color_group, id_yellow, id_green, id_orange) + + +# One-colored Triangles +mesh_object.SetTriangleProperties(0, sTriangleColorRed) +mesh_object.SetTriangleProperties(1, sTriangleColorRed) +mesh_object.SetTriangleProperties(2, sTriangleColorGreen) +mesh_object.SetTriangleProperties(3, sTriangleColorGreen) +mesh_object.SetTriangleProperties(4, sTriangleColorBlue) +mesh_object.SetTriangleProperties(5, sTriangleColorBlue) + +# Gradient-colored Triangles +mesh_object.SetTriangleProperties(6, sTriangleColor1) +mesh_object.SetTriangleProperties(7, sTriangleColor2) +mesh_object.SetTriangleProperties(8, sTriangleColor1) +mesh_object.SetTriangleProperties(9, sTriangleColor2) +mesh_object.SetTriangleProperties(10, sTriangleColor1) +mesh_object.SetTriangleProperties(11, sTriangleColor2) + +# Set object level property +mesh_object.SetObjectLevelProperty(sTriangleColorRed.ResourceID, sTriangleColorRed.PropertyIDs[0]) + +# Add build item and write to file +model.AddBuildItem(mesh_object, wrapper.GetIdentityTransform()) +writer = model.QueryWriter("3mf") +writer.WriteToFile("colorcube.3mf") diff --git a/SDK/Examples/Python/create_components.py b/SDK/Examples/Python/create_components.py new file mode 100644 index 000000000..f0bf17c0f --- /dev/null +++ b/SDK/Examples/Python/create_components.py @@ -0,0 +1,92 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: An example that creates multiple components using transformations + +Interface version: 2.3.2 + +''' + + +from lib3mf_common import * + +# Get wrapper +wrapper = get_wrapper() + +# Get version +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() +mesh_object = model.AddMeshObject() +mesh_object.SetName("Box") + +# Define the size of the box +fSizeX, fSizeY, fSizeZ = 10.0, 20.0, 30.0 + +# Create vertices +vertices = [ + create_vertex(mesh_object, 0, 0, 0), + create_vertex(mesh_object, fSizeX, 0, 0), + create_vertex(mesh_object, fSizeX, fSizeY, 0), + create_vertex(mesh_object, 0, fSizeY, 0), + create_vertex(mesh_object, 0, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0, fSizeY, fSizeZ) +] + +# Define triangles by vertices indices +triangle_indices = [ + (2, 1, 0), (0, 3, 2), (4, 5, 6), (6, 7, 4), + (0, 1, 5), (5, 4, 0), (2, 3, 7), (7, 6, 2), + (1, 2, 6), (6, 5, 1), (3, 0, 4), (4, 7, 3) +] + +# Create a list of triangles +triangles = [] +for v0, v1, v2 in triangle_indices: + triangles.append(add_triangle(mesh_object, v0, v1, v2)) + +# Set geometry to the mesh object after creating vertices and triangles +mesh_object.SetGeometry(vertices, triangles) + +# Adding components with different transformations +components_object = model.AddComponentsObject() +components_object.AddComponent(mesh_object, create_translation_matrix(0.0, 0.0, 0.0)) +components_object.AddComponent(mesh_object, create_translation_matrix(40.0, 60.0, 80.0)) +components_object.AddComponent(mesh_object, create_translation_matrix(120.0, 30.0, 70.0)) + +# Add the components object to the model as a build item +model.AddBuildItem(components_object, create_translation_matrix(0.0, 0.0, 0.0)) + +# Writing to files (3MF) +writer_3mf = model.QueryWriter("3mf") +writer_3mf.WriteToFile("components.3mf") + +# Dump to a STL file +writer_stl = model.QueryWriter("stl") +writer_stl.WriteToFile("components.stl") diff --git a/SDK/Examples/Python/create_cube.py b/SDK/Examples/Python/create_cube.py new file mode 100644 index 000000000..5a5aa007e --- /dev/null +++ b/SDK/Examples/Python/create_cube.py @@ -0,0 +1,82 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: Create a simple cube + +Interface version: 2.3.2 + +''' + + +from lib3mf_common import * + +# Get a wrapper object +wrapper = get_wrapper() + +# Check version always +get_version(wrapper) + +# Create a model +model = wrapper.CreateModel() +mesh_object = model.AddMeshObject() +mesh_object.SetName("Box") + +# Define the size of the cube +fSizeX, fSizeY, fSizeZ = 100.0, 200.0, 300.0 + +# Create vertices +vertices = [ + create_vertex(mesh_object, 0, 0, 0), + create_vertex(mesh_object, fSizeX, 0, 0), + create_vertex(mesh_object, fSizeX, fSizeY, 0), + create_vertex(mesh_object, 0, fSizeY, 0), + create_vertex(mesh_object, 0, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, 0, fSizeZ), + create_vertex(mesh_object, fSizeX, fSizeY, fSizeZ), + create_vertex(mesh_object, 0, fSizeY, fSizeZ) +] + +# Define triangles by vertices indices +triangle_indices = [ + (2, 1, 0), (0, 3, 2), (4, 5, 6), (6, 7, 4), + (0, 1, 5), (5, 4, 0), (2, 3, 7), (7, 6, 2), + (1, 2, 6), (6, 5, 1), (3, 0, 4), (4, 7, 3) +] + +# Create triangles +triangles = [] +for v0, v1, v2 in triangle_indices: + triangles.append(add_triangle(mesh_object, v0, v1, v2)) + +# Set geometry to the mesh object after creating vertices and triangles +mesh_object.SetGeometry(vertices, triangles) + +# Add build item with an identity transform +model.AddBuildItem(mesh_object, wrapper.GetIdentityTransform()) + +# Save the model to a 3MF file +writer = model.QueryWriter("3mf") +writer.WriteToFile("cube.3mf") diff --git a/SDK/Examples/Python/extract_info.py b/SDK/Examples/Python/extract_info.py new file mode 100644 index 000000000..0aa1be623 --- /dev/null +++ b/SDK/Examples/Python/extract_info.py @@ -0,0 +1,62 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: Extract info from a 3MF model + +Interface version: 2.3.2 + +''' + + +import sys +from lib3mf_common import * + + +def extract_info(file_path): + wrapper = get_wrapper() + model = wrapper.CreateModel() + + # Initialize a 3MF reader + read_3mf_file_to_model(model, file_path) + + # Print library version + get_version(wrapper) + + # Show meta data info + show_metadata_information(model.GetMetaDataGroup()) + + # Show slice stack info + show_slice_stack_information(model) + + # Show object info + show_object_information(model) + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python extract_info.py model.3mf") + sys.exit() + extract_info(sys.argv[1]) diff --git a/SDK/Examples/Python/lib3mf_common.py b/SDK/Examples/Python/lib3mf_common.py new file mode 100644 index 000000000..c9296d1f1 --- /dev/null +++ b/SDK/Examples/Python/lib3mf_common.py @@ -0,0 +1,194 @@ +'''++ + +Copyright (C) 2019 3MF Consortium (Vijai Kumar Suriyababu) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. 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. + +Abstract: Common set of functions that are used across all examples + +Interface version: 2.3.2 + +''' + +import os +import sys + +try: + import lib3mf + from lib3mf import get_wrapper +except ImportError: + sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..", "Bindings", "Python")) + import Lib3MF as lib3mf + import Lib3MF + + + def get_wrapper(): + libpath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..", "Bin") + wrapper = Lib3MF.Wrapper(os.path.join(libpath, "lib3mf")) + return wrapper + + +def create_vertex(_mesh, x, y, z): + position = lib3mf.Position() + position.Coordinates[0] = float(x) + position.Coordinates[1] = float(y) + position.Coordinates[2] = float(z) + _mesh.AddVertex(position) + return position + + +def create_vertex_and_return_index(_mesh, x, y, z): + position = lib3mf.Position() + position.Coordinates[0] = float(x) + position.Coordinates[1] = float(y) + position.Coordinates[2] = float(z) + vertex_index = _mesh.AddVertex(position) + return vertex_index + + +def add_triangle(_mesh, p1, p2, p3): + triangle = lib3mf.Triangle() + triangle.Indices[0] = p1 + triangle.Indices[1] = p2 + triangle.Indices[2] = p3 + _mesh.AddTriangle(triangle) + return triangle + + +def get_version(wrapper): + major, minor, micro = wrapper.GetLibraryVersion() + print("Lib3MF version: {:d}.{:d}.{:d}".format(major, minor, micro), end="") + hasInfo, prereleaseinfo = wrapper.GetPrereleaseInformation() + if hasInfo: + print("-" + prereleaseinfo, end="") + hasInfo, buildinfo = wrapper.GetBuildInformation() + if hasInfo: + print("+" + buildinfo, end="") + print("") + + +# Show metadata information +def show_metadata_information(metadata_group): + count = metadata_group.GetMetaDataCount() + for i in range(count): + metadata = metadata_group.GetMetaData(i) + print(f"Metadata: {metadata.GetName()} = {metadata.GetValue()}") + + +# Show slice stack information +def show_slice_stack_information(model): + slice_stacks = model.GetSliceStacks() + while slice_stacks.MoveNext(): + slice_stack = slice_stacks.GetCurrentSliceStack() + print(f"Slice Stack: {slice_stack.GetResourceID()}") + + +# Show object information +def show_object_information(model): + object_iterator = model.GetObjects() + while object_iterator.MoveNext(): + obj = object_iterator.GetCurrentObject() + if obj.IsMeshObject(): + print(f"Mesh Object: {obj.GetResourceID()}") + elif obj.IsComponentsObject(): + print(f"Components Object: {obj.GetResourceID()}") + else: + print(f"Unknown Object: {obj.GetResourceID()}") + + +def read_3mf_file_to_model(model, file_path): + reader = model.QueryReader("3mf") + reader.SetStrictModeActive(False) + reader.ReadFromFile(file_path) + + +def create_translation_matrix(x, y, z): + matrix = lib3mf.Transform() + + # Default to identity matrix with translation + identity_matrix = [ + (1.0, 0.0, 0.0), # Row for X axis + (0.0, 1.0, 0.0), # Row for Y axis + (0.0, 0.0, 1.0), # Row for Z axis + (x, y, z) # Translation + ] + + # Fill the Fields with identity matrix values + for i in range(4): + for j in range(3): + matrix.Fields[i][j] = identity_matrix[i][j] + + return matrix + + +def convert_beam_string_to_enum(beam_mode): + beam_mode = str(beam_mode).lower() + if beam_mode == "butt": + return lib3mf.BeamLatticeCapMode.Butt + if beam_mode == "sphere": + return lib3mf.BeamLatticeCapMode.Sphere + if beam_mode == "hemisphere": + return lib3mf.BeamLatticeCapMode.HemiSphere + + +def create_beam(v0, v1, r0, r1, c0, c1): + beam = lib3mf.Beam() + beam.Indices[0] = v0 + beam.Indices[1] = v1 + beam.Radii[0] = r0 + beam.Radii[1] = r1 + beam.CapModes[0] = convert_beam_string_to_enum(c0) + beam.CapModes[1] = convert_beam_string_to_enum(c1) + return beam + + +def create_triangle_color(color_group, color_id1, color_id2, color_id3): + triangle_properties = lib3mf.TriangleProperties() + triangle_properties.ResourceID = color_group.GetResourceID() + triangle_properties.PropertyIDs[0] = color_id1 + triangle_properties.PropertyIDs[1] = color_id2 + triangle_properties.PropertyIDs[2] = color_id3 + return triangle_properties + + +def convert_list_to_array(_list, _datatype): + _array_type = _datatype * len(_list) # Define the type of the array + _array = _array_type() # Create an instance of the array + + # Populate the array + for i, _list_entry in enumerate(_list): + _array[i] = _list_entry + + return _array + + +def vertex_array(_position_list): + return convert_list_to_array(_position_list, lib3mf.Position) + + +def triangle_array(_triangle_list): + return convert_list_to_array(_triangle_list, lib3mf.Triangle) + + +def beam_array(_beam_list): + return convert_list_to_array(_beam_list, lib3mf.Beam) diff --git a/SDK/GenerateSDK_github.sh b/SDK/GenerateSDK_github.sh index 6a59330ea..00a0d6236 100644 --- a/SDK/GenerateSDK_github.sh +++ b/SDK/GenerateSDK_github.sh @@ -43,4 +43,4 @@ echo "GITRevision = "`git rev-parse HEAD` >> $VERSIONTXT echo Zip SDK artifacts cd $SDKARTIFACT -zip -r ../$OUTFILE ./* || failed "Error zipping SDK" +zip -r ../$OUTFILE ./* || failed "Error zipping SDK" \ No newline at end of file diff --git a/SDK/Readme.md b/SDK/Readme.md index fa392dda7..7ed4124cd 100644 --- a/SDK/Readme.md +++ b/SDK/Readme.md @@ -18,4 +18,4 @@ The specification can be downloaded at ## Documentation -lib3mf's documentation is available on https://lib3mf.readthedocs.io or as PDF in [Documentation/lib3mf_v2.3.1.pdf](Documentation/lib3mf_v2.3.1.pdf). +lib3mf's documentation is available on https://lib3mf.readthedocs.io or as PDF in [Documentation/lib3mf_v2.3.2.pdf](Documentation/lib3mf_v2.3.2.pdf). diff --git a/Source/API/lib3mf.cpp b/Source/API/lib3mf.cpp index 79d207aab..4b309cab2 100644 --- a/Source/API/lib3mf.cpp +++ b/Source/API/lib3mf.cpp @@ -29,7 +29,7 @@ This file has been generated by the Automatic Component Toolkit (ACT) version 1. Abstract: This is an autogenerated C++ implementation file in order to allow easy development of the 3MF Library. It needs to be generated only once. -Interface version: 2.3.1 +Interface version: 2.3.2 */ diff --git a/Source/Common/NMR_StringUtils.cpp b/Source/Common/NMR_StringUtils.cpp index 7c663e492..81dad377b 100644 --- a/Source/Common/NMR_StringUtils.cpp +++ b/Source/Common/NMR_StringUtils.cpp @@ -153,6 +153,9 @@ namespace NMR { __NMRASSERT(pwszValue); nfDouble dResult = 0.0; + //skip leading whitespaces + for (; *pszValue && *pszValue == ' '; pszValue++); + // Convert to double and make a input and range check! auto answer = fast_float::from_chars(pszValue, pszValue + strlen(pszValue), dResult); diff --git a/Source/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.cpp b/Source/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.cpp index d25fb17a5..1889288d9 100644 --- a/Source/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.cpp +++ b/Source/Model/Writer/v100/NMR_ModelWriterNode100_Mesh.cpp @@ -52,7 +52,7 @@ namespace NMR { CModelWriterNode100_Mesh::CModelWriterNode100_Mesh(_In_ CModelMeshObject * pModelMeshObject, _In_ CXmlWriter * pXMLWriter, _In_ PProgressMonitor pProgressMonitor, _In_ PMeshInformation_PropertyIndexMapping pPropertyIndexMapping, _In_ int nPosAfterDecPoint, _In_ nfBool bWriteMaterialExtension, _In_ nfBool bWriteBeamLatticeExtension) - :CModelWriterNode_ModelBase(pModelMeshObject->getModel(), pXMLWriter, pProgressMonitor), m_nPosAfterDecPoint(nPosAfterDecPoint), m_nPutDoubleFactor((int)(pow(10, CModelWriterNode100_Mesh::m_nPosAfterDecPoint))) + :CModelWriterNode_ModelBase(pModelMeshObject->getModel(), pXMLWriter, pProgressMonitor), m_nPosAfterDecPoint(nPosAfterDecPoint), m_nPutDoubleFactor((nfInt64)(pow(10, CModelWriterNode100_Mesh::m_nPosAfterDecPoint))) { __NMRASSERT(pModelMeshObject != nullptr); if (!pPropertyIndexMapping.get()) @@ -79,7 +79,7 @@ namespace NMR { putBallRefString(MODELWRITERMESH100_BEAMLATTICE_BALLREFLINESTART); } - bool stringRepresentationsDiffer(double a, double b, double putFactor) { + bool stringRepresentationsDiffer(double a, double b, nfInt64 putFactor) { return fabs(a - b) * putFactor > 0.1; } diff --git a/Tests/CPP_Bindings/Source/Reader.cpp b/Tests/CPP_Bindings/Source/Reader.cpp index 03e4b4698..27f911e31 100644 --- a/Tests/CPP_Bindings/Source/Reader.cpp +++ b/Tests/CPP_Bindings/Source/Reader.cpp @@ -161,9 +161,17 @@ namespace Lib3MF TEST_F(Reader, ReadVerticesWithLeadingPLUSSign) { // This file P_XXM_0519_01.3mf contains vertices with leading + sign e.g +1E+2. - // The 3MFReader allows leading = sign at NMR_StringUtils::fnStringToDouble when reading this file. + // The 3MFReader allows leading + sign at NMR_StringUtils::fnStringToDouble when reading this file. auto reader = model->QueryReader("3mf"); reader->ReadFromFile(sTestFilesPath + "/Reader/" + "P_XXM_0519_01.3mf"); CheckReaderWarnings(Reader::reader3MF, 0); } + + TEST_F(Reader, ReadVerticesValueWithLeadingTrialingSpaces) { + // This file cam-51476-test.3mf contains vertices with leading whitespaces. + // The 3MFReader allows leading/trialing whitespaces at NMR_StringUtils::fnStringToDouble when reading this file. + auto reader = model->QueryReader("3mf"); + reader->ReadFromFile(sTestFilesPath + "/Reader/" + "cam_51476_test.3mf"); + CheckReaderWarnings(Reader::reader3MF, 0); + } } diff --git a/Tests/TestFiles/Reader/cam_51476_test.3mf b/Tests/TestFiles/Reader/cam_51476_test.3mf new file mode 100644 index 000000000..97d858084 Binary files /dev/null and b/Tests/TestFiles/Reader/cam_51476_test.3mf differ diff --git a/cmake/GenerateMake.sh b/cmake/GenerateMake.sh index 2dd76c964..4f593f3f4 100644 --- a/cmake/GenerateMake.sh +++ b/cmake/GenerateMake.sh @@ -4,4 +4,22 @@ basepath="$(cd "$(dirname "$0")" && pwd)" builddir="$basepath/../build" mkdir -p "$builddir" cd "$builddir" -cmake .. -G "Unix Makefiles" "$@" + +# Check if we are on macOS +if [ "$(uname)" = "Darwin" ]; then + # Check if the first argument is Debug mode + if [ "$1" = "Debug" ]; then + shift # Remove the first argument to pass remaining arguments + cmake .. -G "Unix Makefiles" -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_BUILD_TYPE=Debug "$@" + else + cmake .. -G "Unix Makefiles" -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_BUILD_TYPE=Release "$@" + fi +else + # For Linux and other OSes + if [ "$1" = "Debug" ]; then + shift # Remove the first argument to pass remaining arguments + cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug "$@" + else + cmake .. -G "Unix Makefiles" "$@" + fi +fi \ No newline at end of file diff --git a/cmake/lib3mfConfig.cmake b/cmake/lib3mfConfig.cmake new file mode 100644 index 000000000..f1305b8f5 --- /dev/null +++ b/cmake/lib3mfConfig.cmake @@ -0,0 +1,104 @@ +# lib3mfConfig.cmake + +if(VCPKG_TOOLCHAIN) + message("Lib3MF - VCPKG Tool Chain") + set(LIB3MF_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") +else() + message("Lib3MF - General CMake Tool Chain") + set(LIB3MF_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../../..") +endif() + + +# Initial setup for known components and default selection +set(lib3mf_known_components "C" "CDynamic" "Cpp" "CppDynamic") +set(lib3mf_selected_variant "Cpp") # Default variant + +# Check if any known component was specified and select it +foreach(comp ${lib3mf_FIND_COMPONENTS}) + if(comp IN_LIST lib3mf_known_components) + set(lib3mf_selected_variant ${comp}) + break() # Use the first specified known component + endif() +endforeach() + +# Configure paths based on the selected variant +set(lib3mf_INCLUDE_DIR "${LIB3MF_ROOT_DIR}/include/Bindings/${lib3mf_selected_variant}") +set(lib3mf_LIBRARY_DIR "${LIB3MF_ROOT_DIR}/lib") +set(lib3mf_BINARY_DIR "${LIB3MF_ROOT_DIR}/bin") + +# Adjust library file name based on platform +if(WIN32) + set(lib3mf_LIBRARY "${lib3mf_BINARY_DIR}/lib3mf.dll") + set(lib3mf_LIBRARY_IMPORT "${lib3mf_LIBRARY_DIR}/lib3mf.lib") # For importing symbols +elseif(APPLE) + set(lib3mf_LIBRARY "${lib3mf_LIBRARY_DIR}/lib3mf.dylib") +else() # Linux and others + set(lib3mf_LIBRARY "${lib3mf_LIBRARY_DIR}/lib3mf.so") +endif() + +# Print the chosen variant +message("***********************************") +message("LIB3MF Chosen Variant : " ${lib3mf_selected_variant}) +message("***********************************") + +# Create a special interface for dynamic loading scenarios +if("${lib3mf_selected_variant}" STREQUAL "CppDynamic" OR "${lib3mf_selected_variant}" STREQUAL "CDynamic") + if("${lib3mf_selected_variant}" STREQUAL "CDynamic") + message("*****************************************************************************") + message("") + message(" For CDynamic Variant, an additional source called lib3mf_dynamic.cc ") + message(" is required ") + message(" It is made available using the variable LIB3MF_CDYNAMIC_ADDITIONAL_SOURCE ") + message(" You must append this to your sources ") + message("") + message("*****************************************************************************") + set(LIB3MF_CDYNAMIC_ADDITIONAL_SOURCE "${LIB3MF_ROOT_DIR}/include/Bindings/CDynamic/lib3mf_dynamic.cc") + endif() + add_library(lib3mfdynamic INTERFACE) + # Now alias lib3mfdynamic to include the namespace + add_library(lib3mf::lib3mf ALIAS lib3mfdynamic) + # Set properties and compile definitions for lib3mfdynamic + target_compile_definitions(lib3mfdynamic INTERFACE + "LIB3MF_LIBRARY_LOCATION=\"${lib3mf_LIBRARY}\"" + ) + target_include_directories(lib3mfdynamic INTERFACE "${lib3mf_INCLUDE_DIR}") +else() + # Define the imported target for static linking + add_library(lib3mf::lib3mf SHARED IMPORTED) + set_target_properties(lib3mf::lib3mf PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${lib3mf_INCLUDE_DIR}" + IMPORTED_LOCATION "${lib3mf_LIBRARY}" + ) + if(WIN32) + set_property(TARGET lib3mf::lib3mf PROPERTY IMPORTED_IMPLIB "${lib3mf_LIBRARY_IMPORT}") + endif() + + # Define a custom function to handle library copying + function(copy_lib3mf_libraries target) + if(TARGET ${target}) + if(APPLE) + # On macOS, copy .dylib files, preserving symlinks only if they don't already exist in the target directory + file(GLOB LIB3MF_FILES "${lib3mf_LIBRARY_DIR}/lib3mf.dylib*") + foreach(file ${LIB3MF_FILES}) + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${file}" "$/$(basename ${file})" + COMMENT "Copying $(basename ${file}) to target directory on macOS if it is different") + endforeach() + + + elseif(UNIX) + # On Unix-like systems (excluding macOS), copy .so files, preserving symlinks + add_custom_command(TARGET ${target} POST_BUILD + COMMAND sh -c "cp -P '${lib3mf_LIBRARY_DIR}/lib3mf.so'* '$'" + COMMENT "Copying all lib3mf.so* files to target directory on Linux") + else() + # On Windows, directly copy the .dll file without worrying about symlinks + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${lib3mf_LIBRARY}" "$" + COMMENT "Copying lib3mf.dll to target directory on Windows") + endif() + else() + message(WARNING "Target '${target}' not found. lib3mf library was not copied.") + endif() + endfunction() +endif() diff --git a/lib3mf_version_update.py b/lib3mf_version_update.py new file mode 100644 index 000000000..bcae19022 --- /dev/null +++ b/lib3mf_version_update.py @@ -0,0 +1,250 @@ +''' + +@author: Vijai Kumar Suriyababu + +A simple script to update the lib3mf version number in all the necessary places. +Its run as follows + +python lib3mf_version_update.py 2.3.1 2.3.2 + +First argument is current version number and the second one is new version number + +It does the following +* Update version number in lib3mf.xml and generate bindings using ACT +* Patch the Python bindings +* Update the CMakeLists.txt +* Update all the docs, readme's and python, CPP examples and so on + +''' + +import os +import argparse +import re +import platform +import subprocess + + +def update_version_in_xml(file_path, old_version, new_version): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + + # Use regex to replace the old version with the new version + updated_content = re.sub( + fr'(]*version="){old_version}(")', + fr'\g<1>{new_version}\g<2>', + content + ) + + with open(file_path, 'w', encoding='utf-8') as file: + file.write(updated_content) + + print(f"Updated {file_path}") + + +def run_act_command(): + start_dir = os.getcwd() + act_dir = os.path.join(start_dir, 'AutomaticComponentToolkit') + + # Determine the command based on the operating system and architecture + os_type = platform.system() + arch = platform.machine() + + if os_type == 'Darwin': + if 'arm' in arch.lower(): + command = './act.arm.darwin lib3mf.xml -bindings ../Autogenerated/Bindings -interfaces ../Autogenerated/Source -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples' + else: + command = './act.darwin lib3mf.xml -bindings ../Autogenerated/Bindings -interfaces ../Autogenerated/Source -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples' + elif os_type == 'Linux': + if 'arm' in arch.lower(): + command = './act.arm.linux64 lib3mf.xml -bindings ../Autogenerated/Bindings -interfaces ../Autogenerated/Source -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples' + else: + command = './act.linux64 lib3mf.xml -bindings ../Autogenerated/Bindings -interfaces ../Autogenerated/Source -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples' + elif os_type == 'Windows': + command = 'act.win64.exe lib3mf.xml -bindings ..\\Autogenerated\\Bindings -interfaces ..\\Autogenerated\\Source -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples' + else: + raise RuntimeError(f'Unsupported OS: {os_type}') + + try: + # Change to the AutomaticComponentToolkit directory + os.chdir(act_dir) + + # Execute the command + subprocess.run(command, shell=True, check=True) + print(f"Command executed successfully: {command}") + except subprocess.CalledProcessError as e: + print(f"Command failed with error: {e}") + finally: + # Change back to the original directory + os.chdir(start_dir) + + +def patch_python_bindings(): + start_dir = os.getcwd() + bindings_path = os.path.join(start_dir, 'Autogenerated', 'Bindings', 'Python', 'Lib3MF.py') + + search_line = r"\tNone = 0" + new_line = r"\tBeamLatticeBallModeNone = 0" + + with open(bindings_path, 'r', encoding='utf-8') as file: + content = file.read() + + # Use regex to replace the specific line + updated_content = re.sub(search_line, new_line, content) + + with open(bindings_path, 'w', encoding='utf-8') as file: + file.write(updated_content) + + print(f"Python bindings patched successfully: {bindings_path}") + + +def update_version_in_cmakelists(new_version): + if '-' in new_version: + version, prerelease = new_version.split('-', 1) + else: + version, prerelease = new_version, "" + + major, minor, micro = version.split('.') + + with open('CMakeLists.txt', 'r', encoding='utf-8') as file: + content = file.read() + + content = re.sub(r'set\(LIB3MF_VERSION_MAJOR \d+\)', f'set(LIB3MF_VERSION_MAJOR {major})', content) + content = re.sub(r'set\(LIB3MF_VERSION_MINOR \d+\)', f'set(LIB3MF_VERSION_MINOR {minor})', content) + content = re.sub(r'set\(LIB3MF_VERSION_MICRO \d+\)', f'set(LIB3MF_VERSION_MICRO {micro})', content) + content = re.sub(r'set\(LIB3MF_VERSION_PRERELEASE ".*"\)', f'set(LIB3MF_VERSION_PRERELEASE "{prerelease}")', + content) + + with open('CMakeLists.txt', 'w', encoding='utf-8') as file: + file.write(content) + + print(f"Updated CMakeLists.txt") + + +def update_version_in_conf_py(file_path, old_version, new_version): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + + # Update the release version + updated_content = re.sub( + fr"release = 'v{old_version}'", + fr"release = 'v{new_version}'", + content + ) + + with open(file_path, 'w', encoding='utf-8') as file: + file.write(updated_content) + + print(f"Updated {file_path}") + + +def update_version_in_index_rst(file_path, old_version, new_version): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + + # Replace all instances of the old version with the new version + updated_content = content.replace(old_version, new_version) + + with open(file_path, 'w', encoding='utf-8') as file: + file.write(updated_content) + + print(f"Updated {file_path}") + + +def update_version_in_readme_md(file_path, old_version, new_version): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + + # Update the PDF link version + updated_content = re.sub( + fr"lib3mf_v{old_version}\.pdf", + fr"lib3mf_v{new_version}.pdf", + content) + + with open(file_path, 'w', encoding='utf-8') as file: + file.write(updated_content) + + print(f"Updated {file_path}") + + +def update_version_in_file(file_path, old_version, new_version): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + + # Replace all instances of the old version with the new version + updated_content = content.replace(old_version, new_version) + + with open(file_path, 'w', encoding='utf-8') as file: + file.write(updated_content) + + print(f"Updated {file_path}") + + +def main(): + parser = argparse.ArgumentParser(description='Update lib3mf version in multiple files.') + parser.add_argument('old_version', type=str, help='The old version number to be replaced.') + parser.add_argument('new_version', type=str, help='The new version number to update to.') + args = parser.parse_args() + old_version = args.old_version + new_version = args.new_version + + # Get the current working directory + start_dir = os.getcwd() + + # Update AutomaticComponentToolkit/lib3mf.xml + xml_file_path = os.path.join(start_dir, 'AutomaticComponentToolkit', 'lib3mf.xml') + update_version_in_xml(xml_file_path, old_version, new_version) + + # Run the act command + run_act_command() + + # Patch the Python bindings + patch_python_bindings() + + # Update CMakeLists.txt + update_version_in_cmakelists(new_version) + + # Update Documentation/conf.py + conf_py_path = os.path.join(start_dir, 'Documentation', 'conf.py') + update_version_in_conf_py(conf_py_path, old_version, new_version) + + # Update Documentation/index.rst + index_rst_path = os.path.join(start_dir, 'Documentation', 'index.rst') + update_version_in_index_rst(index_rst_path, old_version, new_version) + + # Update SDK/Readme.md + readme_md_path = os.path.join(start_dir, 'SDK', 'Readme.md') + update_version_in_readme_md(readme_md_path, old_version, new_version) + + # Update README.md at the same location as this script + readme_path = os.path.join(start_dir, 'README.md') + update_version_in_readme_md(readme_path, old_version, new_version) + + # Define all additional file paths that need to be updated + additional_file_paths = [ + os.path.join(start_dir, 'SDK', 'Readme.md'), + os.path.join(start_dir, 'README.md'), + os.path.join(start_dir, 'Autogenerated', 'Bindings', 'Go', 'lib3mf_impl.go'), + os.path.join(start_dir, 'Autogenerated', 'Bindings', 'CppDynamic', 'lib3mf_abi.hpp'), + os.path.join(start_dir, 'SDK', 'Examples', 'CSharp', 'Lib3MF_Example.cs'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'lib3mf_common.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'Lib3MF_Example.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'create_cube.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'beam_lattice.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'add_triangle.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'color_cube.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', '3mf_convert.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'extract_info.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Python', 'create_components.py'), + os.path.join(start_dir, 'SDK', 'Examples', 'Pascal', 'Lib3MF_Example.lpr'), + os.path.join(start_dir, 'SDK', 'CPackExamples', 'Cpp', 'CMakeLists.txt'), + os.path.join(start_dir, 'SDK', 'CPackExamples', 'CppDynamic', 'CMakeLists.txt'), + os.path.join(start_dir, 'Source', 'API', 'lib3mf.cpp'), + ] + + # Update all additional specified files + for file_path in additional_file_paths: + update_version_in_file(file_path, old_version, new_version) + + +if __name__ == "__main__": + main() diff --git a/submodules/zlib b/submodules/zlib index 09155eaa2..51b7f2abd 160000 --- a/submodules/zlib +++ b/submodules/zlib @@ -1 +1 @@ -Subproject commit 09155eaa2f9270dc4ed1fa13e2b4b2613e6e4851 +Subproject commit 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf