diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml new file mode 100644 index 0000000000..0a625d2b0a --- /dev/null +++ b/.github/workflows/conan-package.yml @@ -0,0 +1,128 @@ +--- +name: conan-package + +# Exports the recipe, sources and binaries for Mac, Windows and Linux and upload these to the server such that these can +# be used downstream. +# +# It should run on pushes against main or CURA-* branches, but it will only create the binaries for main and release branches + +on: + workflow_dispatch: + inputs: + create_binaries_windows: + required: true + default: false + description: 'create binaries Windows' + create_binaries_linux: + required: true + default: false + description: 'create binaries Linux' + create_binaries_macos: + required: true + default: false + description: 'create binaries Macos' + + push: + paths: + - 'src/**' + - 'cmake/**' + - 'tests/**' + - 'conanfile.py' + - 'conandata.yml' + - 'CMakeLists.txt' + - '.github/workflows/conan-package.yml' + - '.github/worflows/requirements-conan-package.txt' + branches: + - main + - 'CURA-*' + - '[1-9]+.[0-9]+' + tags: + - '[0-9]+.[0-9]+.[0-9]+' + +jobs: + conan-recipe-version: + uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main + with: + project_name: curaengine + + conan-package-export: + needs: [ conan-recipe-version ] + uses: ultimaker/cura/.github/workflows/conan-recipe-export.yml@main + with: + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + recipe_id_latest: ${{ needs.conan-recipe-version.outputs.recipe_id_latest }} + recipe_id_pr: ${{ needs.conan-recipe-version.outputs.recipe_id_pr }} + runs_on: 'ubuntu-20.04' + python_version: '3.10.4' + conan_config_branch: 'master' + conan_logging_level: 'info' + secrets: inherit + + conan-package-create-macos: + # FIXME: For release branches: maybe rename the branch to release/** + if: ${{ (github.event_name == 'push' && github.ref_name == 'main') || (github.event_name == 'workflow_dispatch' && inputs.create_binaries_macos) }} + needs: [ conan-recipe-version, conan-package-export ] + + uses: ultimaker/cura/.github/workflows/conan-package-create.yml@main + with: + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + runs_on: 'macos-10.15' + python_version: '3.10.4' + conan_config_branch: 'master' + conan_logging_level: 'info' + secrets: inherit + + conan-package-create-windows: + # FIXME: For release branches: maybe rename the branch to release/** + if: ${{ (github.event_name == 'push' && github.ref_name == 'main') || (github.event_name == 'workflow_dispatch' && inputs.create_binaries_windows) }} + needs: [ conan-recipe-version, conan-package-export ] + + uses: ultimaker/cura/.github/workflows/conan-package-create.yml@main + with: + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + runs_on: 'windows-2022' + python_version: '3.10.4' + conan_config_branch: 'master' + conan_logging_level: 'info' + secrets: inherit + + conan-package-create-linux: + # FIXME: For release branches: maybe rename the branch to release/** + if: ${{ (github.event_name == 'push' && github.ref_name == 'main') || (github.event_name == 'workflow_dispatch' && inputs.create_binaries_linux) }} + needs: [ conan-recipe-version, conan-package-export ] + + uses: ultimaker/cura/.github/workflows/conan-package-create.yml@main + with: + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + runs_on: 'ubuntu-20.04' + python_version: '3.10.4' + conan_config_branch: 'master' + conan_logging_level: 'info' + secrets: inherit + + notify-export: + if: ${{ always() }} + needs: [ conan-package-export ] + + uses: ultimaker/cura/.github/workflows/notify.yml@main + with: + success: ${{ contains(join(needs.*.result, ','), 'success') }} + success_title: "New Conan recipe exported in ${{ github.repository }}" + success_body: "Exported ${{ needs.conan-recipe-version.outputs.recipe_id_full }}" + failure_title: "Failed to export Conan Export in ${{ github.repository }}" + failure_body: "Failed to exported ${{ needs.conan-recipe-version.outputs.recipe_id_full }}" + secrets: inherit + + notify-create: + # FIXME: For release branches: maybe rename the branch to release/** + if: ${{ always() && ((github.event_name == 'push' && github.ref_name == 'main') || (github.event_name == 'workflow_dispatch' && inputs.create_binaries_linux)) }} + needs: [ conan-package-create-macos, conan-package-create-windows, conan-package-create-linux ] + + uses: ultimaker/cura/.github/workflows/notify.yml@main + with: + success: ${{ contains(join(needs.*.result, ','), 'success') }} + success_title: "New binaries created in ${{ github.repository }}" + success_body: "Created binaries for ${{ needs.conan-recipe-version.outputs.recipe_id_full }}" + failure_title: "Failed to create binaries in ${{ github.repository }}" + failure_body: "Failed to created binaries for ${{ needs.conan-recipe-version.outputs.recipe_id_full }}" + secrets: inherit diff --git a/.github/workflows/requirements-conan-package.txt b/.github/workflows/requirements-conan-package.txt new file mode 100644 index 0000000000..49f3f7bb9d --- /dev/null +++ b/.github/workflows/requirements-conan-package.txt @@ -0,0 +1,3 @@ +conan +gitpython +sip==6.5.1 \ No newline at end of file diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 5a7a781bab..dd104df331 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -1,5 +1,6 @@ --- name: unit-test +# FIXME: This should be a reusable workflow on: push: @@ -8,74 +9,110 @@ on: - 'cmake/**' - 'tests/**' - 'conanfile.py' + - 'conandata.yml' - 'CMakeLists.txt' - '.github/workflows/unit-test.yml' + - '.github/worflows/requirements-conan-package.txt' branches: - main - 'CURA-*' - - 'CT_fix' + - '[0-9]+.[0-9]+' tags: - - '[5-9].[0-9].+*' + - '[0-9]+.[0-9]+.[0-9]+' pull_request: paths: - 'src/**' - 'cmake/**' - 'tests/**' - 'conanfile.py' + - 'conandata.yml' - 'CMakeLists.txt' - '.github/workflows/unit-test.yml' + - '.github/worflows/requirements-conan-package.txt' branches: - main - - '[5-9].[0-9]' + - 'CURA-*' + - '[0-9]+.[0-9]+' + tags: + - '[0-9]+.[0-9]+.[0-9]+' env: - CONAN_USER: ${{ secrets.CONAN_USER }} - CONAN_PASS: ${{ secrets.CONAN_PASS }} + CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }} + CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }} + CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }} + CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }} + CONAN_LOG_RUN_TO_OUTPUT: 1 + CONAN_LOGGING_LEVEL: info + CONAN_NON_INTERACTIVE: 1 jobs: + conan-recipe-version: + uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main + with: + project_name: curaengine + testing: runs-on: ubuntu-20.04 + needs: [ conan-recipe-version ] steps: - name: Checkout CuraEngine uses: actions/checkout@v3 - name: Setup Python and pip - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: - python-version: '3.10.4' + python-version: '3.10.x' architecture: 'x64' cache: 'pip' + cache-dependency-path: .github/workflows/requirements-conan-package.txt - - name: Prepare Conan and sip-build (Bash) - if: ${{ runner.os != 'Windows' }} + - name: Install Python requirements and Create default Conan profile run: | - pip install --require-hashes -r requirements.txt - # FIXME: Once we fully support Conan change to: `conan config install https://github.com/Ultimaker/conan-config.git` - conan config install https://github.com/Ultimaker/conan-config.git -a "-b CURA-9177_Fix_CI_CD" -tf $HOME/.conan + pip install -r requirements-conan-package.txt conan profile new default --detect - conan user -p $CONAN_PASS -r ultimaker $CONAN_USER + working-directory: .github/workflows/ + + - name: Use Conan download cache (Bash) + if: ${{ runner.os != 'Windows' }} + run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache" - name: Cache Conan local repository packages (Bash) uses: actions/cache@v3 + if: ${{ runner.os != 'Windows' }} with: path: | $HOME/.conan/data - key: ${{ runner.os }}-testing + $HOME/.conan/conan_download_cache + key: conan-${{ runner.os }}-${{ runner.arch }} + + - name: Install Linux system requirements + if: ${{ runner.os == 'Linux' }} + run: sudo apt install build-essential checkinstall zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev -y + + - name: Get Conan configuration + run: conan config install https://github.com/Ultimaker/conan-config.git - name: Install dependencies - run: conan install . -o enable_testing=True -pr:b cura_build.jinja -pr:h cura_release.jinja --build=missing --update -g VirtualBuildEnv + run: conan install . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} -o enable_testing=True -s build_type=Release --build=missing --update -g GitHubActionsRunEnv -g GitHubActionsBuildEnv - name: Upload the Dependency package(s) - run: conan upload "*" -r ultimaker --all -c + run: conan upload "*" -r cura --all -c + + - name: Set Environment variables from Conan install (bash) + if: ${{ runner.os != 'Windows' }} + run: | + . ./activate_github_actions_runenv.sh + . ./activate_github_actions_buildenv.sh + working-directory: cmake-build-release/conan - name: Run Unit Test CuraEngine id: run-test run: | - cmake --toolchain cmake-build-release/conan/conan_toolchain.cmake -S . -B cmake-build-release/ - cmake --build cmake-build-release/ - cd cmake-build-release/ + cmake --toolchain ./conan/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -S .. -B . + cmake --build . ctest --output-junit engine_test.xml + working-directory: cmake-build-release - name: Publish Unit Test Results id: test-results @@ -86,4 +123,4 @@ jobs: **/*.xml - name: Conclusion - run: echo "Conclusion is ${{ fromJSON( steps.test-results.outputs.json ).conclusion }}" \ No newline at end of file + run: echo "Conclusion is ${{ fromJSON( steps.test-results.outputs.json ).conclusion }}" diff --git a/.gitignore b/.gitignore index 7b789a2f75..eeddac5803 100644 --- a/.gitignore +++ b/.gitignore @@ -17,8 +17,8 @@ callgrind/* build/* debug_build/* release_build/* -cmake-build-debug/* -cmake-build-release/* +cmake-build-* +cmake-build-* libs/stb *.pyc *.exe @@ -64,3 +64,6 @@ documentation/latex/* ## Test results. tests/output.xml callgrind.out.* + +CMakeUserPresets.json +/conan_imports_manifest.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e979a058a3..f3a427af98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,7 @@ if (ENABLE_ARCUS) message(STATUS "Building with Arcus") find_package(arcus 5.0.0 REQUIRED) - find_package(protobuf_BUILD 3.17.1 REQUIRED) # Used for protoc - find_package(protobuf 3.17.1 REQUIRED) # Used for linking + find_package(protobuf 3.17.1 REQUIRED) protobuf_generate_cpp(engine_PB_SRCS engine_PB_HEADERS Cura.proto) endif () diff --git a/README.md b/README.md index eb198e3a4b..ce217952ae 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@

+ + diff --git a/clang-format b/clang-format deleted file mode 100644 index e3c247c51d..0000000000 --- a/clang-format +++ /dev/null @@ -1,35 +0,0 @@ ---- -AllowAllParametersOfDeclarationOnNextLine: 'true' -AllowShortBlocksOnASingleLine: 'true' -AllowShortFunctionsOnASingleLine: None -AllowShortIfStatementsOnASingleLine: 'false' -AllowShortLoopsOnASingleLine: 'false' -AlwaysBreakTemplateDeclarations: 'true' -BreakBeforeBinaryOperators: 'true' -BreakBeforeBraces: Allman -BreakConstructorInitializersBeforeComma: 'true' -ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' -Cpp11BracedListStyle: 'false' -DerivePointerAlignment: 'false' -IndentCaseLabels: 'true' -IndentWidth: '4' -KeepEmptyLinesAtTheStartOfBlocks: 'false' -Language: Cpp -MaxEmptyLinesToKeep: '2' -NamespaceIndentation: None -ObjCSpaceAfterProperty: 'true' -ObjCSpaceBeforeProtocolList: 'false' -PointerAlignment: Left -SpaceBeforeAssignmentOperators: 'true' -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: 'false' -SpacesBeforeTrailingComments: '1' -SpacesInAngles: 'false' -SpacesInCStyleCastParentheses: 'false' -SpacesInContainerLiterals: 'true' -SpacesInParentheses: 'false' -Standard: Cpp11 -TabWidth: '5' -UseTab: Never - -... diff --git a/conandata.yml b/conandata.yml new file mode 100644 index 0000000000..8d1546b888 --- /dev/null +++ b/conandata.yml @@ -0,0 +1,56 @@ +"None": + requirements: + - "clipper/6.4.2" + - "boost/1.78.0" + - "rapidjson/1.1.0" + - "stb/20200203" + requirements_arcus: + - "protobuf/3.17.1" + - "arcus/(latest)@ultimaker/stable" + - "zlib/1.2.12" + build_requirements_arcus: + - "protobuf/3.17.1" + build_requirements_testing: + - "gtest/[>=1.10.0]" +"5.1.0": + requirements: + - "clipper/6.4.2" + - "boost/1.78.0" + - "rapidjson/1.1.0" + - "stb/20200203" + requirements_arcus: + - "protobuf/3.17.1" + - "arcus/5.1.0" + - "zlib/1.2.12" + build_requirements_arcus: + - "protobuf/3.17.1" + build_requirements_testing: + - "gtest/[>=1.10.0]" +"5.1.0-beta": + requirements: + - "clipper/6.4.2" + - "boost/1.78.0" + - "rapidjson/1.1.0" + - "stb/20200203" + requirements_arcus: + - "protobuf/3.17.1" + - "arcus/(latest)@ultimaker/stable" + - "zlib/1.2.12" + build_requirements_arcus: + - "protobuf/3.17.1" + build_requirements_testing: + - "gtest/[>=1.10.0]" +"5.1.0-alpha": + requirements: + - "clipper/6.4.2" + - "boost/1.78.0" + - "rapidjson/1.1.0" + - "stb/20200203" + requirements_arcus: + - "protobuf/3.17.1" + - "arcus/(latest)@ultimaker/cura_9365" + - "zlib/1.2.12" + build_requirements_arcus: + - "protobuf/3.17.1" + build_requirements_testing: + - "gtest/[>=1.10.0]" \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index 2dcdd53ece..4b067ede23 100644 --- a/conanfile.py +++ b/conanfile.py @@ -20,6 +20,10 @@ class CuraEngineConan(ConanFile): build_policy = "missing" exports = "LICENSE*" settings = "os", "compiler", "build_type", "arch" + + python_requires = "umbase/0.1.1@ultimaker/testing" + python_requires_extend = "umbase.UMBaseConanfile" + options = { "enable_arcus": [True, False], "enable_openmp": [True, False], @@ -37,13 +41,24 @@ class CuraEngineConan(ConanFile): "revision": "auto" } + _cmake = None + + @property + def cmake(self): + if self._cmake is None: + self._cmake = CMake(self) + return self._cmake + def config_options(self): if self.settings.os == "Macos": self.options.enable_openmp = False def configure(self): self.options["boost"].header_only = True - self.options["*"].shared = True + self.options["clipper"].shared = True + if self.options.enable_arcus: + self.options["arcus"].shared = True + self.options["protobuf"].shared = True def validate(self): if self.settings.compiler.get_safe("cppstd"): @@ -53,44 +68,28 @@ def validate(self): raise ConanInvalidConfiguration("Only versions 5+ are support") def build_requirements(self): - self.tool_requires("ninja/[>=1.10.0]") - self.tool_requires("cmake/[>=3.23.0]") if self.options.enable_arcus: - self.tool_requires("protobuf/3.17.1") + for req in self._um_data(self.version)["build_requirements_arcus"]: + self.tool_requires(req) if self.options.enable_testing: - self.test_requires("gtest/[>=1.10.0]") + for req in self._um_data(self.version)["build_requirements_testing"]: + self.test_requires(req) def requirements(self): - self.requires("protobuf/3.17.1") - self.requires("clipper/6.4.2") - self.requires("boost/1.78.0") - self.requires("rapidjson/1.1.0") - self.requires("stb/20200203") + for req in self._um_data(self.version)["requirements"]: + self.requires(req) if self.options.enable_arcus: - self.requires("protobuf/3.17.1") - self.requires("arcus/5.0.1-PullRequest0137.86@ultimaker/testing") + for req in self._um_data(self.version)["requirements_arcus"]: + self.requires(req) def generate(self): cmake = CMakeDeps(self) - if self.options.enable_arcus: - if len(cmake.build_context_activated) == 0: - cmake.build_context_activated = ["protobuf"] - else: - cmake.build_context_activated.append("protobuf") - cmake.build_context_suffix = {"protobuf": "_BUILD"} - if len(cmake.build_context_activated) == 0: - cmake.build_context_build_modules = ["protobuf"] - else: - cmake.build_context_build_modules.append("protobuf") if self.options.enable_testing: - if len(cmake.build_context_build_modules) == 0: - cmake.build_context_activated = ["gtest"] - else: - cmake.build_context_activated.append("gtest") + cmake.build_context_activated = ["gtest"] cmake.generate() - tc = CMakeToolchain(self, generator = "Ninja") + tc = CMakeToolchain(self) tc.variables["ENABLE_ARCUS"] = self.options.enable_arcus tc.variables["BUILD_TESTING"] = self.options.enable_testing @@ -105,6 +104,10 @@ def generate(self): tc.generate() def layout(self): + # TODO: Use the cmake_layout provided by Conan, that requires restructuring the headers and sources, + # or if we decided against a cmake_layout, we should at least make things uniform across our projects + # and create the layout by defining a function in the UMBaseConanfile. + # https://docs.conan.io/en/latest/reference/conanfile/tools/layout.html self.folders.source = "." try: build_type = str(self.settings.build_type) @@ -126,21 +129,25 @@ def layout(self): self.cpp.package.bindirs = ['bin'] def imports(self): - if self.settings.os == "Windows": - self.copy("*", dst=self.build_folder, src="@bindirs") - self.copy("*", dst=self.build_folder, src="@libdirs") - if self.options.enable_testing: - dest = os.path.join(self.build_folder, "tests") - self.copy("*", dst=dest, src="@bindirs") - self.copy("*", dst=dest, src="@libdirs") + self.copy("*.dll", dst=self.build_folder, src="@bindirs") + self.copy("*.dylib", dst=self.build_folder, src="@bindirs") + if self.options.enable_testing: + dest = os.path.join(self.build_folder, "tests") + self.copy("*.dll", dst=dest, src="@bindirs") + self.copy("*.dylib", dst=dest, src="@bindirs") def build(self): - cmake = CMake(self) + cmake = self.cmake cmake.configure() cmake.build() - if self.options.enable_testing: - cmake.test() + + def test(self): + if not tools.cross_building(self) and self.options.enable_testing: + self.cmake.test() def package(self): packager = files.AutoPackager(self) - packager.run() \ No newline at end of file + packager.patterns.bin = ["CuraEngine.exe", "CuraEngine"] + packager.run() + self.copy("CuraEngine", src = self.build_folder, dst = "bin") + self.copy("CuraEngine.exe", src = self.build_folder, dst = "bin") diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 59ebda4b26..0000000000 --- a/requirements.txt +++ /dev/null @@ -1,152 +0,0 @@ -### Conan ### - -conan==1.47.0 \ - --hash=sha256:c0f066be1871ae23a9dbe7465929ae38f221531b7025f85cdd56d4790c1816be -colorama==0.4.4 \ - --hash=sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b \ - --hash=sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2 -urllib3==1.26.9 \ - --hash=sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e \ - --hash=sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14 -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 -distro==1.6.0 \ - --hash=sha256:83f5e5a09f9c5f68f60173de572930effbcc0287bb84fdc4426cb4168c088424 \ - --hash=sha256:c8713330ab31a034623a9515663ed87696700b55f04556b97c39cd261aa70dc7 -requests==2.27.1 \ - --hash=sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61 \ - --hash=sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d -charset-normalizer==2.0.10 \ - --hash=sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd \ - --hash=sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455 -certifi==2021.10.8 \ - --hash=sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872 \ - --hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569 -PyYAML==5.4.1 \ - --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \ - --hash=sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696 \ - --hash=sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393 \ - --hash=sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77 \ - --hash=sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922 \ - --hash=sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5 \ - --hash=sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8 \ - --hash=sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10 \ - --hash=sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc \ - --hash=sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018 \ - --hash=sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e \ - --hash=sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253 \ - --hash=sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347 \ - --hash=sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183 \ - --hash=sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541 \ - --hash=sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb \ - --hash=sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185 \ - --hash=sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc \ - --hash=sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db \ - --hash=sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa \ - --hash=sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46 \ - --hash=sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122 \ - --hash=sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b \ - --hash=sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63 \ - --hash=sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df \ - --hash=sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc \ - --hash=sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247 \ - --hash=sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6 \ - --hash=sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0 -Pygments==2.11.2 \ - --hash=sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65 \ - --hash=sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a -bottle==0.12.19 \ - --hash=sha256:a9d73ffcbc6a1345ca2d7949638db46349f5b2b77dac65d6494d45c23628da2c \ - --hash=sha256:f6b8a34fe9aa406f9813c02990db72ca69ce6a158b5b156d2c41f345016a723d -node-semver==0.6.1 \ - --hash=sha256:4016f7c1071b0493f18db69ea02d3763e98a633606d7c7beca811e53b5ac66b7 \ - --hash=sha256:d4bf83873894591a0cbb6591910d96917fbadc9731e8e39e782d3a2fbc2b841e -Jinja2==3.0.3 \ - --hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \ - --hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7 -python-dateutil==2.8.2 \ - --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ - --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 -patch-ng==1.17.4 \ - --hash=sha256:627abc5bd723c8b481e96849b9734b10065426224d4d22cd44137004ac0d4ace -tqdm==4.63.0 \ - --hash=sha256:1d9835ede8e394bb8c9dcbffbca02d717217113adc679236873eeaac5bc0b3cd \ - --hash=sha256:e643e071046f17139dea55b880dc9b33822ce21613b4a4f5ea57f202833dbc29 -PyJWT==1.7.1 \ - --hash=sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e \ - --hash=sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96 -fasteners==0.17.3 \ - --hash=sha256:a9a42a208573d4074c77d041447336cf4e3c1389a256fd3e113ef59cf29b7980 \ - --hash=sha256:cae0772df265923e71435cc5057840138f4e8b6302f888a567d06ed8e1cbca03 -pluginbase==1.0.1 \ - --hash=sha256:ff6c33a98fce232e9c73841d787a643de574937069f0d18147028d70d7dee287 -MarkupSafe==2.1.1 \ - --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ - --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ - --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ - --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ - --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ - --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ - --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ - --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ - --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ - --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ - --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ - --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ - --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ - --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ - --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ - --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ - --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ - --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ - --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ - --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ - --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ - --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ - --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ - --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ - --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ - --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ - --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ - --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ - --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ - --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ - --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ - --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ - --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ - --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ - --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ - --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ - --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ - --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ - --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ - --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 -chardet==4.0.0 \ - --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \ - --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 -idna==3.3 \ - --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ - --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d - - -### sip ### - -sip==6.5.1 \ - --hash=sha256:01a637b44c5918505801c3d56e1e010b8e86a4edee71c0bd8541c54387b57ae2 \ - --hash=sha256:13b09357615c2d8bcb23bf21c1637941ac8ff5f28b346c1ccad7efafa57673e9 \ - --hash=sha256:204f0240db8999a749d638a987b351861843e69239b811ec3d1881412c3706a6 \ - --hash=sha256:57e5ac40744c0f10a6c53dd45d2ef2c90e52f34a0210d8309e6563a07f914d0d \ - --hash=sha256:de1cb4004d75a3a236f82a69cd7a3e51ff76b414df412fea22bf433b28876e3f -setuptools==59.4.0 \ - --hash=sha256:b4c634615a0cf5b02cf83c7bedffc8da0ca439f00e79452699454da6fbd4153d \ - --hash=sha256:feb5ff19b354cde9efd2344ef6d5e79880ce4be643037641b49508bbb850d060 -toml==0.10.2 \ - --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ - --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f -packaging==20.9 \ - --hash=sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5 \ - --hash=sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a -pyparsing==3.0.7 \ - --hash=sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea \ - --hash=sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484 \ No newline at end of file diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 762eb91d6e..e235b78ef0 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -697,6 +697,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) constexpr double fill_overlap = 0; // raft line shouldn't be expanded - there is no boundary polygon printed constexpr int infill_multiplier = 1; // rafts use single lines constexpr int extra_infill_shift = 0; + constexpr bool fill_gaps = true; Polygons raft_polygons; // should remain empty, since we only have the lines pattern for the raft... std::optional last_planned_position = std::optional(); @@ -746,24 +747,37 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) const coord_t max_resolution = base_settings.get("meshfix_maximum_resolution"); const coord_t max_deviation = base_settings.get("meshfix_maximum_deviation"); - Infill infill_comp( - EFillMethod::LINES, zig_zaggify_infill, connect_polygons, storage.raftOutline, gcode_layer.configs_storage.raft_base_config.getLineWidth(), line_spacing, - fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, - max_resolution, max_deviation, - wall_line_count, infill_origin, skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size - ); - std::vector raft_paths; - infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings); - if(!raft_paths.empty()) + std::vector raft_outline_paths; + if (storage.primeRaftOutline.area() > 0) { - const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; - const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, base_settings, base_extruder_nr, - config, config, config, config, - retract_before_outer_wall, wipe_dist, wipe_dist, base_extruder_nr, base_extruder_nr, z_seam_config, raft_paths); - wall_orderer.addToLayer(); + raft_outline_paths.emplace_back(storage.primeRaftOutline); + } + raft_outline_paths.emplace_back(storage.raftOutline); + + for (const Polygons& raft_outline_path : raft_outline_paths) + { + Infill infill_comp( + EFillMethod::LINES, zig_zaggify_infill, connect_polygons, raft_outline_path, gcode_layer.configs_storage.raft_base_config.getLineWidth(), line_spacing, + fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, + max_resolution, max_deviation, + wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size + ); + std::vector raft_paths; + infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings); + if (!raft_paths.empty()) + { + const GCodePathConfig& config = gcode_layer.configs_storage.raft_base_config; + const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + InsetOrderOptimizer wall_orderer(*this, storage, gcode_layer, base_settings, base_extruder_nr, + config, config, config, config, + retract_before_outer_wall, wipe_dist, wipe_dist, base_extruder_nr, base_extruder_nr, z_seam_config, raft_paths); + wall_orderer.addToLayer(); + } + gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_base_config, SpaceFillType::Lines); + + raft_polygons.clear(); + raftLines.clear(); } - gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_base_config, SpaceFillType::Lines); // When we use raft, we need to make sure that all used extruders for this print will get primed on the first raft layer, // and then switch back to the original extruder. @@ -808,10 +822,17 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication->sendLayerComplete(layer_nr, z, interface_layer_height); - Polygons raft_outline_path = storage.raftOutline.offset(-gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2); //Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); //Remove those micron-movements. + std::vector raft_outline_paths; + const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; //Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. + if (storage.primeRaftOutline.area() > 0) + { + raft_outline_paths.emplace_back(storage.primeRaftOutline.offset(-small_offset)); + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. + } + raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); - Polygons raftLines; + Polygons raft_lines; AngleDegrees fill_angle = (num_surface_layers + num_interface_layers - raft_interface_layer) % 2 ? 45 : 135; //90 degrees rotated from the first top layer. constexpr bool zig_zaggify_infill = true; constexpr bool connect_polygons = true; // why not? @@ -825,15 +846,21 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) constexpr int zag_skip_count = 0; constexpr coord_t pocket_size = 0; - Infill infill_comp( - EFillMethod::ZIG_ZAG, zig_zaggify_infill, connect_polygons, raft_outline_path, infill_outline_width, interface_line_spacing, - fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, - interface_max_resolution, interface_max_deviation, - wall_line_count, infill_origin, skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size + for (const Polygons& raft_outline_path : raft_outline_paths) + { + Infill infill_comp( + EFillMethod::ZIG_ZAG, zig_zaggify_infill, connect_polygons, raft_outline_path, infill_outline_width, interface_line_spacing, + fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, + interface_max_resolution, interface_max_deviation, + wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size ); - std::vector raft_paths; //Should remain empty, since we have no walls. - infill_comp.generate(raft_paths, raft_polygons, raftLines, interface_settings); - gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage.raft_interface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); + std::vector raft_paths; //Should remain empty, since we have no walls. + infill_comp.generate(raft_paths, raft_polygons, raft_lines, interface_settings); + gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_interface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); + + raft_polygons.clear(); + raft_lines.clear(); + } layer_plan_buffer.handle(gcode_layer, gcode); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); @@ -870,8 +897,15 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication->sendLayerComplete(layer_nr, z, surface_layer_height); - Polygons raft_outline_path = storage.raftOutline.offset(-gcode_layer.configs_storage.raft_surface_config.getLineWidth() / 2); //Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_path = Simplify(surface_settings).polygon(raft_outline_path); //Remove those micron-movements. + std::vector raft_outline_paths; + const coord_t small_offset = gcode_layer.configs_storage.raft_interface_config.getLineWidth() / 2; //Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. + if (storage.primeRaftOutline.area() > 0) + { + raft_outline_paths.emplace_back(storage.primeRaftOutline.offset(-small_offset)); + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. + } + raft_outline_paths.emplace_back(storage.raftOutline.offset(-small_offset)); + raft_outline_paths.back() = Simplify(interface_settings).polygon(raft_outline_paths.back()); //Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage.raft_interface_config.getLineWidth(); Polygons raft_lines; AngleDegrees fill_angle = (num_surface_layers - raft_surface_layer) % 2 ? 45 : 135; //Alternate between -45 and +45 degrees, ending up 90 degrees rotated from the default skin angle. @@ -887,15 +921,21 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) constexpr size_t zag_skip_count = 0; constexpr coord_t pocket_size = 0; - Infill infill_comp( - EFillMethod::ZIG_ZAG, zig_zaggify_infill, connect_polygons, raft_outline_path, infill_outline_width, surface_line_spacing, - fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, - surface_max_resolution, surface_max_deviation, - wall_line_count, infill_origin, skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size + for (const Polygons& raft_outline_path : raft_outline_paths) + { + Infill infill_comp( + EFillMethod::ZIG_ZAG, zig_zaggify_infill, connect_polygons, raft_outline_path, infill_outline_width, surface_line_spacing, + fill_overlap, infill_multiplier, fill_angle, z, extra_infill_shift, + surface_max_resolution, surface_max_deviation, + wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size ); - std::vector raft_paths; //Should remain empty, since we have no walls. - infill_comp.generate(raft_paths, raft_polygons, raft_lines, surface_settings); - gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_surface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); + std::vector raft_paths; //Should remain empty, since we have no walls. + infill_comp.generate(raft_paths, raft_polygons, raft_lines, surface_settings); + gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage.raft_surface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); + + raft_polygons.clear(); + raft_lines.clear(); + } layer_plan_buffer.handle(gcode_layer, gcode); } @@ -1510,6 +1550,7 @@ bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, La constexpr bool use_endpieces = true; constexpr bool skip_some_zags = false; constexpr size_t zag_skip_count = 0; + const bool fill_gaps = density_idx == 0; //Only fill gaps for the lowest density. const LightningLayer * lightning_layer = nullptr; if (mesh.lightning_generator) @@ -1520,7 +1561,7 @@ bool FffGcodeWriter::processMultiLayerInfill(const SliceDataStorage& storage, La part.infill_area_per_combine_per_density[density_idx][combine_idx], infill_line_width, infill_line_distance_here, infill_overlap, infill_multiplier, infill_angle, gcode_layer.z, infill_shift, max_resolution, max_deviation, wall_line_count, - infill_origin, skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, + infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, mesh.settings.get("cross_infill_pocket_size")); infill_comp.generate(infill_paths, infill_polygons, infill_lines, mesh.settings, mesh.cross_fill_provider, lightning_layer, &mesh); } @@ -1679,6 +1720,7 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L lightning_layer = &mesh.lightning_generator->getTreesForLayer(gcode_layer.getLayerNr()); } + const bool fill_gaps = density_idx == 0; //Only fill gaps in the lowest infill density pattern. if (hasSkinEdgeSupport) { // infill region with skin above has to have at least one infill wall line @@ -1689,10 +1731,8 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L Infill infill_comp(pattern, zig_zaggify_infill, connect_polygons, infill_below_skin, infill_line_width, infill_line_distance_here, overlap, infill_multiplier, infill_angle, gcode_layer.z, infill_shift, max_resolution, max_deviation, skin_below_wall_count, infill_origin, - skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size); + skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size); infill_comp.generate(wall_tool_paths.back(), infill_polygons, infill_lines, mesh.settings, mesh.cross_fill_provider, lightning_layer, &mesh); - - // Fixme: CURA-7848 for libArachne. if (density_idx < last_idx) { const coord_t cut_offset = @@ -1727,10 +1767,8 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L Infill infill_comp(pattern, zig_zaggify_infill, connect_polygons, in_outline, infill_line_width, infill_line_distance_here, overlap, infill_multiplier, infill_angle, gcode_layer.z, infill_shift, max_resolution, max_deviation, wall_line_count_here, infill_origin, - skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size); + skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size); infill_comp.generate(wall_tool_paths.back(), infill_polygons, infill_lines, mesh.settings, mesh.cross_fill_provider, lightning_layer, &mesh); - - // Fixme: CURA-7848 for libArachne. if (density_idx < last_idx) { const coord_t cut_offset = get_cut_offset(zig_zaggify_infill, infill_line_width, wall_line_count); @@ -1742,7 +1780,16 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L } wall_tool_paths.emplace_back(part.infill_wall_toolpaths); //The extra infill walls were generated separately. Add these too. - const bool walls_generated = std::any_of(wall_tool_paths.cbegin(), wall_tool_paths.cend(), [](const std::vector& tp){ return !tp.empty(); }); + const bool walls_generated = + std::any_of + ( + wall_tool_paths.cbegin(), + wall_tool_paths.cend(), + [](const std::vector& tp) + { + return ! (tp.empty() || std::all_of(tp.begin(), tp.end(), [](const VariableWidthLines& vwl) { return vwl.empty(); })); + } + ); if(!infill_lines.empty() || !infill_polygons.empty() || walls_generated) { added_something = true; @@ -1764,7 +1811,7 @@ bool FffGcodeWriter::processSingleLayerInfill(const SliceDataStorage& storage, L else //So walls_generated must be true. { std::vector* start_paths = &wall_tool_paths[rand() % wall_tool_paths.size()]; - while(start_paths->empty()) //We know for sure (because walls_generated) that one of them is not empty. So randomise until we hit it. Should almost always be very quick. + while(start_paths->empty() || (*start_paths)[0].empty()) //We know for sure (because walls_generated) that one of them is not empty. So randomise until we hit it. Should almost always be very quick. { start_paths = &wall_tool_paths[rand() % wall_tool_paths.size()]; } @@ -2413,6 +2460,7 @@ void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, La coord_t max_deviation = mesh.settings.get("meshfix_maximum_deviation"); const Point infill_origin; const bool skip_line_stitching = monotonic; + constexpr bool fill_gaps = true; constexpr bool connected_zigzags = false; constexpr bool use_endpieces = true; constexpr bool skip_some_zags = false; @@ -2423,7 +2471,7 @@ void FffGcodeWriter::processSkinPrintFeature(const SliceDataStorage& storage, La pattern, zig_zaggify_infill, connect_polygons, area, config.getLineWidth(), config.getLineWidth() / skin_density, skin_overlap, infill_multiplier, skin_angle, gcode_layer.z, extra_infill_shift , max_resolution, max_deviation , wall_line_count, infill_origin, - skip_line_stitching, + skip_line_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size ); infill_comp.generate(skin_paths, skin_polygons, skin_lines, mesh.settings); @@ -2716,11 +2764,12 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer constexpr size_t wall_count = 0; // Walls are generated somewhere else, so their layers aren't vertically combined. constexpr bool skip_stitching = false; + const bool fill_gaps = density_idx == 0; //Only fill gaps for one of the densities. Infill infill_comp(support_pattern, zig_zaggify_infill, connect_polygons, area, support_line_width, support_line_distance_here, current_support_infill_overlap - (density_idx == max_density_idx ? 0 : wall_line_count * support_line_width), infill_multiplier, support_infill_angle, gcode_layer.z, support_shift, max_resolution, max_deviation, - wall_count, infill_origin, skip_stitching, support_connect_zigzags, + wall_count, infill_origin, skip_stitching, fill_gaps, support_connect_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size); infill_comp.generate(wall_toolpaths_here, support_polygons, support_lines, infill_extruder.settings, storage.support.cross_fill_provider); } @@ -2855,6 +2904,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay constexpr size_t wall_line_count = 0; const Point infill_origin; constexpr bool skip_stitching = false; + constexpr bool fill_gaps = true; constexpr bool use_endpieces = true; constexpr bool connected_zigzags = false; constexpr bool skip_some_zags = false; @@ -2883,7 +2933,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, Lay pattern, zig_zaggify_infill, connect_polygons, infill_outline, gcode_layer.configs_storage.support_roof_config.getLineWidth(), support_roof_line_distance, support_roof_overlap, infill_multiplier, fill_angle, gcode_layer.z, extra_infill_shift, max_resolution, max_deviation, - wall_line_count, infill_origin, skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size + wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size ); Polygons roof_polygons; std::vector roof_paths; @@ -2952,6 +3002,7 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L constexpr size_t wall_line_count = 0; const Point infill_origin; constexpr bool skip_stitching = false; + constexpr bool fill_gaps = true; constexpr bool use_endpieces = true; constexpr bool connected_zigzags = false; constexpr bool skip_some_zags = false; @@ -2965,7 +3016,7 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L pattern, zig_zaggify_infill, connect_polygons, support_layer.support_bottom, gcode_layer.configs_storage.support_bottom_config.getLineWidth(), support_bottom_line_distance, support_bottom_overlap, infill_multiplier, fill_angle, gcode_layer.z, extra_infill_shift, max_resolution, max_deviation, - wall_line_count, infill_origin, skip_stitching, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size + wall_line_count, infill_origin, skip_stitching, fill_gaps, connected_zigzags, use_endpieces, skip_some_zags, zag_skip_count, pocket_size ); Polygons bottom_polygons; std::vector bottom_paths; diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 53d423d648..ad66bf37ff 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -1308,7 +1308,7 @@ void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRe // when not smoothing, we get to the (unchanged) outline for this layer as quickly as possible so that the remainder of the // outline wall has the correct direction - although this creates a little step, the end result is generally better because when the first // outline wall has the wrong direction (due to it starting from the finish point of the last layer) the visual effect is very noticeable - Point join_first_wall_at = LinearAlg2D::getClosestOnLineSegment(origin, wall[seam_vertex_idx], wall[(seam_vertex_idx + 1) % wall.size()]); + Point join_first_wall_at = LinearAlg2D::getClosestOnLineSegment(origin, wall[seam_vertex_idx % wall.size()], wall[(seam_vertex_idx + 1) % wall.size()]); if (vSize(join_first_wall_at - origin) > 10) { constexpr Ratio flow = 1.0_r; diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index ceb8ec1676..3bebe9758b 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -44,6 +44,7 @@ PrimeTower::PrimeTower() enabled = scene.current_mesh_group->settings.get("prime_tower_enable") && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 && scene.current_mesh_group->settings.get("prime_tower_size") > 10; + would_have_actual_tower = enabled; // Assume so for now. extruder_count = scene.extruders.size(); extruder_order.resize(extruder_count); @@ -92,8 +93,8 @@ void PrimeTower::generateGroundpoly() void PrimeTower::generatePaths(const SliceDataStorage& storage) { - enabled &= storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches. - if (enabled) + would_have_actual_tower = storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches. + if (would_have_actual_tower && enabled) { generatePaths_denseInfill(); generateStartLocations(); @@ -168,7 +169,7 @@ void PrimeTower::generateStartLocations() void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t prev_extruder, const size_t new_extruder) const { - if (!enabled) + if (! (enabled && would_have_actual_tower)) { return; } @@ -178,7 +179,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la } const LayerIndex layer_nr = gcode_layer.getLayerNr(); - if (layer_nr > storage.max_print_height_second_to_last_extruder + 1) + if (layer_nr < 0 || layer_nr > storage.max_print_height_second_to_last_extruder + 1) { return; } diff --git a/src/PrimeTower.h b/src/PrimeTower.h index f89240737d..a2f6510b52 100644 --- a/src/PrimeTower.h +++ b/src/PrimeTower.h @@ -1,4 +1,4 @@ -//Copyright (c) 2021 Ultimaker B.V. +//Copyright (c) 2022 Ultimaker B.V. //CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef PRIME_TOWER_H @@ -44,6 +44,7 @@ class PrimeTower public: bool enabled; //!< Whether the prime tower is enabled. + bool would_have_actual_tower; //!< Whether there is an actual tower. bool multiple_extruders_on_first_layer; //!< Whether multiple extruders are allowed on the first layer of the prime tower (e.g. when a raft is there) Polygons outer_poly; //!< The outline of the outermost prime tower. Polygons outer_poly_first_layer; //!< The outermost outline, plus optional brim on 'brim for prime tower' is enabled. diff --git a/src/infill.cpp b/src/infill.cpp index ac6568706c..9a164350db 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -117,7 +117,10 @@ void Infill::generate(std::vector& toolpaths, Polygons& resu if(path.polygonLength() >= infill_line_width * 4) //Don't fill gaps that are very small (with paths less than 2 line widths long, 4 back and forth). { gap_filled_areas.add(path); - thin_walls_only.push_back(extrusion); + if(fill_gaps) + { + thin_walls_only.push_back(extrusion); + } } } } diff --git a/src/infill.h b/src/infill.h index 12ae8a76e1..0aa298e0fe 100644 --- a/src/infill.h +++ b/src/infill.h @@ -41,6 +41,7 @@ class Infill size_t wall_line_count; //!< Number of walls to generate at the boundary of the infill region, spaced \ref infill_line_width apart const Point infill_origin; //!< origin of the infill pattern bool skip_line_stitching; //!< Whether to bypass the line stitching normally performed for polyline type infills + bool fill_gaps; //!< Whether to fill gaps in strips of infill that would be too thin to fit the infill lines. If disabled, those areas are left empty. bool connected_zigzags; //!< (ZigZag) Whether endpieces of zigzag infill should be connected to the nearest infill line on both sides of the zigzag connector bool use_endpieces; //!< (ZigZag) Whether to include endpieces: zigzag connector segments from one infill line to itself bool skip_some_zags; //!< (ZigZag) Whether to skip some zags @@ -66,6 +67,7 @@ class Infill , size_t wall_line_count = 0 , const Point& infill_origin = Point() , bool skip_line_stitching = false + , bool fill_gaps = true , bool connected_zigzags = false , bool use_endpieces = false , bool skip_some_zags = false @@ -88,6 +90,7 @@ class Infill , wall_line_count(wall_line_count) , infill_origin(infill_origin) , skip_line_stitching(skip_line_stitching) + , fill_gaps(fill_gaps) , connected_zigzags(connected_zigzags) , use_endpieces(use_endpieces) , skip_some_zags(skip_some_zags) diff --git a/src/raft.cpp b/src/raft.cpp index 3d9cf5a9ca..a3820cd2a1 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -18,11 +18,11 @@ namespace cura void Raft::generate(SliceDataStorage& storage) { assert(storage.raftOutline.size() == 0 && "Raft polygon isn't generated yet, so should be empty!"); - const Settings& settings = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("adhesion_extruder_nr").settings; + const Settings& settings = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("raft_base_extruder_nr").settings; const coord_t distance = settings.get("raft_margin"); constexpr bool include_support = true; - constexpr bool include_prime_tower = true; - storage.raftOutline = storage.getLayerOutlines(0, include_support, include_prime_tower).offset(distance, ClipperLib::jtRound); + constexpr bool dont_include_prime_tower = false; // Prime tower raft will be handled separately in 'storage.primeRaftOutline'; see below. + storage.raftOutline = storage.getLayerOutlines(0, include_support, dont_include_prime_tower).offset(distance, ClipperLib::jtRound); const coord_t shield_line_width_layer0 = settings.get("skirt_brim_line_width"); if (storage.draft_protection_shield.size() > 0) { @@ -47,20 +47,45 @@ void Raft::generate(SliceDataStorage& storage) const coord_t smoothing = settings.get("raft_smoothing"); storage.raftOutline = storage.raftOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); // remove small holes and smooth inward corners } + + if (storage.primeTower.enabled && ! storage.primeTower.would_have_actual_tower) + { + // Find out if the prime-tower part of the raft still needs to be printed, even if there is no actual tower. + // This will only happen if the different raft layers are printed by different extruders. + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; + const size_t base_extruder_nr = mesh_group_settings.get("raft_base_extruder_nr").extruder_nr; + const size_t interface_extruder_nr = mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr; + const size_t surface_extruder_nr = mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr; + if (base_extruder_nr == interface_extruder_nr && base_extruder_nr == surface_extruder_nr) + { + return; + } + } + + storage.primeRaftOutline = storage.primeTower.outer_poly_first_layer.offset(distance, ClipperLib::jtRound); + if (settings.get("raft_remove_inside_corners")) + { + storage.primeRaftOutline = storage.primeRaftOutline.unionPolygons(storage.raftOutline); + storage.primeRaftOutline.makeConvex(); + } + storage.primeRaftOutline = storage.primeRaftOutline.difference(storage.raftOutline); // In case of overlaps. } coord_t Raft::getTotalThickness() { - const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("adhesion_extruder_nr"); - return train.settings.get("raft_base_thickness") - + train.settings.get("raft_interface_layers") * train.settings.get("raft_interface_thickness") - + train.settings.get("raft_surface_layers") * train.settings.get("raft_surface_thickness"); + const Settings& mesh_group_settings =Application::getInstance().current_slice->scene.current_mesh_group->settings; + const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); + const ExtruderTrain& interface_train = mesh_group_settings.get("raft_interface_extruder_nr"); + const ExtruderTrain& surface_train = mesh_group_settings.get("raft_surface_extruder_nr"); + return base_train.settings.get("raft_base_thickness") + + interface_train.settings.get("raft_interface_layers") * interface_train.settings.get("raft_interface_thickness") + + surface_train.settings.get("raft_surface_layers") * surface_train.settings.get("raft_surface_thickness"); } coord_t Raft::getZdiffBetweenRaftAndLayer1() { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; - const ExtruderTrain& train = mesh_group_settings.get("adhesion_extruder_nr"); + const ExtruderTrain& train = mesh_group_settings.get("raft_surface_extruder_nr"); if (mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT) { return 0; @@ -94,12 +119,15 @@ coord_t Raft::getFillerLayerHeight() size_t Raft::getTotalExtraLayers() { - const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("adhesion_extruder_nr"); - if (train.settings.get("adhesion_type") != EPlatformAdhesion::RAFT) + const Settings& mesh_group_settings =Application::getInstance().current_slice->scene.current_mesh_group->settings; + const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); + const ExtruderTrain& interface_train = mesh_group_settings.get("raft_interface_extruder_nr"); + const ExtruderTrain& surface_train = mesh_group_settings.get("raft_surface_extruder_nr"); + if (base_train.settings.get("adhesion_type") != EPlatformAdhesion::RAFT) { return 0; } - return 1 + train.settings.get("raft_interface_layers") + train.settings.get("raft_surface_layers") + getFillerLayerCount(); + return 1 + interface_train.settings.get("raft_interface_layers") + surface_train.settings.get("raft_surface_layers") + getFillerLayerCount(); } diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 02684b2529..c6d741e5d2 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -595,12 +595,15 @@ Polygon SliceDataStorage::getMachineBorder(bool adhesion_offset) const } coord_t adhesion_size = 0; //Make sure there is enough room for the platform adhesion around support. - const ExtruderTrain& adhesion_extruder = mesh_group_settings.get("adhesion_extruder_nr"); + const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); + const ExtruderTrain& interface_train = mesh_group_settings.get("raft_interface_extruder_nr"); + const ExtruderTrain& surface_train = mesh_group_settings.get("raft_surface_extruder_nr"); + const ExtruderTrain& skirt_brim_train = mesh_group_settings.get("skirt_brim_extruder_nr"); coord_t extra_skirt_line_width = 0; const std::vector is_extruder_used = getExtrudersUsed(); for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) { - if (extruder_nr == adhesion_extruder.extruder_nr || !is_extruder_used[extruder_nr]) //Unused extruders and the primary adhesion extruder don't generate an extra skirt line. + if (extruder_nr == skirt_brim_train.extruder_nr || !is_extruder_used[extruder_nr]) //Unused extruders and the primary adhesion extruder don't generate an extra skirt line. { continue; } @@ -610,13 +613,23 @@ Polygon SliceDataStorage::getMachineBorder(bool adhesion_offset) const switch (mesh_group_settings.get("adhesion_type")) { case EPlatformAdhesion::BRIM: - adhesion_size = adhesion_extruder.settings.get("skirt_brim_line_width") * adhesion_extruder.settings.get("initial_layer_line_width_factor") * adhesion_extruder.settings.get("brim_line_count") + extra_skirt_line_width; + adhesion_size = skirt_brim_train.settings.get("skirt_brim_line_width") + * skirt_brim_train.settings.get("initial_layer_line_width_factor") + * skirt_brim_train.settings.get("brim_line_count") + extra_skirt_line_width; break; case EPlatformAdhesion::RAFT: - adhesion_size = adhesion_extruder.settings.get("raft_margin"); + adhesion_size = std::max({ + base_train.settings.get("raft_margin"), + interface_train.settings.get("raft_margin"), + surface_train.settings.get("raft_margin") + }); break; case EPlatformAdhesion::SKIRT: - adhesion_size = adhesion_extruder.settings.get("skirt_gap") + adhesion_extruder.settings.get("skirt_brim_line_width") * adhesion_extruder.settings.get("initial_layer_line_width_factor") * adhesion_extruder.settings.get("skirt_line_count") + extra_skirt_line_width; + adhesion_size = skirt_brim_train.settings.get("skirt_gap") + + skirt_brim_train.settings.get("skirt_brim_line_width") + * skirt_brim_train.settings.get("initial_layer_line_width_factor") + * skirt_brim_train.settings.get("skirt_line_count") + + extra_skirt_line_width; break; case EPlatformAdhesion::NONE: adhesion_size = 0; diff --git a/src/sliceDataStorage.h b/src/sliceDataStorage.h index 658932fb52..b131f38e57 100644 --- a/src/sliceDataStorage.h +++ b/src/sliceDataStorage.h @@ -1,4 +1,4 @@ -//Copyright (c) 2021 Ultimaker B.V. +//Copyright (c) 2022 Ultimaker B.V. //CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef SLICE_DATA_STORAGE_H @@ -319,6 +319,7 @@ class SliceDataStorage : public NoCopy Polygons skirt_brim[MAX_EXTRUDERS]; //!< Skirt and brim polygons per extruder, ordered from inner to outer polygons. size_t skirt_brim_max_locked_part_order[MAX_EXTRUDERS]; //!< Some parts (like skirt) always need to be printed before parts like support-brim, so lock 0..n for each extruder, where n is the value saved in this array. Polygons raftOutline; //Storage for the outline of the raft. Will be filled with lines when the GCode is generated. + Polygons primeRaftOutline; // ... the raft underneath the prime-tower will have to be printed first, if there is one. (When the raft has top layers with a different extruder for example.) int max_print_height_second_to_last_extruder; //!< Used in multi-extrusion: the layer number beyond which all models are printed with the same extruder std::vector max_print_height_per_extruder; //!< For each extruder the highest layer number at which it is used. diff --git a/src/support.cpp b/src/support.cpp index 4f088e4f4c..a6f407c86a 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -500,8 +500,11 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp break; case EPlatformAdhesion::RAFT: { - const ExtruderTrain& raft_extruder = mesh_group_settings.get("adhesion_extruder_nr"); - adhesion_size = raft_extruder.settings.get("raft_margin"); + adhesion_size = std::max({ + mesh_group_settings.get("raft_base_extruder_nr").settings.get("raft_margin"), + mesh_group_settings.get("raft_interface_extruder_nr").settings.get("raft_margin"), + mesh_group_settings.get("raft_surface_extruder_nr").settings.get("raft_margin") + }); break; } case EPlatformAdhesion::SKIRT: diff --git a/src/utils/Simplify.h b/src/utils/Simplify.h index c24a7e33bc..a5a8d95e65 100644 --- a/src/utils/Simplify.h +++ b/src/utils/Simplify.h @@ -322,7 +322,7 @@ class Simplify { return; //Cannot remove edge without shifting a long edge. Don't remove anything. } - const coord_t intersection_deviation = LinearAlg2D::getDist2FromLine(intersection, before_to, after_from); + const coord_t intersection_deviation = LinearAlg2D::getDist2FromLineSegment(before_to, intersection, after_from); if(intersection_deviation <= max_deviation * max_deviation) //Intersection point doesn't deviate too much. Use it! { to_delete[vertex] = true; diff --git a/src/utils/ThreadPool.h b/src/utils/ThreadPool.h index 1acf4852d4..f9042fc9eb 100644 --- a/src/utils/ThreadPool.h +++ b/src/utils/ThreadPool.h @@ -230,7 +230,7 @@ void run_multiple_producers_ordered_consumer(ptrdiff_t first, ptrdiff_t last, P& assert(thread_pool); assert(max_pending_per_worker > 0); const size_t max_pending = max_pending_per_worker * (thread_pool->thread_count() + 1); - MultipleProducersOrderedConsumer(first, last, std::forward

(producer), std::forward(consumer), max_pending).run(*thread_pool); + MultipleProducersOrderedConsumer(first, last, std::forward

(producer), std::forward(consumer), max_pending).run(*thread_pool); } template @@ -300,7 +300,7 @@ class MultipleProducersOrderedConsumer ptrdiff_t produce(lock_t& lock) { ptrdiff_t produced_idx = write_idx++; - item_t* slot = &queue[produced_idx % max_pending]; + item_t* slot = &queue[(produced_idx + max_pending) % max_pending]; assert(produced_idx < last_idx); // Unlocks global mutex while producing an item @@ -319,7 +319,7 @@ class MultipleProducersOrderedConsumer void consume_many(lock_t& lock) { assert(read_idx < write_idx); - for (item_t* slot = &queue[read_idx % max_pending]; *slot ; slot = &queue[read_idx % max_pending]) + for (item_t* slot = &queue[(read_idx + max_pending) % max_pending]; *slot ; slot = &queue[(read_idx + max_pending) % max_pending]) { // Unlocks global mutex while consuming an item lock.unlock();