mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 09:17:52 -06:00
1.4.5 features (#319)
* Changes: Improve precise wall Port PS2.6 overhang slowdown feature Implement overhang fan for new overhang slowdown algo Add option to switch between classic/new overhang slowdown implementation Set Arachne as default engine Small adjustment of temp calibration range turn off small perimeter by default Small UI tweaks Change default top_surface_pattern to monotonic Fine tune jerk Signed-off-by: SoftFever <softfeverever@gmail.com> * Disable optimizations for RelWithDebInfo Signed-off-by: SoftFever <softfeverever@gmail.com> * fix an issue that max volumetirc/vfa calibration can't send to print Signed-off-by: SoftFever <softfeverever@gmail.com> #322 * fix build errors Signed-off-by: SoftFever <softfeverever@gmail.com> --------- Signed-off-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
parent
0e0b8d297e
commit
e9613e971d
48 changed files with 3182 additions and 434 deletions
166
.clang-format
Normal file
166
.clang-format
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveMacros: None
|
||||||
|
AlignConsecutiveAssignments: None
|
||||||
|
AlignConsecutiveBitFields: None
|
||||||
|
AlignConsecutiveDeclarations: None
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeConceptDeclarations: true
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 120
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DeriveLineEnding: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentRequires: false
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
Standard: Latest
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- STRINGIZE
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
...
|
||||||
|
|
12
.github/workflows/build_win.yml
vendored
12
.github/workflows/build_win.yml
vendored
|
@ -46,13 +46,13 @@ jobs:
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: .\build_release.bat studio
|
run: .\build_release.bat studio
|
||||||
|
|
||||||
- name: pack app
|
# - name: pack app
|
||||||
working-directory: ${{ github.workspace }}/build
|
# working-directory: ${{ github.workspace }}/build
|
||||||
shell: cmd
|
# shell: cmd
|
||||||
run: '"C:/Program Files/7-Zip/7z.exe" a -tzip BambuStudio-SoftFever_dev_build.zip ${{ github.workspace }}/build/BambuStudio-SoftFever'
|
# run: '"C:/Program Files/7-Zip/7z.exe" a -tzip BambuStudio-SoftFever_dev_build.zip ${{ github.workspace }}/build/BambuStudio-SoftFever'
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: BambuStudio-SoftFever_Win64
|
name: BambuStudio-SoftFever_Win64_nightly
|
||||||
path: ${{ github.workspace }}/build/BambuStudio-SoftFever_dev_build.zip
|
path: ${{ github.workspace }}/build/BambuStudio-SoftFever
|
|
@ -313,20 +313,30 @@ if (SLIC3R_PROFILE)
|
||||||
add_definitions(-DSLIC3R_PROFILE)
|
add_definitions(-DSLIC3R_PROFILE)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Disable optimization even with debugging on.
|
# Disable optimization for RelWithDebInfo
|
||||||
if (0)
|
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES "/O2")
|
||||||
message(STATUS "Perl compiled without optimization. Disabling optimization for the BambuStudio build.")
|
string(REGEX REPLACE "/O2" "/Od" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||||
message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
|
|
||||||
message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}")
|
|
||||||
message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
|
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
|
|
||||||
set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
|
|
||||||
set(CMAKE_C_FLAGS "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "/O2")
|
||||||
|
string(REGEX REPLACE "/O2" "/Od" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES "/Ob1")
|
||||||
|
string(REGEX REPLACE "/Ob1" "/Ob0" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||||
|
endif()
|
||||||
|
if(CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "/Ob1")
|
||||||
|
string(REGEX REPLACE "/Ob1" "/Ob0" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /RTC1")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /RTC1")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(REMOVE_DUPLICATES CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||||
|
list(REMOVE_DUPLICATES CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||||
|
|
||||||
# Find and configure boost
|
# Find and configure boost
|
||||||
if(SLIC3R_STATIC)
|
if(SLIC3R_STATIC)
|
||||||
# Use static boost libraries.
|
# Use static boost libraries.
|
||||||
|
|
|
@ -3,12 +3,21 @@ cd deps
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
set DEPS=%CD%/BambuStudio_dep
|
set DEPS=%CD%/BambuStudio_dep
|
||||||
|
if "%1"=="studio" (
|
||||||
|
GOTO :studio
|
||||||
|
)
|
||||||
|
echo "building deps.."
|
||||||
cmake ../ -G "Visual Studio 16 2019" -DDESTDIR="%CD%/BambuStudio_dep" -DCMAKE_BUILD_TYPE=Release
|
cmake ../ -G "Visual Studio 16 2019" -DDESTDIR="%CD%/BambuStudio_dep" -DCMAKE_BUILD_TYPE=Release
|
||||||
cmake --build . --config Release --target ALL_BUILD -- -m
|
cmake --build . --config Release --target ALL_BUILD -- -m
|
||||||
|
|
||||||
|
if "%1"=="deps" exit /b 0
|
||||||
|
|
||||||
|
:studio
|
||||||
|
echo "building studio..."
|
||||||
cd %WP%
|
cd %WP%
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -G "Visual Studio 16 2019" -DBBL_RELEASE_TO_PUBLIC=1 -DCMAKE_PREFIX_PATH="%DEPS%/usr/local" -DCMAKE_INSTALL_PREFIX="./BambuStudio-SoftFever" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWIN10SDK_PATH="C:/Program Files (x86)/Windows Kits/10/Include/10.0.19041.0"
|
|
||||||
|
cmake .. -G "Visual Studio 16 2019" -DBBL_RELEASE_TO_PUBLIC=1 -DCMAKE_PREFIX_PATH="%DEPS%/usr/local" -DCMAKE_INSTALL_PREFIX="./BambuStudio-SoftFever" -DCMAKE_BUILD_TYPE=Release -DWIN10SDK_PATH="C:/Program Files (x86)/Windows Kits/10/Include/10.0.19041.0"
|
||||||
cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m
|
cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m
|
||||||
@REM cmake --build . --target install --config RelWithDebInfo
|
@REM cmake --build . --target install --config RelWithDebInfo
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Anker",
|
"name": "Anker",
|
||||||
"version": "01.04.00.01",
|
"version": "01.04.04.00",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Anker configurations",
|
"description": "Anker configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"tree_support_with_infill": "0",
|
"tree_support_with_infill": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
"enable_prime_tower": "1",
|
"enable_prime_tower": "1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Anycubic",
|
"name": "Anycubic",
|
||||||
"version": "01.04.00.01",
|
"version": "01.04.04.00",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Anycubic configurations",
|
"description": "Anycubic configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"tree_support_with_infill": "0",
|
"tree_support_with_infill": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
"enable_prime_tower": "1",
|
"enable_prime_tower": "1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Artillery",
|
"name": "Artillery",
|
||||||
"version": "01.04.00.01",
|
"version": "01.04.04.00",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Artillery configurations",
|
"description": "Artillery configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"tree_support_with_infill": "0",
|
"tree_support_with_infill": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
"enable_prime_tower": "1",
|
"enable_prime_tower": "1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Prusa",
|
"name": "Prusa",
|
||||||
"version": "01.04.00.11",
|
"version": "01.04.04.00",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Prusa configurations",
|
"description": "Prusa configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"tree_support_with_infill": "0",
|
"tree_support_with_infill": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
"enable_prime_tower": "1",
|
"enable_prime_tower": "1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "RatRig",
|
"name": "RatRig",
|
||||||
"version": "01.04.00.03",
|
"version": "01.04.04.00",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "RatRig configurations",
|
"description": "RatRig configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
"tree_support_branch_angle": "45",
|
"tree_support_branch_angle": "45",
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_layers": "3",
|
"top_shell_layers": "3",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Snapmaker",
|
"name": "Snapmaker",
|
||||||
"version": "01.04.00.01",
|
"version": "01.04.04.01",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Snapmaker configurations",
|
"description": "Snapmaker configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"tree_support_with_infill": "0",
|
"tree_support_with_infill": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
"enable_prime_tower": "1",
|
"enable_prime_tower": "1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Tronxy",
|
"name": "Tronxy",
|
||||||
"version": "01.04.10.0",
|
"version": "01.04.10.1",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Tronxy configurations",
|
"description": "Tronxy configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
"tree_support_branch_angle": "45",
|
"tree_support_branch_angle": "45",
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_layers": "3",
|
"top_shell_layers": "3",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
"tree_support_branch_angle": "45",
|
"tree_support_branch_angle": "45",
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_layers": "3",
|
"top_shell_layers": "3",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Voron",
|
"name": "Voron",
|
||||||
"version": "01.04.01.00",
|
"version": "01.04.04.00",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Voron configurations",
|
"description": "Voron configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
"tree_support_branch_angle": "45",
|
"tree_support_branch_angle": "45",
|
||||||
"tree_support_wall_count": "0",
|
"tree_support_wall_count": "0",
|
||||||
"detect_thin_wall": "0",
|
"detect_thin_wall": "0",
|
||||||
"top_surface_pattern": "monotonicline",
|
"top_surface_pattern": "monotonic",
|
||||||
"top_surface_line_width": "0.4",
|
"top_surface_line_width": "0.4",
|
||||||
"top_shell_layers": "3",
|
"top_shell_layers": "3",
|
||||||
"top_shell_thickness": "0.8",
|
"top_shell_thickness": "0.8",
|
||||||
|
|
|
@ -607,6 +607,37 @@ namespace detail {
|
||||||
return up_sqr_d;
|
return up_sqr_d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename IndexedPrimitivesDistancerType, typename Scalar>
|
||||||
|
static inline void indexed_primitives_within_distance_squared_recurisve(const IndexedPrimitivesDistancerType &distancer,
|
||||||
|
size_t node_idx,
|
||||||
|
Scalar squared_distance_limit,
|
||||||
|
std::vector<size_t> &found_primitives_indices)
|
||||||
|
{
|
||||||
|
const auto &node = distancer.tree.node(node_idx);
|
||||||
|
assert(node.is_valid());
|
||||||
|
if (node.is_leaf()) {
|
||||||
|
Scalar sqr_dist;
|
||||||
|
distancer.closest_point_to_origin(node.idx, sqr_dist);
|
||||||
|
if (sqr_dist < squared_distance_limit) { found_primitives_indices.push_back(node.idx); }
|
||||||
|
} else {
|
||||||
|
size_t left_node_idx = node_idx * 2 + 1;
|
||||||
|
size_t right_node_idx = left_node_idx + 1;
|
||||||
|
const auto &node_left = distancer.tree.node(left_node_idx);
|
||||||
|
const auto &node_right = distancer.tree.node(right_node_idx);
|
||||||
|
assert(node_left.is_valid());
|
||||||
|
assert(node_right.is_valid());
|
||||||
|
|
||||||
|
if (node_left.bbox.squaredExteriorDistance(distancer.origin) < squared_distance_limit) {
|
||||||
|
indexed_primitives_within_distance_squared_recurisve(distancer, left_node_idx, squared_distance_limit,
|
||||||
|
found_primitives_indices);
|
||||||
|
}
|
||||||
|
if (node_right.bbox.squaredExteriorDistance(distancer.origin) < squared_distance_limit) {
|
||||||
|
indexed_primitives_within_distance_squared_recurisve(distancer, right_node_idx, squared_distance_limit,
|
||||||
|
found_primitives_indices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Build a balanced AABB Tree over an indexed triangles set, balancing the tree
|
// Build a balanced AABB Tree over an indexed triangles set, balancing the tree
|
||||||
|
@ -793,6 +824,33 @@ inline bool is_any_triangle_in_radius(
|
||||||
return hit_point.allFinite();
|
return hit_point.allFinite();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns all triangles within the given radius limit
|
||||||
|
template<typename VertexType, typename IndexedFaceType, typename TreeType, typename VectorType>
|
||||||
|
inline std::vector<size_t> all_triangles_in_radius(
|
||||||
|
// Indexed triangle set - 3D vertices.
|
||||||
|
const std::vector<VertexType> &vertices,
|
||||||
|
// Indexed triangle set - triangular faces, references to vertices.
|
||||||
|
const std::vector<IndexedFaceType> &faces,
|
||||||
|
// AABBTreeIndirect::Tree over vertices & faces, bounding boxes built with the accuracy of vertices.
|
||||||
|
const TreeType &tree,
|
||||||
|
// Point to which the distances on the indexed triangle set is searched for.
|
||||||
|
const VectorType &point,
|
||||||
|
//Square of maximum distance in which triangles are searched for
|
||||||
|
typename VectorType::Scalar max_distance_squared)
|
||||||
|
{
|
||||||
|
auto distancer = detail::IndexedTriangleSetDistancer<VertexType, IndexedFaceType, TreeType, VectorType>
|
||||||
|
{ vertices, faces, tree, point };
|
||||||
|
|
||||||
|
if(tree.empty())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> found_triangles{};
|
||||||
|
detail::indexed_primitives_within_distance_squared_recurisve(distancer, size_t(0), max_distance_squared, found_triangles);
|
||||||
|
return found_triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Traverse the tree and return the index of an entity whose bounding box
|
// Traverse the tree and return the index of an entity whose bounding box
|
||||||
// contains a given point. Returns size_t(-1) when the point is outside.
|
// contains a given point. Returns size_t(-1) when the point is outside.
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
#ifndef SRC_LIBSLIC3R_AABBTREELINES_HPP_
|
#ifndef SRC_LIBSLIC3R_AABBTREELINES_HPP_
|
||||||
#define SRC_LIBSLIC3R_AABBTREELINES_HPP_
|
#define SRC_LIBSLIC3R_AABBTREELINES_HPP_
|
||||||
|
|
||||||
#include "libslic3r/Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "libslic3r/EdgeGrid.hpp"
|
#include "Utils.hpp"
|
||||||
|
#include "libslic3r.h"
|
||||||
#include "libslic3r/AABBTreeIndirect.hpp"
|
#include "libslic3r/AABBTreeIndirect.hpp"
|
||||||
#include "libslic3r/Line.hpp"
|
#include "libslic3r/Line.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
namespace AABBTreeLines {
|
namespace AABBTreeLines {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@ -24,26 +28,141 @@ struct IndexedLinesDistancer {
|
||||||
|
|
||||||
const VectorType origin;
|
const VectorType origin;
|
||||||
|
|
||||||
inline VectorType closest_point_to_origin(size_t primitive_index,
|
inline VectorType closest_point_to_origin(size_t primitive_index, ScalarType& squared_distance) const
|
||||||
ScalarType &squared_distance) {
|
{
|
||||||
VectorType nearest_point;
|
Vec<LineType::Dim, typename LineType::Scalar> nearest_point;
|
||||||
const LineType& line = lines[primitive_index];
|
const LineType& line = lines[primitive_index];
|
||||||
squared_distance = line_alg::distance_to_squared(line, origin, &nearest_point);
|
squared_distance = line_alg::distance_to_squared(line, origin.template cast<typename LineType::Scalar>(), &nearest_point);
|
||||||
return nearest_point;
|
return nearest_point.template cast<ScalarType>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// returns number of intersections of ray starting in ray_origin and following the specified coordinate line with lines in tree
|
||||||
|
// first number is hits in positive direction of ray, second number hits in negative direction. returns neagtive numbers when ray_origin is
|
||||||
|
// on some line exactly.
|
||||||
|
template <typename LineType, typename TreeType, typename VectorType, int coordinate>
|
||||||
|
inline std::tuple<int, int> coordinate_aligned_ray_hit_count(size_t node_idx,
|
||||||
|
const TreeType& tree,
|
||||||
|
const std::vector<LineType>& lines,
|
||||||
|
const VectorType& ray_origin)
|
||||||
|
{
|
||||||
|
static constexpr int other_coordinate = (coordinate + 1) % 2;
|
||||||
|
using Scalar = typename LineType::Scalar;
|
||||||
|
using Floating = typename std::conditional<std::is_floating_point<Scalar>::value, Scalar, double>::type;
|
||||||
|
const auto& node = tree.node(node_idx);
|
||||||
|
assert(node.is_valid());
|
||||||
|
if (node.is_leaf()) {
|
||||||
|
const LineType& line = lines[node.idx];
|
||||||
|
if (ray_origin[other_coordinate] < std::min(line.a[other_coordinate], line.b[other_coordinate]) || ray_origin[other_coordinate] >= std::max(line.a[other_coordinate], line.b[other_coordinate])) {
|
||||||
|
// the second inequality is nonsharp for a reason
|
||||||
|
// without it, we may count contour border twice when the lines meet exactly at the spot of intersection. this prevents is
|
||||||
|
return { 0, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a balanced AABB Tree over a vector of float lines, balancing the tree
|
Scalar line_max = std::max(line.a[coordinate], line.b[coordinate]);
|
||||||
|
Scalar line_min = std::min(line.a[coordinate], line.b[coordinate]);
|
||||||
|
if (ray_origin[coordinate] > line_max) {
|
||||||
|
return { 1, 0 };
|
||||||
|
} else if (ray_origin[coordinate] < line_min) {
|
||||||
|
return { 0, 1 };
|
||||||
|
} else {
|
||||||
|
// find intersection of ray with line
|
||||||
|
// that is when ( line.a + t * (line.b - line.a) )[other_coordinate] == ray_origin[other_coordinate]
|
||||||
|
// t = ray_origin[oc] - line.a[oc] / (line.b[oc] - line.a[oc]);
|
||||||
|
// then we want to get value of intersection[ coordinate]
|
||||||
|
// val_c = line.a[c] + t * (line.b[c] - line.a[c]);
|
||||||
|
// Note that ray and line may overlap, when (line.b[oc] - line.a[oc]) is zero
|
||||||
|
// In that case, we return negative number
|
||||||
|
Floating distance_oc = line.b[other_coordinate] - line.a[other_coordinate];
|
||||||
|
Floating t = (ray_origin[other_coordinate] - line.a[other_coordinate]) / distance_oc;
|
||||||
|
Floating val_c = line.a[coordinate] + t * (line.b[coordinate] - line.a[coordinate]);
|
||||||
|
if (ray_origin[coordinate] > val_c) {
|
||||||
|
return { 1, 0 };
|
||||||
|
} else if (ray_origin[coordinate] < val_c) {
|
||||||
|
return { 0, 1 };
|
||||||
|
} else { // ray origin is on boundary
|
||||||
|
return { -1, -1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int intersections_above = 0;
|
||||||
|
int intersections_below = 0;
|
||||||
|
size_t left_node_idx = node_idx * 2 + 1;
|
||||||
|
size_t right_node_idx = left_node_idx + 1;
|
||||||
|
const auto& node_left = tree.node(left_node_idx);
|
||||||
|
const auto& node_right = tree.node(right_node_idx);
|
||||||
|
assert(node_left.is_valid());
|
||||||
|
assert(node_right.is_valid());
|
||||||
|
|
||||||
|
if (node_left.bbox.min()[other_coordinate] <= ray_origin[other_coordinate] && node_left.bbox.max()[other_coordinate] >= ray_origin[other_coordinate]) {
|
||||||
|
auto [above, below] = coordinate_aligned_ray_hit_count<LineType, TreeType, VectorType, coordinate>(left_node_idx, tree, lines,
|
||||||
|
ray_origin);
|
||||||
|
if (above < 0 || below < 0)
|
||||||
|
return { -1, -1 };
|
||||||
|
intersections_above += above;
|
||||||
|
intersections_below += below;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_right.bbox.min()[other_coordinate] <= ray_origin[other_coordinate] && node_right.bbox.max()[other_coordinate] >= ray_origin[other_coordinate]) {
|
||||||
|
auto [above, below] = coordinate_aligned_ray_hit_count<LineType, TreeType, VectorType, coordinate>(right_node_idx, tree, lines,
|
||||||
|
ray_origin);
|
||||||
|
if (above < 0 || below < 0)
|
||||||
|
return { -1, -1 };
|
||||||
|
intersections_above += above;
|
||||||
|
intersections_below += below;
|
||||||
|
}
|
||||||
|
return { intersections_above, intersections_below };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename LineType, typename TreeType, typename VectorType>
|
||||||
|
inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(size_t node_idx,
|
||||||
|
const TreeType& tree,
|
||||||
|
const std::vector<LineType>& lines,
|
||||||
|
const LineType& line,
|
||||||
|
const typename TreeType::BoundingBox& line_bb)
|
||||||
|
{
|
||||||
|
const auto& node = tree.node(node_idx);
|
||||||
|
assert(node.is_valid());
|
||||||
|
if (node.is_leaf()) {
|
||||||
|
VectorType intersection_pt;
|
||||||
|
if (line_alg::intersection(line, lines[node.idx], &intersection_pt)) {
|
||||||
|
return { std::pair<VectorType, size_t>(intersection_pt, node.idx) };
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t left_node_idx = node_idx * 2 + 1;
|
||||||
|
size_t right_node_idx = left_node_idx + 1;
|
||||||
|
const auto& node_left = tree.node(left_node_idx);
|
||||||
|
const auto& node_right = tree.node(right_node_idx);
|
||||||
|
assert(node_left.is_valid());
|
||||||
|
assert(node_right.is_valid());
|
||||||
|
|
||||||
|
std::vector<std::pair<VectorType, size_t>> result;
|
||||||
|
|
||||||
|
if (node_left.bbox.intersects(line_bb)) {
|
||||||
|
std::vector<std::pair<VectorType, size_t>> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines, line, line_bb);
|
||||||
|
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_right.bbox.intersects(line_bb)) {
|
||||||
|
std::vector<std::pair<VectorType, size_t>> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines, line, line_bb);
|
||||||
|
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// Build a balanced AABB Tree over a vector of lines, balancing the tree
|
||||||
// on centroids of the lines.
|
// on centroids of the lines.
|
||||||
// Epsilon is applied to the bounding boxes of the AABB Tree to cope with numeric inaccuracies
|
// Epsilon is applied to the bounding boxes of the AABB Tree to cope with numeric inaccuracies
|
||||||
// during tree traversal.
|
// during tree traversal.
|
||||||
template <typename LineType>
|
template <typename LineType>
|
||||||
inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over_indexed_lines(
|
inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over_indexed_lines(const std::vector<LineType>& lines)
|
||||||
const std::vector<LineType> &lines,
|
|
||||||
//FIXME do we want to apply an epsilon?
|
|
||||||
const float eps = 0)
|
|
||||||
{
|
{
|
||||||
using TreeType = AABBTreeIndirect::Tree<2, typename LineType::Scalar>;
|
using TreeType = AABBTreeIndirect::Tree<2, typename LineType::Scalar>;
|
||||||
// using CoordType = typename TreeType::CoordType;
|
// using CoordType = typename TreeType::CoordType;
|
||||||
|
@ -51,15 +170,9 @@ inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over
|
||||||
using BoundingBox = typename TreeType::BoundingBox;
|
using BoundingBox = typename TreeType::BoundingBox;
|
||||||
|
|
||||||
struct InputType {
|
struct InputType {
|
||||||
size_t idx() const {
|
size_t idx() const { return m_idx; }
|
||||||
return m_idx;
|
const BoundingBox& bbox() const { return m_bbox; }
|
||||||
}
|
const VectorType& centroid() const { return m_centroid; }
|
||||||
const BoundingBox& bbox() const {
|
|
||||||
return m_bbox;
|
|
||||||
}
|
|
||||||
const VectorType& centroid() const {
|
|
||||||
return m_centroid;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t m_idx;
|
size_t m_idx;
|
||||||
BoundingBox m_bbox;
|
BoundingBox m_bbox;
|
||||||
|
@ -68,7 +181,6 @@ inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over
|
||||||
|
|
||||||
std::vector<InputType> input;
|
std::vector<InputType> input;
|
||||||
input.reserve(lines.size());
|
input.reserve(lines.size());
|
||||||
const VectorType veps(eps, eps);
|
|
||||||
for (size_t i = 0; i < lines.size(); ++i) {
|
for (size_t i = 0; i < lines.size(); ++i) {
|
||||||
const LineType& line = lines[i];
|
const LineType& line = lines[i];
|
||||||
InputType n;
|
InputType n;
|
||||||
|
@ -76,8 +188,6 @@ inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over
|
||||||
n.m_centroid = (line.a + line.b) * 0.5;
|
n.m_centroid = (line.a + line.b) * 0.5;
|
||||||
n.m_bbox = BoundingBox(line.a, line.a);
|
n.m_bbox = BoundingBox(line.a, line.a);
|
||||||
n.m_bbox.extend(line.b);
|
n.m_bbox.extend(line.b);
|
||||||
n.m_bbox.min() -= veps;
|
|
||||||
n.m_bbox.max() += veps;
|
|
||||||
input.emplace_back(n);
|
input.emplace_back(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,25 +198,175 @@ inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over
|
||||||
|
|
||||||
// Finding a closest line, its closest point and squared distance to the closest point
|
// Finding a closest line, its closest point and squared distance to the closest point
|
||||||
// Returns squared distance to the closest point or -1 if the input is empty.
|
// Returns squared distance to the closest point or -1 if the input is empty.
|
||||||
|
// or no closer point than max_sq_dist
|
||||||
template <typename LineType, typename TreeType, typename VectorType>
|
template <typename LineType, typename TreeType, typename VectorType>
|
||||||
inline typename VectorType::Scalar squared_distance_to_indexed_lines(
|
inline typename VectorType::Scalar squared_distance_to_indexed_lines(
|
||||||
const std::vector<LineType>& lines,
|
const std::vector<LineType>& lines,
|
||||||
const TreeType& tree,
|
const TreeType& tree,
|
||||||
const VectorType& point,
|
const VectorType& point,
|
||||||
size_t& hit_idx_out,
|
size_t& hit_idx_out,
|
||||||
Eigen::PlainObjectBase<VectorType> &hit_point_out)
|
Eigen::PlainObjectBase<VectorType>& hit_point_out,
|
||||||
|
typename VectorType::Scalar max_sqr_dist = std::numeric_limits<typename VectorType::Scalar>::infinity())
|
||||||
{
|
{
|
||||||
using Scalar = typename VectorType::Scalar;
|
using Scalar = typename VectorType::Scalar;
|
||||||
auto distancer = detail::IndexedLinesDistancer<LineType, TreeType, VectorType>
|
if (tree.empty())
|
||||||
{ lines, tree, point };
|
return Scalar(-1);
|
||||||
return tree.empty() ?
|
auto distancer = detail::IndexedLinesDistancer<LineType, TreeType, VectorType> { lines, tree, point };
|
||||||
Scalar(-1) :
|
return AABBTreeIndirect::detail::squared_distance_to_indexed_primitives_recursive(distancer, size_t(0), Scalar(0), max_sqr_dist,
|
||||||
AABBTreeIndirect::detail::squared_distance_to_indexed_primitives_recursive(distancer, size_t(0), Scalar(0),
|
hit_idx_out, hit_point_out);
|
||||||
std::numeric_limits<Scalar>::infinity(), hit_idx_out, hit_point_out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns all lines within the given radius limit
|
||||||
|
template <typename LineType, typename TreeType, typename VectorType>
|
||||||
|
inline std::vector<size_t> all_lines_in_radius(const std::vector<LineType>& lines,
|
||||||
|
const TreeType& tree,
|
||||||
|
const VectorType& point,
|
||||||
|
typename VectorType::Scalar max_distance_squared)
|
||||||
|
{
|
||||||
|
auto distancer = detail::IndexedLinesDistancer<LineType, TreeType, VectorType> { lines, tree, point };
|
||||||
|
|
||||||
|
if (tree.empty()) {
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> found_lines {};
|
||||||
|
AABBTreeIndirect::detail::indexed_primitives_within_distance_squared_recurisve(distancer, size_t(0), max_distance_squared, found_lines);
|
||||||
|
return found_lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return 1 if true, -1 if false, 0 for point on contour (or if cannot be determined)
|
||||||
|
template <typename LineType, typename TreeType, typename VectorType>
|
||||||
|
inline int point_outside_closed_contours(const std::vector<LineType>& lines, const TreeType& tree, const VectorType& point)
|
||||||
|
{
|
||||||
|
if (tree.empty()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [hits_above, hits_below] = detail::coordinate_aligned_ray_hit_count<LineType, TreeType, VectorType, 0>(0, tree, lines, point);
|
||||||
|
if (hits_above < 0 || hits_below < 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (hits_above % 2 == 1 && hits_below % 2 == 1) {
|
||||||
|
return -1;
|
||||||
|
} else if (hits_above % 2 == 0 && hits_below % 2 == 0) {
|
||||||
|
return 1;
|
||||||
|
} else { // this should not happen with closed contours. lets check it in Y direction
|
||||||
|
auto [hits_above, hits_below] = detail::coordinate_aligned_ray_hit_count<LineType, TreeType, VectorType, 1>(0, tree, lines, point);
|
||||||
|
if (hits_above < 0 || hits_below < 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (hits_above % 2 == 1 && hits_below % 2 == 1) {
|
||||||
|
return -1;
|
||||||
|
} else if (hits_above % 2 == 0 && hits_below % 2 == 0) {
|
||||||
|
return 1;
|
||||||
|
} else { // both results were unclear
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool sorted, typename VectorType, typename LineType, typename TreeType>
|
||||||
|
inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(const std::vector<LineType>& lines,
|
||||||
|
const TreeType& tree,
|
||||||
|
const LineType& line)
|
||||||
|
{
|
||||||
|
if (tree.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto line_bb = typename TreeType::BoundingBox(line.a, line.a);
|
||||||
|
line_bb.extend(line.b);
|
||||||
|
|
||||||
|
auto intersections = detail::get_intersections_with_line<LineType, TreeType, VectorType>(0, tree, lines, line, line_bb);
|
||||||
|
if (sorted) {
|
||||||
|
using Floating =
|
||||||
|
typename std::conditional<std::is_floating_point<typename LineType::Scalar>::value, typename LineType::Scalar, double>::type;
|
||||||
|
|
||||||
|
std::vector<std::pair<Floating, std::pair<VectorType, size_t>>> points_with_sq_distance {};
|
||||||
|
for (const auto& p : intersections) {
|
||||||
|
points_with_sq_distance.emplace_back((p.first - line.a).template cast<Floating>().squaredNorm(), p);
|
||||||
|
}
|
||||||
|
std::sort(points_with_sq_distance.begin(), points_with_sq_distance.end(),
|
||||||
|
[](const std::pair<Floating, std::pair<VectorType, size_t>>& left,
|
||||||
|
std::pair<Floating, std::pair<VectorType, size_t>>& right) { return left.first < right.first; });
|
||||||
|
for (size_t i = 0; i < points_with_sq_distance.size(); i++) {
|
||||||
|
intersections[i] = points_with_sq_distance[i].second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename LineType>
|
||||||
|
class LinesDistancer {
|
||||||
|
public:
|
||||||
|
using Scalar = typename LineType::Scalar;
|
||||||
|
using Floating = typename std::conditional<std::is_floating_point<Scalar>::value, Scalar, double>::type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<LineType> lines;
|
||||||
|
AABBTreeIndirect::Tree<2, Scalar> tree;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LinesDistancer(const std::vector<LineType>& lines)
|
||||||
|
: lines(lines)
|
||||||
|
{
|
||||||
|
tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(this->lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit LinesDistancer(std::vector<LineType>&& lines)
|
||||||
|
: lines(lines)
|
||||||
|
{
|
||||||
|
tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(this->lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinesDistancer() = default;
|
||||||
|
|
||||||
|
// 1 true, -1 false, 0 cannot determine
|
||||||
|
int outside(const Vec<2, Scalar>& point) const { return point_outside_closed_contours(lines, tree, point); }
|
||||||
|
|
||||||
|
// negative sign means inside
|
||||||
|
template <bool SIGNED_DISTANCE>
|
||||||
|
std::tuple<Floating, size_t, Vec<2, Floating>> distance_from_lines_extra(const Vec<2, Scalar>& point) const
|
||||||
|
{
|
||||||
|
size_t nearest_line_index_out = size_t(-1);
|
||||||
|
Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero();
|
||||||
|
Vec<2, Floating> p = point.template cast<Floating>();
|
||||||
|
auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out);
|
||||||
|
|
||||||
|
if (distance < 0) {
|
||||||
|
return { std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out };
|
||||||
|
}
|
||||||
|
distance = sqrt(distance);
|
||||||
|
|
||||||
|
if (SIGNED_DISTANCE) {
|
||||||
|
distance *= outside(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { distance, nearest_line_index_out, nearest_point_out };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool SIGNED_DISTANCE>
|
||||||
|
Floating distance_from_lines(const Vec<2, typename LineType::Scalar>& point) const
|
||||||
|
{
|
||||||
|
auto [dist, idx, np] = distance_from_lines_extra<SIGNED_DISTANCE>(point);
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> all_lines_in_radius(const Vec<2, typename LineType::Scalar>& point, Floating radius)
|
||||||
|
{
|
||||||
|
return all_lines_in_radius(this->lines, this->tree, point, radius * radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool sorted>
|
||||||
|
std::vector<std::pair<Vec<2, Scalar>, size_t>> intersections_with_line(const LineType& line) const
|
||||||
|
{
|
||||||
|
return get_intersections_with_line<sorted, Vec<2, Scalar>>(lines, tree, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LineType& get_line(size_t line_idx) const { return lines[line_idx]; }
|
||||||
|
|
||||||
|
const std::vector<LineType>& get_lines() const { return lines; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Slic3r::AABBTreeLines
|
||||||
|
|
||||||
#endif /* SRC_LIBSLIC3R_AABBTREELINES_HPP_ */
|
#endif /* SRC_LIBSLIC3R_AABBTREELINES_HPP_ */
|
||||||
|
|
|
@ -134,6 +134,7 @@ set(lisbslic3r_sources
|
||||||
GCode/GCodeProcessor.hpp
|
GCode/GCodeProcessor.hpp
|
||||||
GCode/AvoidCrossingPerimeters.cpp
|
GCode/AvoidCrossingPerimeters.cpp
|
||||||
GCode/AvoidCrossingPerimeters.hpp
|
GCode/AvoidCrossingPerimeters.hpp
|
||||||
|
GCode/ExtrusionProcessor.hpp
|
||||||
GCode.cpp
|
GCode.cpp
|
||||||
GCode.hpp
|
GCode.hpp
|
||||||
GCodeReader.cpp
|
GCodeReader.cpp
|
||||||
|
@ -246,6 +247,10 @@ set(lisbslic3r_sources
|
||||||
SlicingAdaptive.hpp
|
SlicingAdaptive.hpp
|
||||||
SupportMaterial.cpp
|
SupportMaterial.cpp
|
||||||
SupportMaterial.hpp
|
SupportMaterial.hpp
|
||||||
|
PrincipalComponents2D.cpp
|
||||||
|
PrincipalComponents2D.hpp
|
||||||
|
SupportSpotsGenerator.cpp
|
||||||
|
SupportSpotsGenerator.hpp
|
||||||
TreeSupport.hpp
|
TreeSupport.hpp
|
||||||
TreeSupport.cpp
|
TreeSupport.cpp
|
||||||
MinimumSpanningTree.hpp
|
MinimumSpanningTree.hpp
|
||||||
|
|
|
@ -84,6 +84,25 @@ public:
|
||||||
inline bool operator==(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour == rhs.contour && lhs.holes == rhs.holes; }
|
inline bool operator==(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour == rhs.contour && lhs.holes == rhs.holes; }
|
||||||
inline bool operator!=(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour != rhs.contour || lhs.holes != rhs.holes; }
|
inline bool operator!=(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour != rhs.contour || lhs.holes != rhs.holes; }
|
||||||
|
|
||||||
|
inline size_t count_points(const ExPolygons& expolys)
|
||||||
|
{
|
||||||
|
size_t n_points = 0;
|
||||||
|
for (const auto& expoly : expolys) {
|
||||||
|
n_points += expoly.contour.points.size();
|
||||||
|
for (const auto& hole : expoly.holes)
|
||||||
|
n_points += hole.points.size();
|
||||||
|
}
|
||||||
|
return n_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t count_points(const ExPolygon& expoly)
|
||||||
|
{
|
||||||
|
size_t n_points = expoly.contour.points.size();
|
||||||
|
for (const auto& hole : expoly.holes)
|
||||||
|
n_points += hole.points.size();
|
||||||
|
return n_points;
|
||||||
|
}
|
||||||
|
|
||||||
// Count a nuber of polygons stored inside the vector of expolygons.
|
// Count a nuber of polygons stored inside the vector of expolygons.
|
||||||
// Useful for allocating space for polygons when converting expolygons to polygons.
|
// Useful for allocating space for polygons when converting expolygons to polygons.
|
||||||
inline size_t number_polygons(const ExPolygons &expolys)
|
inline size_t number_polygons(const ExPolygons &expolys)
|
||||||
|
@ -130,6 +149,72 @@ inline Lines to_lines(const ExPolygons &src)
|
||||||
}
|
}
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
// Line is from point index(see to_points) to next point.
|
||||||
|
// Next point of last point in polygon is first polygon point.
|
||||||
|
inline Linesf to_linesf(const ExPolygons& src, uint32_t count_lines = 0)
|
||||||
|
{
|
||||||
|
assert(count_lines == 0 || count_lines == count_points(src));
|
||||||
|
if (count_lines == 0)
|
||||||
|
count_lines = count_points(src);
|
||||||
|
Linesf lines;
|
||||||
|
lines.reserve(count_lines);
|
||||||
|
Vec2d prev_pd;
|
||||||
|
auto to_lines = [&lines, &prev_pd](const Points& pts) {
|
||||||
|
assert(pts.size() >= 3);
|
||||||
|
if (pts.size() < 2)
|
||||||
|
return;
|
||||||
|
bool is_first = true;
|
||||||
|
for (const Point& p : pts) {
|
||||||
|
Vec2d pd = p.cast<double>();
|
||||||
|
if (is_first)
|
||||||
|
is_first = false;
|
||||||
|
else
|
||||||
|
lines.emplace_back(prev_pd, pd);
|
||||||
|
prev_pd = pd;
|
||||||
|
}
|
||||||
|
lines.emplace_back(prev_pd, pts.front().cast<double>());
|
||||||
|
};
|
||||||
|
for (const ExPolygon& expoly : src) {
|
||||||
|
to_lines(expoly.contour.points);
|
||||||
|
for (const Polygon& hole : expoly.holes)
|
||||||
|
to_lines(hole.points);
|
||||||
|
}
|
||||||
|
assert(lines.size() == count_lines);
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Linesf to_unscaled_linesf(const ExPolygons& src)
|
||||||
|
{
|
||||||
|
Linesf lines;
|
||||||
|
lines.reserve(count_points(src));
|
||||||
|
for (ExPolygons::const_iterator it_expoly = src.begin(); it_expoly != src.end(); ++it_expoly) {
|
||||||
|
for (size_t i = 0; i <= it_expoly->holes.size(); ++i) {
|
||||||
|
const Points& points = ((i == 0) ? it_expoly->contour : it_expoly->holes[i - 1]).points;
|
||||||
|
Vec2d unscaled_a = unscaled(points.front());
|
||||||
|
Vec2d unscaled_b = unscaled_a;
|
||||||
|
for (Points::const_iterator it = points.begin() + 1; it != points.end(); ++it) {
|
||||||
|
unscaled_b = unscaled(*(it));
|
||||||
|
lines.push_back(Linef(unscaled_a, unscaled_b));
|
||||||
|
unscaled_a = unscaled_b;
|
||||||
|
}
|
||||||
|
lines.push_back(Linef(unscaled_a, unscaled(points.front())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Points to_points(const ExPolygons& src)
|
||||||
|
{
|
||||||
|
Points points;
|
||||||
|
size_t count = count_points(src);
|
||||||
|
points.reserve(count);
|
||||||
|
for (const ExPolygon& expolygon : src) {
|
||||||
|
append(points, expolygon.contour.points);
|
||||||
|
for (const Polygon& hole : expolygon.holes)
|
||||||
|
append(points, hole.points);
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
inline Polylines to_polylines(const ExPolygon &src)
|
inline Polylines to_polylines(const ExPolygon &src)
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,8 +51,7 @@ enum ExtrusionLoopRole {
|
||||||
inline bool is_perimeter(ExtrusionRole role)
|
inline bool is_perimeter(ExtrusionRole role)
|
||||||
{
|
{
|
||||||
return role == erPerimeter
|
return role == erPerimeter
|
||||||
|| role == erExternalPerimeter
|
|| role == erExternalPerimeter;
|
||||||
|| role == erOverhangPerimeter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_internal_perimeter(ExtrusionRole role)
|
inline bool is_internal_perimeter(ExtrusionRole role)
|
||||||
|
@ -217,12 +216,12 @@ public:
|
||||||
double total_volume() const override { return mm3_per_mm * unscale<double>(length()); }
|
double total_volume() const override { return mm3_per_mm * unscale<double>(length()); }
|
||||||
|
|
||||||
void set_overhang_degree(int overhang) {
|
void set_overhang_degree(int overhang) {
|
||||||
if (is_perimeter(m_role))
|
if (is_perimeter(m_role) || is_bridge(m_role))
|
||||||
overhang_degree = (overhang < 0)?0:(overhang > 10 ? 10 : overhang);
|
overhang_degree = (overhang < 0)?0:(overhang > 10 ? 10 : overhang);
|
||||||
};
|
};
|
||||||
int get_overhang_degree() const {
|
int get_overhang_degree() const {
|
||||||
// only perimeter has overhang degree. Other return 0;
|
// only perimeter has overhang degree. Other return 0;
|
||||||
if (is_perimeter(m_role))
|
if (is_perimeter(m_role) || is_bridge(m_role))
|
||||||
return overhang_degree;
|
return overhang_degree;
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "LocalesUtils.hpp"
|
#include "LocalesUtils.hpp"
|
||||||
#include "libslic3r/format.hpp"
|
#include "libslic3r/format.hpp"
|
||||||
#include "Time.hpp"
|
#include "Time.hpp"
|
||||||
|
#include "GCode/ExtrusionProcessor.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -1661,7 +1662,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||||
|
|
||||||
if (m_config.default_jerk.value > 0) {
|
if (m_config.default_jerk.value > 0) {
|
||||||
double jerk = m_config.outer_wall_jerk.value;
|
double jerk = m_config.outer_wall_jerk.value;
|
||||||
gcode += m_writer.set_jerk_xy((unsigned int)floor(jerk + 0.5));
|
gcode += m_writer.set_jerk_xy(jerk);
|
||||||
}
|
}
|
||||||
|
|
||||||
calib_pressure_advance pa_test(this);
|
calib_pressure_advance pa_test(this);
|
||||||
|
@ -2461,6 +2462,7 @@ namespace Skirt {
|
||||||
#if 0
|
#if 0
|
||||||
// Prime just the first printing extruder. This is original Slic3r's implementation.
|
// Prime just the first printing extruder. This is original Slic3r's implementation.
|
||||||
skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirt_loops.value);
|
skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirt_loops.value);
|
||||||
|
skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirt_loops.value);
|
||||||
#else
|
#else
|
||||||
// Prime all extruders planned for this layer, see
|
// Prime all extruders planned for this layer, see
|
||||||
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
|
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
|
||||||
|
@ -2616,14 +2618,10 @@ GCode::LayerResult GCode::process_layer(
|
||||||
gcode += writer().set_temperature(print.calib_params().start - offset);
|
gcode += writer().set_temperature(print.calib_params().start - offset);
|
||||||
} else if (print.calib_mode() == CalibMode::Calib_VFA_Tower) {
|
} else if (print.calib_mode() == CalibMode::Calib_VFA_Tower) {
|
||||||
auto _speed = print.calib_params().start + std::floor(print_z / 5.0) * print.calib_params().step;
|
auto _speed = print.calib_params().start + std::floor(print_z / 5.0) * print.calib_params().step;
|
||||||
DynamicConfig config;
|
m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed)));
|
||||||
config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed)));
|
|
||||||
const_cast<Print*>(&print)->print_regions_mutable()[0]->config_apply_only(config, { "outer_wall_speed" });
|
|
||||||
} else if (print.calib_mode() == CalibMode::Calib_Vol_speed_Tower) {
|
} else if (print.calib_mode() == CalibMode::Calib_Vol_speed_Tower) {
|
||||||
auto _speed = print.calib_params().start + print_z * print.calib_params().step;
|
auto _speed = print.calib_params().start + print_z * print.calib_params().step;
|
||||||
DynamicConfig config;
|
m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed)));
|
||||||
config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed)));
|
|
||||||
const_cast<Print*>(&print)->print_regions_mutable()[0]->config_apply_only(config, { "outer_wall_speed" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
|
@ -2636,7 +2634,7 @@ GCode::LayerResult GCode::process_layer(
|
||||||
|
|
||||||
if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) {
|
if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) {
|
||||||
double jerk = m_config.initial_layer_jerk.value;
|
double jerk = m_config.initial_layer_jerk.value;
|
||||||
gcode += m_writer.set_jerk_xy((unsigned int)floor(jerk + 0.5));
|
gcode += m_writer.set_jerk_xy(jerk);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2665,7 +2663,7 @@ GCode::LayerResult GCode::process_layer(
|
||||||
|
|
||||||
if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) {
|
if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) {
|
||||||
double jerk = m_config.default_jerk.value;
|
double jerk = m_config.default_jerk.value;
|
||||||
gcode += m_writer.set_jerk_xy((unsigned int)floor(jerk + 0.5));
|
gcode += m_writer.set_jerk_xy(jerk);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
|
// Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
|
||||||
|
@ -2699,6 +2697,11 @@ GCode::LayerResult GCode::process_layer(
|
||||||
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) :
|
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) :
|
||||||
Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done);
|
Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done);
|
||||||
|
|
||||||
|
for (const auto& layer_to_print : layers) {
|
||||||
|
m_extrusion_quality_estimator.prepare_for_new_layer(layer_to_print.object_layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Group extrusions by an extruder, then by an object, an island and a region.
|
// Group extrusions by an extruder, then by an object, an island and a region.
|
||||||
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
|
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
|
||||||
bool is_anything_overridden = const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden();
|
bool is_anything_overridden = const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden();
|
||||||
|
@ -3084,6 +3087,8 @@ GCode::LayerResult GCode::process_layer(
|
||||||
if (!m_config.use_relative_e_distances)
|
if (!m_config.use_relative_e_distances)
|
||||||
gcode += m_writer.reset_e(true);
|
gcode += m_writer.reset_e(true);
|
||||||
}
|
}
|
||||||
|
m_extrusion_quality_estimator.set_current_object(&instance_to_print.print_object);
|
||||||
|
|
||||||
// When starting a new object, use the external motion planner for the first travel move.
|
// When starting a new object, use the external motion planner for the first travel move.
|
||||||
const Point &offset = instance_to_print.print_object.instances()[instance_to_print.instance_id].shift;
|
const Point &offset = instance_to_print.print_object.instances()[instance_to_print.instance_id].shift;
|
||||||
std::pair<const PrintObject*, Point> this_object_copy(&instance_to_print.print_object, offset);
|
std::pair<const PrintObject*, Point> this_object_copy(&instance_to_print.print_object, offset);
|
||||||
|
@ -3450,7 +3455,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||||
if (m_config.default_acceleration.value > 0)
|
if (m_config.default_acceleration.value > 0)
|
||||||
gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5));
|
gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5));
|
||||||
if (m_config.default_jerk.value > 0)
|
if (m_config.default_jerk.value > 0)
|
||||||
gcode += m_writer.set_jerk_xy((unsigned int)(m_config.default_jerk.value + 0.5));
|
gcode += m_writer.set_jerk_xy(m_config.default_jerk.value);
|
||||||
}
|
}
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
@ -3480,7 +3485,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string
|
||||||
// reset acceleration
|
// reset acceleration
|
||||||
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
||||||
if(m_config.default_jerk.value > 0)
|
if(m_config.default_jerk.value > 0)
|
||||||
gcode += m_writer.set_jerk_xy((unsigned int)floor(m_config.default_jerk.value + 0.5));
|
gcode += m_writer.set_jerk_xy(m_config.default_jerk.value);
|
||||||
}
|
}
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
@ -3511,7 +3516,7 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string description, dou
|
||||||
// reset acceleration
|
// reset acceleration
|
||||||
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
||||||
if(m_config.default_jerk.value > 0)
|
if(m_config.default_jerk.value > 0)
|
||||||
gcode += m_writer.set_jerk_xy((unsigned int)floor(m_config.default_jerk.value + 0.5));
|
gcode += m_writer.set_jerk_xy(m_config.default_jerk.value);
|
||||||
|
|
||||||
}
|
}
|
||||||
return gcode;
|
return gcode;
|
||||||
|
@ -3698,7 +3703,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
|
|
||||||
// compensate retraction
|
// compensate retraction
|
||||||
gcode += this->unretract();
|
gcode += this->unretract();
|
||||||
|
m_config.apply(m_calib_config);
|
||||||
// adjust acceleration
|
// adjust acceleration
|
||||||
if (m_config.default_acceleration.value > 0) {
|
if (m_config.default_acceleration.value > 0) {
|
||||||
double acceleration;
|
double acceleration;
|
||||||
|
@ -3739,7 +3744,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
else {
|
else {
|
||||||
jerk = m_config.default_jerk.value;
|
jerk = m_config.default_jerk.value;
|
||||||
}
|
}
|
||||||
gcode += m_writer.set_jerk_xy((unsigned int)floor(jerk + 0.5));
|
gcode += m_writer.set_jerk_xy(jerk);
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate extrusion length per distance unit
|
// calculate extrusion length per distance unit
|
||||||
|
@ -3752,13 +3757,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
int overhang_degree = path.get_overhang_degree();
|
int overhang_degree = path.get_overhang_degree();
|
||||||
if (path.role() == erPerimeter) {
|
if (path.role() == erPerimeter) {
|
||||||
speed = m_config.get_abs_value("inner_wall_speed");
|
speed = m_config.get_abs_value("inner_wall_speed");
|
||||||
if (m_config.enable_overhang_speed.value && overhang_degree > 0 && overhang_degree <= 5) {
|
if (m_config.overhang_speed_classic.value && m_config.enable_overhang_speed.value && overhang_degree > 0 &&
|
||||||
|
overhang_degree <= 5) {
|
||||||
double new_speed = m_config.get_abs_value(overhang_speed_key_map[overhang_degree].c_str());
|
double new_speed = m_config.get_abs_value(overhang_speed_key_map[overhang_degree].c_str());
|
||||||
speed = new_speed == 0.0 ? speed : new_speed;
|
speed = new_speed == 0.0 ? speed : new_speed;
|
||||||
}
|
}
|
||||||
} else if (path.role() == erExternalPerimeter) {
|
} else if (path.role() == erExternalPerimeter) {
|
||||||
speed = m_config.get_abs_value("outer_wall_speed");
|
speed = m_config.get_abs_value("outer_wall_speed");
|
||||||
if (m_config.enable_overhang_speed.value && overhang_degree > 0 && overhang_degree <= 5) {
|
if (m_config.overhang_speed_classic.value && m_config.enable_overhang_speed.value &&
|
||||||
|
overhang_degree > 0 && overhang_degree <= 5) {
|
||||||
double new_speed = m_config.get_abs_value(overhang_speed_key_map[overhang_degree].c_str());
|
double new_speed = m_config.get_abs_value(overhang_speed_key_map[overhang_degree].c_str());
|
||||||
speed = new_speed == 0.0 ? speed : new_speed;
|
speed = new_speed == 0.0 ? speed : new_speed;
|
||||||
}
|
}
|
||||||
|
@ -3812,6 +3819,35 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
EXTRUDER_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm
|
EXTRUDER_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool variable_speed = false;
|
||||||
|
std::vector<ProcessedPoint> new_points {};
|
||||||
|
|
||||||
|
if (m_config.enable_overhang_speed && !m_config.overhang_speed_classic && !this->on_first_layer() &&
|
||||||
|
(is_bridge(path.role()) || is_perimeter(path.role()))) {
|
||||||
|
ConfigOptionPercents overhang_overlap_levels({75, 50, 25, 5});
|
||||||
|
ConfigOptionFloatsOrPercents dynamic_overhang_speeds(
|
||||||
|
{(m_config.get_abs_value("overhang_1_4_speed") < 0.5)
|
||||||
|
? FloatOrPercent{100, true}
|
||||||
|
: FloatOrPercent{m_config.get_abs_value("overhang_1_4_speed"), false},
|
||||||
|
(m_config.get_abs_value("overhang_2_4_speed") < 0.5)
|
||||||
|
? FloatOrPercent{100, true}
|
||||||
|
: FloatOrPercent{m_config.get_abs_value("overhang_2_4_speed"), false},
|
||||||
|
(m_config.get_abs_value("overhang_3_4_speed") < 0.5)
|
||||||
|
? FloatOrPercent{100, true}
|
||||||
|
: FloatOrPercent{m_config.get_abs_value("overhang_3_4_speed"), false},
|
||||||
|
(m_config.get_abs_value("overhang_4_4_speed") < 0.5)
|
||||||
|
? FloatOrPercent{100, true}
|
||||||
|
: FloatOrPercent{m_config.get_abs_value("overhang_4_4_speed"), false}});
|
||||||
|
|
||||||
|
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(
|
||||||
|
path, overhang_overlap_levels, dynamic_overhang_speeds, m_config.get_abs_value("outer_wall_speed"), speed);
|
||||||
|
|
||||||
|
variable_speed = std::any_of(new_points.begin(), new_points.end(),
|
||||||
|
[speed](const ProcessedPoint &p) { return p.speed != speed; });
|
||||||
|
}
|
||||||
|
|
||||||
double F = speed * 60; // convert mm/sec to mm/min
|
double F = speed * 60; // convert mm/sec to mm/min
|
||||||
|
|
||||||
// extrude arc or line
|
// extrude arc or line
|
||||||
|
@ -3862,46 +3898,72 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
gcode += buf;
|
gcode += buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto overhang_fan_threshold = EXTRUDER_CONFIG(overhang_fan_threshold);
|
||||||
|
auto enable_overhang_bridge_fan = EXTRUDER_CONFIG(enable_overhang_bridge_fan);
|
||||||
|
|
||||||
|
|
||||||
|
// { "0%", Overhang_threshold_none },
|
||||||
|
// { "5%", Overhang_threshold_1_4 },
|
||||||
|
// { "25%", Overhang_threshold_2_4 },
|
||||||
|
// { "50%", Overhang_threshold_3_4 },
|
||||||
|
// { "75%", Overhang_threshold_4_4 },
|
||||||
|
// { "95%", Overhang_threshold_bridge }
|
||||||
|
auto check_overhang_fan = [&overhang_fan_threshold](float overlap) {
|
||||||
|
switch (overhang_fan_threshold) {
|
||||||
|
case (int)Overhang_threshold_1_4:
|
||||||
|
return overlap <= 0.95f;
|
||||||
|
break;
|
||||||
|
case (int)Overhang_threshold_2_4:
|
||||||
|
return overlap <= 0.75f;
|
||||||
|
break;
|
||||||
|
case (int)Overhang_threshold_3_4:
|
||||||
|
return overlap <= 0.5f;
|
||||||
|
break;
|
||||||
|
case (int)Overhang_threshold_4_4:
|
||||||
|
return overlap <= 0.25f;
|
||||||
|
break;
|
||||||
|
case (int)Overhang_threshold_bridge:
|
||||||
|
return overlap <= 0.05f;
|
||||||
|
break;
|
||||||
|
case (int)Overhang_threshold_none:
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::string comment;
|
std::string comment;
|
||||||
if (m_enable_cooling_markers) {
|
if (m_enable_cooling_markers) {
|
||||||
if (EXTRUDER_CONFIG(enable_overhang_bridge_fan)) {
|
|
||||||
//BBS: Overhang_threshold_none means Overhang_threshold_1_4 and forcing cooling for all external perimeter
|
|
||||||
int overhang_threshold = EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none ?
|
|
||||||
Overhang_threshold_none : EXTRUDER_CONFIG(overhang_fan_threshold) - 1;
|
|
||||||
if ((EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none && path.role() == erExternalPerimeter)) {
|
|
||||||
gcode += ";_OVERHANG_FAN_START\n";
|
|
||||||
comment = ";_EXTRUDE_SET_SPEED";
|
comment = ";_EXTRUDE_SET_SPEED";
|
||||||
} else if (path.get_overhang_degree() > overhang_threshold ||
|
|
||||||
is_bridge(path.role()))
|
|
||||||
gcode += ";_OVERHANG_FAN_START\n";
|
|
||||||
else
|
|
||||||
comment = ";_EXTRUDE_SET_SPEED";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
comment = ";_EXTRUDE_SET_SPEED";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path.role() == erExternalPerimeter)
|
if (path.role() == erExternalPerimeter)
|
||||||
comment += ";_EXTERNAL_PERIMETER";
|
comment += ";_EXTERNAL_PERIMETER";
|
||||||
}
|
}
|
||||||
|
bool is_overhang_fan_on = false;
|
||||||
|
if (!variable_speed) {
|
||||||
// F is mm per minute.
|
// F is mm per minute.
|
||||||
gcode += m_writer.set_speed(F, "", comment);
|
gcode += m_writer.set_speed(F, "", comment);
|
||||||
double path_length = 0.;
|
double path_length = 0.;
|
||||||
{
|
{
|
||||||
std::string comment = GCodeWriter::full_gcode_comment ? description : "";
|
if (m_enable_cooling_markers && enable_overhang_bridge_fan && m_config.overhang_speed_classic) {
|
||||||
|
// BBS: Overhang_threshold_none means Overhang_threshold_1_4 and forcing cooling for all external
|
||||||
|
// perimeter
|
||||||
|
int overhang_threshold = overhang_fan_threshold == Overhang_threshold_none ? Overhang_threshold_none
|
||||||
|
: overhang_fan_threshold - 1;
|
||||||
|
if ((overhang_fan_threshold == Overhang_threshold_none && is_perimeter(path.role())) ||
|
||||||
|
(path.get_overhang_degree() > overhang_threshold || is_bridge(path.role()))) {
|
||||||
|
gcode += ";_OVERHANG_FAN_START\n";
|
||||||
|
is_overhang_fan_on = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
// BBS: use G1 if not enable arc fitting or has no arc fitting result or in spiral_mode mode
|
// BBS: use G1 if not enable arc fitting or has no arc fitting result or in spiral_mode mode
|
||||||
// Attention: G2 and G3 is not supported in spiral_mode mode
|
// Attention: G2 and G3 is not supported in spiral_mode mode
|
||||||
if (!m_config.enable_arc_fitting ||
|
if (!m_config.enable_arc_fitting || path.polyline.fitting_result.empty() || m_config.spiral_mode) {
|
||||||
path.polyline.fitting_result.empty() ||
|
|
||||||
m_config.spiral_mode) {
|
|
||||||
for (const Line& line : path.polyline.lines()) {
|
for (const Line& line : path.polyline.lines()) {
|
||||||
const double line_length = line.length() * SCALING_FACTOR;
|
const double line_length = line.length() * SCALING_FACTOR;
|
||||||
path_length += line_length;
|
path_length += line_length;
|
||||||
gcode += m_writer.extrude_to_xy(
|
gcode += m_writer.extrude_to_xy(
|
||||||
this->point_to_gcode(line.b),
|
this->point_to_gcode(line.b),
|
||||||
e_per_mm * line_length,
|
e_per_mm * line_length,
|
||||||
comment, path.is_force_no_extrusion());
|
GCodeWriter::full_gcode_comment ? description : "", path.is_force_no_extrusion());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// BBS: start to generate gcode from arc fitting data which includes line and arc
|
// BBS: start to generate gcode from arc fitting data which includes line and arc
|
||||||
|
@ -3918,7 +3980,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
gcode += m_writer.extrude_to_xy(
|
gcode += m_writer.extrude_to_xy(
|
||||||
this->point_to_gcode(line.b),
|
this->point_to_gcode(line.b),
|
||||||
e_per_mm * line_length,
|
e_per_mm * line_length,
|
||||||
comment, path.is_force_no_extrusion());
|
GCodeWriter::full_gcode_comment ? description : "", path.is_force_no_extrusion());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3933,7 +3995,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
center_offset,
|
center_offset,
|
||||||
e_per_mm * arc_length,
|
e_per_mm * arc_length,
|
||||||
arc.direction == ArcDirection::Arc_Dir_CCW,
|
arc.direction == ArcDirection::Arc_Dir_CCW,
|
||||||
comment, path.is_force_no_extrusion());
|
GCodeWriter::full_gcode_comment ? description : "", path.is_force_no_extrusion());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -3943,27 +4005,43 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (is_overhang_fan_on) {
|
||||||
|
is_overhang_fan_on = false;
|
||||||
|
gcode += ";_OVERHANG_FAN_END\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
double last_set_speed = std::max((float)EXTRUDER_CONFIG(slow_down_min_speed), new_points[0].speed) * 60.0;
|
||||||
|
|
||||||
|
gcode += m_writer.set_speed(last_set_speed, "", comment);
|
||||||
|
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||||
|
for (size_t i = 1; i < new_points.size(); i++) {
|
||||||
|
const ProcessedPoint &processed_point = new_points[i];
|
||||||
|
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||||
|
const double line_length = (p - prev).norm();
|
||||||
|
if (m_enable_cooling_markers && enable_overhang_bridge_fan) {
|
||||||
|
if (is_bridge(path.role()) || check_overhang_fan(new_points[i - 1].overlap)) {
|
||||||
|
gcode += ";_OVERHANG_FAN_START\n";
|
||||||
|
is_overhang_fan_on = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gcode +=
|
||||||
|
m_writer.extrude_to_xy(p, e_per_mm * line_length, GCodeWriter::full_gcode_comment ? description : "");
|
||||||
|
if (is_overhang_fan_on) {
|
||||||
|
is_overhang_fan_on = false;
|
||||||
|
gcode += ";_OVERHANG_FAN_END\n";
|
||||||
|
}
|
||||||
|
prev = p;
|
||||||
|
double new_speed = std::max((float)EXTRUDER_CONFIG(slow_down_min_speed), processed_point.speed) * 60.0;
|
||||||
|
if (last_set_speed != new_speed) {
|
||||||
|
gcode += m_writer.set_speed(new_speed, "", comment);
|
||||||
|
last_set_speed = new_speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (m_enable_cooling_markers) {
|
if (m_enable_cooling_markers) {
|
||||||
if (EXTRUDER_CONFIG(enable_overhang_bridge_fan)) {
|
|
||||||
//BBS: Overhang_threshold_none means Overhang_threshold_1_4 and forcing cooling for all external perimeter
|
|
||||||
int overhang_threshold = EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none ?
|
|
||||||
Overhang_threshold_none : EXTRUDER_CONFIG(overhang_fan_threshold) - 1;
|
|
||||||
if ((EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none && path.role() == erExternalPerimeter)) {
|
|
||||||
gcode += ";_EXTRUDE_END\n";
|
|
||||||
gcode += ";_OVERHANG_FAN_END\n";
|
|
||||||
|
|
||||||
} else if (path.get_overhang_degree() > overhang_threshold ||
|
|
||||||
is_bridge(path.role()))
|
|
||||||
gcode += ";_OVERHANG_FAN_END\n";
|
|
||||||
else
|
|
||||||
gcode += ";_EXTRUDE_END\n";
|
gcode += ";_EXTRUDE_END\n";
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
gcode += ";_EXTRUDE_END\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->set_last_pos(path.last_point());
|
this->set_last_pos(path.last_point());
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
@ -3986,22 +4064,22 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||||
|
|
||||||
// SoftFever
|
// SoftFever
|
||||||
if (this->on_first_layer()) {
|
if (this->on_first_layer()) {
|
||||||
if(m_config.default_acceleration.value > 0)
|
if (m_config.default_acceleration.value > 0) {
|
||||||
{
|
|
||||||
auto jerk = (unsigned int)floor(m_config.initial_layer_jerk.value + 0.5);
|
|
||||||
auto accel = (unsigned int)floor(m_config.initial_layer_acceleration.value + 0.5);
|
auto accel = (unsigned int)floor(m_config.initial_layer_acceleration.value + 0.5);
|
||||||
if(jerk > 0)
|
|
||||||
gcode += m_writer.set_jerk_xy(jerk);
|
|
||||||
|
|
||||||
if (accel > 0)
|
if (accel > 0)
|
||||||
gcode += m_writer.set_acceleration(accel);
|
gcode += m_writer.set_acceleration(accel);
|
||||||
}
|
}
|
||||||
|
if (m_config.default_jerk.value > 0) {
|
||||||
|
auto jerk = m_config.initial_layer_jerk.value;
|
||||||
|
if (jerk > 0)
|
||||||
|
gcode += m_writer.set_jerk_xy(jerk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(m_config.default_jerk.value > 0)
|
if(m_config.default_jerk.value > 0)
|
||||||
{
|
{
|
||||||
auto jerk = (unsigned int)floor(m_config.travel_jerk.value + 0.5);
|
auto jerk = m_config.travel_jerk.value;
|
||||||
auto accel = (unsigned int)floor(m_config.travel_acceleration.value + 0.5);
|
auto accel = (unsigned int)floor(m_config.travel_acceleration.value + 0.5);
|
||||||
if(jerk > 0)
|
if(jerk > 0)
|
||||||
gcode += m_writer.set_jerk_xy(jerk);
|
gcode += m_writer.set_jerk_xy(jerk);
|
||||||
|
@ -4337,6 +4415,13 @@ Point GCode::gcode_to_point(const Vec2d &point) const
|
||||||
scale_(point(1) - m_origin(1) + extruder_offset(1)));
|
scale_(point(1) - m_origin(1) + extruder_offset(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec2d GCode::point_to_gcode_quantized(const Point& point) const
|
||||||
|
{
|
||||||
|
Vec2d p = this->point_to_gcode(point);
|
||||||
|
return { GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
||||||
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
||||||
// Fills in by_region_per_copy_cache and returns its reference.
|
// Fills in by_region_per_copy_cache and returns its reference.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "EdgeGrid.hpp"
|
#include "EdgeGrid.hpp"
|
||||||
#include "GCode/ThumbnailData.hpp"
|
#include "GCode/ThumbnailData.hpp"
|
||||||
#include "libslic3r/ObjectID.hpp"
|
#include "libslic3r/ObjectID.hpp"
|
||||||
|
#include "GCode/ExtrusionProcessor.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -178,6 +179,7 @@ public:
|
||||||
const Point& last_pos() const { return m_last_pos; }
|
const Point& last_pos() const { return m_last_pos; }
|
||||||
Vec2d point_to_gcode(const Point &point) const;
|
Vec2d point_to_gcode(const Point &point) const;
|
||||||
Point gcode_to_point(const Vec2d &point) const;
|
Point gcode_to_point(const Vec2d &point) const;
|
||||||
|
Vec2d point_to_gcode_quantized(const Point& point) const;
|
||||||
const FullPrintConfig &config() const { return m_config; }
|
const FullPrintConfig &config() const { return m_config; }
|
||||||
const Layer* layer() const { return m_layer; }
|
const Layer* layer() const { return m_layer; }
|
||||||
GCodeWriter& writer() { return m_writer; }
|
GCodeWriter& writer() { return m_writer; }
|
||||||
|
@ -412,11 +414,15 @@ private:
|
||||||
// Cache for custom seam enforcers/blockers for each layer.
|
// Cache for custom seam enforcers/blockers for each layer.
|
||||||
SeamPlacer m_seam_placer;
|
SeamPlacer m_seam_placer;
|
||||||
|
|
||||||
|
ExtrusionQualityEstimator m_extrusion_quality_estimator;
|
||||||
|
|
||||||
|
|
||||||
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
||||||
This affects the input arguments supplied to the extrude*() and travel_to()
|
This affects the input arguments supplied to the extrude*() and travel_to()
|
||||||
methods. */
|
methods. */
|
||||||
Vec2d m_origin;
|
Vec2d m_origin;
|
||||||
FullPrintConfig m_config;
|
FullPrintConfig m_config;
|
||||||
|
DynamicConfig m_calib_config;
|
||||||
// scaled G-code resolution
|
// scaled G-code resolution
|
||||||
double m_scaled_resolution;
|
double m_scaled_resolution;
|
||||||
GCodeWriter m_writer;
|
GCodeWriter m_writer;
|
||||||
|
|
329
src/libslic3r/GCode/ExtrusionProcessor.hpp
Normal file
329
src/libslic3r/GCode/ExtrusionProcessor.hpp
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
#ifndef slic3r_ExtrusionProcessor_hpp_
|
||||||
|
#define slic3r_ExtrusionProcessor_hpp_
|
||||||
|
|
||||||
|
#include "../AABBTreeLines.hpp"
|
||||||
|
//#include "../SupportSpotsGenerator.hpp"
|
||||||
|
#include "../libslic3r.h"
|
||||||
|
#include "../ExtrusionEntity.hpp"
|
||||||
|
#include "../Layer.hpp"
|
||||||
|
#include "../Point.hpp"
|
||||||
|
#include "../SVG.hpp"
|
||||||
|
#include "../BoundingBox.hpp"
|
||||||
|
#include "../Polygon.hpp"
|
||||||
|
#include "../ClipperUtils.hpp"
|
||||||
|
#include "../Flow.hpp"
|
||||||
|
#include "../Config.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <limits>
|
||||||
|
#include <numeric>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class SlidingWindowCurvatureAccumulator
|
||||||
|
{
|
||||||
|
float window_size;
|
||||||
|
float total_distance = 0; // accumulated distance
|
||||||
|
float total_curvature = 0; // accumulated signed ccw angles
|
||||||
|
deque<float> distances;
|
||||||
|
deque<float> angles;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SlidingWindowCurvatureAccumulator(float window_size) : window_size(window_size) {}
|
||||||
|
|
||||||
|
void add_point(float distance, float angle)
|
||||||
|
{
|
||||||
|
total_distance += distance;
|
||||||
|
total_curvature += angle;
|
||||||
|
distances.push_back(distance);
|
||||||
|
angles.push_back(angle);
|
||||||
|
|
||||||
|
while (distances.size() > 1 && total_distance > window_size) {
|
||||||
|
total_distance -= distances.front();
|
||||||
|
total_curvature -= angles.front();
|
||||||
|
distances.pop_front();
|
||||||
|
angles.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_curvature() const
|
||||||
|
{
|
||||||
|
return total_curvature / window_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
total_curvature = 0;
|
||||||
|
total_distance = 0;
|
||||||
|
distances.clear();
|
||||||
|
angles.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CurvatureEstimator
|
||||||
|
{
|
||||||
|
static const size_t sliders_count = 3;
|
||||||
|
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.0},{4.0}, {10.0}};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add_point(float distance, float angle)
|
||||||
|
{
|
||||||
|
if (distance < EPSILON)
|
||||||
|
return;
|
||||||
|
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||||
|
slider.add_point(distance, angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float get_curvature()
|
||||||
|
{
|
||||||
|
float max_curvature = 0.0f;
|
||||||
|
for (const SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||||
|
if (abs(slider.get_curvature()) > abs(max_curvature)) {
|
||||||
|
max_curvature = slider.get_curvature();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_curvature;
|
||||||
|
}
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||||
|
slider.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExtendedPoint
|
||||||
|
{
|
||||||
|
ExtendedPoint(Vec2d position, float distance = 0.0, size_t nearest_prev_layer_line = size_t(-1), float curvature = 0.0)
|
||||||
|
: position(position), distance(distance), nearest_prev_layer_line(nearest_prev_layer_line), curvature(curvature)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Vec2d position;
|
||||||
|
float distance;
|
||||||
|
size_t nearest_prev_layer_line;
|
||||||
|
float curvature;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename P, typename L>
|
||||||
|
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &input_points,
|
||||||
|
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
|
||||||
|
float flow_width,
|
||||||
|
float max_line_length = -1.0f)
|
||||||
|
{
|
||||||
|
using AABBScalar = typename AABBTreeLines::LinesDistancer<L>::Scalar;
|
||||||
|
if (input_points.empty())
|
||||||
|
return {};
|
||||||
|
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
|
||||||
|
CurvatureEstimator cestim;
|
||||||
|
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
|
||||||
|
|
||||||
|
std::vector<ExtendedPoint> points;
|
||||||
|
points.reserve(input_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
|
||||||
|
|
||||||
|
{
|
||||||
|
ExtendedPoint start_point{maybe_unscale(input_points.front())};
|
||||||
|
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
|
||||||
|
start_point.distance = distance + boundary_offset;
|
||||||
|
start_point.nearest_prev_layer_line = nearest_line;
|
||||||
|
points.push_back(start_point);
|
||||||
|
}
|
||||||
|
for (size_t i = 1; i < input_points.size(); i++) {
|
||||||
|
ExtendedPoint next_point{maybe_unscale(input_points[i])};
|
||||||
|
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
|
||||||
|
next_point.distance = distance + boundary_offset;
|
||||||
|
next_point.nearest_prev_layer_line = nearest_line;
|
||||||
|
|
||||||
|
if (ADD_INTERSECTIONS &&
|
||||||
|
((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) {
|
||||||
|
const ExtendedPoint &prev_point = points.back();
|
||||||
|
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position.cast<AABBScalar>(), next_point.position.cast<AABBScalar>()});
|
||||||
|
for (const auto &intersection : intersections) {
|
||||||
|
points.emplace_back(intersection.first.template cast<double>(), boundary_offset, intersection.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points.push_back(next_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) {
|
||||||
|
std::vector<ExtendedPoint> new_points;
|
||||||
|
new_points.reserve(points.size()*2);
|
||||||
|
new_points.push_back(points.front());
|
||||||
|
for (int point_idx = 0; point_idx < int(points.size()) - 1; ++point_idx) {
|
||||||
|
const ExtendedPoint &curr = points[point_idx];
|
||||||
|
const ExtendedPoint &next = points[point_idx + 1];
|
||||||
|
|
||||||
|
if ((curr.distance > 0 && curr.distance < boundary_offset + 2.0f) ||
|
||||||
|
(next.distance > 0 && next.distance < boundary_offset + 2.0f)) {
|
||||||
|
double line_len = (next.position - curr.position).norm();
|
||||||
|
if (line_len > 4.0f) {
|
||||||
|
double a0 = std::clamp((curr.distance + 2 * boundary_offset) / line_len, 0.0, 1.0);
|
||||||
|
double a1 = std::clamp(1.0f - (next.distance + 2 * boundary_offset) / line_len, 0.0, 1.0);
|
||||||
|
double t0 = std::min(a0, a1);
|
||||||
|
double t1 = std::max(a0, a1);
|
||||||
|
|
||||||
|
if (t0 < 1.0) {
|
||||||
|
auto p0 = curr.position + t0 * (next.position - curr.position);
|
||||||
|
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p0.cast<AABBScalar>());
|
||||||
|
new_points.push_back(ExtendedPoint{p0, float(p0_dist + boundary_offset), p0_near_l});
|
||||||
|
}
|
||||||
|
if (t1 > 0.0) {
|
||||||
|
auto p1 = curr.position + t1 * (next.position - curr.position);
|
||||||
|
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p1.cast<AABBScalar>());
|
||||||
|
new_points.push_back(ExtendedPoint{p1, float(p1_dist + boundary_offset), p1_near_l});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_points.push_back(next);
|
||||||
|
}
|
||||||
|
points = new_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_line_length > 0) {
|
||||||
|
std::vector<ExtendedPoint> new_points;
|
||||||
|
new_points.reserve(points.size()*2);
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i + 1 < points.size(); i++) {
|
||||||
|
const ExtendedPoint &curr = points[i];
|
||||||
|
const ExtendedPoint &next = points[i + 1];
|
||||||
|
new_points.push_back(curr);
|
||||||
|
double len = (next.position - curr.position).squaredNorm();
|
||||||
|
double t = sqrt((max_line_length * max_line_length) / len);
|
||||||
|
size_t new_point_count = 1.0 / t;
|
||||||
|
for (size_t j = 1; j < new_point_count + 1; j++) {
|
||||||
|
Vec2d pos = curr.position * (1.0 - j * t) + next.position * (j * t);
|
||||||
|
auto [p_dist, p_near_l,
|
||||||
|
p_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(pos.cast<AABBScalar>());
|
||||||
|
new_points.push_back(ExtendedPoint{pos, float(p_dist + boundary_offset), p_near_l});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_points.push_back(points.back());
|
||||||
|
}
|
||||||
|
points = new_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) {
|
||||||
|
ExtendedPoint &a = points[point_idx];
|
||||||
|
ExtendedPoint &prev = points[point_idx > 0 ? point_idx - 1 : point_idx];
|
||||||
|
|
||||||
|
int prev_point_idx = point_idx;
|
||||||
|
while (prev_point_idx > 0) {
|
||||||
|
prev_point_idx--;
|
||||||
|
if ((a.position - points[prev_point_idx].position).squaredNorm() > EPSILON) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int next_point_index = point_idx;
|
||||||
|
while (next_point_index < int(points.size()) - 1) {
|
||||||
|
next_point_index++;
|
||||||
|
if ((a.position - points[next_point_index].position).squaredNorm() > EPSILON) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev_point_idx != point_idx && next_point_index != point_idx) {
|
||||||
|
float distance = (prev.position - a.position).norm();
|
||||||
|
float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position);
|
||||||
|
cestim.add_point(distance, alfa);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.curvature = cestim.get_curvature();
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProcessedPoint
|
||||||
|
{
|
||||||
|
Point p;
|
||||||
|
float speed = 1.0f;
|
||||||
|
float overlap = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExtrusionQualityEstimator
|
||||||
|
{
|
||||||
|
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> prev_layer_boundaries;
|
||||||
|
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> next_layer_boundaries;
|
||||||
|
const PrintObject *current_object;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_current_object(const PrintObject *object) { current_object = object; }
|
||||||
|
|
||||||
|
void prepare_for_new_layer(const Layer *layer)
|
||||||
|
{
|
||||||
|
if (layer == nullptr) return;
|
||||||
|
const PrintObject *object = layer->object();
|
||||||
|
prev_layer_boundaries[object] = next_layer_boundaries[object];
|
||||||
|
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path,
|
||||||
|
const ConfigOptionPercents &overlaps,
|
||||||
|
const ConfigOptionFloatsOrPercents &speeds,
|
||||||
|
float ext_perimeter_speed,
|
||||||
|
float original_speed)
|
||||||
|
{
|
||||||
|
size_t speed_sections_count = std::min(overlaps.values.size(), speeds.values.size());
|
||||||
|
std::vector<std::pair<float, float>> speed_sections;
|
||||||
|
for (size_t i = 0; i < speed_sections_count; i++) {
|
||||||
|
float distance = path.width * (1.0 - (overlaps.get_at(i) / 100.0));
|
||||||
|
float speed = speeds.get_at(i).percent ? (ext_perimeter_speed * speeds.get_at(i).value / 100.0) : speeds.get_at(i).value;
|
||||||
|
speed_sections.push_back({distance, speed});
|
||||||
|
}
|
||||||
|
std::sort(speed_sections.begin(), speed_sections.end(),
|
||||||
|
[](const std::pair<float, float> &a, const std::pair<float, float> &b) {
|
||||||
|
if (a.first == b.first) {
|
||||||
|
return a.second > b.second;
|
||||||
|
}
|
||||||
|
return a.first < b.first; });
|
||||||
|
|
||||||
|
std::pair<float, float> last_section{INFINITY, 0};
|
||||||
|
for (auto §ion : speed_sections) {
|
||||||
|
if (section.first == last_section.first) {
|
||||||
|
section.second = last_section.second;
|
||||||
|
} else {
|
||||||
|
last_section = section;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ExtendedPoint> extended_points =
|
||||||
|
estimate_points_properties<true, true, true, true>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
||||||
|
const auto width_inv = 1.0f / path.width;
|
||||||
|
std::vector<ProcessedPoint> processed_points;
|
||||||
|
processed_points.reserve(extended_points.size());
|
||||||
|
for (size_t i = 0; i < extended_points.size(); i++) {
|
||||||
|
const ExtendedPoint &curr = extended_points[i];
|
||||||
|
const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
|
||||||
|
|
||||||
|
auto calculate_speed = [&speed_sections, &original_speed](float distance) {
|
||||||
|
float final_speed;
|
||||||
|
if (distance <= speed_sections.front().first) {
|
||||||
|
final_speed = original_speed;
|
||||||
|
} else if (distance >= speed_sections.back().first) {
|
||||||
|
final_speed = speed_sections.back().second;
|
||||||
|
} else {
|
||||||
|
size_t section_idx = 0;
|
||||||
|
while (distance > speed_sections[section_idx + 1].first) {
|
||||||
|
section_idx++;
|
||||||
|
}
|
||||||
|
float t = (distance - speed_sections[section_idx].first) /
|
||||||
|
(speed_sections[section_idx + 1].first - speed_sections[section_idx].first);
|
||||||
|
t = std::clamp(t, 0.0f, 1.0f);
|
||||||
|
final_speed = (1.0f - t) * speed_sections[section_idx].second + t * speed_sections[section_idx + 1].second;
|
||||||
|
}
|
||||||
|
return final_speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance));
|
||||||
|
float overlap = std::min(1 - curr.distance * width_inv, 1 - next.distance * width_inv);
|
||||||
|
|
||||||
|
processed_points.push_back({ scaled(curr.position), extrusion_speed, overlap });
|
||||||
|
}
|
||||||
|
return processed_points;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_ExtrusionProcessor_hpp_
|
|
@ -28,6 +28,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||||
print_config.gcode_flavor.value == gcfRepRapFirmware;
|
print_config.gcode_flavor.value == gcfRepRapFirmware;
|
||||||
m_max_acceleration = std::lrint(use_mach_limits ? print_config.machine_max_acceleration_extruding.values.front() : 0);
|
m_max_acceleration = std::lrint(use_mach_limits ? print_config.machine_max_acceleration_extruding.values.front() : 0);
|
||||||
m_max_jerk = std::lrint(use_mach_limits ? std::min(print_config.machine_max_jerk_x.values.front(), print_config.machine_max_jerk_y.values.front()) : 0);
|
m_max_jerk = std::lrint(use_mach_limits ? std::min(print_config.machine_max_jerk_x.values.front(), print_config.machine_max_jerk_y.values.front()) : 0);
|
||||||
|
m_max_jerk_z = print_config.machine_max_jerk_z.values.front();
|
||||||
|
m_max_jerk_e = print_config.machine_max_jerk_e.values.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||||
|
@ -190,13 +192,13 @@ std::string GCodeWriter::set_acceleration(unsigned int acceleration)
|
||||||
return gcode.str();
|
return gcode.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCodeWriter::set_jerk_xy(unsigned int jerk)
|
std::string GCodeWriter::set_jerk_xy(double jerk)
|
||||||
{
|
{
|
||||||
// Clamp the jerk to the allowed maximum.
|
// Clamp the jerk to the allowed maximum.
|
||||||
if (m_max_jerk > 0 && jerk > m_max_jerk)
|
if (m_max_jerk > 0 && jerk > m_max_jerk)
|
||||||
jerk = m_max_jerk;
|
jerk = m_max_jerk;
|
||||||
|
|
||||||
if (jerk < 1 || jerk == m_last_jerk)
|
if (jerk < 0.01 || is_approx(jerk, m_last_jerk))
|
||||||
return std::string();
|
return std::string();
|
||||||
|
|
||||||
m_last_jerk = jerk;
|
m_last_jerk = jerk;
|
||||||
|
@ -207,6 +209,9 @@ std::string GCodeWriter::set_jerk_xy(unsigned int jerk)
|
||||||
else
|
else
|
||||||
gcode << "M205 X" << jerk << " Y" << jerk;
|
gcode << "M205 X" << jerk << " Y" << jerk;
|
||||||
|
|
||||||
|
if (m_is_bbl_printers)
|
||||||
|
gcode << std::setprecision(2) << " Z" << m_max_jerk_z << " E" << m_max_jerk_e;
|
||||||
|
|
||||||
if (GCodeWriter::full_gcode_comment) gcode << " ; adjust jerk";
|
if (GCodeWriter::full_gcode_comment) gcode << " ; adjust jerk";
|
||||||
gcode << "\n";
|
gcode << "\n";
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
|
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
|
||||||
std::string set_bed_temperature(int temperature, bool wait = false);
|
std::string set_bed_temperature(int temperature, bool wait = false);
|
||||||
std::string set_acceleration(unsigned int acceleration);
|
std::string set_acceleration(unsigned int acceleration);
|
||||||
std::string set_jerk_xy(unsigned int jerk);
|
std::string set_jerk_xy(double jerk);
|
||||||
std::string set_pressure_advance(double pa) const;
|
std::string set_pressure_advance(double pa) const;
|
||||||
std::string reset_e(bool force = false);
|
std::string reset_e(bool force = false);
|
||||||
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
|
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
|
||||||
|
@ -107,8 +107,10 @@ private:
|
||||||
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
|
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
|
||||||
// If set to zero, the limit is not in action.
|
// If set to zero, the limit is not in action.
|
||||||
unsigned int m_max_acceleration;
|
unsigned int m_max_acceleration;
|
||||||
unsigned int m_max_jerk;
|
double m_max_jerk;
|
||||||
unsigned int m_last_jerk;
|
double m_last_jerk;
|
||||||
|
double m_max_jerk_z;
|
||||||
|
double m_max_jerk_e;
|
||||||
|
|
||||||
unsigned int m_travel_acceleration;
|
unsigned int m_travel_acceleration;
|
||||||
unsigned int m_travel_jerk;
|
unsigned int m_travel_jerk;
|
||||||
|
@ -170,6 +172,13 @@ public:
|
||||||
// static constexpr const int XYZF_EXPORT_DIGITS = 6;
|
// static constexpr const int XYZF_EXPORT_DIGITS = 6;
|
||||||
// static constexpr const int E_EXPORT_DIGITS = 9;
|
// static constexpr const int E_EXPORT_DIGITS = 9;
|
||||||
#endif
|
#endif
|
||||||
|
static constexpr const std::array<double, 10> pow_10 { 1., 10., 100., 1000., 10000., 100000., 1000000., 10000000., 100000000., 1000000000. };
|
||||||
|
static constexpr const std::array<double, 10> pow_10_inv { 1. / 1., 1. / 10., 1. / 100., 1. / 1000., 1. / 10000., 1. / 100000., 1. / 1000000., 1. / 10000000., 1. / 100000000., 1. / 1000000000. };
|
||||||
|
|
||||||
|
// Quantize doubles to a resolution of the G-code.
|
||||||
|
static double quantize(double v, size_t ndigits) { return std::round(v * pow_10[ndigits]) * pow_10_inv[ndigits]; }
|
||||||
|
static double quantize_xyzf(double v) { return quantize(v, XYZF_EXPORT_DIGITS); }
|
||||||
|
static double quantize_e(double v) { return quantize(v, E_EXPORT_DIGITS); }
|
||||||
|
|
||||||
void emit_axis(const char axis, const double v, size_t digits);
|
void emit_axis(const char axis, const double v, size_t digits);
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef slic3r_Line_hpp_
|
#ifndef slic3r_Line_hpp_
|
||||||
#define slic3r_Line_hpp_
|
#define slic3r_Line_hpp_
|
||||||
|
|
||||||
#include "libslic3r.h"
|
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
|
#include "libslic3r.h"
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ Linef3 transform(const Linef3& line, const Transform3d& t);
|
||||||
|
|
||||||
namespace line_alg {
|
namespace line_alg {
|
||||||
|
|
||||||
template<class L, class En = void> struct Traits {
|
template <class L, class En = void>
|
||||||
|
struct Traits {
|
||||||
static constexpr int Dim = L::Dim;
|
static constexpr int Dim = L::Dim;
|
||||||
using Scalar = typename L::Scalar;
|
using Scalar = typename L::Scalar;
|
||||||
|
|
||||||
|
@ -32,11 +33,15 @@ template<class L, class En = void> struct Traits {
|
||||||
static const Vec<Dim, Scalar>& get_b(const L& l) { return l.b; }
|
static const Vec<Dim, Scalar>& get_b(const L& l) { return l.b; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class L> const constexpr int Dim = Traits<remove_cvref_t<L>>::Dim;
|
template <class L>
|
||||||
template<class L> using Scalar = typename Traits<remove_cvref_t<L>>::Scalar;
|
const constexpr int Dim = Traits<remove_cvref_t<L>>::Dim;
|
||||||
|
template <class L>
|
||||||
|
using Scalar = typename Traits<remove_cvref_t<L>>::Scalar;
|
||||||
|
|
||||||
template<class L> auto get_a(L &&l) { return Traits<remove_cvref_t<L>>::get_a(l); }
|
template <class L>
|
||||||
template<class L> auto get_b(L &&l) { return Traits<remove_cvref_t<L>>::get_b(l); }
|
auto get_a(L&& l) { return Traits<remove_cvref_t<L>>::get_a(l); }
|
||||||
|
template <class L>
|
||||||
|
auto get_b(L&& l) { return Traits<remove_cvref_t<L>>::get_b(l); }
|
||||||
|
|
||||||
// Distance to the closest point of line.
|
// Distance to the closest point of line.
|
||||||
template <class L>
|
template <class L>
|
||||||
|
@ -54,11 +59,11 @@ double distance_to_squared(const L &line, const Vec<Dim<L>, Scalar<L>> &point, V
|
||||||
// We find projection of this point onto the line.
|
// We find projection of this point onto the line.
|
||||||
// It falls where t = [(this-a) . (b-a)] / |b-a|^2
|
// It falls where t = [(this-a) . (b-a)] / |b-a|^2
|
||||||
const double t = va.dot(v) / l2;
|
const double t = va.dot(v) / l2;
|
||||||
if (t < 0.0) {
|
if (t <= 0.0) {
|
||||||
// beyond the 'a' end of the segment
|
// beyond the 'a' end of the segment
|
||||||
*nearest_point = get_a(line);
|
*nearest_point = get_a(line);
|
||||||
return va.squaredNorm();
|
return va.squaredNorm();
|
||||||
} else if (t > 1.0) {
|
} else if (t >= 1.0) {
|
||||||
// beyond the 'b' end of the segment
|
// beyond the 'b' end of the segment
|
||||||
*nearest_point = get_b(line);
|
*nearest_point = get_b(line);
|
||||||
return (point - get_b(line)).template cast<double>().squaredNorm();
|
return (point - get_b(line)).template cast<double>().squaredNorm();
|
||||||
|
@ -120,18 +125,66 @@ double distance_to_infinite(const L &line, const Vec<Dim<L>, Scalar<L>> &point)
|
||||||
return std::sqrt(distance_to_infinite_squared(line, point));
|
return std::sqrt(distance_to_infinite_squared(line, point));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class L>
|
||||||
|
bool intersection(const L& l1, const L& l2, Vec<Dim<L>, Scalar<L>>* intersection_pt)
|
||||||
|
{
|
||||||
|
using Floating = typename std::conditional<std::is_floating_point<Scalar<L>>::value, Scalar<L>, double>::type;
|
||||||
|
using VecType = const Vec<Dim<L>, Floating>;
|
||||||
|
const VecType v1 = (l1.b - l1.a).template cast<Floating>();
|
||||||
|
const VecType v2 = (l2.b - l2.a).template cast<Floating>();
|
||||||
|
Floating denom = cross2(v1, v2);
|
||||||
|
if (fabs(denom) < EPSILON)
|
||||||
|
#if 0
|
||||||
|
// Lines are collinear. Return true if they are coincident (overlappign).
|
||||||
|
return ! (fabs(nume_a) < EPSILON && fabs(nume_b) < EPSILON);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
const VecType v12 = (l1.a - l2.a).template cast<Floating>();
|
||||||
|
Floating nume_a = cross2(v2, v12);
|
||||||
|
Floating nume_b = cross2(v1, v12);
|
||||||
|
Floating t1 = nume_a / denom;
|
||||||
|
Floating t2 = nume_b / denom;
|
||||||
|
if (t1 >= 0 && t1 <= 1.0f && t2 >= 0 && t2 <= 1.0f) {
|
||||||
|
// Get the intersection point.
|
||||||
|
(*intersection_pt) = (l1.a.template cast<Floating>() + t1 * v1).template cast<Scalar<L>>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false; // not intersecting
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace line_alg
|
} // namespace line_alg
|
||||||
|
|
||||||
class Line
|
class Line {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Line() { }
|
Line() { }
|
||||||
Line(const Point& _a, const Point& _b) : a(_a), b(_b) {}
|
Line(const Point& _a, const Point& _b)
|
||||||
explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; }
|
: a(_a)
|
||||||
void scale(double factor) { this->a *= factor; this->b *= factor; }
|
, b(_b)
|
||||||
void translate(const Point &v) { this->a += v; this->b += v; }
|
{
|
||||||
|
}
|
||||||
|
explicit operator Lines() const
|
||||||
|
{
|
||||||
|
Lines lines;
|
||||||
|
lines.emplace_back(*this);
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
void scale(double factor)
|
||||||
|
{
|
||||||
|
this->a *= factor;
|
||||||
|
this->b *= factor;
|
||||||
|
}
|
||||||
|
void translate(const Point& v)
|
||||||
|
{
|
||||||
|
this->a += v;
|
||||||
|
this->b += v;
|
||||||
|
}
|
||||||
void translate(double x, double y) { this->translate(Point(x, y)); }
|
void translate(double x, double y) { this->translate(Point(x, y)); }
|
||||||
void rotate(double angle, const Point ¢er) { this->a.rotate(angle, center); this->b.rotate(angle, center); }
|
void rotate(double angle, const Point& center)
|
||||||
|
{
|
||||||
|
this->a.rotate(angle, center);
|
||||||
|
this->b.rotate(angle, center);
|
||||||
|
}
|
||||||
void reverse() { std::swap(this->a, this->b); }
|
void reverse() { std::swap(this->a, this->b); }
|
||||||
double length() const { return (b - a).cast<double>().norm(); }
|
double length() const { return (b - a).cast<double>().norm(); }
|
||||||
Point midpoint() const { return (this->a + this->b) / 2; }
|
Point midpoint() const { return (this->a + this->b) / 2; }
|
||||||
|
@ -152,7 +205,6 @@ public:
|
||||||
Vector vector() const { return this->b - this->a; }
|
Vector vector() const { return this->b - this->a; }
|
||||||
Vector normal() const { return Vector((this->b(1) - this->a(1)), -(this->b(0) - this->a(0))); }
|
Vector normal() const { return Vector((this->b(1) - this->a(1)), -(this->b(0) - this->a(0))); }
|
||||||
bool intersection(const Line& line, Point* intersection) const;
|
bool intersection(const Line& line, Point* intersection) const;
|
||||||
double ccw(const Point& point) const { return point.ccw(*this); }
|
|
||||||
// Clip a line with a bounding box. Returns false if the line is completely outside of the bounding box.
|
// Clip a line with a bounding box. Returns false if the line is completely outside of the bounding box.
|
||||||
bool clip_with_bbox(const BoundingBox& bbox);
|
bool clip_with_bbox(const BoundingBox& bbox);
|
||||||
// Extend the line from both sides by an offset.
|
// Extend the line from both sides by an offset.
|
||||||
|
@ -173,21 +225,41 @@ public:
|
||||||
using Scalar = Point::Scalar;
|
using Scalar = Point::Scalar;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThickLine : public Line
|
class ThickLine : public Line {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
ThickLine() : a_width(0), b_width(0) {}
|
ThickLine()
|
||||||
ThickLine(const Point& a, const Point& b) : Line(a, b), a_width(0), b_width(0) {}
|
: a_width(0)
|
||||||
ThickLine(const Point& a, const Point& b, double wa, double wb) : Line(a, b), a_width(wa), b_width(wb) {}
|
, b_width(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
ThickLine(const Point& a, const Point& b)
|
||||||
|
: Line(a, b)
|
||||||
|
, a_width(0)
|
||||||
|
, b_width(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
ThickLine(const Point& a, const Point& b, double wa, double wb)
|
||||||
|
: Line(a, b)
|
||||||
|
, a_width(wa)
|
||||||
|
, b_width(wb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
double a_width, b_width;
|
double a_width, b_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Line3
|
class Line3 {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Line3() : a(Vec3crd::Zero()), b(Vec3crd::Zero()) {}
|
Line3()
|
||||||
Line3(const Vec3crd& _a, const Vec3crd& _b) : a(_a), b(_b) {}
|
: a(Vec3crd::Zero())
|
||||||
|
, b(Vec3crd::Zero())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Line3(const Vec3crd& _a, const Vec3crd& _b)
|
||||||
|
: a(_a)
|
||||||
|
, b(_b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
double length() const { return (this->a - this->b).cast<double>().norm(); }
|
double length() const { return (this->a - this->b).cast<double>().norm(); }
|
||||||
Vec3crd vector() const { return this->b - this->a; }
|
Vec3crd vector() const { return this->b - this->a; }
|
||||||
|
@ -199,11 +271,18 @@ public:
|
||||||
using Scalar = Vec3crd::Scalar;
|
using Scalar = Vec3crd::Scalar;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Linef
|
class Linef {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Linef() : a(Vec2d::Zero()), b(Vec2d::Zero()) {}
|
Linef()
|
||||||
Linef(const Vec2d& _a, const Vec2d& _b) : a(_a), b(_b) {}
|
: a(Vec2d::Zero())
|
||||||
|
, b(Vec2d::Zero())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Linef(const Vec2d& _a, const Vec2d& _b)
|
||||||
|
: a(_a)
|
||||||
|
, b(_b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Vec2d a;
|
Vec2d a;
|
||||||
Vec2d b;
|
Vec2d b;
|
||||||
|
@ -211,15 +290,27 @@ public:
|
||||||
static const constexpr int Dim = 2;
|
static const constexpr int Dim = 2;
|
||||||
using Scalar = Vec2d::Scalar;
|
using Scalar = Vec2d::Scalar;
|
||||||
};
|
};
|
||||||
|
using Linesf = std::vector<Linef>;
|
||||||
|
|
||||||
class Linef3
|
class Linef3 {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Linef3() : a(Vec3d::Zero()), b(Vec3d::Zero()) {}
|
Linef3()
|
||||||
Linef3(const Vec3d& _a, const Vec3d& _b) : a(_a), b(_b) {}
|
: a(Vec3d::Zero())
|
||||||
|
, b(Vec3d::Zero())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Linef3(const Vec3d& _a, const Vec3d& _b)
|
||||||
|
: a(_a)
|
||||||
|
, b(_b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Vec3d intersect_plane(double z) const;
|
Vec3d intersect_plane(double z) const;
|
||||||
void scale(double factor) { this->a *= factor; this->b *= factor; }
|
void scale(double factor)
|
||||||
|
{
|
||||||
|
this->a *= factor;
|
||||||
|
this->b *= factor;
|
||||||
|
}
|
||||||
Vec3d vector() const { return this->b - this->a; }
|
Vec3d vector() const { return this->b - this->a; }
|
||||||
Vec3d unit_vector() const { return (length() == 0.0) ? Vec3d::Zero() : vector().normalized(); }
|
Vec3d unit_vector() const { return (length() == 0.0) ? Vec3d::Zero() : vector().normalized(); }
|
||||||
double length() const { return vector().norm(); }
|
double length() const { return vector().norm(); }
|
||||||
|
@ -237,20 +328,25 @@ BoundingBox get_extents(const Lines &lines);
|
||||||
|
|
||||||
// start Boost
|
// start Boost
|
||||||
#include <boost/polygon/polygon.hpp>
|
#include <boost/polygon/polygon.hpp>
|
||||||
namespace boost { namespace polygon {
|
namespace boost {
|
||||||
|
namespace polygon {
|
||||||
template <>
|
template <>
|
||||||
struct geometry_concept<Slic3r::Line> { typedef segment_concept type; };
|
struct geometry_concept<Slic3r::Line> {
|
||||||
|
typedef segment_concept type;
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct segment_traits<Slic3r::Line> {
|
struct segment_traits<Slic3r::Line> {
|
||||||
typedef coord_t coordinate_type;
|
typedef coord_t coordinate_type;
|
||||||
typedef Slic3r::Point point_type;
|
typedef Slic3r::Point point_type;
|
||||||
|
|
||||||
static inline point_type get(const Slic3r::Line& line, direction_1d dir) {
|
static inline point_type get(const Slic3r::Line& line, direction_1d dir)
|
||||||
|
{
|
||||||
return dir.to_int() ? line.b : line.a;
|
return dir.to_int() ? line.b : line.a;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
// end Boost
|
// end Boost
|
||||||
|
|
||||||
#endif // slic3r_Line_hpp_
|
#endif // slic3r_Line_hpp_
|
||||||
|
|
|
@ -271,7 +271,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||||
Polylines remain_polines;
|
Polylines remain_polines;
|
||||||
|
|
||||||
//BBS: don't calculate overhang degree when enable fuzzy skin. It's unmeaning
|
//BBS: don't calculate overhang degree when enable fuzzy skin. It's unmeaning
|
||||||
if (perimeter_generator.config->enable_overhang_speed && perimeter_generator.config->fuzzy_skin == FuzzySkinType::None) {
|
if (perimeter_generator.config->overhang_speed_classic && perimeter_generator.config->enable_overhang_speed && perimeter_generator.config->fuzzy_skin == FuzzySkinType::None) {
|
||||||
for (auto it = lower_polygons_series->begin();
|
for (auto it = lower_polygons_series->begin();
|
||||||
it != lower_polygons_series->end(); it++)
|
it != lower_polygons_series->end(); it++)
|
||||||
{
|
{
|
||||||
|
@ -635,6 +635,7 @@ void PerimeterGenerator::process_classic()
|
||||||
// external perimeters
|
// external perimeters
|
||||||
m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm();
|
m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm();
|
||||||
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width();
|
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width();
|
||||||
|
|
||||||
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
|
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
|
||||||
coord_t ext_perimeter_spacing2;
|
coord_t ext_perimeter_spacing2;
|
||||||
if(config->precise_outer_wall)
|
if(config->precise_outer_wall)
|
||||||
|
@ -1114,7 +1115,6 @@ void PerimeterGenerator::process_arachne()
|
||||||
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width();
|
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width();
|
||||||
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
|
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
|
||||||
coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
|
coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
|
||||||
|
|
||||||
// overhang perimeters
|
// overhang perimeters
|
||||||
m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
|
m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
|
||||||
|
|
||||||
|
@ -1133,9 +1133,14 @@ void PerimeterGenerator::process_arachne()
|
||||||
// we need to process each island separately because we might have different
|
// we need to process each island separately because we might have different
|
||||||
// extra perimeters for each one
|
// extra perimeters for each one
|
||||||
for (const Surface& surface : this->slices->surfaces) {
|
for (const Surface& surface : this->slices->surfaces) {
|
||||||
|
coord_t bead_width_0 = ext_perimeter_spacing;
|
||||||
|
if (config->precise_outer_wall)
|
||||||
|
bead_width_0 = ext_perimeter_width + this->perimeter_flow.scaled_width() - perimeter_spacing;
|
||||||
// detect how many perimeters must be generated for this island
|
// detect how many perimeters must be generated for this island
|
||||||
int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops
|
int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops
|
||||||
ExPolygons last = offset_ex(surface.expolygon.simplify_p(m_scaled_resolution), -float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.));
|
ExPolygons last = offset_ex(surface.expolygon.simplify_p(m_scaled_resolution),
|
||||||
|
config->precise_outer_wall ? -float(ext_perimeter_width / 2. - bead_width_0 / 2.)
|
||||||
|
: -float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.));
|
||||||
Polygons last_p = to_polygons(last);
|
Polygons last_p = to_polygons(last);
|
||||||
|
|
||||||
double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
|
double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
|
||||||
|
@ -1156,8 +1161,14 @@ void PerimeterGenerator::process_arachne()
|
||||||
input_params.wall_transition_angle = this->object_config->wall_transition_angle.value;
|
input_params.wall_transition_angle = this->object_config->wall_transition_angle.value;
|
||||||
input_params.wall_distribution_count = this->object_config->wall_distribution_count.value;
|
input_params.wall_distribution_count = this->object_config->wall_distribution_count.value;
|
||||||
}
|
}
|
||||||
|
coord_t wall_0_inset = 0;
|
||||||
|
//if (config->precise_outer_wall)
|
||||||
|
// wall_0_inset = 0.5 * (ext_perimeter_width + this->perimeter_flow.scaled_width() - ext_perimeter_spacing -
|
||||||
|
// perimeter_spacing);
|
||||||
|
|
||||||
|
Arachne::WallToolPaths wallToolPaths(last_p, bead_width_0, perimeter_spacing, coord_t(loop_number + 1),
|
||||||
|
wall_0_inset, layer_height, input_params);
|
||||||
|
|
||||||
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, layer_height, input_params);
|
|
||||||
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
|
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
|
||||||
loop_number = int(perimeters.size()) - 1;
|
loop_number = int(perimeters.size()) - 1;
|
||||||
|
|
||||||
|
@ -1399,6 +1410,7 @@ std::map<int, Polygons> PerimeterGenerator::generate_lower_polygons_series(float
|
||||||
// BBS: increase start_offset a little to avoid to calculate 90 degree as overhang
|
// BBS: increase start_offset a little to avoid to calculate 90 degree as overhang
|
||||||
offset_series[0] = start_offset + 0.5 * (end_offset - start_offset) / (overhang_sampling_number - 1);
|
offset_series[0] = start_offset + 0.5 * (end_offset - start_offset) / (overhang_sampling_number - 1);
|
||||||
offset_series[overhang_sampling_number - 2] = end_offset;
|
offset_series[overhang_sampling_number - 2] = end_offset;
|
||||||
|
offset_series.back() = 0.1 * nozzle_diameter;
|
||||||
|
|
||||||
std::map<int, Polygons> lower_polygons_series;
|
std::map<int, Polygons> lower_polygons_series;
|
||||||
if (this->lower_slices == NULL) {
|
if (this->lower_slices == NULL) {
|
||||||
|
|
|
@ -96,6 +96,18 @@ inline typename Derived::Scalar cross2(const Eigen::MatrixBase<Derived> &v1, con
|
||||||
template<typename T, int Options>
|
template<typename T, int Options>
|
||||||
inline Eigen::Matrix<T, 2, 1, Eigen::DontAlign> perp(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v) { return Eigen::Matrix<T, 2, 1, Eigen::DontAlign>(- v.y(), v.x()); }
|
inline Eigen::Matrix<T, 2, 1, Eigen::DontAlign> perp(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v) { return Eigen::Matrix<T, 2, 1, Eigen::DontAlign>(- v.y(), v.x()); }
|
||||||
|
|
||||||
|
// Angle from v1 to v2, returning double atan2(y, x) normalized to <-PI, PI>.
|
||||||
|
template <typename Derived, typename Derived2>
|
||||||
|
inline double angle(const Eigen::MatrixBase<Derived>& v1, const Eigen::MatrixBase<Derived2>& v2)
|
||||||
|
{
|
||||||
|
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "angle(): first parameter is not a 2D vector");
|
||||||
|
static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "angle(): second parameter is not a 2D vector");
|
||||||
|
auto v1d = v1.template cast<double>();
|
||||||
|
auto v2d = v2.template cast<double>();
|
||||||
|
return atan2(cross2(v1d, v2d), v1d.dot(v2d));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T, int N, int Options>
|
template<class T, int N, int Options>
|
||||||
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Eigen::Matrix<T, N, 1, Options>> &ptN) { return { ptN.x(), ptN.y() }; }
|
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Eigen::Matrix<T, N, 1, Options>> &ptN) { return { ptN.x(), ptN.y() }; }
|
||||||
|
|
||||||
|
|
|
@ -752,7 +752,8 @@ static std::vector<std::string> s_Preset_print_options {
|
||||||
"small_perimeter_speed", "small_perimeter_threshold","bridge_angle", "filter_out_gap_fill", "post_process", "travel_acceleration","inner_wall_acceleration",
|
"small_perimeter_speed", "small_perimeter_threshold","bridge_angle", "filter_out_gap_fill", "post_process", "travel_acceleration","inner_wall_acceleration",
|
||||||
"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", "top_surface_jerk", "initial_layer_jerk","travel_jerk",
|
"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", "top_surface_jerk", "initial_layer_jerk","travel_jerk",
|
||||||
"top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio","only_one_wall_first_layer",
|
"top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio","only_one_wall_first_layer",
|
||||||
"print_flow_ratio","seam_gap","role_based_wipe_speed","wipe_speed","accel_to_decel_enable", "accel_to_decel_factor", "wipe_on_loops", "bridge_density", "precise_outer_wall"
|
"print_flow_ratio","seam_gap","role_based_wipe_speed","wipe_speed","accel_to_decel_enable", "accel_to_decel_factor", "wipe_on_loops", "bridge_density", "precise_outer_wall",
|
||||||
|
"overhang_speed_classic"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
140
src/libslic3r/PrincipalComponents2D.cpp
Normal file
140
src/libslic3r/PrincipalComponents2D.cpp
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#include "PrincipalComponents2D.hpp"
|
||||||
|
#include "Point.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// returns triangle area, first_moment_of_area_xy, second_moment_of_area_xy, second_moment_of_area_covariance
|
||||||
|
// none of the values is divided/normalized by area.
|
||||||
|
// The function computes intgeral over the area of the triangle, with function f(x,y) = x for first moments of area (y is analogous)
|
||||||
|
// f(x,y) = x^2 for second moment of area
|
||||||
|
// and f(x,y) = x*y for second moment of area covariance
|
||||||
|
std::tuple<float, Vec2f, Vec2f, float> compute_moments_of_area_of_triangle(const Vec2f &a, const Vec2f &b, const Vec2f &c)
|
||||||
|
{
|
||||||
|
// based on the following guide:
|
||||||
|
// Denote the vertices of S by a, b, c. Then the map
|
||||||
|
// g:(u,v)↦a+u(b−a)+v(c−a) ,
|
||||||
|
// which in coordinates appears as
|
||||||
|
// g:(u,v)↦{x(u,v)y(u,v)=a1+u(b1−a1)+v(c1−a1)=a2+u(b2−a2)+v(c2−a2) ,(1)
|
||||||
|
// obviously maps S′ bijectively onto S. Therefore the transformation formula for multiple integrals steps into action, and we obtain
|
||||||
|
// ∫Sf(x,y)d(x,y)=∫S′f(x(u,v),y(u,v))∣∣Jg(u,v)∣∣ d(u,v) .
|
||||||
|
// In the case at hand the Jacobian determinant is a constant: From (1) we obtain
|
||||||
|
// Jg(u,v)=det[xuyuxvyv]=(b1−a1)(c2−a2)−(c1−a1)(b2−a2) .
|
||||||
|
// Therefore we can write
|
||||||
|
// ∫Sf(x,y)d(x,y)=∣∣Jg∣∣∫10∫1−u0f~(u,v) dv du ,
|
||||||
|
// where f~ denotes the pullback of f to S′:
|
||||||
|
// f~(u,v):=f(x(u,v),y(u,v)) .
|
||||||
|
// Don't forget taking the absolute value of Jg!
|
||||||
|
|
||||||
|
float jacobian_determinant_abs = std::abs((b.x() - a.x()) * (c.y() - a.y()) - (c.x() - a.x()) * (b.y() - a.y()));
|
||||||
|
|
||||||
|
// coordinate transform: gx(u,v) = a.x + u * (b.x - a.x) + v * (c.x - a.x)
|
||||||
|
// coordinate transform: gy(u,v) = a.y + u * (b.y - a.y) + v * (c.y - a.y)
|
||||||
|
// second moment of area for x: f(x, y) = x^2;
|
||||||
|
// f(gx(u,v), gy(u,v)) = gx(u,v)^2 = ... (long expanded form)
|
||||||
|
|
||||||
|
// result is Int_T func = jacobian_determinant_abs * Int_0^1 Int_0^1-u func(gx(u,v), gy(u,v)) dv du
|
||||||
|
// integral_0^1 integral_0^(1 - u) (a + u (b - a) + v (c - a))^2 dv du = 1/12 (a^2 + a (b + c) + b^2 + b c + c^2)
|
||||||
|
|
||||||
|
Vec2f second_moment_of_area_xy = jacobian_determinant_abs *
|
||||||
|
(a.cwiseProduct(a) + b.cwiseProduct(b) + b.cwiseProduct(c) + c.cwiseProduct(c) +
|
||||||
|
a.cwiseProduct(b + c)) /
|
||||||
|
12.0f;
|
||||||
|
// second moment of area covariance : f(x, y) = x*y;
|
||||||
|
// f(gx(u,v), gy(u,v)) = gx(u,v)*gy(u,v) = ... (long expanded form)
|
||||||
|
//(a_1 + u * (b_1 - a_1) + v * (c_1 - a_1)) * (a_2 + u * (b_2 - a_2) + v * (c_2 - a_2))
|
||||||
|
// == (a_1 + u (b_1 - a_1) + v (c_1 - a_1)) (a_2 + u (b_2 - a_2) + v (c_2 - a_2))
|
||||||
|
|
||||||
|
// intermediate result: integral_0^(1 - u) (a_1 + u (b_1 - a_1) + v (c_1 - a_1)) (a_2 + u (b_2 - a_2) + v (c_2 - a_2)) dv =
|
||||||
|
// 1/6 (u - 1) (-c_1 (u - 1) (a_2 (u - 1) - 3 b_2 u) - c_2 (u - 1) (a_1 (u - 1) - 3 b_1 u + 2 c_1 (u - 1)) + 3 b_1 u (a_2 (u - 1) - 2
|
||||||
|
// b_2 u) + a_1 (u - 1) (3 b_2 u - 2 a_2 (u - 1))) result = integral_0^1 1/6 (u - 1) (-c_1 (u - 1) (a_2 (u - 1) - 3 b_2 u) - c_2 (u -
|
||||||
|
// 1) (a_1 (u - 1) - 3 b_1 u + 2 c_1 (u - 1)) + 3 b_1 u (a_2 (u - 1) - 2 b_2 u) + a_1 (u - 1) (3 b_2 u - 2 a_2 (u - 1))) du =
|
||||||
|
// 1/24 (a_2 (b_1 + c_1) + a_1 (2 a_2 + b_2 + c_2) + b_2 c_1 + b_1 c_2 + 2 b_1 b_2 + 2 c_1 c_2)
|
||||||
|
// result is Int_T func = jacobian_determinant_abs * Int_0^1 Int_0^1-u func(gx(u,v), gy(u,v)) dv du
|
||||||
|
float second_moment_of_area_covariance = jacobian_determinant_abs * (1.0f / 24.0f) *
|
||||||
|
(a.y() * (b.x() + c.x()) + a.x() * (2.0f * a.y() + b.y() + c.y()) + b.y() * c.x() +
|
||||||
|
b.x() * c.y() + 2.0f * b.x() * b.y() + 2.0f * c.x() * c.y());
|
||||||
|
|
||||||
|
float area = jacobian_determinant_abs * 0.5f;
|
||||||
|
|
||||||
|
Vec2f first_moment_of_area_xy = jacobian_determinant_abs * (a + b + c) / 6.0f;
|
||||||
|
|
||||||
|
return {area, first_moment_of_area_xy, second_moment_of_area_xy, second_moment_of_area_covariance};
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns two eigenvectors of the area covered by given polygons. The vectors are sorted by their corresponding eigenvalue, largest first
|
||||||
|
std::tuple<Vec2f, Vec2f> compute_principal_components(const Polygons &polys)
|
||||||
|
{
|
||||||
|
Vec2f centroid_accumulator = Vec2f::Zero();
|
||||||
|
Vec2f second_moment_of_area_accumulator = Vec2f::Zero();
|
||||||
|
float second_moment_of_area_covariance_accumulator = 0.0f;
|
||||||
|
float area = 0.0f;
|
||||||
|
|
||||||
|
for (const Polygon &poly : polys) {
|
||||||
|
Vec2f p0 = unscaled(poly.first_point()).cast<float>();
|
||||||
|
for (size_t i = 2; i < poly.points.size(); i++) {
|
||||||
|
Vec2f p1 = unscaled(poly.points[i - 1]).cast<float>();
|
||||||
|
Vec2f p2 = unscaled(poly.points[i]).cast<float>();
|
||||||
|
|
||||||
|
float sign = cross2(p1 - p0, p2 - p1) > 0 ? 1.0f : -1.0f;
|
||||||
|
|
||||||
|
auto [triangle_area, first_moment_of_area, second_moment_area,
|
||||||
|
second_moment_of_area_covariance] = compute_moments_of_area_of_triangle(p0, p1, p2);
|
||||||
|
area += sign * triangle_area;
|
||||||
|
centroid_accumulator += sign * first_moment_of_area;
|
||||||
|
second_moment_of_area_accumulator += sign * second_moment_area;
|
||||||
|
second_moment_of_area_covariance_accumulator += sign * second_moment_of_area_covariance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area <= 0.0) {
|
||||||
|
return {Vec2f::Zero(), Vec2f::Zero()};
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2f centroid = centroid_accumulator / area;
|
||||||
|
Vec2f variance = second_moment_of_area_accumulator / area - centroid.cwiseProduct(centroid);
|
||||||
|
double covariance = second_moment_of_area_covariance_accumulator / area - centroid.x() * centroid.y();
|
||||||
|
#if 0
|
||||||
|
std::cout << "area : " << area << std::endl;
|
||||||
|
std::cout << "variancex : " << variance.x() << std::endl;
|
||||||
|
std::cout << "variancey : " << variance.y() << std::endl;
|
||||||
|
std::cout << "covariance : " << covariance << std::endl;
|
||||||
|
#endif
|
||||||
|
if (abs(covariance) < EPSILON) {
|
||||||
|
std::tuple<Vec2f, Vec2f> result{Vec2f{variance.x(), 0.0}, Vec2f{0.0, variance.y()}};
|
||||||
|
if (variance.y() > variance.x()) {
|
||||||
|
return {std::get<1>(result), std::get<0>(result)};
|
||||||
|
} else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we find the first principal component of the covered area by computing max eigenvalue and the correspoding eigenvector of
|
||||||
|
// covariance matrix
|
||||||
|
// covaraince matrix C is : | VarX Cov |
|
||||||
|
// | Cov VarY |
|
||||||
|
// Eigenvalues are solutions to det(C - lI) = 0, where l is the eigenvalue and I unit matrix
|
||||||
|
// Eigenvector for eigenvalue l is any vector v such that Cv = lv
|
||||||
|
|
||||||
|
float eigenvalue_a = 0.5f * (variance.x() + variance.y() +
|
||||||
|
sqrt((variance.x() - variance.y()) * (variance.x() - variance.y()) + 4.0f * covariance * covariance));
|
||||||
|
float eigenvalue_b = 0.5f * (variance.x() + variance.y() -
|
||||||
|
sqrt((variance.x() - variance.y()) * (variance.x() - variance.y()) + 4.0f * covariance * covariance));
|
||||||
|
Vec2f eigenvector_a{(eigenvalue_a - variance.y()) / covariance, 1.0f};
|
||||||
|
Vec2f eigenvector_b{(eigenvalue_b - variance.y()) / covariance, 1.0f};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
std::cout << "eigenvalue_a: " << eigenvalue_a << std::endl;
|
||||||
|
std::cout << "eigenvalue_b: " << eigenvalue_b << std::endl;
|
||||||
|
std::cout << "eigenvectorA: " << eigenvector_a.x() << " " << eigenvector_a.y() << std::endl;
|
||||||
|
std::cout << "eigenvectorB: " << eigenvector_b.x() << " " << eigenvector_b.y() << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (eigenvalue_a > eigenvalue_b) {
|
||||||
|
return {eigenvector_a, eigenvector_b};
|
||||||
|
} else {
|
||||||
|
return {eigenvector_b, eigenvector_a};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/libslic3r/PrincipalComponents2D.hpp
Normal file
24
src/libslic3r/PrincipalComponents2D.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef slic3r_PrincipalComponents2D_hpp_
|
||||||
|
#define slic3r_PrincipalComponents2D_hpp_
|
||||||
|
|
||||||
|
#include "AABBTreeLines.hpp"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
|
#include "libslic3r.h"
|
||||||
|
#include <vector>
|
||||||
|
#include "Polygon.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
// returns triangle area, first_moment_of_area_xy, second_moment_of_area_xy, second_moment_of_area_covariance
|
||||||
|
// none of the values is divided/normalized by area.
|
||||||
|
// The function computes intgeral over the area of the triangle, with function f(x,y) = x for first moments of area (y is analogous)
|
||||||
|
// f(x,y) = x^2 for second moment of area
|
||||||
|
// and f(x,y) = x*y for second moment of area covariance
|
||||||
|
std::tuple<float, Vec2f, Vec2f, float> compute_moments_of_area_of_triangle(const Vec2f &a, const Vec2f &b, const Vec2f &c);
|
||||||
|
|
||||||
|
// returns two eigenvectors of the area covered by given polygons. The vectors are sorted by their corresponding eigenvalue, largest first
|
||||||
|
std::tuple<Vec2f, Vec2f> compute_principal_components(const Polygons &polys);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -670,7 +670,6 @@ public:
|
||||||
const PrintConfig& config() const { return m_config; }
|
const PrintConfig& config() const { return m_config; }
|
||||||
const PrintObjectConfig& default_object_config() const { return m_default_object_config; }
|
const PrintObjectConfig& default_object_config() const { return m_default_object_config; }
|
||||||
const PrintRegionConfig& default_region_config() const { return m_default_region_config; }
|
const PrintRegionConfig& default_region_config() const { return m_default_region_config; }
|
||||||
PrintRegionConfig& default_region_config() { return m_default_region_config; }
|
|
||||||
ConstPrintObjectPtrsAdaptor objects() const { return ConstPrintObjectPtrsAdaptor(&m_objects); }
|
ConstPrintObjectPtrsAdaptor objects() const { return ConstPrintObjectPtrsAdaptor(&m_objects); }
|
||||||
PrintObject* get_object(size_t idx) { return const_cast<PrintObject*>(m_objects[idx]); }
|
PrintObject* get_object(size_t idx) { return const_cast<PrintObject*>(m_objects[idx]); }
|
||||||
const PrintObject* get_object(size_t idx) const { return m_objects[idx]; }
|
const PrintObject* get_object(size_t idx) const { return m_objects[idx]; }
|
||||||
|
|
|
@ -659,7 +659,7 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->enum_values.emplace_back("75%");
|
def->enum_values.emplace_back("75%");
|
||||||
def->enum_values.emplace_back("95%");
|
def->enum_values.emplace_back("95%");
|
||||||
def->enum_labels.emplace_back("0%");
|
def->enum_labels.emplace_back("0%");
|
||||||
def->enum_labels.emplace_back("10%");
|
def->enum_labels.emplace_back("5%");
|
||||||
def->enum_labels.emplace_back("25%");
|
def->enum_labels.emplace_back("25%");
|
||||||
def->enum_labels.emplace_back("50%");
|
def->enum_labels.emplace_back("50%");
|
||||||
def->enum_labels.emplace_back("75%");
|
def->enum_labels.emplace_back("75%");
|
||||||
|
@ -718,10 +718,10 @@ void PrintConfigDef::init_fff_params()
|
||||||
|
|
||||||
|
|
||||||
def = this->add("precise_outer_wall",coBool);
|
def = this->add("precise_outer_wall",coBool);
|
||||||
def->label = L("Precise wall");
|
def->label = L("Precise wall(experimental)");
|
||||||
def->category = L("Quality");
|
def->category = L("Quality");
|
||||||
def->tooltip = L("Improve outer wall precesion by adjusting outer wall spacing");
|
def->tooltip = L("Improve shell precesion by adjusting outer wall spacing. This also improves layer consistency.");
|
||||||
def->set_default_value(new ConfigOptionBool{true});
|
def->set_default_value(new ConfigOptionBool{false});
|
||||||
|
|
||||||
def = this->add("only_one_wall_top", coBool);
|
def = this->add("only_one_wall_top", coBool);
|
||||||
def->label = L("Only one wall on top surfaces");
|
def->label = L("Only one wall on top surfaces");
|
||||||
|
@ -735,6 +735,13 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->tooltip = L("Use only one wall on first layer, to give more space to the bottom infill pattern");
|
def->tooltip = L("Use only one wall on first layer, to give more space to the bottom infill pattern");
|
||||||
def->set_default_value(new ConfigOptionBool(false));
|
def->set_default_value(new ConfigOptionBool(false));
|
||||||
|
|
||||||
|
def = this->add("overhang_speed_classic", coBool);
|
||||||
|
def->label = L("Classic mode");
|
||||||
|
def->category = L("Speed");
|
||||||
|
def->tooltip = L("Enable this option to use classic mode");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionBool{ false });
|
||||||
|
|
||||||
def = this->add("enable_overhang_speed", coBool);
|
def = this->add("enable_overhang_speed", coBool);
|
||||||
def->label = L("Slow down for overhang");
|
def->label = L("Slow down for overhang");
|
||||||
def->category = L("Speed");
|
def->category = L("Speed");
|
||||||
|
@ -1019,7 +1026,7 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||||
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
|
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonic));
|
||||||
|
|
||||||
def = this->add("bottom_surface_pattern", coEnum);
|
def = this->add("bottom_surface_pattern", coEnum);
|
||||||
def->label = L("Bottom surface pattern");
|
def->label = L("Bottom surface pattern");
|
||||||
|
@ -1052,23 +1059,23 @@ void PrintConfigDef::init_fff_params()
|
||||||
def = this->add("small_perimeter_speed", coFloatOrPercent);
|
def = this->add("small_perimeter_speed", coFloatOrPercent);
|
||||||
def->label = L("Small perimeters");
|
def->label = L("Small perimeters");
|
||||||
def->category = L("Speed");
|
def->category = L("Speed");
|
||||||
def->tooltip = L("This separate setting will affect the speed of perimeters having radius <= 6.5mm "
|
def->tooltip = L("This separate setting will affect the speed of perimeters having radius <= small_perimeter_threshold "
|
||||||
"(usually holes). If expressed as percentage (for example: 80%) it will be calculated "
|
"(usually holes). If expressed as percentage (for example: 80%) it will be calculated "
|
||||||
"on the outer wall speed setting above. Set to zero for auto.");
|
"on the outer wall speed setting above. Set to zero for auto.");
|
||||||
def->sidetext = L("mm/s or %");
|
def->sidetext = L("mm/s or %");
|
||||||
def->ratio_over = "outer_wall_speed";
|
def->ratio_over = "outer_wall_speed";
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloatOrPercent(100, true));
|
def->set_default_value(new ConfigOptionFloatOrPercent(50, true));
|
||||||
|
|
||||||
def = this->add("small_perimeter_threshold", coFloat);
|
def = this->add("small_perimeter_threshold", coFloat);
|
||||||
def->label = L("Small perimeters threshold");
|
def->label = L("Small perimeters threshold");
|
||||||
def->category = L("Speed");
|
def->category = L("Speed");
|
||||||
def->tooltip = L("This sets the threshold for small perimeter length. Default threshold is 6.5mm");
|
def->tooltip = L("This sets the threshold for small perimeter length. Default threshold is 0mm");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloat(6.5));
|
def->set_default_value(new ConfigOptionFloat(0));
|
||||||
|
|
||||||
def = this->add("wall_infill_order", coEnum);
|
def = this->add("wall_infill_order", coEnum);
|
||||||
def->label = L("Order of inner wall/outer wall/infil");
|
def->label = L("Order of inner wall/outer wall/infil");
|
||||||
|
@ -3280,7 +3287,7 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->enum_labels.push_back(L("Classic"));
|
def->enum_labels.push_back(L("Classic"));
|
||||||
def->enum_labels.push_back(L("Arachne"));
|
def->enum_labels.push_back(L("Arachne"));
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionEnum<PerimeterGeneratorType>(PerimeterGeneratorType::Classic));
|
def->set_default_value(new ConfigOptionEnum<PerimeterGeneratorType>(PerimeterGeneratorType::Arachne));
|
||||||
|
|
||||||
def = this->add("wall_transition_length", coPercent);
|
def = this->add("wall_transition_length", coPercent);
|
||||||
def->label = L("Wall transition length");
|
def->label = L("Wall transition length");
|
||||||
|
|
|
@ -763,6 +763,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||||
((ConfigOptionBool, wipe_on_loops))
|
((ConfigOptionBool, wipe_on_loops))
|
||||||
((ConfigOptionEnum<WallInfillOrder>, wall_infill_order))
|
((ConfigOptionEnum<WallInfillOrder>, wall_infill_order))
|
||||||
((ConfigOptionBool, precise_outer_wall))
|
((ConfigOptionBool, precise_outer_wall))
|
||||||
|
((ConfigOptionBool, overhang_speed_classic))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -826,7 +826,8 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||||
//BBS
|
//BBS
|
||||||
|| opt_key == "enable_overhang_speed"
|
|| opt_key == "enable_overhang_speed"
|
||||||
|| opt_key == "detect_thin_wall"
|
|| opt_key == "detect_thin_wall"
|
||||||
|| opt_key == "precise_outer_wall") {
|
|| opt_key == "precise_outer_wall"
|
||||||
|
|| opt_key == "overhang_speed_classic") {
|
||||||
steps.emplace_back(posPerimeters);
|
steps.emplace_back(posPerimeters);
|
||||||
steps.emplace_back(posSupportMaterial);
|
steps.emplace_back(posSupportMaterial);
|
||||||
} else if (opt_key == "bridge_flow" || opt_key == "bridge_density") {
|
} else if (opt_key == "bridge_flow" || opt_key == "bridge_density") {
|
||||||
|
|
1267
src/libslic3r/SupportSpotsGenerator.cpp
Normal file
1267
src/libslic3r/SupportSpotsGenerator.cpp
Normal file
File diff suppressed because it is too large
Load diff
159
src/libslic3r/SupportSpotsGenerator.hpp
Normal file
159
src/libslic3r/SupportSpotsGenerator.hpp
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#ifndef SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_
|
||||||
|
#define SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_
|
||||||
|
/*
|
||||||
|
#include "Layer.hpp"
|
||||||
|
#include "Line.hpp"
|
||||||
|
#include "PrintBase.hpp"
|
||||||
|
#include "PrintConfig.hpp"
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
namespace SupportSpotsGenerator {
|
||||||
|
|
||||||
|
struct Params
|
||||||
|
{
|
||||||
|
Params(
|
||||||
|
const std::vector<std::string> &filament_types, float max_acceleration, int raft_layers_count, BrimType brim_type, float brim_width)
|
||||||
|
: max_acceleration(max_acceleration), raft_layers_count(raft_layers_count), brim_type(brim_type), brim_width(brim_width)
|
||||||
|
{
|
||||||
|
if (filament_types.size() > 1) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< "SupportSpotsGenerator does not currently handle different materials properly, only first will be used";
|
||||||
|
}
|
||||||
|
if (filament_types.empty() || filament_types[0].empty()) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "SupportSpotsGenerator error: empty filament_type";
|
||||||
|
filament_type = std::string("PLA");
|
||||||
|
} else {
|
||||||
|
filament_type = filament_types[0];
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "SupportSpotsGenerator: applying filament type: " << filament_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the algorithm should use the following units for all computations: distance [mm], mass [g], time [s], force [g*mm/s^2]
|
||||||
|
const float bridge_distance = 16.0f; // mm
|
||||||
|
const float max_acceleration; // mm/s^2 ; max acceleration of object in XY -- should be applicable only to printers with bed slinger,
|
||||||
|
// however we do not have such info yet. The force is usually small anyway, so not such a big deal to include it everytime
|
||||||
|
const int raft_layers_count;
|
||||||
|
std::string filament_type;
|
||||||
|
|
||||||
|
BrimType brim_type;
|
||||||
|
const float brim_width;
|
||||||
|
|
||||||
|
const std::pair<float,float> malformation_distance_factors = std::pair<float, float> { 0.5, 1.1 };
|
||||||
|
const float max_curled_height_factor = 10.0f;
|
||||||
|
|
||||||
|
const float min_distance_between_support_points = 3.0f; //mm
|
||||||
|
const float support_points_interface_radius = 1.5f; // mm
|
||||||
|
const float min_distance_to_allow_local_supports = 1.0f; //mm
|
||||||
|
|
||||||
|
const float gravity_constant = 9806.65f; // mm/s^2; gravity acceleration on Earth's surface, algorithm assumes that printer is in upwards position.
|
||||||
|
const double filament_density = 1.25e-3f; // g/mm^3 ; Common filaments are very lightweight, so precise number is not that important
|
||||||
|
const double material_yield_strength = 33.0f * 1e6f; // (g*mm/s^2)/mm^2; 33 MPa is yield strength of ABS, which has the lowest yield strength from common materials.
|
||||||
|
const float standard_extruder_conflict_force = 10.0f * gravity_constant; // force that can occasionally push the model due to various factors (filament leaks, small curling, ... );
|
||||||
|
const float malformations_additive_conflict_extruder_force = 65.0f * gravity_constant; // for areas with possible high layered curled filaments
|
||||||
|
|
||||||
|
// MPa * 1e^6 = (g*mm/s^2)/mm^2 = g/(mm*s^2); yield strength of the bed surface
|
||||||
|
double get_bed_adhesion_yield_strength() const {
|
||||||
|
if (raft_layers_count > 0) {
|
||||||
|
return get_support_spots_adhesion_strength() * 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filament_type == "PLA") {
|
||||||
|
return 0.02 * 1e6;
|
||||||
|
} else if (filament_type == "PET" || filament_type == "PETG") {
|
||||||
|
return 0.3 * 1e6;
|
||||||
|
} else if (filament_type == "ABS" || filament_type == "ASA") {
|
||||||
|
return 0.1 * 1e6; //TODO do measurements
|
||||||
|
} else { //PLA default value - defensive approach, PLA has quite low adhesion
|
||||||
|
return 0.02 * 1e6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_support_spots_adhesion_strength() const {
|
||||||
|
return 0.016f * 1e6;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SupportPointCause {
|
||||||
|
LongBridge, // point generated on bridge and straight perimeter extrusion longer than the allowed length
|
||||||
|
FloatingBridgeAnchor, // point generated on unsupported bridge endpoint
|
||||||
|
FloatingExtrusion, // point generated on extrusion that does not hold on its own
|
||||||
|
SeparationFromBed, // point generated for object parts that are connected to the bed, but the area is too small and there is a risk of separation (brim may help)
|
||||||
|
UnstableFloatingPart, // point generated for object parts not connected to the bed, holded only by the other support points (brim will not help here)
|
||||||
|
WeakObjectPart // point generated when some part of the object is too weak to hold the upper part and may break (imagine hourglass)
|
||||||
|
};
|
||||||
|
|
||||||
|
// The support points can be sorted into two groups
|
||||||
|
// 1. Local extrusion support for extrusions that are printed in the air and would not
|
||||||
|
// withstand on their own (too long bridges, sharp turns in large overhang, concave bridge holes, etc.)
|
||||||
|
// These points have negative force (-EPSILON) and Vec2f::Zero() direction
|
||||||
|
// The algorithm still expects that these points will be supported and accounts for them in the global stability check.
|
||||||
|
// 2. Global stability support points are generated at each spot, where the algorithm detects that extruding the current line
|
||||||
|
// may cause separation of the object part from the bed and/or its support spots or crack in the weak connection of the object parts.
|
||||||
|
// The generated point's direction is the estimated falling direction of the object part, and the force is equal to te difference
|
||||||
|
// between forces that destabilize the object (extruder conflicts with curled filament, weight if instable center of mass, bed movements etc)
|
||||||
|
// and forces that stabilize the object (bed adhesion, other support spots adhesion, weight if stable center of mass).
|
||||||
|
// Note that the force is only the difference - the amount needed to stabilize the object again.
|
||||||
|
struct SupportPoint
|
||||||
|
{
|
||||||
|
SupportPoint(SupportPointCause cause, const Vec3f &position, float force, float spot_radius, const Vec2f &direction)
|
||||||
|
: cause(cause), position(position), force(force), spot_radius(spot_radius), direction(direction)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool is_local_extrusion_support() const
|
||||||
|
{
|
||||||
|
return cause == SupportPointCause::LongBridge || cause == SupportPointCause::FloatingExtrusion;
|
||||||
|
}
|
||||||
|
bool is_global_object_support() const { return !is_local_extrusion_support(); }
|
||||||
|
|
||||||
|
SupportPointCause cause; // reason why this support point was generated. Used for the user alerts
|
||||||
|
// position is in unscaled coords. The z coordinate is aligned with the layers bottom_z coordiantes
|
||||||
|
Vec3f position;
|
||||||
|
// force that destabilizes the object to the point of falling/breaking. g*mm/s^2 units
|
||||||
|
// It is valid only for global_object_support. For local extrusion support points, the force is -EPSILON
|
||||||
|
// values gathered from large XL model: Min : 0 | Max : 18713800 | Average : 1361186 | Median : 329103
|
||||||
|
// For reference 18713800 is weight of 1.8 Kg object, 329103 is weight of 0.03 Kg
|
||||||
|
// The final sliced object weight was approx 0.5 Kg
|
||||||
|
float force;
|
||||||
|
// Expected spot size. The support point strength is calculated from the area defined by this value.
|
||||||
|
// Currently equal to the support_points_interface_radius parameter above
|
||||||
|
float spot_radius;
|
||||||
|
// direction of the fall of the object (z part is neglected)
|
||||||
|
Vec2f direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
using SupportPoints = std::vector<SupportPoint>;
|
||||||
|
|
||||||
|
struct Malformations {
|
||||||
|
std::vector<Lines> layers; //for each layer
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PartialObject
|
||||||
|
{
|
||||||
|
PartialObject(Vec3f centroid, float volume, bool connected_to_bed)
|
||||||
|
: centroid(centroid), volume(volume), connected_to_bed(connected_to_bed)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Vec3f centroid;
|
||||||
|
float volume;
|
||||||
|
bool connected_to_bed;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PartialObjects = std::vector<PartialObject>;
|
||||||
|
|
||||||
|
std::tuple<SupportPoints, PartialObjects> full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms);
|
||||||
|
|
||||||
|
void estimate_supports_malformations(std::vector<SupportLayer *> &layers, float supports_flow_width, const Params ¶ms);
|
||||||
|
void estimate_malformations(std::vector<Layer *> &layers, const Params ¶ms);
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: the boolean marks if the issue is critical or not for now.
|
||||||
|
std::vector<std::pair<SupportPointCause, bool>> gather_issues(const SupportPoints &support_points,
|
||||||
|
PartialObjects &partial_objects);
|
||||||
|
|
||||||
|
}} // namespace Slic3r::SupportSpotsGenerator
|
||||||
|
*/
|
||||||
|
#endif /* SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ */
|
|
@ -323,31 +323,30 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
if (config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne &&
|
if (config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne &&
|
||||||
config->opt_bool("enable_overhang_speed"))
|
config->opt_bool("overhang_speed_classic"))
|
||||||
{
|
{
|
||||||
wxString msg_text = _(L("Arachne engine only works when overhang slowing down is disabled.\n"
|
wxString msg_text = _(L("Arachne engine doesn't work with classic overhang speed mode.\n")) + "\n";
|
||||||
"This may cause decline in the quality of overhang surface when print fastly")) + "\n";
|
|
||||||
if (is_global_config)
|
if (is_global_config)
|
||||||
msg_text += "\n" + _(L("Disable overhang slowing down automatically? \n"
|
msg_text += "\n" + _(L("Turn off classic mode automatically? \n"
|
||||||
"Yes - Enable arachne and disable overhang slowing down\n"
|
"Yes - Enable arachne with classic mode off\n"
|
||||||
"No - Give up using arachne this time"));
|
"No - Give up using arachne this time"));
|
||||||
MessageDialog dialog(m_msg_dlg_parent, msg_text, "",
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, "",
|
||||||
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
is_msg_dlg_already_exist = true;
|
is_msg_dlg_already_exist = true;
|
||||||
auto answer = dialog.ShowModal();
|
auto answer = dialog.ShowModal();
|
||||||
bool enable_overhang_slow_down = true;
|
bool enable_overhang_slow_down_legacy = false;
|
||||||
if (!is_global_config || answer == wxID_YES) {
|
if (!is_global_config || answer == wxID_YES) {
|
||||||
new_conf.set_key_value("enable_overhang_speed", new ConfigOptionBool(false));
|
new_conf.set_key_value("overhang_speed_classic", new ConfigOptionBool(false));
|
||||||
enable_overhang_slow_down = false;
|
enable_overhang_slow_down_legacy = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
new_conf.set_key_value("wall_generator", new ConfigOptionEnum<PerimeterGeneratorType>(PerimeterGeneratorType::Classic));
|
new_conf.set_key_value("wall_generator", new ConfigOptionEnum<PerimeterGeneratorType>(PerimeterGeneratorType::Classic));
|
||||||
}
|
}
|
||||||
apply(config, &new_conf);
|
apply(config, &new_conf);
|
||||||
if (cb_value_change) {
|
if (cb_value_change) {
|
||||||
if (!enable_overhang_slow_down)
|
if (!enable_overhang_slow_down_legacy)
|
||||||
cb_value_change("enable_overhang_speed", false);
|
cb_value_change("overhang_speed_classic", false);
|
||||||
}
|
}
|
||||||
is_msg_dlg_already_exist = false;
|
is_msg_dlg_already_exist = false;
|
||||||
}
|
}
|
||||||
|
@ -639,7 +638,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||||
toggle_line("max_travel_detour_distance", have_avoid_crossing_perimeters);
|
toggle_line("max_travel_detour_distance", have_avoid_crossing_perimeters);
|
||||||
|
|
||||||
bool has_overhang_speed = config->opt_bool("enable_overhang_speed");
|
bool has_overhang_speed = config->opt_bool("enable_overhang_speed");
|
||||||
for (auto el : { "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed"})
|
for (auto el :
|
||||||
|
{"overhang_speed_classic", "overhang_1_4_speed",
|
||||||
|
"overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed"})
|
||||||
toggle_line(el, has_overhang_speed);
|
toggle_line(el, has_overhang_speed);
|
||||||
|
|
||||||
toggle_line("flush_into_objects", !is_global_config);
|
toggle_line("flush_into_objects", !is_global_config);
|
||||||
|
@ -657,7 +658,6 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||||
"min_feature_size", "min_bead_width", "wall_distribution_count" })
|
"min_feature_size", "min_bead_width", "wall_distribution_count" })
|
||||||
toggle_line(el, have_arachne);
|
toggle_line(el, have_arachne);
|
||||||
toggle_field("detect_thin_wall", !have_arachne);
|
toggle_field("detect_thin_wall", !have_arachne);
|
||||||
toggle_field("enable_overhang_speed", !have_arachne);
|
|
||||||
toggle_field("only_one_wall_top", !have_arachne);
|
toggle_field("only_one_wall_top", !have_arachne);
|
||||||
|
|
||||||
// SoftFever
|
// SoftFever
|
||||||
|
|
|
@ -98,7 +98,7 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::PART_CAT
|
||||||
{"infill_combination", "",1}, {"infill_wall_overlap", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1}
|
{"infill_combination", "",1}, {"infill_wall_overlap", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1}
|
||||||
}},
|
}},
|
||||||
{ L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5},
|
{ L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5},
|
||||||
{"enable_overhang_speed", "",6}, {"overhang_1_4_speed", "",7}, {"overhang_2_4_speed", "",8}, {"overhang_3_4_speed", "",9}, {"overhang_4_4_speed", "",10},
|
{"enable_overhang_speed", "",6}, {"overhang_speed_classic", "",6}, {"overhang_1_4_speed", "",7}, {"overhang_2_4_speed", "",8}, {"overhang_3_4_speed", "",9}, {"overhang_4_4_speed", "",10},
|
||||||
{"bridge_speed", "",11}, {"gap_infill_speed", "",12}
|
{"bridge_speed", "",11}, {"gap_infill_speed", "",12}
|
||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2515,7 +2515,7 @@ void MainFrame::init_menubar_as_editor()
|
||||||
},
|
},
|
||||||
"", nullptr,
|
"", nullptr,
|
||||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||||
m_topbar->GetCalibMenu()->AppendSubMenu(advance_menu, _L("More"));
|
m_topbar->GetCalibMenu()->AppendSubMenu(advance_menu, _L("More..."));
|
||||||
|
|
||||||
// help
|
// help
|
||||||
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Tutorial"), _L("Calibration help"),
|
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Tutorial"), _L("Calibration help"),
|
||||||
|
@ -2581,7 +2581,7 @@ void MainFrame::init_menubar_as_editor()
|
||||||
m_vfa_test_dlg->ShowModal();
|
m_vfa_test_dlg->ShowModal();
|
||||||
}, "", nullptr,
|
}, "", nullptr,
|
||||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||||
append_submenu(calib_menu, advance_menu, wxID_ANY, _L("More"), _L("More calibrations"), "",
|
append_submenu(calib_menu, advance_menu, wxID_ANY, _L("More..."), _L("More calibrations"), "",
|
||||||
[this]() {return m_plater->is_view3D_shown();; });
|
[this]() {return m_plater->is_view3D_shown();; });
|
||||||
// help
|
// help
|
||||||
append_menu_item(calib_menu, wxID_ANY, _L("Tutorial"), _L("Calibration help"),
|
append_menu_item(calib_menu, wxID_ANY, _L("Tutorial"), _L("Calibration help"),
|
||||||
|
|
|
@ -1919,7 +1919,12 @@ void TabPrint::build()
|
||||||
optgroup->append_single_option_line("sparse_infill_speed");
|
optgroup->append_single_option_line("sparse_infill_speed");
|
||||||
optgroup->append_single_option_line("internal_solid_infill_speed");
|
optgroup->append_single_option_line("internal_solid_infill_speed");
|
||||||
optgroup->append_single_option_line("top_surface_speed");
|
optgroup->append_single_option_line("top_surface_speed");
|
||||||
|
optgroup->append_single_option_line("gap_infill_speed");
|
||||||
|
optgroup->append_single_option_line("support_speed");
|
||||||
|
optgroup->append_single_option_line("support_interface_speed");
|
||||||
|
optgroup = page->new_optgroup(L("Overhang speed"), L"param_speed", 15);
|
||||||
optgroup->append_single_option_line("enable_overhang_speed", "slow-down-for-overhang");
|
optgroup->append_single_option_line("enable_overhang_speed", "slow-down-for-overhang");
|
||||||
|
optgroup->append_single_option_line("overhang_speed_classic", "slow-down-for-overhang");
|
||||||
Line line = { L("Overhang speed"), L("This is the speed for various overhang degrees. Overhang degrees are expressed as a percentage of line width. 0 speed means no slowing down for the overhang degree range and wall speed is used") };
|
Line line = { L("Overhang speed"), L("This is the speed for various overhang degrees. Overhang degrees are expressed as a percentage of line width. 0 speed means no slowing down for the overhang degree range and wall speed is used") };
|
||||||
line.label_path = "slow-down-for-overhang";
|
line.label_path = "slow-down-for-overhang";
|
||||||
line.append_option(optgroup->get_option("overhang_1_4_speed"));
|
line.append_option(optgroup->get_option("overhang_1_4_speed"));
|
||||||
|
@ -1928,9 +1933,6 @@ void TabPrint::build()
|
||||||
line.append_option(optgroup->get_option("overhang_4_4_speed"));
|
line.append_option(optgroup->get_option("overhang_4_4_speed"));
|
||||||
optgroup->append_line(line);
|
optgroup->append_line(line);
|
||||||
optgroup->append_single_option_line("bridge_speed");
|
optgroup->append_single_option_line("bridge_speed");
|
||||||
optgroup->append_single_option_line("gap_infill_speed");
|
|
||||||
optgroup->append_single_option_line("support_speed");
|
|
||||||
optgroup->append_single_option_line("support_interface_speed");
|
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Travel speed"), L"param_travel_speed", 15);
|
optgroup = page->new_optgroup(L("Travel speed"), L"param_travel_speed", 15);
|
||||||
optgroup->append_single_option_line("travel_speed");
|
optgroup->append_single_option_line("travel_speed");
|
||||||
|
@ -1945,7 +1947,7 @@ void TabPrint::build()
|
||||||
optgroup->append_single_option_line("accel_to_decel_enable");
|
optgroup->append_single_option_line("accel_to_decel_enable");
|
||||||
optgroup->append_single_option_line("accel_to_decel_factor");
|
optgroup->append_single_option_line("accel_to_decel_factor");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Jerk(XY)"));
|
optgroup = page->new_optgroup(L("Jerk(XY)"), L"param_speed", 15);
|
||||||
optgroup->append_single_option_line("default_jerk");
|
optgroup->append_single_option_line("default_jerk");
|
||||||
optgroup->append_single_option_line("outer_wall_jerk");
|
optgroup->append_single_option_line("outer_wall_jerk");
|
||||||
optgroup->append_single_option_line("inner_wall_jerk");
|
optgroup->append_single_option_line("inner_wall_jerk");
|
||||||
|
|
|
@ -238,7 +238,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
|
||||||
// end temp
|
// end temp
|
||||||
auto end_temp_sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto end_temp_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
auto end_temp_text = new wxStaticText(this, wxID_ANY, end_temp_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
auto end_temp_text = new wxStaticText(this, wxID_ANY, end_temp_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||||
m_tiEnd = new TextInput(this, std::to_string(200), _L("\u2103"), "", wxDefaultPosition, ti_size, wxTE_CENTRE);
|
m_tiEnd = new TextInput(this, std::to_string(190), _L("\u2103"), "", wxDefaultPosition, ti_size, wxTE_CENTRE);
|
||||||
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||||
end_temp_sizer->Add(end_temp_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
end_temp_sizer->Add(end_temp_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||||
end_temp_sizer->Add(m_tiEnd, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
end_temp_sizer->Add(m_tiEnd, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||||
|
@ -338,11 +338,11 @@ void Temp_Calibration_Dlg::on_filament_type_changed(wxCommandEvent& event) {
|
||||||
switch(selection)
|
switch(selection)
|
||||||
{
|
{
|
||||||
case tABS_ASA:
|
case tABS_ASA:
|
||||||
start = 260;
|
start = 270;
|
||||||
end = 230;
|
end = 230;
|
||||||
break;
|
break;
|
||||||
case tPETG:
|
case tPETG:
|
||||||
start = 250;
|
start = 260;
|
||||||
end = 230;
|
end = 230;
|
||||||
break;
|
break;
|
||||||
case tTPU:
|
case tTPU:
|
||||||
|
@ -360,7 +360,7 @@ void Temp_Calibration_Dlg::on_filament_type_changed(wxCommandEvent& event) {
|
||||||
case tPLA:
|
case tPLA:
|
||||||
case tCustom:
|
case tCustom:
|
||||||
start = 230;
|
start = 230;
|
||||||
end = 200;
|
end = 190;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue