mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 06:52:03 +08:00
Merge branch 'master' into fs_svg
# Conflicts: # src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
This commit is contained in:
commit
b3d2dbeeb3
@ -1,4 +1,5 @@
|
||||
min_slic3r_version = 2.6.0-alpha6
|
||||
1.0.3 Added Voron Switchwire.
|
||||
1.0.2 Updated g-code flavor and travel accelerations.
|
||||
min_slic3r_version = 2.4.2
|
||||
1.0.1 Added 350mm Voron v1 variant. Updated max print heights. Removed redundant v1 volcano nozzle variants.
|
||||
|
@ -7,7 +7,7 @@
|
||||
name = Voron
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.0.2
|
||||
config_version = 1.0.3
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Voron/
|
||||
|
||||
@ -106,6 +106,28 @@ bed_model = printbed-v0-120.stl
|
||||
bed_texture = bedtexture-v0-120.png
|
||||
default_materials = Basic PLA @VORON; Basic PLA VOLCANO @VORON; Basic PET @VORON; Basic PET VOLCANO @VORON; Basic ABS @VORON; Basic ABS VOLCANO @VORON
|
||||
|
||||
[printer_model:Voron_SW_afterburner]
|
||||
name = Voron Switchwire
|
||||
variants = 0.4; 0.25; 0.3; 0.5; 0.6; 0.8; volcano 0.6; volcano 0.8; volcano 1.0; volcano 1.2
|
||||
technology = FFF
|
||||
family = Voron Switchwire Afterburner
|
||||
bed_model = printbed-SW-MK52.stl
|
||||
bed_texture = bedtexture-SW-250x210.png
|
||||
bed_with_grid = 1
|
||||
default_materials = Basic PLA @VORON; Basic PLA VOLCANO @VORON; Basic PET @VORON; Basic PET VOLCANO @VORON; Basic ABS @VORON; Basic ABS VOLCANO @VORON
|
||||
thumbnail = Voron_SW_thumbnail.png
|
||||
|
||||
[printer_model:Voron_SW]
|
||||
name = Voron Switchwire
|
||||
variants = 0.4; 0.25; 0.3; 0.5; 0.6; 0.8; volcano 0.6; volcano 0.8; volcano 1.0; volcano 1.2
|
||||
technology = FFF
|
||||
family = Voron Switchwire Mobius
|
||||
bed_model = printbed-SW-MK52.stl
|
||||
bed_texture = bedtexture-SW-250x210.png
|
||||
bed_with_grid = 1
|
||||
default_materials = Basic PLA @VORON; Basic PLA VOLCANO @VORON; Basic PET @VORON; Basic PET VOLCANO @VORON; Basic ABS @VORON; Basic ABS VOLCANO @VORON
|
||||
thumbnail = Voron_SW_thumbnail.png
|
||||
|
||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||
# not make it into the user interface
|
||||
|
||||
@ -310,6 +332,18 @@ max_print_height = 120
|
||||
printer_model = Voron_v0_120
|
||||
printer_notes = Unoffical profile.\nPRINTER_HAS_BOWDEN\nE3DV6
|
||||
|
||||
[printer:*Voron_Switchwire*]
|
||||
inherits = *common*
|
||||
bed_shape = 0x0,250x0,250x210,0x210
|
||||
max_print_height = 240
|
||||
printer_model = Voron_SW
|
||||
printer_notes = PRINTER_HAS_BOWDEN\nSTU\nE3DV6
|
||||
|
||||
[printer:*Voron_Switchwire_afterburner*]
|
||||
inherits = *Voron_Switchwire*; *afterburner*
|
||||
printer_model = Voron_SW_afterburner
|
||||
printer_notes = STU\nE3DV6
|
||||
|
||||
[printer:Voron_v2_250 0.25 nozzle]
|
||||
inherits = *Voron_v2_250*; *0.25nozzle*
|
||||
|
||||
@ -658,6 +692,89 @@ printer_variant = volcano 1.2
|
||||
printer_notes = Unoffical profile.\nPRINTER_HAS_BOWDEN\nVOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire 0.25 nozzle]
|
||||
inherits = *Voron_Switchwire*; *0.25nozzle*
|
||||
|
||||
[printer:Voron_Switchwire 0.3 nozzle]
|
||||
inherits = *Voron_Switchwire*; *0.3nozzle*
|
||||
|
||||
[printer:Voron_Switchwire 0.4 nozzle]
|
||||
inherits = *Voron_Switchwire*; *0.4nozzle*
|
||||
|
||||
[printer:Voron_Switchwire 0.5 nozzle]
|
||||
inherits = *Voron_Switchwire*; *0.5nozzle*
|
||||
|
||||
[printer:Voron_Switchwire 0.6 nozzle]
|
||||
inherits = *Voron_Switchwire*; *0.6nozzle*
|
||||
|
||||
[printer:Voron_Switchwire 0.8 nozzle]
|
||||
inherits = *Voron_Switchwire*; *0.8nozzle*
|
||||
|
||||
[printer:Voron_Switchwire 0.6 volcano]
|
||||
inherits = *Voron_Switchwire*; *0.6nozzle*; *volcano*
|
||||
printer_variant = volcano 0.6
|
||||
printer_notes = PRINTER_HAS_BOWDEN\nVOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire 0.8 volcano]
|
||||
inherits = *Voron_Switchwire*; *0.8nozzle*; *volcano*
|
||||
printer_variant = volcano 0.8
|
||||
printer_notes = PRINTER_HAS_BOWDEN\nVOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire 1.0 volcano]
|
||||
inherits = *Voron_Switchwire*; *1.0nozzle*; *volcano*
|
||||
printer_variant = volcano 1.0
|
||||
printer_notes = PRINTER_HAS_BOWDEN\nVOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire 1.2 volcano]
|
||||
inherits = *Voron_Switchwire*; *1.2nozzle*; *volcano*
|
||||
printer_variant = volcano 1.2
|
||||
printer_notes = PRINTER_HAS_BOWDEN\nVOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire_afterburner 0.25 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.25nozzle*
|
||||
|
||||
[printer:Voron_Switchwire_afterburner 0.3 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.3nozzle*
|
||||
|
||||
[printer:Voron_Switchwire_afterburner 0.4 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.4nozzle*
|
||||
|
||||
[printer:Voron_Switchwire_afterburner 0.5 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.5nozzle*
|
||||
|
||||
[printer:Voron_Switchwire_afterburner 0.6 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.6nozzle*
|
||||
|
||||
[printer:Voron_Switchwire_afterburner 0.8 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.8nozzle*
|
||||
|
||||
[printer:Voron_Switchwire_afterburner volcano 0.6 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.6nozzle*; *volcano_afterburner*
|
||||
printer_variant = volcano 0.6
|
||||
printer_notes = VOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire_afterburner volcano 0.8 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *0.8nozzle*; *volcano_afterburner*
|
||||
printer_variant = volcano 0.8
|
||||
printer_notes = VOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire_afterburner volcano 1.0 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *1.0nozzle*; *volcano_afterburner*
|
||||
printer_variant = volcano 1.0
|
||||
printer_notes = VOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
[printer:Voron_Switchwire_afterburner volcano 1.2 nozzle]
|
||||
inherits = *Voron_Switchwire_afterburner*; *1.2nozzle*; *volcano_afterburner*
|
||||
printer_variant = volcano 1.2
|
||||
printer_notes = VOLCANO
|
||||
default_filament_profile = Basic PLA VOLCANO @VORON
|
||||
|
||||
# Common print preset, mostly derived from MK2 single material with a 0.4mm nozzle.
|
||||
# All other print presets will derive from the *common* print preset.
|
||||
@ -1022,6 +1139,22 @@ compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diamete
|
||||
inherits = *0.05mm*; *0.5nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==0.5
|
||||
|
||||
[print:0.05mm 0.25nozzle SW]
|
||||
inherits = *0.05mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.25
|
||||
|
||||
[print:0.05mm 0.3nozzle SW]
|
||||
inherits = *0.05mm*; *0.3nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.3
|
||||
|
||||
[print:0.05mm 0.4nozzle SW]
|
||||
inherits = *0.05mm*; *0.4nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:0.05mm 0.5nozzle SW]
|
||||
inherits = *0.05mm*; *0.5nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.5
|
||||
|
||||
[print:0.10mm 0.25nozzle V2]
|
||||
inherits = *0.10mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v2.*/ and nozzle_diameter[0]==0.25
|
||||
@ -1094,6 +1227,30 @@ compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diamete
|
||||
inherits = *0.10mm*; *0.8nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==0.8
|
||||
|
||||
[print:0.10mm 0.25nozzle SW]
|
||||
inherits = *0.10mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.25
|
||||
|
||||
[print:0.10mm 0.3nozzle SW]
|
||||
inherits = *0.10mm*; *0.3nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.3
|
||||
|
||||
[print:0.10mm 0.4nozzle SW]
|
||||
inherits = *0.10mm*; *0.4nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:0.10mm 0.5nozzle SW]
|
||||
inherits = *0.10mm*; *0.5nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.5
|
||||
|
||||
[print:0.10mm 0.6nozzle SW]
|
||||
inherits = *0.10mm*; *0.6nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.6
|
||||
|
||||
[print:0.10mm 0.8nozzle SW]
|
||||
inherits = *0.10mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.8
|
||||
|
||||
[print:0.15mm 0.25nozzle V2]
|
||||
inherits = *0.15mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v2.*/ and nozzle_diameter[0]==0.25
|
||||
@ -1182,6 +1339,37 @@ compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diamete
|
||||
inherits = *0.15mm*; *1.2nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.15mm 0.25nozzle SW]
|
||||
inherits = *0.15mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.25
|
||||
|
||||
[print:0.15mm 0.3nozzle SW]
|
||||
inherits = *0.15mm*; *0.3nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.3
|
||||
|
||||
[print:0.15mm 0.4nozzle SW]
|
||||
inherits = *0.15mm*; *0.4nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:0.15mm 0.5nozzle SW]
|
||||
inherits = *0.15mm*; *0.5nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.5
|
||||
|
||||
[print:0.15mm 0.6nozzle SW]
|
||||
inherits = *0.15mm*; *0.6nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.6
|
||||
|
||||
[print:0.15mm 0.8nozzle SW]
|
||||
inherits = *0.15mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.8
|
||||
|
||||
[print:0.15mm 1.0nozzle SW]
|
||||
inherits = *0.15mm*; *1.0nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.0
|
||||
|
||||
[print:0.15mm 1.2nozzle SW]
|
||||
inherits = *0.15mm*; *1.2nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.2mm 0.3nozzle V2]
|
||||
inherits = *0.2mm*; *0.3nozzle*
|
||||
@ -1263,6 +1451,37 @@ compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diamete
|
||||
inherits = *0.2mm*; *1.2nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.2mm 0.25nozzle SW]
|
||||
inherits = *0.2mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.25
|
||||
|
||||
[print:0.2mm 0.3nozzle SW]
|
||||
inherits = *0.2mm*; *0.3nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.3
|
||||
|
||||
[print:0.2mm 0.4nozzle SW]
|
||||
inherits = *0.2mm*; *0.4nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:0.2mm 0.5nozzle SW]
|
||||
inherits = *0.2mm*; *0.5nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.5
|
||||
|
||||
[print:0.2mm 0.6nozzle SW]
|
||||
inherits = *0.2mm*; *0.6nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.6
|
||||
|
||||
[print:0.2mm 0.8nozzle SW]
|
||||
inherits = *0.2mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.8
|
||||
|
||||
[print:0.2mm 1.0nozzle SW]
|
||||
inherits = *0.2mm*; *1.0nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.0
|
||||
|
||||
[print:0.2mm 1.2nozzle SW]
|
||||
inherits = *0.2mm*; *1.2nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.3mm 0.4nozzle V2]
|
||||
inherits = *0.3mm*; *0.4nozzle*
|
||||
@ -1336,6 +1555,37 @@ compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diamete
|
||||
inherits = *0.3mm*; *1.2nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.3mm 0.25nozzle SW]
|
||||
inherits = *0.3mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.25
|
||||
|
||||
[print:0.3mm 0.3nozzle SW]
|
||||
inherits = *0.3mm*; *0.3nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.3
|
||||
|
||||
[print:0.3mm 0.4nozzle SW]
|
||||
inherits = *0.3mm*; *0.4nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:0.3mm 0.5nozzle SW]
|
||||
inherits = *0.3mm*; *0.5nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.5
|
||||
|
||||
[print:0.3mm 0.6nozzle SW]
|
||||
inherits = *0.3mm*; *0.6nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.6
|
||||
|
||||
[print:0.3mm 0.8nozzle SW]
|
||||
inherits = *0.3mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.8
|
||||
|
||||
[print:0.3mm 1.0nozzle SW]
|
||||
inherits = *0.3mm*; *1.0nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.0
|
||||
|
||||
[print:0.3mm 1.2nozzle SW]
|
||||
inherits = *0.3mm*; *1.2nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.4mm 0.6nozzle V2]
|
||||
inherits = *0.4mm*; *0.6nozzle*
|
||||
@ -1393,6 +1643,38 @@ compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diamete
|
||||
inherits = *0.4mm*; *1.2nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.4mm 0.25nozzle SW]
|
||||
inherits = *0.4mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.25
|
||||
|
||||
[print:0.4mm 0.3nozzle SW]
|
||||
inherits = *0.4mm*; *0.3nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.3
|
||||
|
||||
[print:0.4mm 0.4nozzle SW]
|
||||
inherits = *0.4mm*; *0.4nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.4
|
||||
|
||||
[print:0.4mm 0.5nozzle SW]
|
||||
inherits = *0.4mm*; *0.5nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.5
|
||||
|
||||
[print:0.4mm 0.6nozzle SW]
|
||||
inherits = *0.4mm*; *0.6nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.6
|
||||
|
||||
[print:0.4mm 0.8nozzle SW]
|
||||
inherits = *0.4mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.8
|
||||
|
||||
[print:0.4mm 1.0nozzle SW]
|
||||
inherits = *0.4mm*; *1.0nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.0
|
||||
|
||||
[print:0.4mm 1.2nozzle SW]
|
||||
inherits = *0.4mm*; *1.2nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.6mm 0.8nozzle V2]
|
||||
inherits = *0.6mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v2.*/ and nozzle_diameter[0]==0.8
|
||||
@ -1429,6 +1711,18 @@ compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diamete
|
||||
inherits = *0.6mm*; *1.2nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.6mm 0.8nozzle SW]
|
||||
inherits = *0.6mm*; *0.6nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==0.8
|
||||
|
||||
[print:0.6mm 1.0nozzle SW]
|
||||
inherits = *0.6mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.0
|
||||
|
||||
[print:0.6mm 1.2nozzle SW]
|
||||
inherits = *0.6mm*; *0.8nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.8mm 1.2nozzle V2]
|
||||
inherits = *0.8mm*; *1.2nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v2.*/ and nozzle_diameter[0]==1.2
|
||||
@ -1441,6 +1735,10 @@ compatible_printers_condition = printer_model=~/.*Voron_v1.*/ and nozzle_diamete
|
||||
inherits = *0.8mm*; *1.2nozzle*; *zero_toolhead*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_v0.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
[print:0.8mm 1.2nozzle SW]
|
||||
inherits = *0.8mm*; *1.2nozzle*
|
||||
compatible_printers_condition = printer_model=~/.*Voron_SW.*/ and nozzle_diameter[0]==1.2
|
||||
|
||||
|
||||
[filament:*common*]
|
||||
cooling = 1
|
||||
|
BIN
resources/profiles/Voron/Voron_SW_thumbnail.png
Normal file
BIN
resources/profiles/Voron/Voron_SW_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
resources/profiles/Voron/bedtexture-SW-250x210.png
Normal file
BIN
resources/profiles/Voron/bedtexture-SW-250x210.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 460 KiB |
BIN
resources/profiles/Voron/printbed-SW-MK52.stl
Normal file
BIN
resources/profiles/Voron/printbed-SW-MK52.stl
Normal file
Binary file not shown.
7
src/ankerl/README.txt
Normal file
7
src/ankerl/README.txt
Normal file
@ -0,0 +1,7 @@
|
||||
THIS DIRECTORY CONTAINS PIECES OF THE
|
||||
ankerl::unordered_dense::{map, set}
|
||||
https://github.com/martinus/unordered_dense
|
||||
unordered_dense 3.1.1 10782bfc651c2bb75b11bf90491f50da122e5432
|
||||
SOURCE DISTRIBUTION.
|
||||
|
||||
THIS IS NOT THE COMPLETE unordered_dense DISTRIBUTION. ONLY FILES NEEDED FOR COMPILING PRUSASLICER WERE PUT INTO THE PRUSASLICER SOURCE DISTRIBUTION.
|
1584
src/ankerl/unordered_dense.h
Normal file
1584
src/ankerl/unordered_dense.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -206,7 +206,7 @@ std::vector<WaveSeed> wave_seeds(
|
||||
{
|
||||
assert(tiny_expansion > 0);
|
||||
|
||||
if (src.empty())
|
||||
if (src.empty() || boundary.empty())
|
||||
return {};
|
||||
|
||||
using Intersection = ClipperZUtils::ClipperZIntersectionVisitor::Intersection;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "ShortestPath.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
// #define CLIPPER_UTILS_DEBUG
|
||||
|
||||
@ -1167,34 +1168,45 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v
|
||||
return out;
|
||||
}
|
||||
|
||||
Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||
static void variable_offset_inner_raw(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit, ClipperLib::Paths &contours, ClipperLib::Paths &holes)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Verify that the deltas are all non positive.
|
||||
for (const std::vector<float> &ds : deltas)
|
||||
for (float delta : ds)
|
||||
assert(delta <= 0.);
|
||||
assert(expoly.holes.size() + 1 == deltas.size());
|
||||
// Verify that the deltas are all non positive.
|
||||
for (const std::vector<float> &ds : deltas)
|
||||
for (float delta : ds)
|
||||
assert(delta <= 0.);
|
||||
assert(expoly.holes.size() + 1 == deltas.size());
|
||||
assert(ClipperLib::Area(expoly.contour.points) > 0.);
|
||||
for (auto &h : expoly.holes)
|
||||
assert(ClipperLib::Area(h.points) < 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
// 1) Offset the outer contour.
|
||||
contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
|
||||
#ifndef NDEBUG
|
||||
// Shrinking a contour may split it into pieces, but never create a new hole inside the contour.
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
|
||||
#ifndef NDEBUG
|
||||
// Offsetting a hole curve of a C shape may close the C into a ring with a new hole inside, thus creating a hole inside a hole shape, thus a hole will be created with negative area
|
||||
// and the following test will fail.
|
||||
// for (auto &c : holes)
|
||||
// assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
}
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||
{
|
||||
ClipperLib::Paths contours, holes;
|
||||
variable_offset_inner_raw(expoly, deltas, miter_limit, contours, holes);
|
||||
|
||||
// Subtract holes from the contours.
|
||||
ClipperLib::Paths output;
|
||||
if (holes.empty())
|
||||
output = std::move(contours);
|
||||
@ -1202,6 +1214,8 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.Clear();
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
// Holes may contain holes in holes produced by expanding a C hole shape.
|
||||
// The situation is processed correctly by Clipper diff operation.
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
@ -1209,129 +1223,120 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
|
||||
return to_polygons(std::move(output));
|
||||
}
|
||||
|
||||
ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||
{
|
||||
ClipperLib::Paths contours, holes;
|
||||
variable_offset_inner_raw(expoly, deltas, miter_limit, contours, holes);
|
||||
|
||||
// Subtract holes from the contours.
|
||||
ExPolygons output;
|
||||
if (holes.empty()) {
|
||||
output.reserve(contours.size());
|
||||
// Shrinking a CCW contour may only produce more CCW contours, but never new holes.
|
||||
for (ClipperLib::Path &path : contours)
|
||||
output.emplace_back(std::move(path));
|
||||
} else {
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
// Holes may contain holes in holes produced by expanding a C hole shape.
|
||||
// The situation is processed correctly by Clipper diff operation, producing concentric expolygons.
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::PolyTree polytree;
|
||||
clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
output = PolyTreeToExPolygons(std::move(polytree));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static void variable_offset_outer_raw(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit, ClipperLib::Paths &contours, ClipperLib::Paths &holes)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Verify that the deltas are all non positive.
|
||||
for (const std::vector<float> &ds : deltas)
|
||||
for (float delta : ds)
|
||||
assert(delta >= 0.);
|
||||
assert(expoly.holes.size() + 1 == deltas.size());
|
||||
assert(ClipperLib::Area(expoly.contour.points) > 0.);
|
||||
for (auto &h : expoly.holes)
|
||||
assert(ClipperLib::Area(h.points) < 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 1) Offset the outer contour.
|
||||
contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
|
||||
// Inflating a contour must not remove it.
|
||||
assert(contours.size() >= 1);
|
||||
#ifndef NDEBUG
|
||||
// Offsetting a positive curve of a C shape may close the C into a ring with hole shape, thus a hole will be created with negative area
|
||||
// and the following test will fail.
|
||||
// for (auto &c : contours)
|
||||
// assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
|
||||
#ifndef NDEBUG
|
||||
// Shrinking a hole may split it into pieces, but never create a new hole inside a hole.
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
}
|
||||
|
||||
Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Verify that the deltas are all non positive.
|
||||
for (const std::vector<float>& ds : deltas)
|
||||
for (float delta : ds)
|
||||
assert(delta >= 0.);
|
||||
assert(expoly.holes.size() + 1 == deltas.size());
|
||||
#endif /* NDEBUG */
|
||||
ClipperLib::Paths contours, holes;
|
||||
variable_offset_outer_raw(expoly, deltas, miter_limit, contours, holes);
|
||||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
// Subtract holes from the contours.
|
||||
ClipperLib::Paths output;
|
||||
if (holes.empty())
|
||||
output = std::move(contours);
|
||||
else {
|
||||
//FIXME the difference is not needed as the holes may never intersect with other holes.
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.Clear();
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
ClipperLib::Paths output;
|
||||
if (holes.empty())
|
||||
output = std::move(contours);
|
||||
else {
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.Clear();
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
|
||||
return to_polygons(std::move(output));
|
||||
return to_polygons(std::move(output));
|
||||
}
|
||||
|
||||
ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Verify that the deltas are all non positive.
|
||||
for (const std::vector<float>& ds : deltas)
|
||||
for (float delta : ds)
|
||||
assert(delta >= 0.);
|
||||
assert(expoly.holes.size() + 1 == deltas.size());
|
||||
#endif /* NDEBUG */
|
||||
ClipperLib::Paths contours, holes;
|
||||
variable_offset_outer_raw(expoly, deltas, miter_limit, contours, holes);
|
||||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
// Subtract holes from the contours.
|
||||
ExPolygons output;
|
||||
if (holes.empty()) {
|
||||
output.reserve(contours.size());
|
||||
for (ClipperLib::Path &path : contours)
|
||||
output.emplace_back(std::move(path));
|
||||
} else {
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::PolyTree polytree;
|
||||
clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
output = PolyTreeToExPolygons(std::move(polytree));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Verify that the deltas are all non positive.
|
||||
for (const std::vector<float>& ds : deltas)
|
||||
for (float delta : ds)
|
||||
assert(delta <= 0.);
|
||||
assert(expoly.holes.size() + 1 == deltas.size());
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
ExPolygons output;
|
||||
if (holes.empty()) {
|
||||
output.reserve(contours.size());
|
||||
for (ClipperLib::Path &path : contours)
|
||||
output.emplace_back(std::move(path));
|
||||
output.reserve(1);
|
||||
if (contours.size() > 1) {
|
||||
// One expolygon with holes created by closing a C shape. Which is which?
|
||||
output.push_back({});
|
||||
ExPolygon &out = output.back();
|
||||
out.holes.reserve(contours.size() - 1);
|
||||
for (ClipperLib::Path &path : contours) {
|
||||
if (ClipperLib::Area(path) > 0) {
|
||||
// Only one contour with positive area is expected to be created by an outer offset of an ExPolygon.
|
||||
assert(out.contour.empty());
|
||||
out.contour.points = std::move(path);
|
||||
} else
|
||||
out.holes.push_back(Polygon{ std::move(path) });
|
||||
}
|
||||
} else {
|
||||
// Single contour must be CCW.
|
||||
assert(contours.size() == 1);
|
||||
assert(ClipperLib::Area(contours.front()) > 0);
|
||||
output.push_back(ExPolygon{ std::move(contours.front()) });
|
||||
}
|
||||
} else {
|
||||
//FIXME the difference is not needed as the holes may never intersect with other holes.
|
||||
ClipperLib::Clipper clipper;
|
||||
// Contours may have holes if they were created by closing a C shape.
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::PolyTree polytree;
|
||||
@ -1339,6 +1344,7 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
|
||||
output = PolyTreeToExPolygons(std::move(polytree));
|
||||
}
|
||||
|
||||
assert(output.size() == 1);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -597,7 +597,8 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_c
|
||||
}
|
||||
|
||||
ExPolygons out_vec = variable_offset_inner_ex(resampled, deltas, 2.);
|
||||
if (out_vec.size() == 1)
|
||||
if (out_vec.size() == 1 && out_vec.front().holes.size() == resampled.holes.size())
|
||||
// No contour of the original compensated expolygon was lost.
|
||||
out = std::move(out_vec.front());
|
||||
else {
|
||||
// Something went wrong, don't compensate.
|
||||
@ -610,6 +611,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_c
|
||||
{ { out_vec }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } } });
|
||||
}
|
||||
#endif /* TESTS_EXPORT_SVGS */
|
||||
// It may be that the source expolygons contained non-manifold vertices, for which the variable offset may not produce the same number of contours or holes.
|
||||
assert(out_vec.size() == 1);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void ExPolygon::scale(double factor)
|
||||
@ -416,20 +418,36 @@ bool has_duplicate_points(const ExPolygons &expolys)
|
||||
{
|
||||
#if 1
|
||||
// Check globally.
|
||||
size_t cnt = 0;
|
||||
for (const ExPolygon &expoly : expolys) {
|
||||
cnt += expoly.contour.points.size();
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
cnt += hole.points.size();
|
||||
}
|
||||
#if 0
|
||||
// Detect duplicates by sorting with quicksort. It is quite fast, but ankerl::unordered_dense is around 1/4 faster.
|
||||
std::vector<Point> allpts;
|
||||
allpts.reserve(cnt);
|
||||
allpts.reserve(count_points(expolys));
|
||||
for (const ExPolygon &expoly : expolys) {
|
||||
allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end());
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
allpts.insert(allpts.end(), hole.points.begin(), hole.points.end());
|
||||
}
|
||||
return has_duplicate_points(std::move(allpts));
|
||||
#else
|
||||
// Detect duplicates by inserting into an ankerl::unordered_dense hash set, which is is around 1/4 faster than qsort.
|
||||
struct PointHash {
|
||||
uint64_t operator()(const Point &p) const noexcept {
|
||||
uint64_t h;
|
||||
static_assert(sizeof(h) == sizeof(p));
|
||||
memcpy(&h, &p, sizeof(p));
|
||||
return ankerl::unordered_dense::detail::wyhash::hash(h);
|
||||
}
|
||||
};
|
||||
ankerl::unordered_dense::set<Point, PointHash> allpts;
|
||||
allpts.reserve(count_points(expolys));
|
||||
for (const ExPolygon &expoly : expolys)
|
||||
for (size_t icontour = 0; icontour < expoly.num_contours(); ++ icontour)
|
||||
for (const Point &pt : expoly.contour_or_hole(icontour).points)
|
||||
if (! allpts.insert(pt).second)
|
||||
// Duplicate point was discovered.
|
||||
return true;
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
// Check per contour.
|
||||
for (const ExPolygon &expoly : expolys)
|
||||
|
@ -2354,11 +2354,10 @@ void GCode::process_layer_single_object(
|
||||
// Round 1 (wiping into object or infill) or round 2 (normal extrusions).
|
||||
const bool print_wipe_extrusions)
|
||||
{
|
||||
//FIXME what the heck ID is this? Layer ID or Object ID? More likely an Object ID.
|
||||
uint32_t layer_id = 0;
|
||||
bool first = true;
|
||||
bool first = true;
|
||||
int object_id = 0;
|
||||
// Delay layer initialization as many layers may not print with all extruders.
|
||||
auto init_layer_delayed = [this, &print_instance, &layer_to_print, layer_id, &first, &gcode]() {
|
||||
auto init_layer_delayed = [this, &print_instance, &layer_to_print, &first, &object_id, &gcode]() {
|
||||
if (first) {
|
||||
first = false;
|
||||
const PrintObject &print_object = print_instance.print_object;
|
||||
@ -2374,8 +2373,14 @@ void GCode::process_layer_single_object(
|
||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
m_last_obj_copy = this_object_copy;
|
||||
this->set_origin(unscale(offset));
|
||||
if (this->config().gcode_label_objects)
|
||||
gcode += std::string("; printing object ") + print_object.model_object()->name + " id:" + std::to_string(layer_id) + " copy " + std::to_string(print_instance.instance_id) + "\n";
|
||||
if (this->config().gcode_label_objects) {
|
||||
for (const PrintObject *po : print_object.print()->objects())
|
||||
if (po == &print_object)
|
||||
break;
|
||||
else
|
||||
++ object_id;
|
||||
gcode += std::string("; printing object ") + print_object.model_object()->name + " id:" + std::to_string(object_id) + " copy " + std::to_string(print_instance.instance_id) + "\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -2548,7 +2553,7 @@ void GCode::process_layer_single_object(
|
||||
}
|
||||
}
|
||||
if (! first && this->config().gcode_label_objects)
|
||||
gcode += std::string("; stop printing object ") + print_object.model_object()->name + " id:" + std::to_string(layer_id) + " copy " + std::to_string(print_instance.instance_id) + "\n";
|
||||
gcode += std::string("; stop printing object ") + print_object.model_object()->name + " id:" + std::to_string(object_id) + " copy " + std::to_string(print_instance.instance_id) + "\n";
|
||||
}
|
||||
|
||||
void GCode::apply_print_config(const PrintConfig &print_config)
|
||||
@ -3020,9 +3025,16 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
{100, ConfigOptionInts{0}}};
|
||||
}
|
||||
|
||||
double external_perim_reference_speed = std::min(m_config.get_abs_value("external_perimeter_speed"),
|
||||
std::min(EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm,
|
||||
m_config.max_volumetric_speed.value / path.mm3_per_mm));
|
||||
double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed");
|
||||
if (external_perim_reference_speed == 0)
|
||||
external_perim_reference_speed = m_volumetric_speed / path.mm3_per_mm;
|
||||
if (m_config.max_volumetric_speed.value > 0)
|
||||
external_perim_reference_speed = std::min(external_perim_reference_speed, m_config.max_volumetric_speed.value / path.mm3_per_mm);
|
||||
if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
|
||||
external_perim_reference_speed = std::min(external_perim_reference_speed,
|
||||
EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm);
|
||||
}
|
||||
|
||||
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, overhangs_with_speeds, overhang_w_fan_speeds,
|
||||
m_writer.extruder()->id(), external_perim_reference_speed,
|
||||
speed);
|
||||
|
@ -272,6 +272,7 @@ public:
|
||||
float distance = path.width * (1.0 - (overhangs_w_speeds[i].first / 100.0));
|
||||
float speed = overhangs_w_speeds[i].second.percent ? (speed_base * overhangs_w_speeds[i].second.value / 100.0) :
|
||||
overhangs_w_speeds[i].second.value;
|
||||
if (speed < EPSILON) speed = speed_base;
|
||||
speed_sections[distance] = speed;
|
||||
}
|
||||
|
||||
|
@ -3566,7 +3566,7 @@ void GCodeProcessor::post_process()
|
||||
++m_curr_g1_id;
|
||||
}
|
||||
|
||||
if (it != init_it || m_curr_g1_id == 0)
|
||||
if ((it != m_machine.g1_times_cache.end() && it != init_it) || m_curr_g1_id == 0)
|
||||
m_time = it->elapsed_time;
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,7 @@ Slic3r::Pointfs Slic3r::intersection_points(const ExPolygons &expolygons)
|
||||
#include <libslic3r/BoundingBox.hpp>
|
||||
|
||||
namespace priv {
|
||||
//FIXME O(n^2) complexity!
|
||||
Slic3r::Pointfs compute_intersections(const Slic3r::Lines &lines)
|
||||
{
|
||||
using namespace Slic3r;
|
||||
|
@ -6,6 +6,7 @@
|
||||
namespace Slic3r {
|
||||
|
||||
// collect all intersecting points
|
||||
//FIXME O(n^2) complexity!
|
||||
Pointfs intersection_points(const Lines &lines);
|
||||
Pointfs intersection_points(const Polygon &polygon);
|
||||
Pointfs intersection_points(const Polygons &polygons);
|
||||
|
@ -60,7 +60,10 @@ void Layer::make_slices()
|
||||
}
|
||||
|
||||
// used by Layer::build_up_down_graph()
|
||||
[[nodiscard]] static ClipperLib_Z::Paths expolygons_to_zpaths(const ExPolygons &expolygons, coord_t isrc)
|
||||
// Shrink source polygons one by one, so that they will be separated if they were touching
|
||||
// at vertices (non-manifold situation).
|
||||
// Then convert them to Z-paths with Z coordinate indicating index of the source expolygon.
|
||||
[[nodiscard]] static ClipperLib_Z::Paths expolygons_to_zpaths_shrunk(const ExPolygons &expolygons, coord_t isrc)
|
||||
{
|
||||
size_t num_paths = 0;
|
||||
for (const ExPolygon &expolygon : expolygons)
|
||||
@ -69,14 +72,49 @@ void Layer::make_slices()
|
||||
ClipperLib_Z::Paths out;
|
||||
out.reserve(num_paths);
|
||||
|
||||
for (const ExPolygon &expolygon : expolygons) {
|
||||
for (size_t icontour = 0; icontour < expolygon.num_contours(); ++ icontour) {
|
||||
const Polygon &contour = expolygon.contour_or_hole(icontour);
|
||||
out.emplace_back();
|
||||
ClipperLib_Z::Path &path = out.back();
|
||||
path.reserve(contour.size());
|
||||
for (const Point &p : contour.points)
|
||||
path.push_back({ p.x(), p.y(), isrc });
|
||||
ClipperLib::Paths contours;
|
||||
ClipperLib::Paths holes;
|
||||
ClipperLib::Clipper clipper;
|
||||
ClipperLib::ClipperOffset co;
|
||||
ClipperLib::Paths out2;
|
||||
|
||||
static constexpr const float delta = ClipperSafetyOffset; // *10.f;
|
||||
co.MiterLimit = scaled<double>(3.);
|
||||
// Use the default zero edge merging distance. For this kind of safety offset the accuracy of normal direction is not important.
|
||||
// co.ShortestEdgeLength = delta * ClipperOffsetShortestEdgeFactor;
|
||||
|
||||
for (const ExPolygon &expoly : expolygons) {
|
||||
contours.clear();
|
||||
co.Clear();
|
||||
co.AddPath(expoly.contour.points, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
|
||||
co.Execute(contours, - delta);
|
||||
if (! contours.empty()) {
|
||||
holes.clear();
|
||||
for (const Polygon &hole : expoly.holes) {
|
||||
co.Clear();
|
||||
co.AddPath(hole.points, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
|
||||
// Execute reorients the contours so that the outer most contour has a positive area. Thus the output
|
||||
// contours will be CCW oriented even though the input paths are CW oriented.
|
||||
// Offset is applied after contour reorientation, thus the signum of the offset value is reversed.
|
||||
out2.clear();
|
||||
co.Execute(out2, delta);
|
||||
append(holes, std::move(out2));
|
||||
}
|
||||
// Subtract holes from the contours.
|
||||
if (! holes.empty()) {
|
||||
clipper.Clear();
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
contours.clear();
|
||||
clipper.Execute(ClipperLib::ctDifference, contours, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
for (const auto &contour : contours) {
|
||||
out.emplace_back();
|
||||
ClipperLib_Z::Path &path = out.back();
|
||||
path.reserve(contour.size());
|
||||
for (const Point &p : contour)
|
||||
path.push_back({ p.x(), p.y(), isrc });
|
||||
}
|
||||
}
|
||||
++ isrc;
|
||||
}
|
||||
@ -183,6 +221,10 @@ static void connect_layer_slices(
|
||||
break;
|
||||
}
|
||||
}
|
||||
//FIXME remove the following block one day, it should not be needed.
|
||||
// The following shall not happen now as the source expolygons are being shrunk a bit before intersecting,
|
||||
// thus each point of each intersection polygon should fit completely inside one of the original (unshrunk) expolygons.
|
||||
assert(found);
|
||||
if (!found) {
|
||||
// The check above might sometimes fail when the polygons overlap only on points, which causes the clipper to detect no intersection.
|
||||
// The problem happens rarely, mostly on simple polygons (in terms of number of points), but regardless of size!
|
||||
@ -191,10 +233,7 @@ static void connect_layer_slices(
|
||||
// layer B = Polygon{(-24877897,-11100524),(-22504249,-8726874),(-22504249,11477151),(-23244827,12218916),(-23752371,12727276),(-25002495,12727276),(-27502745,10227026),(-27502745,-12727274),(-26504645,-12727274)}
|
||||
// note that first point is not identical, and the check above picks (-24877897,-11100524) as the first contour point (polynode.Contour.front()).
|
||||
// that point is sadly slightly outisde of the layer A, so no link is detected, eventhough they are overlaping "completely"
|
||||
Polygon contour_poly;
|
||||
for (const auto& p : polynode.Contour) {
|
||||
contour_poly.points.emplace_back(p.x(), p.y());
|
||||
}
|
||||
Polygon contour_poly(ClipperZUtils::from_zpath(polynode.Contour));
|
||||
BoundingBox contour_aabb{contour_poly.points};
|
||||
for (int l = int(m_above.lslices_ex.size()) - 1; l >= 0; --l) {
|
||||
LayerSlice &lslice = m_above.lslices_ex[l];
|
||||
@ -222,11 +261,11 @@ static void connect_layer_slices(
|
||||
break;
|
||||
}
|
||||
}
|
||||
//FIXME remove the following block one day, it should not be needed.
|
||||
// The following shall not happen now as the source expolygons are being shrunk a bit before intersecting,
|
||||
// thus each point of each intersection polygon should fit completely inside one of the original (unshrunk) expolygons.
|
||||
if (!found) { // Explanation for aditional check is above.
|
||||
Polygon contour_poly;
|
||||
for (const auto &p : polynode.Contour) {
|
||||
contour_poly.points.emplace_back(p.x(), p.y());
|
||||
}
|
||||
Polygon contour_poly(ClipperZUtils::from_zpath(polynode.Contour));
|
||||
BoundingBox contour_aabb{contour_poly.points};
|
||||
for (int l = int(m_below.lslices_ex.size()) - 1; l >= 0; --l) {
|
||||
LayerSlice &lslice = m_below.lslices_ex[l];
|
||||
@ -249,6 +288,8 @@ static void connect_layer_slices(
|
||||
found = true;
|
||||
}
|
||||
if (found) {
|
||||
assert(i >= 0 && i < m_below.lslices_ex.size());
|
||||
assert(j >= 0 && j < m_above.lslices_ex.size());
|
||||
// Subtract area of holes from the area of outer contour.
|
||||
double area = ClipperLib_Z::Area(polynode.Contour);
|
||||
for (int icontour = 0; icontour < polynode.ChildCount(); ++ icontour)
|
||||
@ -340,9 +381,9 @@ static void connect_layer_slices(
|
||||
void Layer::build_up_down_graph(Layer& below, Layer& above)
|
||||
{
|
||||
coord_t paths_below_offset = 0;
|
||||
ClipperLib_Z::Paths paths_below = expolygons_to_zpaths(below.lslices, paths_below_offset);
|
||||
ClipperLib_Z::Paths paths_below = expolygons_to_zpaths_shrunk(below.lslices, paths_below_offset);
|
||||
coord_t paths_above_offset = paths_below_offset + coord_t(below.lslices.size());
|
||||
ClipperLib_Z::Paths paths_above = expolygons_to_zpaths(above.lslices, paths_above_offset);
|
||||
ClipperLib_Z::Paths paths_above = expolygons_to_zpaths_shrunk(above.lslices, paths_above_offset);
|
||||
#ifndef NDEBUG
|
||||
coord_t paths_end = paths_above_offset + coord_t(above.lslices.size());
|
||||
#endif // NDEBUG
|
||||
|
@ -837,13 +837,10 @@ ModelInstance* ModelObject::add_instance(const ModelInstance &other)
|
||||
return i;
|
||||
}
|
||||
|
||||
ModelInstance* ModelObject::add_instance(const Vec3d &offset, const Vec3d &scaling_factor, const Vec3d &rotation, const Vec3d &mirror)
|
||||
ModelInstance* ModelObject::add_instance(const Geometry::Transformation& trafo)
|
||||
{
|
||||
auto *instance = add_instance();
|
||||
instance->set_offset(offset);
|
||||
instance->set_scaling_factor(scaling_factor);
|
||||
instance->set_rotation(rotation);
|
||||
instance->set_mirror(mirror);
|
||||
ModelInstance* instance = add_instance();
|
||||
instance->set_transformation(trafo);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
@ -393,7 +393,7 @@ public:
|
||||
|
||||
ModelInstance* add_instance();
|
||||
ModelInstance* add_instance(const ModelInstance &instance);
|
||||
ModelInstance* add_instance(const Vec3d &offset, const Vec3d &scaling_factor, const Vec3d &rotation, const Vec3d &mirror);
|
||||
ModelInstance* add_instance(const Geometry::Transformation& trafo);
|
||||
void delete_instance(size_t idx);
|
||||
void delete_last_instance();
|
||||
void clear_instances();
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
double Polygon::length() const
|
||||
@ -400,14 +402,32 @@ bool has_duplicate_points(const Polygons &polys)
|
||||
{
|
||||
#if 1
|
||||
// Check globally.
|
||||
size_t cnt = 0;
|
||||
for (const Polygon &poly : polys)
|
||||
cnt += poly.points.size();
|
||||
#if 0
|
||||
// Detect duplicates by sorting with quicksort. It is quite fast, but ankerl::unordered_dense is around 1/4 faster.
|
||||
std::vector<Point> allpts;
|
||||
allpts.reserve(cnt);
|
||||
allpts.reserve(count_points(polys));
|
||||
for (const Polygon &poly : polys)
|
||||
allpts.insert(allpts.end(), poly.points.begin(), poly.points.end());
|
||||
return has_duplicate_points(std::move(allpts));
|
||||
#else
|
||||
// Detect duplicates by inserting into an ankerl::unordered_dense hash set, which is is around 1/4 faster than qsort.
|
||||
struct PointHash {
|
||||
uint64_t operator()(const Point &p) const noexcept {
|
||||
uint64_t h;
|
||||
static_assert(sizeof(h) == sizeof(p));
|
||||
memcpy(&h, &p, sizeof(p));
|
||||
return ankerl::unordered_dense::detail::wyhash::hash(h);
|
||||
}
|
||||
};
|
||||
ankerl::unordered_dense::set<Point, PointHash> allpts;
|
||||
allpts.reserve(count_points(polys));
|
||||
for (const Polygon &poly : polys)
|
||||
for (const Point &pt : poly.points)
|
||||
if (! allpts.insert(pt).second)
|
||||
// Duplicate point was discovered.
|
||||
return true;
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
// Check per contour.
|
||||
for (const Polygon &poly : polys)
|
||||
|
@ -518,8 +518,12 @@ std::string Print::validate(std::string* warning) const
|
||||
//FIXME It is quite expensive to generate object layers just to get the print height!
|
||||
if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx));
|
||||
! layers.empty() && layers.back() > this->config().max_print_height + EPSILON) {
|
||||
return _u8L("The print is taller than the maximum allowed height. You might want to reduce the size of your model"
|
||||
" or change current print settings and retry.");
|
||||
return
|
||||
// Test whether the last slicing plane is below or above the print volume.
|
||||
0.5 * (layers[layers.size() - 2] + layers.back()) > this->config().max_print_height + EPSILON ?
|
||||
format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name) :
|
||||
format(_u8L("While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height."), print_object.model_object()->name) +
|
||||
" " + _u8L("You might want to reduce the size of your model or change current print settings and retry.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2908,7 +2908,8 @@ void PrintConfigDef::init_fff_params()
|
||||
// TRN PrintSettings: "Organic supports" > "Tip Diameter"
|
||||
def->tooltip = L("Branch tip diameter for organic supports.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->min = 0.1f;
|
||||
def->max = 100.f;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.8));
|
||||
|
||||
@ -2919,7 +2920,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("The diameter of the thinnest branches of organic support. Thicker branches are more sturdy. "
|
||||
"Branches towards the base will be thicker than this.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->min = 0.1f;
|
||||
def->max = 100.f;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(2));
|
||||
|
||||
|
@ -44,7 +44,7 @@ enum class MachineLimitsUsage {
|
||||
};
|
||||
|
||||
enum PrintHostType {
|
||||
htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htMainSail
|
||||
htPrusaLink, htPrusaConnect, htOctoPrint, htMainSail, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS
|
||||
};
|
||||
|
||||
enum AuthorizationType {
|
||||
|
@ -102,7 +102,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transfor
|
||||
m_center_offset = Point::new_scale(bbox_center.x(), bbox_center.y());
|
||||
// Size of the transformed mesh. This bounding may not be snug in XY plane, but it is snug in Z.
|
||||
m_size = (bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
|
||||
m_size.z() = model_object->max_z();
|
||||
m_size.z() = coord_t(model_object->max_z() * (1. / SCALING_FACTOR));
|
||||
|
||||
this->set_instances(std::move(instances));
|
||||
}
|
||||
@ -1603,21 +1603,18 @@ void PrintObject::bridge_over_infill()
|
||||
int layer_index,
|
||||
Polygons new_polys,
|
||||
const LayerRegion *region,
|
||||
double bridge_angle,
|
||||
bool supported_by_lightning)
|
||||
double bridge_angle)
|
||||
: original_surface(original_surface)
|
||||
, layer_index(layer_index)
|
||||
, new_polys(new_polys)
|
||||
, region(region)
|
||||
, bridge_angle(bridge_angle)
|
||||
, supported_by_lightning(supported_by_lightning)
|
||||
{}
|
||||
const Surface *original_surface;
|
||||
int layer_index;
|
||||
Polygons new_polys;
|
||||
const LayerRegion *region;
|
||||
double bridge_angle;
|
||||
bool supported_by_lightning;
|
||||
};
|
||||
|
||||
std::map<size_t, std::vector<CandidateSurface>> surfaces_by_layer;
|
||||
@ -1677,7 +1674,7 @@ void PrintObject::bridge_over_infill()
|
||||
}
|
||||
}
|
||||
worth_bridging = intersection(closing(worth_bridging, SCALED_EPSILON), s->expolygon);
|
||||
candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0, contains_only_lightning));
|
||||
candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0));
|
||||
|
||||
#ifdef DEBUG_BRIDGE_OVER_INFILL
|
||||
debug_draw(std::to_string(lidx) + "_candidate_surface_" + std::to_string(area(s->expolygon)),
|
||||
@ -2135,6 +2132,7 @@ void PrintObject::bridge_over_infill()
|
||||
deep_infill_area = expand(deep_infill_area, spacing * 1.5);
|
||||
|
||||
// Now gather expansion polygons - internal infill on current layer, from which we can cut off anchors
|
||||
Polygons lightning_area;
|
||||
Polygons expansion_area;
|
||||
Polygons total_fill_area;
|
||||
for (const LayerRegion *region : layer->regions()) {
|
||||
@ -2142,6 +2140,10 @@ void PrintObject::bridge_over_infill()
|
||||
expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end());
|
||||
Polygons fill_polys = to_polygons(region->fill_expolygons());
|
||||
total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end());
|
||||
if (region->region().config().fill_pattern == ipLightning) {
|
||||
Polygons l = to_polygons(region->fill_surfaces().filter_by_type(stInternal));
|
||||
lightning_area.insert(lightning_area.end(), l.begin(), l.end());
|
||||
}
|
||||
}
|
||||
total_fill_area = closing(total_fill_area, SCALED_EPSILON);
|
||||
expansion_area = closing(expansion_area, SCALED_EPSILON);
|
||||
@ -2196,7 +2198,7 @@ void PrintObject::bridge_over_infill()
|
||||
}
|
||||
|
||||
boundary_plines.insert(boundary_plines.end(), anchors.begin(), anchors.end());
|
||||
if (candidate.supported_by_lightning) {
|
||||
if (!lightning_area.empty() && !intersection(area_to_be_bridge, lightning_area).empty()) {
|
||||
boundary_plines = intersection_pl(boundary_plines, expand(area_to_be_bridge, scale_(10)));
|
||||
}
|
||||
Polygons bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle);
|
||||
@ -2229,7 +2231,7 @@ void PrintObject::bridge_over_infill()
|
||||
#endif
|
||||
|
||||
expanded_surfaces.push_back(CandidateSurface(candidate.original_surface, candidate.layer_index, bridging_area,
|
||||
candidate.region, bridging_angle, candidate.supported_by_lightning));
|
||||
candidate.region, bridging_angle));
|
||||
}
|
||||
surfaces_by_layer[lidx].swap(expanded_surfaces);
|
||||
expanded_surfaces.clear();
|
||||
|
@ -257,6 +257,8 @@ void TreeModelVolumes::precalculate(const PrintObject& print_object, const coord
|
||||
auto it = radius_until_layer.find(r);
|
||||
if (it == radius_until_layer.end())
|
||||
radius_until_layer.emplace_hint(it, r, current_layer);
|
||||
else
|
||||
assert(it->second >= current_layer);
|
||||
};
|
||||
// regular radius
|
||||
update_radius_until_layer(ceilRadius(config.getRadius(distance_to_top, 0) + m_current_min_xy_dist_delta));
|
||||
@ -359,7 +361,7 @@ const Polygons& TreeModelVolumes::getCollision(const coord_t orig_radius, LayerI
|
||||
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate collision at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
|
||||
tree_supports_show_error("Not precalculated Collision requested."sv, false);
|
||||
}
|
||||
const_cast<TreeModelVolumes*>(this)->calculateCollision(radius, layer_idx, {});
|
||||
const_cast<TreeModelVolumes*>(this)->calculateCollision(radius, layer_idx, []{});
|
||||
return getCollision(orig_radius, layer_idx, min_xy_dist);
|
||||
}
|
||||
|
||||
|
@ -512,7 +512,7 @@ private:
|
||||
*/
|
||||
void calculateCollisionHolefree(RadiusLayerPair key)
|
||||
{
|
||||
calculateCollisionHolefree(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) }, {});
|
||||
calculateCollisionHolefree(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) }, []{});
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -533,7 +533,7 @@ private:
|
||||
*/
|
||||
void calculateAvoidance(RadiusLayerPair key, bool to_build_plate, bool to_model)
|
||||
{
|
||||
calculateAvoidance(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) }, to_build_plate, to_model, {});
|
||||
calculateAvoidance(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) }, to_build_plate, to_model, []{});
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -567,7 +567,7 @@ private:
|
||||
*/
|
||||
void calculateWallRestrictions(RadiusLayerPair key)
|
||||
{
|
||||
calculateWallRestrictions(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) }, {});
|
||||
calculateWallRestrictions(std::vector<RadiusLayerPair>{ RadiusLayerPair(key) }, []{});
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -70,16 +70,17 @@ TreeSupportSettings::TreeSupportSettings(const TreeSupportMeshGroupSettings& mes
|
||||
maximum_move_distance_slow((angle_slow < M_PI / 2.) ? (coord_t)(tan(angle_slow) * layer_height) : std::numeric_limits<coord_t>::max()),
|
||||
support_bottom_layers(mesh_group_settings.support_bottom_enable ? (mesh_group_settings.support_bottom_height + layer_height / 2) / layer_height : 0),
|
||||
tip_layers(std::max((branch_radius - min_radius) / (support_line_width / 3), branch_radius / layer_height)), // Ensure lines always stack nicely even if layer height is large
|
||||
diameter_angle_scale_factor(sin(mesh_group_settings.support_tree_branch_diameter_angle) * layer_height / branch_radius),
|
||||
branch_radius_increase_per_layer(tan(mesh_group_settings.support_tree_branch_diameter_angle) * layer_height),
|
||||
max_to_model_radius_increase(mesh_group_settings.support_tree_max_diameter_increase_by_merges_when_support_to_model / 2),
|
||||
min_dtt_to_model(round_up_divide(mesh_group_settings.support_tree_min_height_to_model, layer_height)),
|
||||
increase_radius_until_radius(mesh_group_settings.support_tree_branch_diameter / 2),
|
||||
increase_radius_until_layer(increase_radius_until_radius <= branch_radius ? tip_layers * (increase_radius_until_radius / branch_radius) : (increase_radius_until_radius - branch_radius) / (branch_radius * diameter_angle_scale_factor)),
|
||||
increase_radius_until_layer(increase_radius_until_radius <= branch_radius ? tip_layers * (increase_radius_until_radius / branch_radius) : (increase_radius_until_radius - branch_radius) / branch_radius_increase_per_layer),
|
||||
support_rests_on_model(! mesh_group_settings.support_material_buildplate_only),
|
||||
xy_distance(mesh_group_settings.support_xy_distance),
|
||||
xy_min_distance(std::min(mesh_group_settings.support_xy_distance, mesh_group_settings.support_xy_distance_overhang)),
|
||||
bp_radius(mesh_group_settings.support_tree_bp_diameter / 2),
|
||||
diameter_scale_bp_radius(std::min(sin(0.7) * layer_height / branch_radius, 1.0 / (branch_radius / (support_line_width / 2.0)))), // Either 40? or as much as possible so that 2 lines will overlap by at least 50%, whichever is smaller.
|
||||
// Increase by half a line overlap, but not faster than 40 degrees angle (0 degrees means zero increase in radius).
|
||||
bp_radius_increase_per_layer(std::min(tan(0.7) * layer_height, 0.5 * support_line_width)),
|
||||
z_distance_bottom_layers(size_t(round(double(mesh_group_settings.support_bottom_distance) / double(layer_height)))),
|
||||
z_distance_top_layers(size_t(round(double(mesh_group_settings.support_top_distance) / double(layer_height)))),
|
||||
performance_interface_skip_layers(round_up_divide(mesh_group_settings.support_interface_skip_height, layer_height)),
|
||||
@ -96,7 +97,7 @@ TreeSupportSettings::TreeSupportSettings(const TreeSupportMeshGroupSettings& mes
|
||||
settings(mesh_group_settings),
|
||||
min_feature_size(mesh_group_settings.min_feature_size)
|
||||
{
|
||||
layer_start_bp_radius = (bp_radius - branch_radius) / (branch_radius * diameter_scale_bp_radius);
|
||||
layer_start_bp_radius = (bp_radius - branch_radius) / bp_radius_increase_per_layer;
|
||||
|
||||
if (TreeSupportSettings::soluble) {
|
||||
// safeOffsetInc can only work in steps of the size xy_min_distance in the worst case => xy_min_distance has to be a bit larger than 0 in this worst case and should be large enough for performance to not suffer extremely
|
||||
@ -1857,7 +1858,7 @@ static Point move_inside_if_outside(const Polygons &polygons, Point from, int di
|
||||
}
|
||||
radius = config.getCollisionRadius(current_elem);
|
||||
|
||||
const coord_t foot_radius_increase = config.branch_radius * (std::max(config.diameter_scale_bp_radius - config.diameter_angle_scale_factor, 0.0));
|
||||
const coord_t foot_radius_increase = std::max(config.bp_radius_increase_per_layer - config.branch_radius_increase_per_layer, 0.0);
|
||||
// Is nearly all of the time 1, but sometimes an increase of 1 could cause the radius to become bigger than recommendedMinRadius,
|
||||
// which could cause the radius to become bigger than precalculated.
|
||||
double planned_foot_increase = std::min(1.0, double(config.recommendedMinRadius(layer_idx - 1) - config.getRadius(current_elem)) / foot_radius_increase);
|
||||
@ -2015,9 +2016,9 @@ static void increase_areas_one_layer(
|
||||
config.recommendedMinRadius(layer_idx - 1) < config.getRadius(elem.effective_radius_height + 1, elem.elephant_foot_increases)) {
|
||||
// can guarantee elephant foot radius increase
|
||||
if (ceiled_parent_radius == volumes.ceilRadius(config.getRadius(parent.state.effective_radius_height + 1, parent.state.elephant_foot_increases + 1), parent.state.use_min_xy_dist))
|
||||
extra_speed += config.branch_radius * config.diameter_scale_bp_radius;
|
||||
extra_speed += config.bp_radius_increase_per_layer;
|
||||
else
|
||||
extra_slow_speed += std::min(coord_t(config.branch_radius * config.diameter_scale_bp_radius),
|
||||
extra_slow_speed += std::min(coord_t(config.bp_radius_increase_per_layer),
|
||||
config.maximum_move_distance - (config.maximum_move_distance_slow + extra_slow_speed));
|
||||
}
|
||||
|
||||
@ -2236,11 +2237,11 @@ static void increase_areas_one_layer(
|
||||
out.to_model_gracious = first.to_model_gracious && second.to_model_gracious; // valid as we do not merge non-gracious with gracious
|
||||
|
||||
out.elephant_foot_increases = 0;
|
||||
if (config.diameter_scale_bp_radius > 0) {
|
||||
if (config.bp_radius_increase_per_layer > 0) {
|
||||
coord_t foot_increase_radius = std::abs(std::max(config.getCollisionRadius(second), config.getCollisionRadius(first)) - config.getCollisionRadius(out));
|
||||
// elephant_foot_increases has to be recalculated, as when a smaller tree with a larger elephant_foot_increases merge with a larger branch
|
||||
// the elephant_foot_increases may have to be lower as otherwise the radius suddenly increases. This results often in a non integer value.
|
||||
out.elephant_foot_increases = foot_increase_radius / (config.branch_radius * (config.diameter_scale_bp_radius - config.diameter_angle_scale_factor));
|
||||
out.elephant_foot_increases = foot_increase_radius / (config.bp_radius_increase_per_layer - config.branch_radius_increase_per_layer);
|
||||
}
|
||||
|
||||
// set last settings to the best out of both parents. If this is wrong, it will only cause a small performance penalty instead of weird behavior.
|
||||
|
@ -302,9 +302,9 @@ public:
|
||||
*/
|
||||
size_t tip_layers;
|
||||
/*!
|
||||
* \brief Factor by which to increase the branch radius.
|
||||
* \brief How much a branch radius increases with each layer to guarantee the prescribed tree widening.
|
||||
*/
|
||||
double diameter_angle_scale_factor;
|
||||
double branch_radius_increase_per_layer;
|
||||
/*!
|
||||
* \brief How much a branch resting on the model may grow in radius by merging with branches that can reach the buildplate.
|
||||
*/
|
||||
@ -330,17 +330,18 @@ public:
|
||||
*/
|
||||
coord_t xy_distance;
|
||||
/*!
|
||||
* \brief Radius a branch should have when reaching the buildplate.
|
||||
* \brief A minimum radius a tree trunk should expand to at the buildplate if possible.
|
||||
*/
|
||||
coord_t bp_radius;
|
||||
/*!
|
||||
* \brief The layer index at which an increase in radius may be required to reach the bp_radius.
|
||||
*/
|
||||
coord_t layer_start_bp_radius;
|
||||
LayerIndex layer_start_bp_radius;
|
||||
/*!
|
||||
* \brief Factor by which to increase the branch radius to reach the required bp_radius at layer 0. Note that this radius increase will not happen in the tip, to ensure the tip is structurally sound.
|
||||
* \brief How much one is allowed to increase the tree branch radius close to print bed to reach the required bp_radius at layer 0.
|
||||
* Note that this radius increase will not happen in the tip, to ensure the tip is structurally sound.
|
||||
*/
|
||||
double diameter_scale_bp_radius;
|
||||
double bp_radius_increase_per_layer;
|
||||
/*!
|
||||
* \brief minimum xy_distance. Only relevant when Z overrides XY, otherwise equal to xy_distance-
|
||||
*/
|
||||
@ -418,7 +419,9 @@ public:
|
||||
public:
|
||||
bool operator==(const TreeSupportSettings& other) const
|
||||
{
|
||||
return branch_radius == other.branch_radius && tip_layers == other.tip_layers && diameter_angle_scale_factor == other.diameter_angle_scale_factor && layer_start_bp_radius == other.layer_start_bp_radius && bp_radius == other.bp_radius && diameter_scale_bp_radius == other.diameter_scale_bp_radius && min_radius == other.min_radius && xy_min_distance == other.xy_min_distance && // as a recalculation of the collision areas is required to set a new min_radius.
|
||||
return branch_radius == other.branch_radius && tip_layers == other.tip_layers && branch_radius_increase_per_layer == other.branch_radius_increase_per_layer && layer_start_bp_radius == other.layer_start_bp_radius && bp_radius == other.bp_radius &&
|
||||
// as a recalculation of the collision areas is required to set a new min_radius.
|
||||
bp_radius_increase_per_layer == other.bp_radius_increase_per_layer && min_radius == other.min_radius && xy_min_distance == other.xy_min_distance &&
|
||||
xy_distance - xy_min_distance == other.xy_distance - other.xy_min_distance && // if the delta of xy_min_distance and xy_distance is different the collision areas have to be recalculated.
|
||||
support_rests_on_model == other.support_rests_on_model && increase_radius_until_layer == other.increase_radius_until_layer && min_dtt_to_model == other.min_dtt_to_model && max_to_model_radius_increase == other.max_to_model_radius_increase && maximum_move_distance == other.maximum_move_distance && maximum_move_distance_slow == other.maximum_move_distance_slow && z_distance_bottom_layers == other.z_distance_bottom_layers && support_line_width == other.support_line_width &&
|
||||
support_line_spacing == other.support_line_spacing && support_roof_line_width == other.support_roof_line_width && // can not be set on a per-mesh basis currently, so code to enable processing different roof line width in the same iteration seems useless.
|
||||
@ -470,9 +473,9 @@ public:
|
||||
{
|
||||
return (distance_to_top <= tip_layers ? min_radius + (branch_radius - min_radius) * distance_to_top / tip_layers : // tip
|
||||
branch_radius + // base
|
||||
branch_radius * (distance_to_top - tip_layers) * diameter_angle_scale_factor)
|
||||
(distance_to_top - tip_layers) * branch_radius_increase_per_layer)
|
||||
+ // gradual increase
|
||||
branch_radius * elephant_foot_increases * (std::max(diameter_scale_bp_radius - diameter_angle_scale_factor, 0.0));
|
||||
elephant_foot_increases * (std::max(bp_radius_increase_per_layer - branch_radius_increase_per_layer, 0.0));
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -502,8 +505,8 @@ public:
|
||||
*/
|
||||
[[nodiscard]] inline coord_t recommendedMinRadius(LayerIndex layer_idx) const
|
||||
{
|
||||
double scale = (layer_start_bp_radius - int(layer_idx)) * diameter_scale_bp_radius;
|
||||
return scale > 0 ? branch_radius + branch_radius * scale : 0;
|
||||
double num_layers_widened = layer_start_bp_radius - layer_idx;
|
||||
return num_layers_widened > 0 ? branch_radius + num_layers_widened * bp_radius_increase_per_layer : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1911,6 +1911,16 @@ std::vector<ExPolygons> slice_mesh_ex(
|
||||
this_mode == MeshSlicingParams::SlicingMode::EvenOdd ? ClipperLib::pftEvenOdd :
|
||||
this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour ? ClipperLib::pftPositive : ClipperLib::pftNonZero,
|
||||
&expolygons);
|
||||
#if 0
|
||||
//#ifndef _NDEBUG
|
||||
for (const ExPolygon &ex : expolygons) {
|
||||
assert(! has_duplicate_points(ex.contour));
|
||||
for (const Polygon &hole : ex.holes)
|
||||
assert(! has_duplicate_points(hole));
|
||||
assert(! has_duplicate_points(ex));
|
||||
}
|
||||
assert(!has_duplicate_points(expolygons));
|
||||
#endif // _NDEBUG
|
||||
//FIXME simplify
|
||||
if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour)
|
||||
keep_largest_contour_only(expolygons);
|
||||
@ -1921,6 +1931,16 @@ std::vector<ExPolygons> slice_mesh_ex(
|
||||
append(simplified, ex.simplify(resolution));
|
||||
expolygons = std::move(simplified);
|
||||
}
|
||||
#if 0
|
||||
//#ifndef _NDEBUG
|
||||
for (const ExPolygon &ex : expolygons) {
|
||||
assert(! has_duplicate_points(ex.contour));
|
||||
for (const Polygon &hole : ex.holes)
|
||||
assert(! has_duplicate_points(hole));
|
||||
assert(! has_duplicate_points(ex));
|
||||
}
|
||||
assert(! has_duplicate_points(expolygons));
|
||||
#endif // _NDEBUG
|
||||
}
|
||||
});
|
||||
// BOOST_LOG_TRIVIAL(debug) << "slice_mesh make_expolygons in parallel - end";
|
||||
|
@ -252,6 +252,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/Http.hpp
|
||||
Utils/FixModelByWin10.cpp
|
||||
Utils/FixModelByWin10.hpp
|
||||
Utils/Mainsail.cpp
|
||||
Utils/Mainsail.hpp
|
||||
Utils/OctoPrint.cpp
|
||||
Utils/OctoPrint.hpp
|
||||
Utils/Duet.cpp
|
||||
|
@ -362,6 +362,16 @@ bool GLGizmoEmboss::init_create(ModelVolumeType volume_type)
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
TransformationType get_transformation_type(const Selection &selection)
|
||||
{
|
||||
assert(selection.is_single_full_object() || selection.is_single_volume());
|
||||
return selection.is_single_volume() ?
|
||||
TransformationType::Local_Relative_Joint :
|
||||
TransformationType::Instance_Relative_Joint; // object
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Moving()) return false;
|
||||
@ -381,9 +391,8 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
||||
angle -= PI / 2; // Grabber is upward
|
||||
|
||||
// temporary rotation
|
||||
const TransformationType transformation_type = m_parent.get_selection().is_single_text() ?
|
||||
TransformationType::Local_Relative_Joint : TransformationType::World_Relative_Joint;
|
||||
m_parent.get_selection().rotate(Vec3d(0., 0., angle), transformation_type);
|
||||
Selection& selection = m_parent.get_selection();
|
||||
selection.rotate(Vec3d(0., 0., angle), get_transformation_type(selection));
|
||||
|
||||
angle += *m_rotate_start_angle;
|
||||
// move to range <-M_PI, M_PI>
|
||||
@ -2466,6 +2475,38 @@ bool GLGizmoEmboss::rev_slider(const std::string &name,
|
||||
undo_tooltip, undo_offset, draw_slider_float);
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::do_translate(const Vec3d &relative_move)
|
||||
{
|
||||
assert(m_volume != nullptr);
|
||||
assert(m_volume->text_configuration.has_value());
|
||||
Selection &selection = m_parent.get_selection();
|
||||
assert(!selection.is_empty());
|
||||
selection.setup_cache();
|
||||
selection.translate(relative_move, TransformationType::Local);
|
||||
|
||||
std::string snapshot_name; // empty mean no store undo / redo
|
||||
// NOTE: it use L instead of _L macro because prefix _ is appended inside
|
||||
// function do_move
|
||||
// snapshot_name = L("Set surface distance");
|
||||
m_parent.do_move(snapshot_name);
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::do_rotate(float relative_z_angle)
|
||||
{
|
||||
assert(m_volume != nullptr);
|
||||
assert(m_volume->text_configuration.has_value());
|
||||
Selection &selection = m_parent.get_selection();
|
||||
assert(!selection.is_empty());
|
||||
selection.setup_cache();
|
||||
selection.rotate(Vec3d(0., 0., relative_z_angle), get_transformation_type(selection));
|
||||
|
||||
std::string snapshot_name; // empty meand no store undo / redo
|
||||
// NOTE: it use L instead of _L macro because prefix _ is appended
|
||||
// inside function do_move
|
||||
// snapshot_name = L("Set text rotation");
|
||||
m_parent.do_rotate(snapshot_name);
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::draw_advanced()
|
||||
{
|
||||
const auto &ff = m_style_manager.get_font_file_with_cache();
|
||||
|
@ -135,7 +135,11 @@ void GLGizmoSlaBase::render_volumes()
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
|
||||
ClippingPlane clipping_plane = (m_c->object_clipper()->get_position() == 0.0) ? ClippingPlane::ClipsNothing() : *m_c->object_clipper()->get_clipping_plane();
|
||||
clipping_plane.set_normal(-clipping_plane.get_normal());
|
||||
if (m_c->object_clipper()->get_position() != 0.0)
|
||||
clipping_plane.set_normal(-clipping_plane.get_normal());
|
||||
else
|
||||
// on Linux the clipping plane does not work when using DBL_MAX
|
||||
clipping_plane.set_offset(FLT_MAX);
|
||||
m_volumes.set_clipping_plane(clipping_plane.get_data());
|
||||
|
||||
for (GLVolume* v : m_volumes.volumes) {
|
||||
|
@ -1827,6 +1827,7 @@ struct Plater::priv
|
||||
const Selection& get_selection() const;
|
||||
Selection& get_selection();
|
||||
int get_selected_object_idx() const;
|
||||
int get_selected_instance_idx() const;
|
||||
int get_selected_volume_idx() const;
|
||||
void selection_changed();
|
||||
void object_list_changed();
|
||||
@ -2967,6 +2968,17 @@ int Plater::priv::get_selected_object_idx() const
|
||||
return (0 <= idx && idx < int(model.objects.size())) ? idx : -1;
|
||||
}
|
||||
|
||||
int Plater::priv::get_selected_instance_idx() const
|
||||
{
|
||||
const int obj_idx = get_selected_object_idx();
|
||||
if (obj_idx >= 0) {
|
||||
const int inst_idx = get_selection().get_instance_idx();
|
||||
return (0 <= inst_idx && inst_idx < int(model.objects[obj_idx]->instances.size())) ? inst_idx : -1;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Plater::priv::get_selected_volume_idx() const
|
||||
{
|
||||
auto& selection = get_selection();
|
||||
@ -6062,7 +6074,8 @@ void Plater::increase_instances(size_t num, int obj_idx/* = -1*/)
|
||||
}
|
||||
|
||||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
ModelInstance* model_instance = model_object->instances.back();
|
||||
const int inst_idx = p->get_selected_instance_idx();
|
||||
ModelInstance* model_instance = (inst_idx >= 0) ? model_object->instances[inst_idx] : model_object->instances.back();
|
||||
|
||||
bool was_one_instance = model_object->instances.size()==1;
|
||||
|
||||
@ -6070,7 +6083,9 @@ void Plater::increase_instances(size_t num, int obj_idx/* = -1*/)
|
||||
double offset = offset_base;
|
||||
for (size_t i = 0; i < num; i++, offset += offset_base) {
|
||||
Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0);
|
||||
model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation(), model_instance->get_mirror());
|
||||
Geometry::Transformation trafo = model_instance->get_transformation();
|
||||
trafo.set_offset(offset_vec);
|
||||
model_object->add_instance(trafo);
|
||||
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,10 @@
|
||||
#include <devpropdef.h>
|
||||
#include <devpkey.h>
|
||||
#include <usbioctl.h>
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <atlcom.h>
|
||||
#include <shldisp.h>
|
||||
#else
|
||||
// unix, linux & OSX includes
|
||||
#include <errno.h>
|
||||
@ -80,7 +84,7 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
|
||||
namespace {
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
// From https://github.com/microsoft/Windows-driver-samples/tree/main/usb/usbview
|
||||
typedef struct _STRING_DESCRIPTOR_NODE
|
||||
{
|
||||
@ -581,6 +585,57 @@ void eject_alt(std::string path, wxEvtHandler* callback_evt_handler, DriveData d
|
||||
if (callback_evt_handler)
|
||||
wxPostEvent(callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(drive_data), true)));
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
// C++ equivavalent of PowerShell script:
|
||||
// $driveEject = New - Object - comObject Shell.Application
|
||||
// $driveEject.Namespace(17).ParseName("E:").InvokeVerb("Eject")
|
||||
// from https://superuser.com/a/1750403
|
||||
bool eject_inner(const std::string& path)
|
||||
{
|
||||
std::wstring wpath = boost::nowide::widen(path);
|
||||
CoInitialize(nullptr);
|
||||
CComPtr<IShellDispatch> pShellDisp;
|
||||
HRESULT hr = pShellDisp.CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to get Shell pointer has failed.", path);
|
||||
CoUninitialize();
|
||||
return false;
|
||||
}
|
||||
CComPtr<Folder> pFolder;
|
||||
VARIANT vtDrives;
|
||||
VariantInit(&vtDrives);
|
||||
vtDrives.vt = VT_I4;
|
||||
vtDrives.lVal = ssfDRIVES;
|
||||
hr = pShellDisp->NameSpace(vtDrives, &pFolder);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to create Namespace has failed.", path);
|
||||
CoUninitialize();
|
||||
return false;
|
||||
}
|
||||
CComPtr<FolderItem> pItem;
|
||||
hr = pFolder->ParseName(static_cast<BSTR>(const_cast<wchar_t*>(wpath.c_str())), &pItem);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to Parse name has failed.", path);
|
||||
CoUninitialize();
|
||||
return false;
|
||||
}
|
||||
VARIANT vtEject;
|
||||
VariantInit(&vtEject);
|
||||
vtEject.vt = VT_BSTR;
|
||||
vtEject.bstrVal = SysAllocString(L"Eject");
|
||||
hr = pItem->InvokeVerb(vtEject);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to Invoke Verb has failed.", path);
|
||||
VariantClear(&vtEject);
|
||||
CoUninitialize();
|
||||
return false;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(debug) << "Ejecting via InvokeVerb has succeeded.";
|
||||
VariantClear(&vtEject);
|
||||
CoUninitialize();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Called from UI therefore it blocks the UI thread.
|
||||
@ -597,27 +652,19 @@ void RemovableDriveManager::eject_drive()
|
||||
BOOST_LOG_TRIVIAL(info) << "Ejecting started";
|
||||
std::scoped_lock<std::mutex> lock(m_drives_mutex);
|
||||
auto it_drive_data = this->find_last_save_path_drive_data();
|
||||
#if 1
|
||||
if (it_drive_data != m_current_drives.end()) {
|
||||
if (!eject_inner(m_last_save_path)) {
|
||||
if (eject_inner(m_last_save_path)) {
|
||||
// success
|
||||
BOOST_LOG_TRIVIAL(info) << "Ejecting has succeeded.";
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(*it_drive_data), true)));
|
||||
} else {
|
||||
if (m_eject_thread.joinable())
|
||||
m_eject_thread.join();
|
||||
m_eject_thread = boost::thread(eject_alt, m_last_save_path, m_callback_evt_handler, std::move(*it_drive_data));
|
||||
|
||||
// failed to eject
|
||||
// this should not happen, throwing exception might be the way here
|
||||
/*
|
||||
BOOST_LOG_TRIVIAL(error) << "Ejecting has failed.";
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
// drive not found in m_current_drives
|
||||
@ -626,47 +673,6 @@ void RemovableDriveManager::eject_drive()
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>({"",""}, false)));
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
// Implementation used until 2.5.x version
|
||||
// Some usb drives does not eject properly (still visible in file explorer). Some even does not write all content and eject.
|
||||
if (it_drive_data != m_current_drives.end()) {
|
||||
// get handle to device
|
||||
std::string mpath = "\\\\.\\" + m_last_save_path;
|
||||
mpath = mpath.substr(0, mpath.size() - 1);
|
||||
HANDLE handle = CreateFileW(boost::nowide::widen(mpath).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Ejecting " << mpath << " failed (handle == INVALID_HANDLE_VALUE): " << GetLastError();
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
|
||||
return;
|
||||
}
|
||||
DWORD deviceControlRetVal(0);
|
||||
//these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger.
|
||||
//sd cards does trigger WM_DEVICECHANGE messege, usb drives dont
|
||||
BOOL e1 = DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
BOOST_LOG_TRIVIAL(error) << "FSCTL_LOCK_VOLUME " << e1 << " ; " << deviceControlRetVal << " ; " << GetLastError();
|
||||
BOOL e2 = DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
BOOST_LOG_TRIVIAL(error) << "FSCTL_DISMOUNT_VOLUME " << e2 << " ; " << deviceControlRetVal << " ; " << GetLastError();
|
||||
// some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here with FALSE as third parameter, which should set PreventMediaRemoval
|
||||
BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
if (error == 0) {
|
||||
CloseHandle(handle);
|
||||
BOOST_LOG_TRIVIAL(error) << "Ejecting " << mpath << " failed (IOCTL_STORAGE_EJECT_MEDIA)" << deviceControlRetVal << " " << GetLastError();
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
|
||||
return;
|
||||
}
|
||||
CloseHandle(handle);
|
||||
BOOST_LOG_TRIVIAL(info) << "Ejecting finished";
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(*it_drive_data), true)));
|
||||
m_current_drives.erase(it_drive_data);
|
||||
}
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
std::string RemovableDriveManager::get_removable_drive_path(const std::string &path)
|
||||
|
@ -106,12 +106,6 @@ private:
|
||||
#endif /* _WIN32 */
|
||||
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
|
||||
|
||||
#ifdef _WIN32
|
||||
// Another worker thread, used only to perform alt_eject method (external SD cards only).
|
||||
// Does not share data with m_thread
|
||||
boost::thread m_eject_thread;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
// Called from update() to enumerate removable drives.
|
||||
std::vector<DriveData> search_for_removable_drives() const;
|
||||
|
||||
|
257
src/slic3r/Utils/Mainsail.cpp
Normal file
257
src/slic3r/Utils/Mainsail.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
#include "Mainsail.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "Http.hpp"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::property_tree;
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
#ifdef WIN32
|
||||
// Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail.
|
||||
std::string substitute_host(const std::string& orig_addr, std::string sub_addr)
|
||||
{
|
||||
// put ipv6 into [] brackets
|
||||
if (sub_addr.find(':') != std::string::npos && sub_addr.at(0) != '[')
|
||||
sub_addr = "[" + sub_addr + "]";
|
||||
// Using the new CURL API for handling URL. https://everything.curl.dev/libcurl/url
|
||||
// If anything fails, return the input unchanged.
|
||||
std::string out = orig_addr;
|
||||
CURLU* hurl = curl_url();
|
||||
if (hurl) {
|
||||
// Parse the input URL.
|
||||
CURLUcode rc = curl_url_set(hurl, CURLUPART_URL, orig_addr.c_str(), 0);
|
||||
if (rc == CURLUE_OK) {
|
||||
// Replace the address.
|
||||
rc = curl_url_set(hurl, CURLUPART_HOST, sub_addr.c_str(), 0);
|
||||
if (rc == CURLUE_OK) {
|
||||
// Extract a string fromt the CURL URL handle.
|
||||
char* url;
|
||||
rc = curl_url_get(hurl, CURLUPART_URL, &url, 0);
|
||||
if (rc == CURLUE_OK) {
|
||||
out = url;
|
||||
curl_free(url);
|
||||
}
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "OctoPrint substitute_host: failed to extract the URL after substitution";
|
||||
}
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "OctoPrint substitute_host: failed to substitute host " << sub_addr << " in URL " << orig_addr;
|
||||
}
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "OctoPrint substitute_host: failed to parse URL " << orig_addr;
|
||||
curl_url_cleanup(hurl);
|
||||
}
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "OctoPrint substitute_host: failed to allocate curl_url";
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Mainsail::Mainsail(DynamicPrintConfig *config) :
|
||||
m_host(config->opt_string("print_host")),
|
||||
m_apikey(config->opt_string("printhost_apikey")),
|
||||
m_cafile(config->opt_string("printhost_cafile")),
|
||||
m_ssl_revoke_best_effort(config->opt_bool("printhost_ssl_ignore_revoke"))
|
||||
{}
|
||||
|
||||
const char* Mainsail::get_name() const { return "Mainsail"; }
|
||||
|
||||
wxString Mainsail::get_test_ok_msg () const
|
||||
{
|
||||
return _(L("Connection to Mainsail works correctly."));
|
||||
}
|
||||
|
||||
wxString Mainsail::get_test_failed_msg (wxString &msg) const
|
||||
{
|
||||
return GUI::format_wxstr("%s: %s"
|
||||
, _L("Could not connect to Mainsail")
|
||||
, msg);
|
||||
}
|
||||
|
||||
bool Mainsail::test(wxString& msg) const
|
||||
{
|
||||
// GET /server/info
|
||||
|
||||
// Since the request is performed synchronously here,
|
||||
// it is ok to refer to `msg` from within the closure
|
||||
const char* name = get_name();
|
||||
|
||||
bool res = true;
|
||||
auto url = make_url("server/info");
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url;
|
||||
|
||||
auto http = Http::get(std::move(url));
|
||||
set_auth(http);
|
||||
http.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
|
||||
res = false;
|
||||
msg = format_error(body, error, status);
|
||||
})
|
||||
.on_complete([&, this](std::string body, unsigned) {
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got server/info: %2%") % name % body;
|
||||
|
||||
try {
|
||||
// All successful HTTP requests will return a json encoded object in the form of :
|
||||
// {result: <response data>}
|
||||
std::stringstream ss(body);
|
||||
pt::ptree ptree;
|
||||
pt::read_json(ss, ptree);
|
||||
if (ptree.front().first != "result") {
|
||||
msg = "Could not parse server response";
|
||||
res = false;
|
||||
return;
|
||||
}
|
||||
if (!ptree.front().second.get_optional<std::string>("moonraker_version")) {
|
||||
msg = "Could not parse server response";
|
||||
res = false;
|
||||
return;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Got version: %2%") % name % ptree.front().second.get_optional<std::string>("moonraker_version");
|
||||
} catch (const std::exception&) {
|
||||
res = false;
|
||||
msg = "Could not parse server response";
|
||||
}
|
||||
})
|
||||
#ifdef _WIN32
|
||||
.ssl_revoke_best_effort(m_ssl_revoke_best_effort)
|
||||
.on_ip_resolve([&](std::string address) {
|
||||
// Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail.
|
||||
// Remember resolved address to be reused at successive REST API call.
|
||||
msg = GUI::from_u8(address);
|
||||
})
|
||||
#endif // _WIN32
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Mainsail::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const
|
||||
{
|
||||
// POST /server/files/upload
|
||||
|
||||
const char* name = get_name();
|
||||
const auto upload_filename = upload_data.upload_path.filename();
|
||||
const auto upload_parent_path = upload_data.upload_path.parent_path();
|
||||
|
||||
// If test fails, test_msg_or_host_ip contains the error message.
|
||||
wxString test_msg_or_host_ip;
|
||||
if (!test(test_msg_or_host_ip)) {
|
||||
error_fn(std::move(test_msg_or_host_ip));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string url;
|
||||
bool res = true;
|
||||
|
||||
#ifdef WIN32
|
||||
// Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail.
|
||||
if (m_host.find("https://") == 0 || test_msg_or_host_ip.empty() || !GUI::get_app_config()->get_bool("allow_ip_resolve"))
|
||||
#endif // _WIN32
|
||||
{
|
||||
// If https is entered we assume signed ceritificate is being used
|
||||
// IP resolving will not happen - it could resolve into address not being specified in cert
|
||||
url = make_url("server/files/upload");
|
||||
}
|
||||
#ifdef WIN32
|
||||
else {
|
||||
// Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail.
|
||||
// Curl uses easy_getinfo to get ip address of last successful transaction.
|
||||
// If it got the address use it instead of the stored in "host" variable.
|
||||
// This new address returns in "test_msg_or_host_ip" variable.
|
||||
// Solves troubles of uploades failing with name address.
|
||||
// in original address (m_host) replace host for resolved ip
|
||||
info_fn(L"resolve", test_msg_or_host_ip);
|
||||
url = substitute_host(make_url("server/files/upload"), GUI::into_u8(test_msg_or_host_ip));
|
||||
BOOST_LOG_TRIVIAL(info) << "Upload address after ip resolve: " << url;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%")
|
||||
% name
|
||||
% upload_data.source_path
|
||||
% url
|
||||
% upload_filename.string()
|
||||
% upload_parent_path.string()
|
||||
% (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false");
|
||||
/*
|
||||
The file must be uploaded in the request's body multipart/form-data (ie: <input type="file">). The following arguments may also be added to the form-data:
|
||||
root: The root location in which to upload the file.Currently this may be gcodes or config.If not specified the default is gcodes.
|
||||
path : This argument may contain a path(relative to the root) indicating a subdirectory to which the file is written.If a path is present the server will attempt to create any subdirectories that do not exist.
|
||||
checksum : A SHA256 hex digest calculated by the client for the uploaded file.If this argument is supplied the server will compare it to its own checksum calculation after the upload has completed.A checksum mismatch will result in a 422 error.
|
||||
Arguments available only for the gcodes root :
|
||||
print: If set to "true", Klippy will attempt to start the print after uploading.Note that this value should be a string type, not boolean.This provides compatibility with OctoPrint's upload API.
|
||||
*/
|
||||
auto http = Http::post(std::move(url));
|
||||
set_auth(http);
|
||||
|
||||
http.form_add("root", "gcodes");
|
||||
if (!upload_parent_path.empty())
|
||||
http.form_add("path", upload_parent_path.string());
|
||||
if (upload_data.post_action == PrintHostPostUploadAction::StartPrint)
|
||||
http.form_add("print", "true");
|
||||
|
||||
http.form_add_file("file", upload_data.source_path.string(), upload_filename.string())
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: File uploaded: HTTP %2%: %3%") % name % status % body;
|
||||
})
|
||||
.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error uploading file: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
|
||||
error_fn(format_error(body, error, status));
|
||||
res = false;
|
||||
})
|
||||
.on_progress([&](Http::Progress progress, bool& cancel) {
|
||||
prorgess_fn(std::move(progress), cancel);
|
||||
if (cancel) {
|
||||
// Upload was canceled
|
||||
BOOST_LOG_TRIVIAL(info) << name << ": Upload canceled";
|
||||
res = false;
|
||||
}
|
||||
})
|
||||
#ifdef WIN32
|
||||
.ssl_revoke_best_effort(m_ssl_revoke_best_effort)
|
||||
#endif
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Mainsail::set_auth(Http &http) const
|
||||
{
|
||||
if (!m_apikey.empty())
|
||||
http.header("X-Api-Key", m_apikey);
|
||||
if (!m_cafile.empty())
|
||||
http.ca_file(m_cafile);
|
||||
}
|
||||
|
||||
std::string Mainsail::make_url(const std::string &path) const
|
||||
{
|
||||
if (m_host.find("http://") == 0 || m_host.find("https://") == 0) {
|
||||
if (m_host.back() == '/') {
|
||||
return (boost::format("%1%%2%") % m_host % path).str();
|
||||
} else {
|
||||
return (boost::format("%1%/%2%") % m_host % path).str();
|
||||
}
|
||||
} else {
|
||||
return (boost::format("http://%1%/%2%") % m_host % path).str();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
64
src/slic3r/Utils/Mainsail.hpp
Normal file
64
src/slic3r/Utils/Mainsail.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef slic3r_Mainsail_hpp_
|
||||
#define slic3r_Mainsail_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
|
||||
#include "PrintHost.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
class Http;
|
||||
|
||||
// https://moonraker.readthedocs.io/en/latest/web_api
|
||||
class Mainsail : public PrintHost
|
||||
{
|
||||
public:
|
||||
Mainsail(DynamicPrintConfig *config);
|
||||
~Mainsail() override = default;
|
||||
|
||||
const char* get_name() const override;
|
||||
|
||||
virtual bool test(wxString &curl_msg) const override;
|
||||
wxString get_test_ok_msg () const override;
|
||||
wxString get_test_failed_msg (wxString &msg) const override;
|
||||
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override;
|
||||
bool has_auto_discovery() const override { return true; }
|
||||
bool can_test() const override { return true; }
|
||||
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
|
||||
std::string get_host() const override { return m_host; }
|
||||
const std::string& get_apikey() const { return m_apikey; }
|
||||
const std::string& get_cafile() const { return m_cafile; }
|
||||
|
||||
protected:
|
||||
/*
|
||||
#ifdef WIN32
|
||||
virtual bool upload_inner_with_resolved_ip(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn, const boost::asio::ip::address& resolved_addr) const;
|
||||
#endif
|
||||
virtual bool validate_version_text(const boost::optional<std::string> &version_text) const;
|
||||
virtual bool upload_inner_with_host(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const;
|
||||
*/
|
||||
std::string m_host;
|
||||
std::string m_apikey;
|
||||
std::string m_cafile;
|
||||
bool m_ssl_revoke_best_effort;
|
||||
|
||||
virtual void set_auth(Http &http) const;
|
||||
std::string make_url(const std::string &path) const;
|
||||
|
||||
private:
|
||||
/*
|
||||
#ifdef WIN32
|
||||
bool test_with_resolved_ip(wxString& curl_msg) const;
|
||||
#endif
|
||||
*/
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -203,7 +203,7 @@ bool OctoPrint::test_with_resolved_ip(wxString &msg) const
|
||||
const auto text = ptree.get_optional<std::string>("text");
|
||||
res = validate_version_text(text);
|
||||
if (!res) {
|
||||
msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "OctoPrint"));
|
||||
msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : name));
|
||||
}
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
@ -252,7 +252,7 @@ bool OctoPrint::test(wxString& msg) const
|
||||
const auto text = ptree.get_optional<std::string>("text");
|
||||
res = validate_version_text(text);
|
||||
if (! res) {
|
||||
msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "OctoPrint"));
|
||||
msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : name));
|
||||
}
|
||||
}
|
||||
catch (const std::exception &) {
|
||||
@ -396,7 +396,7 @@ bool OctoPrint::upload_inner_with_resolved_ip(PrintHostUpload upload_data, Progr
|
||||
prorgess_fn(std::move(progress), cancel);
|
||||
if (cancel) {
|
||||
// Upload was canceled
|
||||
BOOST_LOG_TRIVIAL(info) << "Octoprint: Upload canceled";
|
||||
BOOST_LOG_TRIVIAL(info) << name << ": Upload canceled";
|
||||
result = false;
|
||||
}
|
||||
})
|
||||
@ -473,7 +473,7 @@ bool OctoPrint::upload_inner_with_host(PrintHostUpload upload_data, ProgressFn p
|
||||
prorgess_fn(std::move(progress), cancel);
|
||||
if (cancel) {
|
||||
// Upload was canceled
|
||||
BOOST_LOG_TRIVIAL(info) << "Octoprint: Upload canceled";
|
||||
BOOST_LOG_TRIVIAL(info) << name << ": Upload canceled";
|
||||
res = false;
|
||||
}
|
||||
})
|
||||
@ -1126,5 +1126,4 @@ wxString PrusaConnect::get_test_failed_msg(wxString& msg) const
|
||||
{
|
||||
return GUI::format_wxstr("%s: %s", _L("Could not connect to Prusa Connect"), msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -117,16 +117,6 @@ protected:
|
||||
void set_http_post_header_args(Http& http, PrintHostPostUploadAction post_action) const override;
|
||||
};
|
||||
|
||||
|
||||
class Mainsail : public OctoPrint
|
||||
{
|
||||
public:
|
||||
Mainsail(DynamicPrintConfig* config) : OctoPrint(config) {}
|
||||
~Mainsail() override = default;
|
||||
|
||||
const char* get_name() const override { return "Mainsail/Fluidd"; }
|
||||
};
|
||||
|
||||
class SL1Host : public PrusaLink
|
||||
{
|
||||
public:
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "AstroBox.hpp"
|
||||
#include "Repetier.hpp"
|
||||
#include "MKS.hpp"
|
||||
#include "Mainsail.hpp"
|
||||
#include "../GUI/PrintHostDialogs.hpp"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
Loading…
x
Reference in New Issue
Block a user