diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 059ef365cf..ee49634a2a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -37,10 +37,10 @@ jobs: benchmark: uses: ultimaker/cura-workflows/.github/workflows/benchmark.yml@main with: - conan_extra_args: "-o \"curaengine/*:enable_benchmarks=True\"" - benchmark_cmd: "./build/Release/benchmark/benchmarks --benchmark_format=json --benchmark_out=benchmark_result.json" + conan_extra_args: "-c tools.build:skip_test=False -o \"curaengine/*:enable_benchmarks=True\"" + benchmark_cmd: "benchmark/benchmarks --benchmark_format=json --benchmark_out=benchmark_result.json" name: "C++ Benchmark" - output_file_path: "build/Release/benchmark_result.json" + output_file_path: "benchmark_result.json" data_dir: "dev/bench" tool: "googlecpp" alert_threshold: "150%" diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index be45106c2c..8145b07e83 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -24,20 +24,13 @@ permissions: contents: write deployments: write -# TODO: Make cura-workflows/benchmark.yml generic enough to fit the gcodeanalyzer benchmark jobs: check_actor: uses: ultimaker/cura-workflows/.github/workflows/check-actor.yml@main secrets: inherit - conan-recipe-version: - needs: [ check_actor ] - if: ${{ needs.check_actor.outputs.proceed == 'true' }} - uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main - gcodeanalyzer: - needs: [ conan-recipe-version ] name: Run GCodeAnalyzer on the engine runs-on: ubuntu-latest steps: @@ -64,17 +57,19 @@ jobs: fetch-depth: 1 token: ${{ secrets.GITHUB_TOKEN }} - - name: Install dependencies - run: conan install . ${{ needs.conan-recipe-version.outputs.version_full }} -s "*:build_type=Release" --build=missing --update -g VirtualRunEnv -c tools.build:skip_test=True -o with_cura_resources=True - - - name: Build CuraEngine and tests + - name: Install Python requirements run: | - source build/Release/generators/conanbuild.sh - cmake --preset release - cmake --build --preset release + pip install pandas + pip install git+https://github.com/ultimaker/libcharon@CURA-9495_analyzer_requisites#egg=charon + + - name: Install dependencies and build CuraEngine + run: conan build . -s build_type=Release --build=missing --update -g VirtualRunEnv -o "curaengine/*:with_cura_resources=True" - name: Collect STL-files, run CuraEngine, output GCode-files run: | + source build/Release/generators/conanrun.sh + echo $CURA_RESOURCES + ls $CURA_RESOURCES for file in `ls NightlyTestModels/*.stl`; do ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j $CURA_RESOURCES/definitions/ultimaker_s3.def.json -l $file -o `basename $file .stl`.gcode ) 2> `basename $file .stl`.time @@ -83,6 +78,8 @@ jobs: # TODO: Move this to GCodeAnalyzer - name: Run GCodeAnalyzer on generated GCode files id: gcode_out + shell: python + working-directory: GCodeAnalyzer run: | import sys import os @@ -205,8 +202,6 @@ jobs: with open("../output.json", "w") as outfile: outfile.write(json.dumps(jzon)) - shell: python - working-directory: GCodeAnalyzer - name: Store benchmark result uses: benchmark-action/github-action-benchmark@v1 diff --git a/.github/workflows/lint-formatter.yml b/.github/workflows/lint-formatter.yml index ac5620f16a..5316ab9599 100644 --- a/.github/workflows/lint-formatter.yml +++ b/.github/workflows/lint-formatter.yml @@ -1,46 +1,21 @@ name: lint-formatter on: - workflow_dispatch: - push: paths: - 'include/**/*.h*' - 'src/**/*.c*' + pull_request: + types: [ opened ] + paths: + - 'include/**/*.h*' + - 'src/**/*.c*' + jobs: lint-formatter-job: - name: Auto-apply clang-format - - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - uses: greguintow/get-diff-action@v7 - with: - PATTERNS: | - include/**/*.h* - src/**/*.c* - - - name: Setup Python and pip - if: env.GIT_DIFF && !env.MATCHED_FILES # If nothing happens with python and/or pip after, the clean-up crashes. - uses: actions/setup-python@v5 - with: - python-version: 3.11.x - cache: 'pip' - cache-dependency-path: .github/workflows/requirements-linter.txt - - - name: Install Python requirements for runner - if: env.GIT_DIFF && !env.MATCHED_FILES - run: pip install -r .github/workflows/requirements-linter.txt - - - name: Format file - if: env.GIT_DIFF && !env.MATCHED_FILES - run: | - clang-format -i ${{ env.GIT_DIFF_FILTERED }} - - - uses: stefanzweifel/git-auto-commit-action@v4 - if: env.GIT_DIFF && !env.MATCHED_FILES - with: - commit_message: "Applied clang-format." + uses: ultimaker/cura-workflows/.github/workflows/lint-formatter.yml@main + with: + file_patterns: +(include|src)/**/*.+(h|hpp|c|cpp) + command: clang-format --verbose -i + commit_message: "Apply clang-format" diff --git a/.github/workflows/npm-package.yml b/.github/workflows/npm-package.yml deleted file mode 100644 index ed7fd365df..0000000000 --- a/.github/workflows/npm-package.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: NPM package - -on: - workflow_dispatch: - inputs: - branch: - description: 'Branch to build' - required: true - default: 'main' - -jobs: - build: - runs-on: ubuntu-latest - - permissions: - contents: read - packages: write - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.branch }} - - - name: Sync pip requirements - run: curl -O https://raw.githubusercontent.com/Ultimaker/cura-workflows/main/.github/workflows/requirements-runner.txt - working-directory: .github/workflows - - - name: Setup Python and pip - uses: actions/setup-python@v4 - with: - python-version: 3.11.x - cache: pip - cache-dependency-path: .github/workflows/requirements-runner.txt - - - name: Install Python requirements and Create default Conan profile - run: pip install -r .github/workflows/requirements-runner.txt - - - name: Install Linux system requirements for building - run: | - mkdir runner_scripts - cd runner_scripts - curl -O https://raw.githubusercontent.com/Ultimaker/cura-workflows/main/runner_scripts/ubuntu_setup.sh - chmod +x ubuntu_setup.sh - sudo ./ubuntu_setup.sh - - - name: Setup pipeline caches - run: | - mkdir -p /home/runner/.conan/downloads - mkdir -p /home/runner/.conan/data - - - name: Create default Conan profile - run: conan profile new default --detect - - # FIXME: Once merged to main: conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}" - - name: Get Conan configuration - run: | - conan config install https://github.com/Ultimaker/conan-config.git - conan config install https://github.com/Ultimaker/conan-config.git -a "-b NP-419" - - - name: Add runner credentials to cura remote - run: conan user -p ${{ secrets.CONAN_PASS }} -r cura ${{ secrets.CONAN_USER }} - - - name: Cache Conan packages - uses: actions/cache@v3 - with: - path: /home/runner/.conan/data - key: ${{ runner.os }}-conan-data-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-conan-data- - - - name: Cache Conan downloads - uses: actions/cache@v3 - with: - path: /home/runner/.conan/downloads - key: ${{ runner.os }}-conan-downloads-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-conan-downloads- - - - name: Use Node.js - uses: actions/setup-node@v4 - with: - registry-url: 'https://npm.pkg.github.com' - scope: '@ultimaker' - - - name: Set npm config - run: | - cd CuraEngineJS - npm publish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Upload the Package(s) - if: ${{ always() }} - run: | - conan remove "cura_private_data/*" --force - conan remove "fdm_materials/*" --force - conan upload "*" -r cura --all -c diff --git a/.github/workflows/conan-package.yml b/.github/workflows/package.yml similarity index 60% rename from .github/workflows/conan-package.yml rename to .github/workflows/package.yml index d0f493dd16..e736de02d8 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/package.yml @@ -1,4 +1,4 @@ -name: conan-package +name: package on: push: @@ -9,7 +9,7 @@ on: - 'conanfile.py' - 'conandata.yml' - 'CMakeLists.txt' - - '.github/workflows/conan-package.yml' + - '.github/workflows/package.yml' branches: - main - 'CURA-*' @@ -29,7 +29,7 @@ on: - 'conanfile.py' - 'conandata.yml' - 'CMakeLists.txt' - - '.github/workflows/conan-package.yml' + - '.github/workflows/package.yml' branches: - main - 'CURA-*' @@ -44,3 +44,11 @@ jobs: with: platform_wasm: true secrets: inherit + + npm-package: + needs: [ conan-package ] + if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || startsWith(github.ref_name, 'NP-') || startsWith(github.ref_name, '5.')) }} # FIXME: have a more generic way to determine release branches + uses: ultimaker/cura-workflows/.github/workflows/npm-package.yml@main + with: + package_version_full: ${{ needs.conan-package.outputs.package_version_full }} + secrets: inherit diff --git a/.github/workflows/stress_benchmark.yml b/.github/workflows/stress_benchmark.yml index 56432c9899..a76be61f33 100644 --- a/.github/workflows/stress_benchmark.yml +++ b/.github/workflows/stress_benchmark.yml @@ -27,30 +27,19 @@ permissions: contents: write deployments: write -env: - CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD: ${{ secrets.CONAN_PASS }} - jobs: check_actor: uses: ultimaker/cura-workflows/.github/workflows/check-actor.yml@main secrets: inherit - conan-recipe-version: - needs: [ check_actor ] - if: ${{ needs.check_actor.outputs.proceed == 'true' }} - uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main - benchmark: - needs: [ conan-recipe-version ] uses: ultimaker/cura-workflows/.github/workflows/benchmark.yml@main with: - recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} - conan_extra_args: "-o curaengine:enable_benchmarks=True" + conan_extra_args: "-c tools.build:skip_test=False -o \"curaengine/*:enable_benchmarks=True\"" benchmark_cmd: "stress_benchmark/stress_benchmark -o benchmark_result.json" name: "Stress Benchmark" - output_file_path: "build/Release/benchmark_result.json" + output_file_path: "benchmark_result.json" data_dir: "dev/stress_bench" tool: "customSmallerIsBetter" secrets: inherit diff --git a/CuraEngineJS/.npmrc b/CuraEngineJS/.npmrc deleted file mode 100644 index 858f5af943..0000000000 --- a/CuraEngineJS/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} -@ultimaker:registry=https://npm.pkg.github.com -always-auth=true diff --git a/CuraEngineJS/package-lock.json b/CuraEngineJS/package-lock.json deleted file mode 100644 index 40e4254ba7..0000000000 --- a/CuraEngineJS/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@ultimaker/curaenginejs", - "version": "0.2.3", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@ultimaker/curaenginejs", - "version": "0.2.1", - "devDependencies": {} - } - } -} diff --git a/CuraEngineJS/package.json b/CuraEngineJS/package.json deleted file mode 100644 index 9ccdc78abd..0000000000 --- a/CuraEngineJS/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "@ultimaker/curaenginejs", - "version": "0.2.3", - "description": "CuraEngineJS a TS component to run CuraEngine in a browser", - "main": "dist/CuraEngine.js", - "scripts": { - "install_curaengine": "conan install ${npm_package_config_conan_package} -s build_type=Release --build=missing --update -c tools.build:skip_test=True -pr:h cura_wasm.jinja -if dist && rm -f dist/*conan*", - "build": "npm run install_curaengine", - "prepublishOnly": "npm run build" - }, - "config": { - "conan_package": "curaengine/5.9.0@_/_" - }, - "repository": { - "type": "git", - "url": "https://github.com/Ultimaker/CuraEngine.git" - }, - "keywords": [ - "Cura", - "CuraEngine", - "Slicer" - ], - "author": "UltiMaker", - "license": "", - "bugs": { - "url": "https://github.com/Ultimaker/CuraEngine/issues" - }, - "homepage": "https://github.com/Ultimaker/CuraEngine#readme", - "dependencies": { - }, - "devDependencies": { - }, - "files": [ - "dist", - "package.json", - "README.md" - ] -} \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index 8a3c74258b..0146155226 100644 --- a/conanfile.py +++ b/conanfile.py @@ -4,9 +4,10 @@ from conan import ConanFile from conan.errors import ConanInvalidConfiguration -from conan.tools.files import copy, mkdir, update_conandata -from conan.tools.cmake import CMakeToolchain, CMakeDeps, CMake, cmake_layout from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMakeToolchain, CMakeDeps, CMake, cmake_layout +from conan.tools.files import copy, mkdir, update_conandata +from conan.tools.microsoft import check_min_vs, is_msvc from conan.tools.scm import Version, Git required_conan_version = ">=2.7.0" @@ -22,7 +23,7 @@ class CuraEngineConan(ConanFile): exports = "LICENSE*" settings = "os", "compiler", "build_type", "arch" package_type = "application" - python_requires = "sentrylibrary/1.0.0@ultimaker/stable" + python_requires = "sentrylibrary/1.0.0@ultimaker/stable", "npmpackage/[>=1.0.0]@ultimaker/np_637" python_requires_extend = "sentrylibrary.SentryLibrary" options = { @@ -42,6 +43,16 @@ class CuraEngineConan(ConanFile): "with_cura_resources": False, } + @property + def _compilers_minimum_version(self): + return { + "gcc": "12", + "clang": "14", + "apple-clang": "13", + "msvc": "191", + "visual_studio": "17", + } + def init(self): base = self.python_requires["sentrylibrary"].module.SentryLibrary self.options.update(base.options, base.default_options) @@ -61,8 +72,10 @@ def export_sources(self): copy(self, "CuraEngine.rc", self.recipe_folder, self.export_sources_folder) copy(self, "LICENSE", self.recipe_folder, self.export_sources_folder) copy(self, "*", os.path.join(self.recipe_folder, "src"), os.path.join(self.export_sources_folder, "src")) - copy(self, "*", os.path.join(self.recipe_folder, "include"), os.path.join(self.export_sources_folder, "include")) - copy(self, "*", os.path.join(self.recipe_folder, "benchmark"), os.path.join(self.export_sources_folder, "benchmark")) + copy(self, "*", os.path.join(self.recipe_folder, "include"), + os.path.join(self.export_sources_folder, "include")) + copy(self, "*", os.path.join(self.recipe_folder, "benchmark"), + os.path.join(self.export_sources_folder, "benchmark")) copy(self, "*", os.path.join(self.recipe_folder, "stress_benchmark"), os.path.join(self.export_sources_folder, "stress_benchmark")) copy(self, "*", os.path.join(self.recipe_folder, "tests"), os.path.join(self.export_sources_folder, "tests")) @@ -86,6 +99,12 @@ def validate(self): if self.settings.compiler.get_safe("cppstd"): check_min_cppstd(self, 20) + check_min_vs(self, 191) + if not is_msvc(self): + minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False) + if minimum_version and Version(self.settings.compiler.version) < minimum_version: + raise ConanInvalidConfiguration( + f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support.") def build_requirements(self): self.test_requires("standardprojectsettings/[>=0.2.0]@ultimaker/stable") @@ -136,7 +155,8 @@ def generate(self): tc.variables["ENABLE_TESTING"] = not self.conf.get("tools.build:skip_test", False, check_type=bool) tc.variables["ENABLE_BENCHMARKS"] = self.options.enable_benchmarks tc.variables["EXTENSIVE_WARNINGS"] = self.options.enable_extensive_warnings - tc.variables["OLDER_APPLE_CLANG"] = self.settings.compiler == "apple-clang" and Version(self.settings.compiler.version) < "14" + tc.variables["OLDER_APPLE_CLANG"] = self.settings.compiler == "apple-clang" and Version( + self.settings.compiler.version) < "14" tc.variables["ENABLE_THREADING"] = not (self.settings.arch == "wasm" and self.settings.os == "Emscripten") if self.options.enable_plugins: tc.variables["ENABLE_PLUGINS"] = True @@ -180,7 +200,7 @@ def build(self): cmake.configure() cmake.build() - self.send_sentry_debug_files(binary_basename = "CuraEngine") + self.send_sentry_debug_files(binary_basename="CuraEngine") def deploy(self): copy(self, "CuraEngine*", src=os.path.join(self.package_folder, "bin"), dst=self.deploy_folder) @@ -202,3 +222,6 @@ def package_info(self): ext = ".exe" if self.settings.os == "Windows" else "" self.conf_info.define_path("user.curaengine:curaengine", os.path.join(self.package_folder, "bin", f"CuraEngine{ext}")) + + if self.settings.os == "Emscripten": + self.python_requires["npmpackage"].module.conf_package_json(self) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 469d5f4854..87a8b9284f 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -3090,8 +3091,13 @@ bool FffGcodeWriter::processInsets( // the supported region is made up of those areas that really are supported by either model or support on the layer below // expanded to take into account the overhang angle, the greater the overhang angle, the larger the supported area is // considered to be - const coord_t overhang_width = layer_height * std::tan(AngleRadians(overhang_angle)); - return fully_supported_region.offset(overhang_width + 10); + if (overhang_angle < 90.0) + { + const coord_t overhang_width = layer_height * std::tan(AngleRadians(overhang_angle)); + return fully_supported_region.offset(overhang_width + 10); + } + + return Shape(); }; // Build supported regions for all the overhang speeds. For a visual explanation of the result, see doc/gradual_overhang_speed.svg @@ -3101,17 +3107,46 @@ bool FffGcodeWriter::processInsets( const auto wall_overhang_angle = mesh.settings.get("wall_overhang_angle"); if (overhang_angles_count > 0 && wall_overhang_angle < 90.0) { + struct SpeedRegion + { + AngleDegrees overhang_angle; + Ratio speed_factor; + }; + + // Create raw speed regions const AngleDegrees overhang_step = (90.0 - wall_overhang_angle) / static_cast(overhang_angles_count); - for (size_t angle_index = 0; angle_index < overhang_angles_count; ++angle_index) + std::vector speed_regions; + speed_regions.reserve(overhang_angles_count + 1); + + speed_regions.push_back(SpeedRegion{ wall_overhang_angle, 1.0_r }); // Initial internal region, always 100% speed factor + + for (size_t angle_index = 1; angle_index < overhang_angles_count; ++angle_index) { const AngleDegrees actual_wall_overhang_angle = wall_overhang_angle + static_cast(angle_index) * overhang_step; - const Ratio speed_factor = angle_index == 0 ? 1.0_r : overhang_speed_factors[angle_index - 1]; + const Ratio speed_factor = overhang_speed_factors[angle_index - 1]; - overhang_masks.push_back(LayerPlan::OverhangMask{ get_supported_region(actual_wall_overhang_angle), speed_factor }); + speed_regions.push_back(SpeedRegion{ actual_wall_overhang_angle, speed_factor }); } - // Add an empty region, which actually means everything and should be ignored anyway - overhang_masks.push_back(LayerPlan::OverhangMask{ Shape(), overhang_speed_factors.back() }); + speed_regions.push_back(SpeedRegion{ 90.0, overhang_speed_factors.back() }); // Final "everything else" speed region + + // Now merge regions that have similar speed factors (saves calculations and avoid generating micro-segments) + auto merged_regions = speed_regions + | ranges::views::chunk_by( + [](const auto& region_a, const auto& region_b) + { + return region_a.speed_factor == region_b.speed_factor; + }); + + // If finally necessary, add actual calculated speed regions + if (std::ranges::distance(merged_regions) > 1) + { + for (const auto& regions : merged_regions) + { + const SpeedRegion& last_region = *std::ranges::prev(regions.end()); + overhang_masks.push_back(LayerPlan::OverhangMask{ get_supported_region(last_region.overhang_angle), last_region.speed_factor }); + } + } } gcode_layer.setOverhangMasks(overhang_masks);