Merge remote-tracking branch 'remotes/origin/master' into vb_ensurovani

This commit is contained in:
Vojtech Bubnik 2023-02-02 09:53:14 +01:00
commit 001358cbba
264 changed files with 105765 additions and 67926 deletions

View File

@ -1,4 +1,9 @@
# In PrusaSlicer 2.6.0 we switched from https://github.com/memononen/nanosvg to its fork https://github.com/fltk/nanosvg
# because this last implements the new function nsvgRasterizeXY() which we now use in GLTexture::load_from_svg()
# for rasterizing svg files from their original size to a squared power of two texture on Windows systems using
# AMD Radeon graphics cards
prusaslicer_add_cmake_project(NanoSVG prusaslicer_add_cmake_project(NanoSVG
URL https://github.com/memononen/nanosvg/archive/4c8f0139b62c6e7faa3b67ce1fbe6e63590ed148.zip URL https://github.com/fltk/nanosvg/archive/abcd277ea45e9098bed752cf9c6875b533c0892f.zip
URL_HASH SHA256=584e084af1a75bf633f79753ce2f6f6ec8686002ca27f35f1037c25675fecfb6 URL_HASH SHA256=e859938fbaee4b351bd8a8b3d3c7a75b40c36885ce00b73faa1ce0b98aa0ad34
) )

View File

@ -13,8 +13,8 @@ if (UNIX AND NOT APPLE) # wxWidgets will not use char as the underlying type for
endif() endif()
prusaslicer_add_cmake_project(wxWidgets prusaslicer_add_cmake_project(wxWidgets
URL https://github.com/prusa3d/wxWidgets/archive/34b524f8d5134a40a90d93a16360d533af2676ae.zip URL https://github.com/prusa3d/wxWidgets/archive/4fd2120c913c20c3bb66ee9d01d8ff5087a8b90a.zip
URL_HASH SHA256=e76ca0dd998905c4dbb86f41f264e6e0468504dc2398f7e7e3bba8dc37de2f45 URL_HASH SHA256=5b59e8b4dccf73e109c6588f6a69bcfe4e02e930af53c43d5d1329c1f3d83ec9
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG dep_NanoSVG DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG dep_NanoSVG
CMAKE_ARGS CMAKE_ARGS
-DwxBUILD_PRECOMP=ON -DwxBUILD_PRECOMP=ON

View File

@ -231,6 +231,30 @@ disabled_tags = SLA
text = Fullscreen mode\nDid you know that you can switch PrusaSlicer to fullscreen mode? Use the <b>F11</b> hotkey. text = Fullscreen mode\nDid you know that you can switch PrusaSlicer to fullscreen mode? Use the <b>F11</b> hotkey.
enabled_tags = Windows enabled_tags = Windows
[hint:Printables integration]
text = Printables.com integration\nDid you know that when you are browsing Printables.com, you can send 3D model files to PrusaSlicer with a single click? Learn more in the documentation.
documentation_link = https://help.prusa3d.com/article/prusaslicer-printables-com-integration_399198
weight = 3
[hint:Cut tool]
text = Cut tool\nDid you know that you can cut a model at any angle and even create aligning pins with the updated Cut tool? Learn more in the documentation.
documentation_link = https://help.prusa3d.com/article/cut-tool_1779
hypertext_type = gizmo
hypertext_gizmo_item = cut
weight = 3
[hint:Measurement tool]
text = Measurement tool\nDid you know that you can measure the distances between points, edges and planes, the radius of a hole or the angle between edges or planes? Learn more in the documentation.
documentation_link = https://help.prusa3d.com/article/measurement-tool_399451
hypertext_type = gizmo
hypertext_gizmo_item = measure
weight = 3
[hint:Text tool]
text = Text tool\nDid you know that you can add custom text labels to your models or even use the text as a modifier? Learn more in the documentation.
documentation_link = https://help.prusa3d.com/article/text-tool_399460
weight = 3
#[hint:] #[hint:]
#text = #text =
#hypertext = #hypertext =

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,19 +9,26 @@ src/slic3r/GUI/ConfigSnapshotDialog.cpp
src/slic3r/GUI/ConfigWizard.cpp src/slic3r/GUI/ConfigWizard.cpp
src/slic3r/GUI/DesktopIntegrationDialog.cpp src/slic3r/GUI/DesktopIntegrationDialog.cpp
src/slic3r/GUI/DoubleSlider.cpp src/slic3r/GUI/DoubleSlider.cpp
src/slic3r/GUI/Downloader.cpp
src/slic3r/GUI/DownloaderFileGet.cpp
src/slic3r/GUI/ExtraRenderers.cpp src/slic3r/GUI/ExtraRenderers.cpp
src/slic3r/GUI/ExtruderSequenceDialog.cpp src/slic3r/GUI/ExtruderSequenceDialog.cpp
src/slic3r/GUI/Field.cpp src/slic3r/GUI/Field.cpp
src/slic3r/GUI/FileArchiveDialog.cpp
src/slic3r/GUI/FirmwareDialog.cpp src/slic3r/GUI/FirmwareDialog.cpp
src/slic3r/GUI/GalleryDialog.cpp src/slic3r/GUI/GalleryDialog.cpp
src/slic3r/GUI/GCodeViewer.cpp src/slic3r/GUI/GCodeViewer.cpp
src/slic3r/GUI/GLCanvas3D.cpp src/slic3r/GUI/GLCanvas3D.cpp
src/slic3r/GUI/Gizmos/GLGizmoCut.cpp src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
src/slic3r/GUI/Gizmos/GLGizmoCut.hpp src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp
src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp
src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp
src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp
src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp
src/slic3r/GUI/Gizmos/GLGizmoMove.cpp src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
@ -32,7 +39,6 @@ src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp
src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
src/slic3r/GUI/Gizmos/GLGizmosManager.cpp src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
src/slic3r/GUI/GUI.cpp src/slic3r/GUI/GUI.cpp
@ -48,8 +54,7 @@ src/slic3r/GUI/HintNotification.cpp
src/slic3r/GUI/ImGuiWrapper.cpp src/slic3r/GUI/ImGuiWrapper.cpp
src/slic3r/GUI/Jobs/ArrangeJob.cpp src/slic3r/GUI/Jobs/ArrangeJob.cpp
src/slic3r/GUI/Jobs/FillBedJob.cpp src/slic3r/GUI/Jobs/FillBedJob.cpp
src/slic3r/GUI/Jobs/Job.cpp src/slic3r/GUI/Jobs/EmbossJob.cpp
src/slic3r/GUI/Jobs/PlaterJob.cpp
src/slic3r/GUI/Jobs/RotoptimizeJob.hpp src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
src/slic3r/GUI/Jobs/RotoptimizeJob.cpp src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
src/slic3r/GUI/Jobs/SLAImportJob.cpp src/slic3r/GUI/Jobs/SLAImportJob.cpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
min_slic3r_version = 2.6.0-alpha1
0.1.0 Initial version

437
resources/profiles/BIQU.ini Normal file
View File

@ -0,0 +1,437 @@
# Print profiles for BIQU printers.
# Based on PR https://github.com/slic3r/slic3r-profiles/pull/32 by @bkonosky
[vendor]
name = BIQU
config_version = 0.1.0
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/BIQU/
# The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install.
# Printer model name will be shown by the installation wizard.
[printer_model:BIQUBX]
name = BIQU BX
variants = 0.4
technology = FFF
bed_model = BX_Bed.stl
bed_texture = BX_Texture.png
default_materials = Generic PLA @BIQU; Generic PETG @BIQU; Generic ABS @BIQU
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
# Common print preset
[print:*common*]
avoid_crossing_perimeters = 0
bottom_fill_pattern = monotonic
bridge_angle = 0
bridge_flow_ratio = 0.95
bridge_speed = 25
brim_width = 0
clip_multipart_objects = 1
complete_objects = 0
bridge_acceleration = 250
perimeter_acceleration = 500
infill_acceleration = 500
first_layer_acceleration = 500
default_acceleration = 500
dont_support_bridges = 1
ensure_vertical_shell_thickness = 1
external_perimeters_first = 0
external_perimeter_speed = 25
extra_perimeters = 0
extruder_clearance_height = 34
extruder_clearance_radius = 47
fill_angle = 45
fill_density = 15%
fill_pattern = gyroid
first_layer_height = 0.2
elefant_foot_compensation = 0.1
first_layer_speed = 20
gap_fill_speed = 30
gcode_comments = 0
infill_every_layers = 1
infill_extruder = 1
infill_first = 0
infill_only_where_needed = 0
infill_overlap = 25%
infill_speed = 50
interface_shells = 0
max_print_speed = 100
max_volumetric_extrusion_rate_slope_negative = 0
max_volumetric_extrusion_rate_slope_positive = 0
max_volumetric_speed = 0
min_skirt_length = 4
notes =
only_retract_when_crossing_perimeters = 0
ooze_prevention = 0
output_filename_format = {input_filename_base}_{print_time}_{digits(layer_height,1,2)}mm_{temperature[0]}C_{filament_type[0]}_{printer_model}.gcode
perimeters = 2
perimeter_extruder = 1
perimeter_speed = 40
raft_layers = 0
seam_position = nearest
single_extruder_multi_material_priming = 0
skirts = 1
skirt_distance = 3
skirt_height = 2
small_perimeter_speed = 25
solid_infill_below_area = 0
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_speed = 40
spiral_vase = 0
standby_temperature_delta = -5
support_material = 0
support_material_extruder = 0
support_material_interface_extruder = 0
support_material_angle = 0
support_material_buildplate_only = 0
support_material_enforce_layers = 0
support_material_contact_distance = 0.15
support_material_bottom_contact_distance = 0.15
support_material_interface_contact_loops = 0
support_material_interface_layers = 2
support_material_interface_pattern = rectilinear
support_material_interface_spacing = 0.2
support_material_interface_speed = 100%
support_material_pattern = rectilinear
support_material_solid_first_layer = 1
support_material_spacing = 2
support_material_speed = 40
support_material_synchronize_layers = 0
support_material_threshold = 40
support_material_with_sheath = 0
support_material_xy_spacing = 60%
thin_perimeters = 1
thin_walls = 1
top_fill_pattern = monotonic
top_solid_infill_speed = 30
travel_speed = 150
wipe_tower = 1
wipe_tower_bridging = 10
wipe_tower_rotation_angle = 0
wipe_tower_width = 60
wipe_tower_x = 160
wipe_tower_y = 160
xy_size_compensation = 0
extrusion_width = 0.45
external_perimeter_extrusion_width = 0.43
first_layer_extrusion_width = 0.55
support_material_extrusion_width = 0.38
top_infill_extrusion_width = 0.43
[print:*0.08mm*]
inherits = *common*
layer_height = 0.08
perimeters = 3
bottom_solid_layers = 9
top_solid_layers = 11
bridge_flow_ratio = 0.7
[print:*0.10mm*]
inherits = *common*
layer_height = 0.10
perimeters = 3
bottom_solid_layers = 7
top_solid_layers = 9
bridge_flow_ratio = 0.7
[print:*0.12mm*]
inherits = *common*
layer_height = 0.12
perimeters = 3
bottom_solid_layers = 6
top_solid_layers = 7
bridge_flow_ratio = 0.7
[print:*0.16mm*]
inherits = *common*
layer_height = 0.16
bottom_solid_layers = 5
top_solid_layers = 7
bridge_flow_ratio = 0.85
[print:*0.20mm*]
inherits = *common*
layer_height = 0.20
bottom_solid_layers = 4
top_solid_layers = 5
[print:*0.24mm*]
inherits = *common*
layer_height = 0.24
bottom_solid_layers = 3
top_solid_layers = 4
[print:*0.28mm*]
inherits = *common*
layer_height = 0.28
bottom_solid_layers = 3
top_solid_layers = 4
[print:*0.32mm*]
inherits = *common*
layer_height = 0.32
bottom_solid_layers = 3
top_solid_layers = 4
[print:0.08mm HIGHDETAIL @BIQU]
inherits = *0.08mm*
compatible_printers_condition = printer_model=~/(BIQUBX).*/
[print:0.10mm HIGHDETAIL @BIQU]
inherits = *0.10mm*
compatible_printers_condition = printer_model=~/(BIQUBX).*/
[print:0.12mm DETAIL @BIQU]
inherits = *0.12mm*
compatible_printers_condition = printer_model=~/(BIQUBX).*/
[print:0.16mm OPTIMAL @BIQU]
inherits = *0.16mm*
compatible_printers_condition = printer_model=~/(BIQUBX).*/
[print:0.20mm NORMAL @BIQU]
inherits = *0.20mm*
compatible_printers_condition = printer_model=~/(BIQUBX).*/
[print:0.24mm DRAFT @BIQU]
inherits = *0.24mm*
compatible_printers_condition = printer_model=~/(BIQUBX).*/
[print:0.28mm SUPERDRAFT @BIQU]
inherits = *0.28mm*
compatible_printers_condition = printer_model=~/(BIQUBX).*/
[filament:*common*]
cooling = 0
compatible_printers =
extrusion_multiplier = 1
filament_cost = 0
filament_density = 0
filament_diameter = 1.75
filament_notes = ""
filament_settings_id = ""
filament_soluble = 0
min_print_speed = 15
slowdown_below_layer_time = 20
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_BIQU.*/
[filament:*PLA*]
inherits = *common*
bed_temperature = 60
fan_below_layer_time = 100
filament_colour = #DDDDDD
filament_max_volumetric_speed = 15
filament_type = PLA
filament_density = 1.24
filament_cost = 20
first_layer_bed_temperature = 60
first_layer_temperature = 210
fan_always_on = 1
cooling = 1
max_fan_speed = 100
min_fan_speed = 100
bridge_fan_speed = 100
disable_fan_first_layers = 1
temperature = 205
[filament:*PET*]
inherits = *common*
bed_temperature = 70
cooling = 1
disable_fan_first_layers = 3
fan_below_layer_time = 20
filament_colour = #DDDDDD
filament_max_volumetric_speed = 8
filament_type = PETG
filament_density = 1.27
filament_cost = 30
first_layer_bed_temperature = 70
first_layer_temperature = 240
fan_always_on = 1
max_fan_speed = 50
min_fan_speed = 20
bridge_fan_speed = 100
temperature = 240
[filament:*ABS*]
inherits = *common*
bed_temperature = 100
cooling = 0
disable_fan_first_layers = 3
fan_below_layer_time = 20
filament_colour = #DDDDDD
filament_max_volumetric_speed = 11
filament_type = ABS
filament_density = 1.04
filament_cost = 20
first_layer_bed_temperature = 100
first_layer_temperature = 245
fan_always_on = 0
max_fan_speed = 0
min_fan_speed = 0
bridge_fan_speed = 30
top_fan_speed = 0
temperature = 245
[filament:Generic PLA @BIQU]
inherits = *PLA*
filament_vendor = Generic
[filament:Generic PETG @BIQU]
inherits = *PET*
filament_vendor = Generic
[filament:Generic ABS @BIQU]
inherits = *ABS*
first_layer_bed_temperature = 90
bed_temperature = 90
filament_vendor = Generic
# Common printer preset
[printer:*common*]
printer_technology = FFF
before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;{layer_z}\n\n
between_objects_gcode =
pause_print_gcode =
deretract_speed = 40
extruder_colour = #FCE94F
extruder_offset = 0x0
gcode_flavor = marlin2
silent_mode = 0
remaining_times = 0
machine_max_acceleration_e = 10000
machine_max_acceleration_extruding = 1000
machine_max_acceleration_retracting = 1000
machine_max_acceleration_x = 1000
machine_max_acceleration_y = 1000
machine_max_acceleration_z = 100
machine_max_feedrate_e = 65
machine_max_feedrate_x = 200
machine_max_feedrate_y = 200
machine_max_feedrate_z = 10
machine_max_jerk_e = 5
machine_max_jerk_x = 10
machine_max_jerk_y = 10
machine_max_jerk_z = 2
machine_min_extruding_rate = 0
machine_min_travel_rate = 0
layer_gcode = ;AFTER_LAYER_CHANGE\n;{layer_z}
max_layer_height = 0.28
min_layer_height = 0.08
max_print_height = 250
nozzle_diameter = 0.4
printer_notes =
printer_settings_id =
retract_before_travel = 2
retract_before_wipe = 70%
retract_layer_change = 1
retract_length = 5
retract_length_toolchange = 1
retract_lift = 0
retract_lift_above = 0
retract_lift_below = 0
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 60
single_extruder_multi_material = 0
thumbnails = 16x16,220x124
thumbnails_color = #018aff
thumbnails_custom_color = 0
thumbnails_end_file = 0
thumbnails_format = PNG
thumbnails_with_bed = 0
toolchange_gcode =
use_firmware_retraction = 0
use_relative_e_distances = 0
use_volumetric_e = 0
variable_layer_height = 1
wipe = 1
z_offset = 0
z_step = 0.04
printer_model =
default_print_profile = 0.16mm OPTIMAL @BIQU
default_filament_profile = Generic PLA @BIQU
start_gcode = M117 Initial homing sequence. ; Home so that the probe is positioned to heat\nG28\n\nM117 Probe heating position\nG0 X65 Y5 Z1 ; Move the probe to the heating position.\n\nM117 Getting the heaters up to temp!\nM104 S140 ; Set Extruder temperature, no wait\nM140 S[first_layer_bed_temperature] ; Set Heat Bed temperature\nM190 S[first_layer_bed_temperature] ; Wait for Heat Bed temperature\n\nM117 Waiting for probe to warm!\nG4 S90 ; Wait another 90s for the probe to absorb heat.\n\nM117 Post warming re-home\nG28 ; Home all axes again after warming\n\nM117 Z-Align\nG34\n\nM117 ABL Probing\nG29\n\nM900 K0 L0 T0 ; Edit the K and L values if you have calibrated a k factor for your filament\nM900 T0 S0\n\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X4.1 Y10 Z0.3 F5000.0 ; Move to start position\n\nM117 Getting the extruder up to temp\nM140 S[first_layer_bed_temperature] ; Set Heat Bed temperature\nM104 S{first_layer_temperature[initial_tool]} ; Set Extruder temperature\nM109 S{first_layer_temperature[initial_tool]} ; Wait for Extruder temperature\nM190 S[first_layer_bed_temperature] ; Wait for Heat Bed temperature\n\nG92 E0 ; Reset Extruder\nM117 Purging\nG1 X4.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X4.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X4.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nM117 Printing...\nG1 X8 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish
end_gcode = G91 ;Relative positioning\nG1 E-2 F2700 ;Retract a bit\nG1 E-2 Z0.2 F2400 ;Retract a bit more and raise Z\nG1 X5 Y5 F3000 ;Wipe out\nG1 Z10 ;Raise Z by 10mm\nG90 ;Return to absolute positioning\n\nG1 X0 Y{print_bed_max[1]*0.8} ;TaDaaaa\nM106 S0 ;Turn-off fan\nM104 S0 ;Turn-off hotend\nM140 S0 ;Turn-off bed\n\nM84 X Y E ;Disable all steppers but Z\n
[printer:*spriteextruder*]
retract_length = 0.6
retract_speed = 40
deretract_speed = 40
retract_before_travel = 1
retract_before_wipe = 0%
# Intended for printers with dual extruders and a single hotend/nozzle, like the CR-X series
[printer:*dualextruder*]
single_extruder_multi_material = 1
cooling_tube_length = 5
cooling_tube_retraction = 91.5
extra_loading_move = -2
parking_pos_retraction = 92
deretract_speed = 40,40
extruder_colour = #FCE94F;#729FCF
extruder_offset = 0x0,0x0
max_layer_height = 0.28,0.28
min_layer_height = 0.08,0.08
nozzle_diameter = 0.4,0.4
retract_before_travel = 2,2
retract_before_wipe = 70%,70%
retract_layer_change = 1,1
retract_length = 5,5
retract_length_toolchange = 1,1
retract_lift = 0,0
retract_lift_above = 0,0
retract_lift_below = 0,0
retract_restart_extra = 0,0
retract_restart_extra_toolchange = 0,0
retract_speed = 60,60
wipe = 1,1
[printer:*SmallBowden*]
inherits = *common*
machine_max_acceleration_e = 5000
machine_max_acceleration_extruding = 500
machine_max_acceleration_retracting = 1000
machine_max_acceleration_x = 500
machine_max_acceleration_y = 500
machine_max_acceleration_z = 100
machine_max_feedrate_e = 60
machine_max_feedrate_x = 500
machine_max_feedrate_y = 500
machine_max_feedrate_z = 10
machine_max_jerk_e = 5
machine_max_jerk_x = 8
machine_max_jerk_y = 8
machine_max_jerk_z = 0.4
machine_min_extruding_rate = 0
machine_min_travel_rate = 0
retract_before_travel = 2
retract_length = 5
retract_speed = 60
deretract_speed = 40
retract_before_wipe = 70%
default_filament_profile = Generic PLA @BIQU
[printer:*0.4nozzle*]
nozzle_diameter = 0.4
max_layer_height = 0.32
min_layer_height = 0.04
printer_variant = 0.4
default_print_profile = 0.20mm NORMAL @BIQU
[printer:*BIQU BX*]
inherits = *common*; *spriteextruder*
bed_shape = 0x0,250x0,250x250,0x250
max_print_height = 250
printer_model = BIQUBX
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_BIQU\nPRINTER_MODEL_BIQUBX
[printer:BIQU BX]
inherits = *BIQU BX*; *0.4nozzle*

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -1,4 +1,8 @@
min_slic3r_version = 2.6.0-alpha0
0.2.6 Add Ender-5 Pro, Ender-5 S1, Sermoon-V1, Sermoon-V1 Pro. Unlock HIGHSPEED/SUPERSPEED presets for Ender-5 S1/Ender-6/Ender-7.
min_slic3r_version = 2.5.0-alpha0 min_slic3r_version = 2.5.0-alpha0
0.2.4 Add SPEED presets. More conservative extruder clearance.
0.2.3 Improve start_gcode's. Object labeling. MatterHackers filament profiles.
0.2.2 General improvements. 0.2.2 General improvements.
0.2.1 Added Ender 3 Neo and Ender 3 S1 Plus. Various updates. 0.2.1 Added Ender 3 Neo and Ender 3 S1 Plus. Various updates.
0.2.0 Added alternative nozzle support 0.2.0 Added alternative nozzle support

View File

@ -5,7 +5,7 @@
name = Creality name = Creality
# Configuration version of this file. Config file will only be installed, if the config_version differs. # 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. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.2.2 config_version = 0.2.6
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% # changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -131,14 +131,14 @@ bed_model = ender3_bed.stl
bed_texture = ender3.svg bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
#[printer_model:ENDER5PRO] [printer_model:ENDER5PRO]
#name = Creality Ender-5 Pro name = Creality Ender-5 Pro
#variants = 0.4; 0.3; 0.5; 0.6 variants = 0.4; 0.3; 0.5; 0.6
#technology = FFF technology = FFF
#family = ENDER family = ENDER
#bed_model = ender3_bed.stl bed_model = ender3_bed.stl
#bed_texture = ender3.svg bed_texture = ender3.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER5PLUS] [printer_model:ENDER5PLUS]
name = Creality Ender-5 Plus name = Creality Ender-5 Plus
@ -149,6 +149,15 @@ bed_model = ender5plus_bed.stl
bed_texture = ender5plus.svg bed_texture = ender5plus.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER5S1]
name = Creality Ender-5 S1
variants = 0.4; 0.3; 0.5; 0.6
technology = FFF
family = ENDER
bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER6] [printer_model:ENDER6]
name = Creality Ender-6 name = Creality Ender-6
variants = 0.4; 0.3; 0.5; 0.6 variants = 0.4; 0.3; 0.5; 0.6
@ -394,6 +403,28 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
[printer_model:SERMOONV1]
name = Creality Sermoon-V1
variants = 0.4; 0.3; 0.5; 0.6
technology = FFF
family = SERMOON
bed_model = sermoonv1_bed.stl
bed_texture = sermoonv1.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:SERMOONV1PRO]
name = Creality Sermoon-V1 Pro
variants = 0.4; 0.3; 0.5; 0.6
technology = FFF
family = SERMOON
bed_model = sermoonv1_bed.stl
bed_texture = sermoonv1.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
# All presets starting with asterisk, for example *common*, are intermediate and they will # All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface. # not make it into the user interface.
@ -416,8 +447,8 @@ external_fill_pattern = rectilinear
external_perimeters_first = 0 external_perimeters_first = 0
external_perimeter_speed = 25 external_perimeter_speed = 25
extra_perimeters = 0 extra_perimeters = 0
extruder_clearance_height = 34 extruder_clearance_height = 25
extruder_clearance_radius = 47 extruder_clearance_radius = 55
fill_angle = 45 fill_angle = 45
fill_density = 15% fill_density = 15%
fill_pattern = grid fill_pattern = grid
@ -425,6 +456,7 @@ first_layer_height = 0.2
first_layer_speed = 20 first_layer_speed = 20
gap_fill_speed = 30 gap_fill_speed = 30
gcode_comments = 0 gcode_comments = 0
gcode_label_objects = 1
infill_every_layers = 1 infill_every_layers = 1
infill_extruder = 1 infill_extruder = 1
infill_first = 0 infill_first = 0
@ -489,7 +521,62 @@ wipe_tower_x = 170
wipe_tower_y = 140 wipe_tower_y = 140
xy_size_compensation = 0 xy_size_compensation = 0
[print:*speed*]
perimeter_speed = 60
small_perimeter_speed = 30
external_perimeter_speed = 30
infill_speed = 60
solid_infill_speed = 60
top_solid_infill_speed = 30
support_material_speed = 40
support_material_interface_speed = 100%
bridge_speed = 25
ironing_speed = 15
travel_speed = 150
travel_speed_z = 0
first_layer_speed = 20
first_layer_speed_over_raft = 30
[print:*highspeed*]
perimeter_speed = 120
small_perimeter_speed = 60
external_perimeter_speed = 60
infill_speed = 120
solid_infill_speed = 120
top_solid_infill_speed = 60
support_material_speed = 80
support_material_interface_speed = 100%
bridge_speed = 50
ironing_speed = 30
travel_speed = 150
travel_speed_z = 0
first_layer_speed = 40
first_layer_speed_over_raft = 60
[print:*superspeed*]
perimeter_speed = 180
small_perimeter_speed = 90
external_perimeter_speed = 90
infill_speed = 180
solid_infill_speed = 180
top_solid_infill_speed = 90
support_material_speed = 120
support_material_interface_speed = 100%
bridge_speed = 75
ironing_speed = 45
travel_speed = 250
travel_speed_z = 0
first_layer_speed = 60
first_layer_speed_over_raft = 90
[print:*0.06mm*]
inherits = *common*
layer_height = 0.06
bottom_solid_layers = 11
top_solid_layers = 13
bridge_flow_ratio = 0.70
[print:*0.08mm*] [print:*0.08mm*]
inherits = *common* inherits = *common*
@ -609,6 +696,16 @@ support_material_extrusion_width = 0.54
[print:0.06 mm ULTRADETAIL (0.3 mm nozzle) @CREALITY]
inherits = *0.06mm*; *0.3nozzle*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3 and printer_notes=~/.*PRINTER_HAS_ULTRADETAIL.*/
[print:0.06 mm ULTRADETAIL (0.4 mm nozzle) @CREALITY]
inherits = *0.06mm*; *0.4nozzle*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_ULTRADETAIL.*/
[print:0.08 mm SUPERDETAIL (0.3 mm nozzle) @CREALITY] [print:0.08 mm SUPERDETAIL (0.3 mm nozzle) @CREALITY]
inherits = *0.08mm*; *0.3nozzle* inherits = *0.08mm*; *0.3nozzle*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3 compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3
@ -685,6 +782,60 @@ compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle
[print:0.16 mm OPTIMAL SPEED (0.3 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.3nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3
[print:0.16 mm OPTIMAL SPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.4nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4
[print:0.16 mm OPTIMAL SPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.5nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5
[print:0.16 mm OPTIMAL SPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.6nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6
[print:0.16 mm OPTIMAL HIGHSPEED (0.3 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.3nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.16 mm OPTIMAL HIGHSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.4nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.16 mm OPTIMAL HIGHSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.5nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.16 mm OPTIMAL HIGHSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.6nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.16 mm OPTIMAL SUPERSPEED (0.3 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.3nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.16 mm OPTIMAL SUPERSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.4nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.16 mm OPTIMAL SUPERSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.5nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.16 mm OPTIMAL SUPERSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.16mm*; *0.6nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.20 mm NORMAL (0.3 mm nozzle) @CREALITY] [print:0.20 mm NORMAL (0.3 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.3nozzle* inherits = *0.20mm*; *0.3nozzle*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3 compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3
@ -704,6 +855,60 @@ compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle
[print:0.20 mm NORMAL SPEED (0.3 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.3nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3
[print:0.20 mm NORMAL SPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.4nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4
[print:0.20 mm NORMAL SPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.5nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5
[print:0.20 mm NORMAL SPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.6nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6
[print:0.20 mm NORMAL HIGHSPEED (0.3 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.3nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.20 mm NORMAL HIGHSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.4nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.20 mm NORMAL HIGHSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.5nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.20 mm NORMAL HIGHSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.6nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.20 mm NORMAL SUPERSPEED (0.3 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.3nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.3 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.20 mm NORMAL SUPERSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.4nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.20 mm NORMAL SUPERSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.5nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.20 mm NORMAL SUPERSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.20mm*; *0.6nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.24 mm DRAFT (0.4 mm nozzle) @CREALITY] [print:0.24 mm DRAFT (0.4 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.4nozzle* inherits = *0.24mm*; *0.4nozzle*
renamed_from = "0.24mm DRAFT @CREALITY"; "0.24mm DRAFT @ENDER3" renamed_from = "0.24mm DRAFT @CREALITY"; "0.24mm DRAFT @ENDER3"
@ -719,6 +924,48 @@ compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle
[print:0.24 mm DRAFT SPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.4nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4
[print:0.24 mm DRAFT SPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.5nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5
[print:0.24 mm DRAFT SPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.6nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6
[print:0.24 mm DRAFT HIGHSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.4nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.24 mm DRAFT HIGHSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.5nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.24 mm DRAFT HIGHSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.6nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.24 mm DRAFT SUPERSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.4nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.24 mm DRAFT SUPERSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.5nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.24 mm DRAFT SUPERSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.24mm*; *0.6nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.28 mm SUPERDRAFT (0.4 mm nozzle) @CREALITY] [print:0.28 mm SUPERDRAFT (0.4 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.4nozzle* inherits = *0.28mm*; *0.4nozzle*
renamed_from = "0.28mm SUPERDRAFT @CREALITY" renamed_from = "0.28mm SUPERDRAFT @CREALITY"
@ -734,6 +981,48 @@ compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle
[print:0.28 mm SUPERDRAFT SPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.4nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4
[print:0.28 mm SUPERDRAFT SPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.5nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5
[print:0.28 mm SUPERDRAFT SPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.6nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6
[print:0.28 mm SUPERDRAFT HIGHSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.4nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.28 mm SUPERDRAFT HIGHSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.5nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.28 mm SUPERDRAFT HIGHSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.6nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.28 mm SUPERDRAFT SUPERSPEED (0.4 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.4nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.28 mm SUPERDRAFT SUPERSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.5nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.28 mm SUPERDRAFT SUPERSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.28mm*; *0.6nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.36 mm CHUNKY (0.5 mm nozzle) @CREALITY] [print:0.36 mm CHUNKY (0.5 mm nozzle) @CREALITY]
inherits = *0.36mm*; *0.5nozzle* inherits = *0.36mm*; *0.5nozzle*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5
@ -744,12 +1033,60 @@ compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle
[print:0.36 mm CHUNKY SPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.36mm*; *0.5nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5
[print:0.36 mm CHUNKY SPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.36mm*; *0.6nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6
[print:0.36 mm CHUNKY HIGHSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.36mm*; *0.5nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.36 mm CHUNKY HIGHSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.36mm*; *0.6nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.36 mm CHUNKY SUPERSPEED (0.5 mm nozzle) @CREALITY]
inherits = *0.36mm*; *0.5nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.5 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.36 mm CHUNKY SUPERSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.36mm*; *0.6nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
[print:0.44 mm SUPERCHUNKY (0.6 mm nozzle) @CREALITY] [print:0.44 mm SUPERCHUNKY (0.6 mm nozzle) @CREALITY]
inherits = *0.44mm*; *0.6nozzle* inherits = *0.44mm*; *0.6nozzle*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6
[print:0.44 mm SUPERCHUNKY SPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.44mm*; *0.6nozzle*; *speed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6
[print:0.44 mm SUPERCHUNKY HIGHSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.44mm*; *0.6nozzle*; *highspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_HIGHSPEED.*/
[print:0.44 mm SUPERCHUNKY SUPERSPEED (0.6 mm nozzle) @CREALITY]
inherits = *0.44mm*; *0.6nozzle*; *superspeed*
compatible_printers_condition = printer_model=~/(ENDER|CR|SERMOON).*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*PRINTER_HAS_SUPERSPEED.*/
# When submitting new filaments please print the following temperature tower at 0.1mm layer height: # When submitting new filaments please print the following temperature tower at 0.1mm layer height:
# https://www.thingiverse.com/thing:2615842 # https://www.thingiverse.com/thing:2615842
# Pay particular attention to bridging, overhangs and retractions. # Pay particular attention to bridging, overhangs and retractions.
@ -830,6 +1167,26 @@ bridge_fan_speed = 30
top_fan_speed = 0 top_fan_speed = 0
temperature = 245 temperature = 245
[filament:*TPU*]
inherits = *common*
bed_temperature = 50
cooling = 0
disable_fan_first_layers = 3
fan_below_layer_time = 20
filament_colour = #DDDDDD
filament_max_volumetric_speed = 11
filament_type = TPU
filament_density = 1.2
filament_cost = 30
first_layer_bed_temperature = 55
first_layer_temperature = 245
fan_always_on = 0
max_fan_speed = 0
min_fan_speed = 0
bridge_fan_speed = 30
top_fan_speed = 0
temperature = 245
[filament:Generic PLA @CREALITY] [filament:Generic PLA @CREALITY]
inherits = *PLA* inherits = *PLA*
renamed_from = "Generic PLA @ENDER3" renamed_from = "Generic PLA @ENDER3"
@ -1109,6 +1466,50 @@ filament_cost = 16.99
filament_density = 1.24 filament_density = 1.24
filament_colour = #2862C4 filament_colour = #2862C4
[filament:MatterHackers MH Build Series PLA @CREALITY]
inherits = *PLA*
filament_vendor = MatterHackers
temperature = 205
bed_temperature = 60
first_layer_temperature = 210
first_layer_bed_temperature = 60
filament_cost = 20.87
filament_density = 1.25
filament_colour = #3598DB
[filament:MatterHackers MH Build Series PETG @CREALITY]
inherits = *PET*
filament_vendor = MatterHackers
temperature = 245
bed_temperature = 60
first_layer_temperature = 250
first_layer_bed_temperature = 65
filament_cost = 21.98
filament_density = 1.27
filament_colour = #3598DB
[filament:MatterHackers MH Build Series ABS @CREALITY]
inherits = *ABS*
filament_vendor = MatterHackers
temperature = 230
bed_temperature = 90
first_layer_temperature = 240
first_layer_bed_temperature = 100
filament_cost = 20.87
filament_density = 1.07
filament_colour = #3598DB
[filament:MatterHackers MH Build Series TPU @CREALITY]
inherits = *TPU*
filament_vendor = MatterHackers
temperature = 240
bed_temperature = 50
first_layer_temperature = 250
first_layer_bed_temperature = 60
filament_cost = 28.99
filament_density = 1.12
filament_colour = #3598DB
# Common printer preset # Common printer preset
@ -1165,7 +1566,7 @@ wipe = 1
z_offset = 0 z_offset = 0
printer_model = printer_model =
default_filament_profile = "Generic PLA @CREALITY" default_filament_profile = "Generic PLA @CREALITY"
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nG4 S30 ; allow partial nozzle warmup\nG28 ; home all axis\nG1 Z50 F240\nG1 X2.0 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 X2.0 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 Y140 F5000\nG92 E0\nG1 X2.3 Y10 E10 F1200 ; prime the nozzle\nG92 E0
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.85} F{travel_speed*60} ; present print\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+min(max_layer_z+70, max_print_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{max_print_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.85} F{travel_speed*60} ; present print\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+min(max_layer_z+70, max_print_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{max_print_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors
# Intended for printers that have exclusively shipped with a 32bit mainboard # Intended for printers that have exclusively shipped with a 32bit mainboard
@ -1174,19 +1575,19 @@ gcode_flavor = marlin2
# Intended for printers equipped with a strain gauge mechanism, like the CR-6 series # Intended for printers equipped with a strain gauge mechanism, like the CR-6 series
[printer:*straingauge*] [printer:*straingauge*]
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM109 S{first_layer_temperature[0]-50} ; set temporary nozzle temp to prevent oozing during homing\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nG28 ; home all axis\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM109 S{first_layer_temperature[0]-50} ; set temporary nozzle temp to prevent oozing during homing\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nG28 ; home all axis\nG1 Z50 F240\nG1 X2.0 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 X2.0 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 Y140 F5000\nG92 E0\nG1 X2.3 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# Intended for printers with a smaller bed, like the Ender-3 series # Intended for printers with a smaller bed, like the Ender-3 series
[printer:*fastabl*] [printer:*fastabl*]
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nG4 S30 ; allow partial nozzle warmup\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2.0 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 X2.0 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 Y140 F5000\nG92 E0\nG1 X2.3 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# Intended for printers with a larger bed, like the CR-10 series # Intended for printers with a larger bed, like the CR-10 series
[printer:*slowabl*] [printer:*slowabl*]
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2.0 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 X2.0 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 Y140 F5000\nG92 E0\nG1 X2.3 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# intended for printers that have RESTORE_LEVELING_AFTER_G28 enabled in firmware # intended for printers that have RESTORE_LEVELING_AFTER_G28 enabled in firmware
[printer:*storedabl*] [printer:*storedabl*]
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis and restore leveling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nG4 S30 ; allow partial nozzle warmup\nG28 ; home all axis and restore leveling\nG1 Z50 F240\nG1 X2.0 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 X2.0 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 Y140 F5000\nG92 E0\nG1 X2.3 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# Intended for printers with vendor official firmware verified to support M25 # Intended for printers with vendor official firmware verified to support M25
[printer:*pauseprint*] [printer:*pauseprint*]
@ -1238,7 +1639,7 @@ retract_before_wipe = 0%
[printer:*0.3nozzle*] [printer:*0.3nozzle*]
nozzle_diameter = 0.3 nozzle_diameter = 0.3
printer_variant = 0.3 printer_variant = 0.3
min_layer_height = 0.08 min_layer_height = 0.06
max_layer_height = 0.24 max_layer_height = 0.24
retract_lift_above = 0.2 retract_lift_above = 0.2
default_print_profile = "0.12 mm DETAIL (0.3 mm nozzle) @CREALITY" default_print_profile = "0.12 mm DETAIL (0.3 mm nozzle) @CREALITY"
@ -1246,7 +1647,7 @@ default_print_profile = "0.12 mm DETAIL (0.3 mm nozzle) @CREALITY"
[printer:*0.4nozzle*] [printer:*0.4nozzle*]
nozzle_diameter = 0.4 nozzle_diameter = 0.4
printer_variant = 0.4 printer_variant = 0.4
min_layer_height = 0.08 min_layer_height = 0.06
max_layer_height = 0.32 max_layer_height = 0.32
retract_lift_above = 0.2 retract_lift_above = 0.2
default_print_profile = "0.16 mm OPTIMAL (0.4 mm nozzle) @CREALITY" default_print_profile = "0.16 mm OPTIMAL (0.4 mm nozzle) @CREALITY"
@ -1405,7 +1806,7 @@ inherits = *common*; *storedabl*; *spriteextruder*; *pauseprint*
bed_shape = 5x0,215x0,215x220,5x220 bed_shape = 5x0,215x0,215x220,5x220
max_print_height = 270 max_print_height = 270
printer_model = ENDER3S1 printer_model = ENDER3S1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1\nPRINTER_HAS_ULTRADETAIL
[printer:Creality Ender-3 S1 (0.3 mm nozzle)] [printer:Creality Ender-3 S1 (0.3 mm nozzle)]
inherits = *ENDER3S1*; *0.3nozzle* inherits = *ENDER3S1*; *0.3nozzle*
@ -1427,7 +1828,7 @@ inherits = *common*; *storedabl*; *spriteextruder*; *pauseprint*
bed_shape = 5x0,215x0,215x220,5x220 bed_shape = 5x0,215x0,215x220,5x220
max_print_height = 270 max_print_height = 270
printer_model = ENDER3S1PRO printer_model = ENDER3S1PRO
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1PRO printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1PRO\nPRINTER_HAS_ULTRADETAIL
[printer:Creality Ender-3 S1 Pro (0.3 mm nozzle)] [printer:Creality Ender-3 S1 Pro (0.3 mm nozzle)]
inherits = *ENDER3S1PRO*; *0.3nozzle* inherits = *ENDER3S1PRO*; *0.3nozzle*
@ -1449,7 +1850,7 @@ inherits = *common*; *storedabl*; *spriteextruder*; *pauseprint*
bed_shape = 5x5,295x5,295x295,5x295 bed_shape = 5x5,295x5,295x295,5x295
max_print_height = 300 max_print_height = 300
printer_model = ENDER3S1PLUS printer_model = ENDER3S1PLUS
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1PLUS printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1PLUS\nPRINTER_HAS_ULTRADETAIL
[printer:Creality Ender-3 S1 Plus (0.3 mm nozzle)] [printer:Creality Ender-3 S1 Plus (0.3 mm nozzle)]
inherits = *ENDER3S1PLUS*; *0.3nozzle* inherits = *ENDER3S1PLUS*; *0.3nozzle*
@ -1554,26 +1955,26 @@ inherits = *ENDER5*; *0.6nozzle*
#[printer:*ENDER5PRO*] [printer:*ENDER5PRO*]
#inherits = *common*; *bowdencapricorn*; *descendingz* inherits = *common*; *bowdencapricorn*; *descendingz*
#bed_shape = 5x2.5,225x2.5,225x222.5,5x222.5 bed_shape = 5x2.5,225x2.5,225x222.5,5x222.5
#max_print_height = 300 max_print_height = 300
#printer_model = ENDER5PRO printer_model = ENDER5PRO
#printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER5PRO\nPRINTER_HAS_BOWDEN printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER5PRO\nPRINTER_HAS_BOWDEN
#machine_max_acceleration_e = 1000 machine_max_acceleration_e = 1000
#machine_max_feedrate_z = 5 machine_max_feedrate_z = 5
#
#[printer:Creality Ender-5 Pro (0.3 mm nozzle)] [printer:Creality Ender-5 Pro (0.3 mm nozzle)]
#inherits = *ENDER5PRO*; *0.3nozzle* inherits = *ENDER5PRO*; *0.3nozzle*
#
#[printer:Creality Ender-5 Pro (0.4 mm nozzle)] [printer:Creality Ender-5 Pro (0.4 mm nozzle)]
#inherits = *ENDER5PRO*; *0.4nozzle* inherits = *ENDER5PRO*; *0.4nozzle*
#
#[printer:Creality Ender-5 Pro (0.5 mm nozzle)] [printer:Creality Ender-5 Pro (0.5 mm nozzle)]
#inherits = *ENDER5PRO*; *0.5nozzle* inherits = *ENDER5PRO*; *0.5nozzle*
#
#[printer:Creality Ender-5 Pro (0.6 mm nozzle)] [printer:Creality Ender-5 Pro (0.6 mm nozzle)]
#inherits = *ENDER5PRO*; *0.6nozzle* inherits = *ENDER5PRO*; *0.6nozzle*
@ -1603,12 +2004,33 @@ inherits = *ENDER5PLUS*; *0.6nozzle*
[printer:*ENDER5S1*]
inherits = *common*; *descendingz*; *spriteextruder*
bed_shape = 5x0,215x0,215x220,5x220
max_print_height = 280
printer_model = ENDER5S1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER5S1\nPRINTER_HAS_ULTRADETAIL\nPRINTER_HAS_HIGHSPEED\nPRINTER_HAS_SUPERSPEED
[printer:Creality Ender-5 S1 (0.3 mm nozzle)]
inherits = *ENDER5S1*; *0.3nozzle*
[printer:Creality Ender-5 S1 (0.4 mm nozzle)]
inherits = *ENDER5S1*; *0.4nozzle*
[printer:Creality Ender-5 S1 (0.5 mm nozzle)]
inherits = *ENDER5S1*; *0.5nozzle*
[printer:Creality Ender-5 S1 (0.6 mm nozzle)]
inherits = *ENDER5S1*; *0.6nozzle*
[printer:*ENDER6*] [printer:*ENDER6*]
inherits = *common*; *bowden*; *descendingz* inherits = *common*; *bowden*; *descendingz*
bed_shape = 5x5,255x5,255x255,5x255 bed_shape = 5x5,255x5,255x255,5x255
max_print_height = 400 max_print_height = 400
printer_model = ENDER6 printer_model = ENDER6
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER6\nPRINTER_HAS_BOWDEN printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER6\nPRINTER_HAS_BOWDEN\nPRINTER_HAS_HIGHSPEED
[printer:Creality Ender-6 (0.3 mm nozzle)] [printer:Creality Ender-6 (0.3 mm nozzle)]
inherits = *ENDER6*; *0.3nozzle* inherits = *ENDER6*; *0.3nozzle*
@ -1630,7 +2052,7 @@ inherits = *common*; *bowden*; *descendingz*
bed_shape = 5x5,245x5,245x245,5x245 bed_shape = 5x5,245x5,245x245,5x245
max_print_height = 300 max_print_height = 300
printer_model = ENDER7 printer_model = ENDER7
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER7\nPRINTER_HAS_BOWDEN printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER7\nPRINTER_HAS_BOWDEN\nPRINTER_HAS_HIGHSPEED\nPRINTER_HAS_SUPERSPEED
[printer:Creality Ender-7 (0.3 mm nozzle)] [printer:Creality Ender-7 (0.3 mm nozzle)]
inherits = *ENDER7*; *0.3nozzle* inherits = *ENDER7*; *0.3nozzle*
@ -1805,7 +2227,7 @@ inherits = *common*; *slowabl*; *spriteextruder*
bed_shape = 5x5,295x5,295x295,5x295 bed_shape = 5x5,295x5,295x295,5x295
max_print_height = 400 max_print_height = 400
printer_model = CR10SMARTPRO printer_model = CR10SMARTPRO
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_CR10SMARTPRO\nPRINTER_HAS_BOWDEN printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_CR10SMARTPRO\nPRINTER_HAS_ULTRADETAIL
[printer:Creality CR-10 SMART Pro (0.3 mm nozzle)] [printer:Creality CR-10 SMART Pro (0.3 mm nozzle)]
inherits = *CR10SMARTPRO*; *0.3nozzle* inherits = *CR10SMARTPRO*; *0.3nozzle*
@ -2130,7 +2552,7 @@ inherits = *common*; *directdriveextruder*; *descendingz*
bed_shape = 5x5,275x5,275x255,5x255 bed_shape = 5x5,275x5,275x255,5x255
max_print_height = 310 max_print_height = 310
printer_model = SERMOOND1 printer_model = SERMOOND1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_SERMOOND1\nPRINTER_HAS_BOWDEN printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_SERMOOND1
[printer:Creality Sermoon-D1 (0.3 mm nozzle)] [printer:Creality Sermoon-D1 (0.3 mm nozzle)]
inherits = *SERMOOND1*; *0.3nozzle* inherits = *SERMOOND1*; *0.3nozzle*
@ -2144,3 +2566,45 @@ inherits = *SERMOOND1*; *0.5nozzle*
[printer:Creality Sermoon-D1 (0.6 mm nozzle)] [printer:Creality Sermoon-D1 (0.6 mm nozzle)]
inherits = *SERMOOND1*; *0.6nozzle* inherits = *SERMOOND1*; *0.6nozzle*
[printer:*SERMOONV1*]
inherits = *common*; *spriteextruder*; *descendingz*
bed_shape = 5x5,170x5,170x170,5x170
max_print_height = 165
printer_model = SERMOONV1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_SERMOONV1\nPRINTER_HAS_ULTRADETAIL
[printer:Creality Sermoon-V1 (0.3 mm nozzle)]
inherits = *SERMOONV1*; *0.3nozzle*
[printer:Creality Sermoon-V1 (0.4 mm nozzle)]
inherits = *SERMOONV1*; *0.4nozzle*
[printer:Creality Sermoon-V1 (0.5 mm nozzle)]
inherits = *SERMOONV1*; *0.5nozzle*
[printer:Creality Sermoon-V1 (0.6 mm nozzle)]
inherits = *SERMOONV1*; *0.6nozzle*
[printer:*SERMOONV1PRO*]
inherits = *common*; *spriteextruder*; *descendingz*
bed_shape = 5x5,170x5,170x170,5x170
max_print_height = 165
printer_model = SERMOONV1PRO
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_SERMOONV1PRO\nPRINTER_HAS_ULTRADETAIL
[printer:Creality Sermoon-V1 Pro (0.3 mm nozzle)]
inherits = *SERMOONV1PRO*; *0.3nozzle*
[printer:Creality Sermoon-V1 Pro (0.4 mm nozzle)]
inherits = *SERMOONV1PRO*; *0.4nozzle*
[printer:Creality Sermoon-V1 Pro (0.5 mm nozzle)]
inherits = *SERMOONV1PRO*; *0.5nozzle*
[printer:Creality Sermoon-V1 Pro (0.6 mm nozzle)]
inherits = *SERMOONV1PRO*; *0.6nozzle*

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,3 +1,5 @@
min_slic3r_version = 2.6.0-alpha1
1.0.2 Added new printer models.
min_slic3r_version = 2.5.0-alpha3 min_slic3r_version = 2.5.0-alpha3
1.0.1 Decreased bed size to 220x220. 1.0.1 Decreased bed size to 220x220.
1.0.0 Initial version 1.0.0 Initial version

View File

@ -6,7 +6,7 @@
name = Elegoo name = Elegoo
# Configuration version of this file. Config file will only be installed, if the config_version differs. # 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. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.0.1 config_version = 1.0.2
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Elegoo/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Elegoo/
# The printer models will be shown by the Configuration Wizard in this order, # The printer models will be shown by the Configuration Wizard in this order,
@ -58,6 +58,33 @@ bed_model =
bed_texture = bed_texture =
default_materials = Generic PLA @ELEGOO; Generic PETG @ELEGOO; Generic ABS @ELEGOO default_materials = Generic PLA @ELEGOO; Generic PETG @ELEGOO; Generic ABS @ELEGOO
[printer_model:NEPTUNE3MAX]
name = Elegoo Neptune-3 Max
variants = 0.4
technology = FFF
family = NEPTUNE
bed_model =
bed_texture =
default_materials = Generic PLA @ELEGOO; Generic PETG @ELEGOO; Generic ABS @ELEGOO
[printer_model:NEPTUNE3PLUS]
name = Elegoo Neptune-3 Plus
variants = 0.4
technology = FFF
family = NEPTUNE
bed_model =
bed_texture =
default_materials = Generic PLA @ELEGOO; Generic PETG @ELEGOO; Generic ABS @ELEGOO
[printer_model:NEPTUNE3PRO]
name = Elegoo Neptune-3 Pro
variants = 0.4
technology = FFF
family = NEPTUNE
bed_model =
bed_texture =
default_materials = Generic PLA @ELEGOO; Generic PETG @ELEGOO; Generic ABS @ELEGOO
[printer_model:NEPTUNEX] [printer_model:NEPTUNEX]
name = Elegoo Neptune-X name = Elegoo Neptune-X
variants = 0.4 variants = 0.4
@ -428,26 +455,9 @@ retract_length = 5
retract_speed = 60 retract_speed = 60
deretract_speed = 40 deretract_speed = 40
retract_before_wipe = 70% retract_before_wipe = 70%
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 start_gcode = M413 S0 ; disable Power Loss Recovery\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+min(max_layer_z+70, max_print_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{max_print_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+min(max_layer_z+70, max_print_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{max_print_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors
# Intended for printers with a smaller bed
# [printer:*fastabl*]
# start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# Intended for printers with a larger bed
# [printer:*slowabl*]
# start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nG28 ; home all axis\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0
# Intended for printers with vendor official firmware verified to support M25
# [printer:*pauseprint*]
# pause_print_gcode = M25 ; pause print
# Intended for printers where the Z-axis lowers the print bed during printing
# [printer:*invertedz*]
# end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600{endif} ; Move print bed down\nG1 X50 Y50 F{travel_speed*60} ; present print\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+max_print_height-10} F600{endif} ; Move print bed down further down\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors
# Intended for printers with dual extruders and a single hotend/nozzle # Intended for printers with dual extruders and a single hotend/nozzle
[printer:*dualextruder*] [printer:*dualextruder*]
single_extruder_multi_material = 1 single_extruder_multi_material = 1
@ -473,7 +483,7 @@ retract_restart_extra = 0,0
retract_restart_extra_toolchange = 0,0 retract_restart_extra_toolchange = 0,0
retract_speed = 60,60 retract_speed = 60,60
wipe = 1,1 wipe = 1,1
start_gcode = T[initial_tool] ; set active extruder\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\n;G29 ; auto bed levelling - remove ; at beginning of line to enable\n;M420 S1 ; enable mesh - remove ; at beginning of line to enable\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240 ; move down to prime nozzle\nG92 E0 ; reset extruder\nG1 E90 ; load filament\nG92 E0 ; reset extruder\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000 ; move over for second prime line\nG92 E0 ; reset extruder\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 ; reset extruder start_gcode = T[initial_tool] ; set active extruder\nM413 S0 ; disable Power Loss Recovery\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM140 S{first_layer_bed_temperature[0]} ; set final bed temp\nM104 S150 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\n;G29 ; auto bed levelling - remove ; at beginning of line to enable\n;M420 S1 ; enable mesh - remove ; at beginning of line to enable\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG1 Z0.28 F240 ; move down to prime nozzle\nG92 E0 ; reset extruder\nG1 E90 ; load filament\nG92 E0 ; reset extruder\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000 ; move over for second prime line\nG92 E0 ; reset extruder\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 ; reset extruder
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\nG1 E-80 F2000 ; unload filament\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+min(max_layer_z+70, max_print_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{max_print_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\nG1 E-80 F2000 ; unload filament\n{if max_layer_z < max_print_height-10}G1 Z{z_offset+min(max_layer_z+70, max_print_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{max_print_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors
# Copy of Creality CR-X config for the Neptune 2D (dual extruder, single hotend) # Copy of Creality CR-X config for the Neptune 2D (dual extruder, single hotend)
@ -482,29 +492,57 @@ end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2,
inherits = Elegoo Neptune-2; *dualextruder* inherits = Elegoo Neptune-2; *dualextruder*
retract_length = 6,6 retract_length = 6,6
printer_model = NEPTUNE2D printer_model = NEPTUNE2D
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE2D\nPRINTER_HAS_BOWDEN printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE2D
[printer:Elegoo Neptune-2S] [printer:Elegoo Neptune-2S]
inherits = Elegoo Neptune-2 inherits = Elegoo Neptune-2
printer_model = NEPTUNE2S printer_model = NEPTUNE2S
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE2D\nPRINTER_HAS_BOWDEN printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE2S
[printer:Elegoo Neptune-X] [printer:Elegoo Neptune-X]
inherits = Elegoo Neptune-2 inherits = Elegoo Neptune-2
max_print_height = 300 max_print_height = 300
printer_model = NEPTUNEX printer_model = NEPTUNEX
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE2D\nPRINTER_HAS_BOWDEN printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNEX
[printer:Elegoo Neptune-3] [printer:Elegoo Neptune-3]
inherits = Elegoo Neptune-2 inherits = Elegoo Neptune-2
max_print_height = 280 max_print_height = 280
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\nG29 ; run abl mesh\nM420 S1 ; load mesh\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0 start_gcode = M413 S0 ; disable Power Loss Recovery\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S120 ; set temporary nozzle temp to prevent oozing during homing and auto bed leveling\nM140 S[first_layer_bed_temperature] ; set final bed temp\nG4 S10 ; allow partial nozzle warmup\nG28 ; home all axis\n;G29 ; run abl mesh\nM420 S1 ; load mesh\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set final nozzle temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp to stabilize\nM109 S[first_layer_temperature] ; wait for nozzle temp to stabilize\nG1 Z0.28 F240\nG92 E0\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E10 F1200 ; prime the nozzle\nG92 E0
printer_model = NEPTUNE3 printer_model = NEPTUNE3
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE2D\nPRINTER_HAS_BOWDEN printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE3
[printer:Elegoo Neptune-1] [printer:Elegoo Neptune-1]
inherits = Elegoo Neptune-2 inherits = Elegoo Neptune-2
bed_shape = 0x0,210x0,210x210,0x210 bed_shape = 0x0,210x0,210x210,0x210
max_print_height = 200 max_print_height = 200
printer_model = NEPTUNE1 printer_model = NEPTUNE1
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE2D\nPRINTER_HAS_BOWDEN printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE1
[printer:Elegoo Neptune-3 Max]
inherits = Elegoo Neptune-3
retract_length = 2.5
retract_speed = 25
bed_shape = 0x0,420x0,420x420,0x420
max_print_height = 500
printer_model = NEPTUNE3MAX
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE3MAX
[printer:Elegoo Neptune-3 Plus]
inherits = Elegoo Neptune-3
retract_length = 2.5
retract_speed = 25
bed_shape = 0x0,320x0,320x320,0x320
max_print_height = 400
printer_model = NEPTUNE3PLUS
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE3PLUS
[printer:Elegoo Neptune-3 Pro]
inherits = Elegoo Neptune-3
bed_shape = 0x0,225x0,225x225,0x225
max_print_height = 280
retract_length = 2.5
retract_speed = 25
printer_model = NEPTUNE3PRO
printer_notes = Do not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_NEPTUNE3PRO

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,4 +1,7 @@
min_slic3r_version = 2.6.0-alpha1
1.6.0-alpha0 Default top fill set to monotonic lines. Updated infill/perimeter overlap values. Updated output filename format. Enabled dynamic overhang speeds.
min_slic3r_version = 2.5.0-alpha0 min_slic3r_version = 2.5.0-alpha0
1.5.5 Added new Prusament Resin material profiles. Enabled g-code thumbnails for MK2.5 family printers.
1.5.4 Added material profiles for Prusament Resin BioBased60. 1.5.4 Added material profiles for Prusament Resin BioBased60.
1.5.3 Added filament profiles for ColorFabb VarioShore TPU, FormFutura PP, NinjaTek NinjaFlex/Cheetah TPU and for multiple Eolas Prints filaments. Updated bridging settings in 50um and 70um profiles. 1.5.3 Added filament profiles for ColorFabb VarioShore TPU, FormFutura PP, NinjaTek NinjaFlex/Cheetah TPU and for multiple Eolas Prints filaments. Updated bridging settings in 50um and 70um profiles.
1.5.2 Added SLA material profiles. 1.5.2 Added SLA material profiles.

View File

@ -5,7 +5,7 @@
name = Prusa Research name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs. # 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. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.5.4 config_version = 1.6.0-alpha0
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -173,7 +173,7 @@ infill_extruder = 1
infill_extrusion_width = 0.45 infill_extrusion_width = 0.45
infill_first = 0 infill_first = 0
infill_only_where_needed = 0 infill_only_where_needed = 0
infill_overlap = 25% infill_overlap = 10%
interface_shells = 0 interface_shells = 0
max_print_speed = 100 max_print_speed = 100
max_volumetric_extrusion_rate_slope_negative = 0 max_volumetric_extrusion_rate_slope_negative = 0
@ -184,7 +184,7 @@ notes =
overhangs = 1 overhangs = 1
only_retract_when_crossing_perimeters = 0 only_retract_when_crossing_perimeters = 0
ooze_prevention = 0 ooze_prevention = 0
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode output_filename_format = {input_filename_base}_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.gcode
perimeters = 2 perimeters = 2
perimeter_extruder = 1 perimeter_extruder = 1
perimeter_extrusion_width = 0.45 perimeter_extrusion_width = 0.45
@ -248,6 +248,8 @@ wall_transition_filter_deviation = 25%
wall_transition_length = 0.4 wall_transition_length = 0.4
wall_distribution_count = 1 wall_distribution_count = 1
min_bead_width = 85% min_bead_width = 85%
enable_dynamic_overhang_speeds = 1
top_fill_pattern = monotoniclines
[print:*MK3*] [print:*MK3*]
fill_pattern = grid fill_pattern = grid
@ -289,7 +291,7 @@ support_material_interface_spacing = 0.15
support_material_spacing = 1 support_material_spacing = 1
support_material_xy_spacing = 150% support_material_xy_spacing = 150%
support_material_contact_distance = 0.1 support_material_contact_distance = 0.1
output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.gcode
thick_bridges = 0 thick_bridges = 0
bridge_flow_ratio = 1 bridge_flow_ratio = 1
bridge_speed = 20 bridge_speed = 20
@ -299,6 +301,8 @@ wall_transition_filter_deviation = 25%
wall_transition_length = 0.25 wall_transition_length = 0.25
wall_distribution_count = 1 wall_distribution_count = 1
min_bead_width = 85% min_bead_width = 85%
infill_overlap = 10%
dynamic_overhang_speeds[0] = 20,20,15,15
[print:*0.25nozzleMK3*] [print:*0.25nozzleMK3*]
inherits = *0.25nozzle* inherits = *0.25nozzle*
@ -340,7 +344,7 @@ support_material_extrusion_width = 0.55
support_material_contact_distance = 0.15 support_material_contact_distance = 0.15
support_material_xy_spacing = 80% support_material_xy_spacing = 80%
support_material_interface_spacing = 0.3 support_material_interface_spacing = 0.3
output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.gcode
infill_anchor_max = 15 infill_anchor_max = 15
top_solid_min_thickness = 0.9 top_solid_min_thickness = 0.9
bottom_solid_min_thickness = 0.6 bottom_solid_min_thickness = 0.6
@ -352,6 +356,7 @@ wall_transition_filter_deviation = 25%
wall_transition_length = 0.6 wall_transition_length = 0.6
wall_distribution_count = 1 wall_distribution_count = 1
min_bead_width = 85% min_bead_width = 85%
infill_overlap = 15%
[print:*0.6nozzleMK3*] [print:*0.6nozzleMK3*]
inherits = *0.6nozzle* inherits = *0.6nozzle*
@ -390,7 +395,7 @@ support_material_interface_speed = 100%
support_material_spacing = 2 support_material_spacing = 2
support_material_xy_spacing = 80% support_material_xy_spacing = 80%
support_material_threshold = 50 support_material_threshold = 50
output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode output_filename_format = {input_filename_base}_{nozzle_diameter[0]}n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.gcode
fill_pattern = gyroid fill_pattern = gyroid
fill_density = 15% fill_density = 15%
infill_anchor_max = 20 infill_anchor_max = 20
@ -399,7 +404,7 @@ bottom_solid_layers = 3
skirt_distance = 3 skirt_distance = 3
skirt_height = 2 skirt_height = 2
first_layer_height = 0.3 first_layer_height = 0.3
infill_overlap = 30% infill_overlap = 15%
bridge_speed = 22 bridge_speed = 22
gap_fill_speed = 30 gap_fill_speed = 30
bridge_flow_ratio = 0.9 bridge_flow_ratio = 0.9
@ -4065,7 +4070,6 @@ inherits = *FLEX*
filament_vendor = Eolas Prints filament_vendor = Eolas Prints
filament_cost = 34.99 filament_cost = 34.99
filament_density = 1.21 filament_density = 1.21
filament_spool_weight = 1000
filament_colour = #4D9398 filament_colour = #4D9398
filament_max_volumetric_speed = 1.2 filament_max_volumetric_speed = 1.2
temperature = 235 temperature = 235
@ -4495,6 +4499,8 @@ filament_soluble = 1
filament_type = PVB filament_type = PVB
filament_colour = #FFFF6F filament_colour = #FFFF6F
filament_spool_weight = 201 filament_spool_weight = 201
bed_temperature = 75
first_layer_bed_temperature = 75
slowdown_below_layer_time = 20 slowdown_below_layer_time = 20
filament_ramming_parameters = "120 110 1.74194 1.90323 2.16129 2.48387 2.83871 3.25806 3.83871 4.6129 5.41935 5.96774| 0.05 1.69677 0.45 1.96128 0.95 2.63872 1.45 3.46129 1.95 4.99031 2.45 6.12908 2.95 8.30974 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6" filament_ramming_parameters = "120 110 1.74194 1.90323 2.16129 2.48387 2.83871 3.25806 3.83871 4.6129 5.41935 5.96774| 0.05 1.69677 0.45 1.96128 0.95 2.63872 1.45 3.46129 1.95 4.99031 2.45 6.12908 2.95 8.30974 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6"
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.05{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.05{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0"
@ -5755,6 +5761,14 @@ material_type = Tough
material_vendor = BlueCast material_vendor = BlueCast
material_colour = #007EFD material_colour = #007EFD
[sla_material:BlueCast X-One @0.025]
inherits = *common 0.025*
exposure_time = 25
initial_exposure_time = 35
material_type = Casting
material_vendor = BlueCast
material_colour = #C0C0C0
[sla_material:DruckWege Type D High Temp @0.025] [sla_material:DruckWege Type D High Temp @0.025]
inherits = *common 0.025* inherits = *common 0.025*
exposure_time = 6 exposure_time = 6
@ -5957,6 +5971,14 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #FCB30E material_colour = #FCB30E
[sla_material:Prusament Resin Tough Classic Red @0.025]
inherits = *common 0.025*
exposure_time = 3
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #EC0000
[sla_material:Prusament Resin BioBased60 Herbal Green @0.025] [sla_material:Prusament Resin BioBased60 Herbal Green @0.025]
inherits = *common 0.025* inherits = *common 0.025*
exposure_time = 7 exposure_time = 7
@ -5981,6 +6003,22 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #ECDE05 material_colour = #ECDE05
[sla_material:Prusament Resin Flex80 Transparent Clear @0.025]
inherits = *common 0.025*
exposure_time = 10
initial_exposure_time = 30
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #F3F6F4
[sla_material:Prusament Resin Flex80 Black @0.025]
inherits = *common 0.025*
exposure_time = 8
initial_exposure_time = 30
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #595959
## Prusa 0.025 ## Prusa 0.025
[sla_material:Prusa Orange Tough @0.025] [sla_material:Prusa Orange Tough @0.025]
@ -6432,6 +6470,14 @@ material_type = Tough
material_vendor = BlueCast material_vendor = BlueCast
material_colour = #007EFD material_colour = #007EFD
[sla_material:BlueCast X-One @0.05]
inherits = *common 0.05*
exposure_time = 27
initial_exposure_time = 35
material_type = Casting
material_vendor = BlueCast
material_colour = #C0C0C0
[sla_material:DruckWege Type D High Temp @0.05] [sla_material:DruckWege Type D High Temp @0.05]
inherits = *common 0.05* inherits = *common 0.05*
exposure_time = 10 exposure_time = 10
@ -6938,6 +6984,14 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #FCB30E material_colour = #FCB30E
[sla_material:Prusament Resin Tough Classic Red @0.05]
inherits = *common 0.05*
exposure_time = 4
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #EC0000
[sla_material:Prusament Resin BioBased60 Herbal Green @0.05] [sla_material:Prusament Resin BioBased60 Herbal Green @0.05]
inherits = *common 0.05* inherits = *common 0.05*
exposure_time = 8 exposure_time = 8
@ -6962,6 +7016,22 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #ECDE05 material_colour = #ECDE05
[sla_material:Prusament Resin Flex80 Transparent Clear @0.05]
inherits = *common 0.05*
exposure_time = 15
initial_exposure_time = 30
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #F3F6F4
[sla_material:Prusament Resin Flex80 Black @0.05]
inherits = *common 0.05*
exposure_time = 10
initial_exposure_time = 30
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #595959
## Prusa 0.05 ## Prusa 0.05
[sla_material:Prusa Beige Tough @0.05] [sla_material:Prusa Beige Tough @0.05]
@ -7252,6 +7322,14 @@ material_type = Tough
material_vendor = BlueCast material_vendor = BlueCast
material_colour = #FFEEE6 material_colour = #FFEEE6
[sla_material:BlueCast X-One @0.1]
inherits = *common 0.1*
exposure_time = 30
initial_exposure_time = 45
material_type = Casting
material_vendor = BlueCast
material_colour = #C0C0C0
[sla_material:Ameralabs TGM-7 LED @0.1] [sla_material:Ameralabs TGM-7 LED @0.1]
inherits = *common 0.1* inherits = *common 0.1*
exposure_time = 10 exposure_time = 10
@ -7286,6 +7364,14 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #808080 material_colour = #808080
[sla_material:Prusament Resin Tough Classic Red @0.1]
inherits = *common 0.1*
exposure_time = 6
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #EC0000
[sla_material:Prusament Resin Tough Sandstone Model @0.1] [sla_material:Prusament Resin Tough Sandstone Model @0.1]
inherits = *common 0.1* inherits = *common 0.1*
exposure_time = 13 exposure_time = 13
@ -7374,6 +7460,22 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #ECDE05 material_colour = #ECDE05
[sla_material:Prusament Resin Flex80 Transparent Clear @0.1]
inherits = *common 0.1*
exposure_time = 20
initial_exposure_time = 30
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #F3F6F4
[sla_material:Prusament Resin Flex80 Black @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 30
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #595959
## Prusa 0.1 ## Prusa 0.1
[sla_material:Prusa Orange Tough @0.1] [sla_material:Prusa Orange Tough @0.1]
@ -7590,6 +7692,14 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #FCB30E material_colour = #FCB30E
[sla_material:Prusament Resin Tough Classic Red @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 1.8
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #EC0000
[sla_material:Prusament Resin BioBased60 Herbal Green @0.025 SL1S] [sla_material:Prusament Resin BioBased60 Herbal Green @0.025 SL1S]
inherits = *0.025_sl1s* inherits = *0.025_sl1s*
exposure_time = 3.5 exposure_time = 3.5
@ -7615,6 +7725,24 @@ material_vendor = Prusa Polymers
material_colour = #ECDE05 material_colour = #ECDE05
material_print_speed = slow material_print_speed = slow
[sla_material:Prusament Resin Flex80 Transparent Clear @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 4
initial_exposure_time = 25
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #F3F6F4
material_print_speed = slow
[sla_material:Prusament Resin Flex80 Black @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 2.6
initial_exposure_time = 25
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #595959
material_print_speed = slow
## Made for Prusa 0.025 ## Made for Prusa 0.025
[sla_material:Prusa Orange Tough @0.025 SL1S] [sla_material:Prusa Orange Tough @0.025 SL1S]
@ -8042,6 +8170,14 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #FCB30E material_colour = #FCB30E
[sla_material:Prusament Resin Tough Classic Red @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 2
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #EC0000
[sla_material:Prusament Resin BioBased60 Herbal Green @0.05 SL1S] [sla_material:Prusament Resin BioBased60 Herbal Green @0.05 SL1S]
inherits = *0.05_sl1s* inherits = *0.05_sl1s*
exposure_time = 4 exposure_time = 4
@ -8067,6 +8203,24 @@ material_vendor = Prusa Polymers
material_colour = #ECDE05 material_colour = #ECDE05
material_print_speed = slow material_print_speed = slow
[sla_material:Prusament Resin Flex80 Transparent Clear @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 5
initial_exposure_time = 25
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #F3F6F4
material_print_speed = slow
[sla_material:Prusament Resin Flex80 Black @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 3
initial_exposure_time = 25
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #595959
material_print_speed = slow
## Made for Prusa 0.05 ## Made for Prusa 0.05
[sla_material:Prusa Orange Tough @0.05 SL1S] [sla_material:Prusa Orange Tough @0.05 SL1S]
@ -8798,6 +8952,14 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #FCB30E material_colour = #FCB30E
[sla_material:Prusament Resin Tough Classic Red @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 2.6
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #EC0000
[sla_material:Prusament Resin BioBased60 Herbal Green @0.1 SL1S] [sla_material:Prusament Resin BioBased60 Herbal Green @0.1 SL1S]
inherits = *0.1_sl1s* inherits = *0.1_sl1s*
exposure_time = 5 exposure_time = 5
@ -8823,6 +8985,24 @@ material_vendor = Prusa Polymers
material_colour = #ECDE05 material_colour = #ECDE05
material_print_speed = slow material_print_speed = slow
[sla_material:Prusament Resin Flex80 Transparent Clear @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 6
initial_exposure_time = 25
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #F3F6F4
material_print_speed = slow
[sla_material:Prusament Resin Flex80 Black @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 3.5
initial_exposure_time = 25
material_type = Flexible
material_vendor = Prusa Polymers
material_colour = #595959
material_print_speed = slow
## Made for Prusa 0.1 ## Made for Prusa 0.1
[sla_material:Prusa Orange Tough @0.1 SL1S] [sla_material:Prusa Orange Tough @0.1 SL1S]
@ -9312,6 +9492,8 @@ printer_model = MK2.5
remaining_times = 1 remaining_times = 1
machine_max_jerk_e = 4.5 machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0 start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y200 F3600 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
thumbnails = 160x120
[printer:Original Prusa i3 MK2.5 0.25 nozzle] [printer:Original Prusa i3 MK2.5 0.25 nozzle]
inherits = Original Prusa i3 MK2S 0.25 nozzle inherits = Original Prusa i3 MK2S 0.25 nozzle
@ -9319,6 +9501,8 @@ printer_model = MK2.5
remaining_times = 1 remaining_times = 1
machine_max_jerk_e = 4.5 machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0 start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y200 F3600 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
thumbnails = 160x120
[printer:Original Prusa i3 MK2.5 0.6 nozzle] [printer:Original Prusa i3 MK2.5 0.6 nozzle]
inherits = Original Prusa i3 MK2S 0.6 nozzle inherits = Original Prusa i3 MK2S 0.6 nozzle
@ -9327,6 +9511,8 @@ remaining_times = 1
machine_max_jerk_e = 4.5 machine_max_jerk_e = 4.5
deretract_speed = 25 deretract_speed = 25
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0 start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y200 F3600 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
thumbnails = 160x120
[printer:Original Prusa i3 MK2.5 0.8 nozzle] [printer:Original Prusa i3 MK2.5 0.8 nozzle]
inherits = Original Prusa i3 MK2S 0.6 nozzle inherits = Original Prusa i3 MK2S 0.6 nozzle
@ -9342,9 +9528,11 @@ retract_lift = 0.25
remaining_times = 1 remaining_times = 1
machine_max_jerk_e = 4.5 machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0 start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n{if filament_settings_id[initial_tool]=~/.*Prusament PA11.*/}\nG1 Z0.3 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E9 F1000 ; intro line\n{else}\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\n{endif}\nG92 E0
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y200 F3600 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
default_print_profile = 0.40mm QUALITY @0.8 nozzle default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
thumbnails = 160x120
[printer:Original Prusa i3 MK2.5 MMU2 Single] [printer:Original Prusa i3 MK2.5 MMU2 Single]
inherits = *25mm2* inherits = *25mm2*
@ -9379,7 +9567,7 @@ single_extruder_multi_material = 1
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors\n end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
[printer:Original Prusa i3 MK2.5S] [printer:Original Prusa i3 MK2.5S]
inherits = Original Prusa i3 MK2.5 inherits = Original Prusa i3 MK2.5
@ -9406,7 +9594,7 @@ default_print_profile = 0.15mm OPTIMAL @MK2.5
default_filament_profile = Prusament PLA default_filament_profile = Prusament PLA
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
[printer:Original Prusa i3 MK2.5S MMU2S Single 0.8 nozzle] [printer:Original Prusa i3 MK2.5S MMU2S Single 0.8 nozzle]
inherits = Original Prusa i3 MK2.5S MMU2S Single inherits = Original Prusa i3 MK2.5S MMU2S Single
@ -9457,7 +9645,7 @@ single_extruder_multi_material = 1
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors\n end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
[printer:Original Prusa i3 MK2.5S MMU2S 0.6 nozzle] [printer:Original Prusa i3 MK2.5S MMU2S 0.6 nozzle]
inherits = Original Prusa i3 MK2.5S MMU2S inherits = Original Prusa i3 MK2.5S MMU2S
@ -9527,7 +9715,7 @@ color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK3] [printer:Original Prusa i3 MK3]
inherits = *common* inherits = *common*
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y200 F3600 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM84 ; disable motors end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y200 F3600 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
machine_max_acceleration_e = 5000,5000 machine_max_acceleration_e = 5000,5000
machine_max_acceleration_extruding = 1250,1250 machine_max_acceleration_extruding = 1250,1250
machine_max_acceleration_retracting = 1250,1250 machine_max_acceleration_retracting = 1250,1250
@ -9659,7 +9847,7 @@ inherits = *mm2*
single_extruder_multi_material = 0 single_extruder_multi_material = 0
default_filament_profile = Prusament PLA default_filament_profile = Prusament PLA
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif} start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
[printer:Original Prusa i3 MK3 MMU2 Single 0.6 nozzle] [printer:Original Prusa i3 MK3 MMU2 Single 0.6 nozzle]
inherits = Original Prusa i3 MK3 MMU2 Single inherits = Original Prusa i3 MK3 MMU2 Single
@ -9707,7 +9895,7 @@ machine_max_acceleration_e = 8000,8000
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif} start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors\n end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single] [printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single]
inherits = *mm2s* inherits = *mm2s*
@ -9715,7 +9903,7 @@ renamed_from = "Original Prusa i3 MK3S MMU2S Single"
single_extruder_multi_material = 0 single_extruder_multi_material = 0
default_filament_profile = Prusament PLA default_filament_profile = Prusament PLA
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif} start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.6 nozzle] [printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.6 nozzle]
inherits = Original Prusa i3 MK3S & MK3S+ MMU2S Single inherits = Original Prusa i3 MK3S & MK3S+ MMU2S Single
@ -9766,7 +9954,7 @@ machine_max_acceleration_e = 8000,8000
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif} start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.11.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors\n end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nG1 X0 Y210 F7200 ; park\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
## 0.6mm nozzle MMU2/S printer profiles ## 0.6mm nozzle MMU2/S printer profiles
@ -9883,7 +10071,7 @@ retract_layer_change = 1
silent_mode = 0 silent_mode = 0
remaining_times = 1 remaining_times = 1
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM204 T1250 ; set travel acceleration\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM204 T[machine_max_acceleration_travel] ; restore travel acceleration\nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0\nG1 Y-2 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110 E8 F900\nG1 X40 E10 F700\nG92 E0\n\nM221 S95 ; set flow start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM204 T1250 ; set travel acceleration\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM204 T[machine_max_acceleration_travel] ; restore travel acceleration\nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0\nG1 Y-2 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110 E8 F900\nG1 X40 E10 F700\nG92 E0\n\nM221 S95 ; set flow
end_gcode = G1 E-1 F2100 ; retract\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720 ; Move print head up{endif}\nG1 X178 Y178 F4200 ; park print head\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow\nM900 K0 ; reset LA\nM84 ; disable motors end_gcode = G1 E-1 F2100 ; retract\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720 ; Move print head up{endif}\nG1 X178 Y178 F4200 ; park print head\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MINI\n printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MINI\n
extruder_colour = extruder_colour =
color_change_gcode = M600 color_change_gcode = M600

View File

@ -0,0 +1,2 @@
min_slic3r_version = 2.6.0-alpha0
1.0.0 Initial

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
#version 110
uniform vec4 uniform_color;
uniform float emission_factor;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
if (clipping_planes_dot < 0.0)
discard;
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@ -0,0 +1,54 @@
#version 110
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
uniform mat3 view_normal_matrix;
uniform mat4 volume_world_matrix;
// Clipping plane - general orientation. Used by the SLA gizmo.
uniform vec4 clipping_plane;
attribute vec3 v_position;
attribute vec3 v_normal;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 eye_normal = normalize(view_normal_matrix * v_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec4 eye_position = view_model_matrix * vec4(v_position, 1.0);
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = projection_matrix * eye_position;
// Fill in the scalar for fragment shader clipping. Fragments with this value lower than zero are discarded.
clipping_planes_dot = dot(volume_world_matrix * vec4(v_position, 1.0), clipping_plane);
}

View File

@ -0,0 +1,19 @@
#version 140
uniform vec4 uniform_color;
uniform float emission_factor;
// x = tainted, y = specular;
in vec2 intensity;
in float clipping_planes_dot;
out vec4 out_color;
void main()
{
if (clipping_planes_dot < 0.0)
discard;
out_color = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@ -0,0 +1,54 @@
#version 140
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
uniform mat3 view_normal_matrix;
uniform mat4 volume_world_matrix;
// Clipping plane - general orientation. Used by the SLA gizmo.
uniform vec4 clipping_plane;
in vec3 v_position;
in vec3 v_normal;
// x = tainted, y = specular;
out vec2 intensity;
out float clipping_planes_dot;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 eye_normal = normalize(view_normal_matrix * v_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec4 eye_position = view_model_matrix * vec4(v_position, 1.0);
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = projection_matrix * eye_position;
// Fill in the scalar for fragment shader clipping. Fragments with this value lower than zero are discarded.
clipping_planes_dot = dot(volume_world_matrix * vec4(v_position, 1.0), clipping_plane);
}

View File

@ -0,0 +1,19 @@
#version 100
precision highp float;
uniform vec4 uniform_color;
uniform float emission_factor;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
if (clipping_planes_dot < 0.0)
discard;
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@ -0,0 +1,54 @@
#version 100
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
uniform mat3 view_normal_matrix;
uniform mat4 volume_world_matrix;
// Clipping plane - general orientation. Used by the SLA gizmo.
uniform vec4 clipping_plane;
attribute vec3 v_position;
attribute vec3 v_normal;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 eye_normal = normalize(view_normal_matrix * v_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec4 eye_position = view_model_matrix * vec4(v_position, 1.0);
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = projection_matrix * eye_position;
// Fill in the scalar for fragment shader clipping. Fragments with this value lower than zero are discarded.
clipping_planes_dot = dot(volume_world_matrix * vec4(v_position, 1.0), clipping_plane);
}

View File

@ -242,13 +242,14 @@ int wmain(int argc, wchar_t **argv)
#ifdef SLIC3R_GUI #ifdef SLIC3R_GUI
// Here one may push some additional parameters based on the wrapper type. // Here one may push some additional parameters based on the wrapper type.
bool force_mesa = false; bool force_mesa = false;
bool force_hw = false;
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */
for (int i = 1; i < argc; ++ i) { for (int i = 1; i < argc; ++ i) {
#ifdef SLIC3R_GUI #ifdef SLIC3R_GUI
if (wcscmp(argv[i], L"--sw-renderer") == 0) if (wcscmp(argv[i], L"--sw-renderer") == 0)
force_mesa = true; force_mesa = true;
else if (wcscmp(argv[i], L"--no-sw-renderer") == 0) else if (wcscmp(argv[i], L"--no-sw-renderer") == 0)
force_mesa = false; force_hw = true;
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */
argv_extended.emplace_back(argv[i]); argv_extended.emplace_back(argv[i]);
} }
@ -261,7 +262,7 @@ int wmain(int argc, wchar_t **argv)
force_mesa || force_mesa ||
// Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context. // Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context.
// In that case, use Mesa. // In that case, use Mesa.
::GetSystemMetrics(SM_REMOTESESSION) || (::GetSystemMetrics(SM_REMOTESESSION) && !force_hw) ||
// Try to load the default OpenGL driver and test its context version. // Try to load the default OpenGL driver and test its context version.
! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0);
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */

View File

@ -68,9 +68,6 @@ public:
template<class M> void AABBMesh::init(const M &mesh, bool calculate_epsilon) template<class M> void AABBMesh::init(const M &mesh, bool calculate_epsilon)
{ {
BoundingBoxf3 bb = bounding_box(mesh);
m_ground_level += bb.min(Z);
// Build the AABB accelaration tree // Build the AABB accelaration tree
m_aabb->init(*m_tm, calculate_epsilon); m_aabb->init(*m_tm, calculate_epsilon);
} }
@ -97,7 +94,6 @@ AABBMesh::~AABBMesh() {}
AABBMesh::AABBMesh(const AABBMesh &other) AABBMesh::AABBMesh(const AABBMesh &other)
: m_tm(other.m_tm) : m_tm(other.m_tm)
, m_ground_level(other.m_ground_level)
, m_aabb(new AABBImpl(*other.m_aabb)) , m_aabb(new AABBImpl(*other.m_aabb))
, m_vfidx{other.m_vfidx} , m_vfidx{other.m_vfidx}
, m_fnidx{other.m_fnidx} , m_fnidx{other.m_fnidx}
@ -106,7 +102,6 @@ AABBMesh::AABBMesh(const AABBMesh &other)
AABBMesh &AABBMesh::operator=(const AABBMesh &other) AABBMesh &AABBMesh::operator=(const AABBMesh &other)
{ {
m_tm = other.m_tm; m_tm = other.m_tm;
m_ground_level = other.m_ground_level;
m_aabb.reset(new AABBImpl(*other.m_aabb)); m_aabb.reset(new AABBImpl(*other.m_aabb));
m_vfidx = other.m_vfidx; m_vfidx = other.m_vfidx;
m_fnidx = other.m_fnidx; m_fnidx = other.m_fnidx;

View File

@ -28,7 +28,6 @@ class AABBMesh {
class AABBImpl; class AABBImpl;
const indexed_triangle_set* m_tm; const indexed_triangle_set* m_tm;
double m_ground_level = 0/*, m_gnd_offset = 0*/;
std::unique_ptr<AABBImpl> m_aabb; std::unique_ptr<AABBImpl> m_aabb;
VertexFaceIndex m_vfidx; // vertex-face index VertexFaceIndex m_vfidx; // vertex-face index
@ -57,10 +56,6 @@ public:
~AABBMesh(); ~AABBMesh();
inline double ground_level() const { return m_ground_level /*+ m_gnd_offset*/; }
// inline void ground_level_offset(double o) { m_gnd_offset = o; }
// inline double ground_level_offset() const { return m_gnd_offset; }
const std::vector<Vec3f>& vertices() const; const std::vector<Vec3f>& vertices() const;
const std::vector<Vec3i>& indices() const; const std::vector<Vec3i>& indices() const;
const Vec3f& vertices(size_t idx) const; const Vec3f& vertices(size_t idx) const;
@ -72,9 +67,9 @@ public:
double m_t = infty(); double m_t = infty();
int m_face_id = -1; int m_face_id = -1;
const AABBMesh *m_mesh = nullptr; const AABBMesh *m_mesh = nullptr;
Vec3d m_dir; Vec3d m_dir = Vec3d::Zero();
Vec3d m_source; Vec3d m_source = Vec3d::Zero();
Vec3d m_normal; Vec3d m_normal = Vec3d::Zero();
friend class AABBMesh; friend class AABBMesh;
// A valid object of this class can only be obtained from // A valid object of this class can only be obtained from

View File

@ -117,7 +117,7 @@ inline std::tuple<int, int> coordinate_aligned_ray_hit_count(size_t
} }
template<typename LineType, typename TreeType, typename VectorType> template<typename LineType, typename TreeType, typename VectorType>
inline std::vector<VectorType> get_intersections_with_line(size_t node_idx, inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(size_t node_idx,
const TreeType &tree, const TreeType &tree,
const std::vector<LineType> &lines, const std::vector<LineType> &lines,
const LineType &line, const LineType &line,
@ -128,7 +128,7 @@ inline std::vector<VectorType> get_intersections_with_line(size_t
if (node.is_leaf()) { if (node.is_leaf()) {
VectorType intersection_pt; VectorType intersection_pt;
if (line_alg::intersection(line, lines[node.idx], &intersection_pt)) { if (line_alg::intersection(line, lines[node.idx], &intersection_pt)) {
return {intersection_pt}; return {std::pair<VectorType, size_t>(intersection_pt, node.idx)};
} else { } else {
return {}; return {};
} }
@ -140,17 +140,17 @@ inline std::vector<VectorType> get_intersections_with_line(size_t
assert(node_left.is_valid()); assert(node_left.is_valid());
assert(node_right.is_valid()); assert(node_right.is_valid());
std::vector<VectorType> result; std::vector<std::pair<VectorType, size_t>> result;
if (node_left.bbox.intersects(line_bb)) { if (node_left.bbox.intersects(line_bb)) {
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines, std::vector<std::pair<VectorType, size_t>> intersections =
line, line_bb); get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines, line, line_bb);
result.insert(result.end(), intersections.begin(), intersections.end()); result.insert(result.end(), intersections.begin(), intersections.end());
} }
if (node_right.bbox.intersects(line_bb)) { if (node_right.bbox.intersects(line_bb)) {
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines, std::vector<std::pair<VectorType, size_t>> intersections =
line, line_bb); get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines, line, line_bb);
result.insert(result.end(), intersections.begin(), intersections.end()); result.insert(result.end(), intersections.begin(), intersections.end());
} }
@ -263,9 +263,13 @@ inline int point_outside_closed_contours(const std::vector<LineType> &lines, con
} }
template<bool sorted, typename VectorType, typename LineType, typename TreeType> template<bool sorted, typename VectorType, typename LineType, typename TreeType>
inline std::vector<VectorType> get_intersections_with_line(const std::vector<LineType> &lines, const TreeType &tree, const LineType &line) inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(const std::vector<LineType> &lines,
const TreeType &tree,
const LineType &line)
{ {
if (tree.empty()) { return {}; } if (tree.empty()) {
return {};
}
auto line_bb = typename TreeType::BoundingBox(line.a, line.a); auto line_bb = typename TreeType::BoundingBox(line.a, line.a);
line_bb.extend(line.b); line_bb.extend(line.b);
@ -274,15 +278,16 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
using Floating = using Floating =
typename std::conditional<std::is_floating_point<typename LineType::Scalar>::value, typename LineType::Scalar, double>::type; typename std::conditional<std::is_floating_point<typename LineType::Scalar>::value, typename LineType::Scalar, double>::type;
std::vector<std::pair<Floating, VectorType>> points_with_sq_distance{}; std::vector<std::pair<Floating, std::pair<VectorType, size_t>>> points_with_sq_distance{};
for (const VectorType &p : intersections) { for (const auto &p : intersections) {
points_with_sq_distance.emplace_back((p - line.a).template cast<Floating>().squaredNorm(), p); points_with_sq_distance.emplace_back((p.first - line.a).template cast<Floating>().squaredNorm(), p);
} }
std::sort(points_with_sq_distance.begin(), points_with_sq_distance.end(), std::sort(points_with_sq_distance.begin(), points_with_sq_distance.end(),
[](const std::pair<Floating, VectorType> &left, std::pair<Floating, VectorType> &right) { [](const std::pair<Floating, std::pair<VectorType, size_t>> &left,
return left.first < right.first; std::pair<Floating, std::pair<VectorType, size_t>> &right) { return left.first < right.first; });
}); for (size_t i = 0; i < points_with_sq_distance.size(); i++) {
for (size_t i = 0; i < points_with_sq_distance.size(); i++) { intersections[i] = points_with_sq_distance[i].second; } intersections[i] = points_with_sq_distance[i].second;
}
} }
return intersections; return intersections;
@ -290,10 +295,11 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
template<typename LineType> class LinesDistancer template<typename LineType> class LinesDistancer
{ {
private: public:
std::vector<LineType> lines;
using Scalar = typename LineType::Scalar; using Scalar = typename LineType::Scalar;
using Floating = typename std::conditional<std::is_floating_point<Scalar>::value, Scalar, double>::type; using Floating = typename std::conditional<std::is_floating_point<Scalar>::value, Scalar, double>::type;
private:
std::vector<LineType> lines;
AABBTreeIndirect::Tree<2, Scalar> tree; AABBTreeIndirect::Tree<2, Scalar> tree;
public: public:
@ -313,23 +319,29 @@ public:
int outside(const Vec<2, Scalar> &point) const { return point_outside_closed_contours(lines, tree, point); } int outside(const Vec<2, Scalar> &point) const { return point_outside_closed_contours(lines, tree, point); }
// negative sign means inside // negative sign means inside
std::tuple<Floating, size_t, Vec<2, Floating>> signed_distance_from_lines_extra(const Vec<2, Scalar> &point) const template<bool SIGNED_DISTANCE>
std::tuple<Floating, size_t, Vec<2, Floating>> distance_from_lines_extra(const Vec<2, Scalar> &point) const
{ {
size_t nearest_line_index_out = size_t(-1); size_t nearest_line_index_out = size_t(-1);
Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero(); Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero();
Vec<2, Floating> p = point.template cast<Floating>(); Vec<2, Floating> p = point.template cast<Floating>();
auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out); auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out);
if (distance < 0) { return {std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out}; } if (distance < 0) {
return {std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out};
}
distance = sqrt(distance); distance = sqrt(distance);
if (SIGNED_DISTANCE) {
distance *= outside(point); distance *= outside(point);
}
return {distance, nearest_line_index_out, nearest_point_out}; return {distance, nearest_line_index_out, nearest_point_out};
} }
Floating signed_distance_from_lines(const Vec<2, typename LineType::Scalar> &point) const template<bool SIGNED_DISTANCE> Floating distance_from_lines(const Vec<2, typename LineType::Scalar> &point) const
{ {
auto [dist, idx, np] = signed_distance_from_lines_extra(point); auto [dist, idx, np] = distance_from_lines_extra<SIGNED_DISTANCE>(point);
return dist; return dist;
} }
@ -338,7 +350,7 @@ public:
return all_lines_in_radius(this->lines, this->tree, point, radius * radius); return all_lines_in_radius(this->lines, this->tree, point, radius * radius);
} }
template<bool sorted> std::vector<Vec<2, Scalar>> intersections_with_line(const LineType &line) const template<bool sorted> std::vector<std::pair<Vec<2, Scalar>, size_t>> intersections_with_line(const LineType &line) const
{ {
return get_intersections_with_line<sorted, Vec<2, Scalar>>(lines, tree, line); return get_intersections_with_line<sorted, Vec<2, Scalar>>(lines, tree, line);
} }

130
src/libslic3r/AnyPtr.hpp Normal file
View File

@ -0,0 +1,130 @@
#ifndef ANYPTR_HPP
#define ANYPTR_HPP
#include <memory>
#include <type_traits>
#include <boost/variant.hpp>
namespace Slic3r {
// A general purpose pointer holder that can hold any type of smart pointer
// or raw pointer which can own or not own any object they point to.
// In case a raw pointer is stored, it is not destructed so ownership is
// assumed to be foreign.
//
// The stored pointer is not checked for being null when dereferenced.
//
// This is a movable only object due to the fact that it can possibly hold
// a unique_ptr which a non-copy.
template<class T>
class AnyPtr {
enum { RawPtr, UPtr, ShPtr, WkPtr };
boost::variant<T*, std::unique_ptr<T>, std::shared_ptr<T>, std::weak_ptr<T>> ptr;
template<class Self> static T *get_ptr(Self &&s)
{
switch (s.ptr.which()) {
case RawPtr: return boost::get<T *>(s.ptr);
case UPtr: return boost::get<std::unique_ptr<T>>(s.ptr).get();
case ShPtr: return boost::get<std::shared_ptr<T>>(s.ptr).get();
case WkPtr: {
auto shptr = boost::get<std::weak_ptr<T>>(s.ptr).lock();
return shptr.get();
}
}
return nullptr;
}
public:
template<class TT = T, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr(TT *p = nullptr) : ptr{p}
{}
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr(std::unique_ptr<TT> p) : ptr{std::unique_ptr<T>(std::move(p))}
{}
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr(std::shared_ptr<TT> p) : ptr{std::shared_ptr<T>(std::move(p))}
{}
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr(std::weak_ptr<TT> p) : ptr{std::weak_ptr<T>(std::move(p))}
{}
~AnyPtr() = default;
AnyPtr(AnyPtr &&other) noexcept : ptr{std::move(other.ptr)} {}
AnyPtr(const AnyPtr &other) = delete;
AnyPtr &operator=(AnyPtr &&other) noexcept { ptr = std::move(other.ptr); return *this; }
AnyPtr &operator=(const AnyPtr &other) = delete;
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr &operator=(TT *p) { ptr = p; return *this; }
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr &operator=(std::unique_ptr<TT> p) { ptr = std::move(p); return *this; }
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr &operator=(std::shared_ptr<TT> p) { ptr = p; return *this; }
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT, T>>>
AnyPtr &operator=(std::weak_ptr<TT> p) { ptr = std::move(p); return *this; }
const T &operator*() const { return *get_ptr(*this); }
T &operator*() { return *get_ptr(*this); }
T *operator->() { return get_ptr(*this); }
const T *operator->() const { return get_ptr(*this); }
T *get() { return get_ptr(*this); }
const T *get() const { return get_ptr(*this); }
operator bool() const
{
switch (ptr.which()) {
case RawPtr: return bool(boost::get<T *>(ptr));
case UPtr: return bool(boost::get<std::unique_ptr<T>>(ptr));
case ShPtr: return bool(boost::get<std::shared_ptr<T>>(ptr));
case WkPtr: {
auto shptr = boost::get<std::weak_ptr<T>>(ptr).lock();
return bool(shptr);
}
}
return false;
}
// If the stored pointer is a shared or weak pointer, returns a reference
// counted copy. Empty shared pointer is returned otherwise.
std::shared_ptr<T> get_shared_cpy() const
{
std::shared_ptr<T> ret;
switch (ptr.which()) {
case ShPtr: ret = boost::get<std::shared_ptr<T>>(ptr); break;
case WkPtr: ret = boost::get<std::weak_ptr<T>>(ptr).lock(); break;
default:
;
}
return ret;
}
// If the underlying pointer is unique, convert to shared pointer
void convert_unique_to_shared()
{
if (ptr.which() == UPtr)
ptr = std::shared_ptr<T>{std::move(boost::get<std::unique_ptr<T>>(ptr))};
}
// Returns true if the data is owned by this AnyPtr instance
bool is_owned() const noexcept
{
return ptr.which() == UPtr || ptr.which() == ShPtr;
}
};
} // namespace Slic3r
#endif // ANYPTR_HPP

View File

@ -34,8 +34,13 @@ static const std::string MODEL_PREFIX = "model:";
// to show this notification. On the other hand, we would like PrusaSlicer 2.3.2 to show an update notification of the upcoming PrusaSlicer 2.4.0. // to show this notification. On the other hand, we would like PrusaSlicer 2.3.2 to show an update notification of the upcoming PrusaSlicer 2.4.0.
// Thus we will let PrusaSlicer 2.3.2 and couple of follow-up versions to download the version number from an alternate file until the PrusaSlicer 2.3.0/2.3.1 // Thus we will let PrusaSlicer 2.3.2 and couple of follow-up versions to download the version number from an alternate file until the PrusaSlicer 2.3.0/2.3.1
// are phased out, then we will revert to the original name. // are phased out, then we will revert to the original name.
//static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version"; // For 2.6.0-alpha1 we have switched back to the original. The file should contain data for AppUpdater.cpp
static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version2"; static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version";
//static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version2";
// Url to index archive zip that contains latest indicies
static const std::string INDEX_ARCHIVE_URL= "https://files.prusa3d.com/wp-content/uploads/repository/vendor_indices.zip";
// Url to folder with vendor profile files. Used when downloading new profiles that are not in resources folder.
static const std::string PROFILE_FOLDER_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/";
const std::string AppConfig::SECTION_FILAMENTS = "filaments"; const std::string AppConfig::SECTION_FILAMENTS = "filaments";
const std::string AppConfig::SECTION_MATERIALS = "sla_materials"; const std::string AppConfig::SECTION_MATERIALS = "sla_materials";
@ -61,6 +66,9 @@ void AppConfig::set_defaults()
// Disable background processing by default as it is not stable. // Disable background processing by default as it is not stable.
if (get("background_processing").empty()) if (get("background_processing").empty())
set("background_processing", "0"); set("background_processing", "0");
// Enable support issues alerts by default
if (get("alert_when_supports_needed").empty())
set("alert_when_supports_needed", "1");
// If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. // If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
// By default, Prusa has the controller hidden. // By default, Prusa has the controller hidden.
if (get("no_controller").empty()) if (get("no_controller").empty())
@ -68,6 +76,8 @@ void AppConfig::set_defaults()
// If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available. // If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available.
if (get("no_defaults").empty()) if (get("no_defaults").empty())
set("no_defaults", "1"); set("no_defaults", "1");
if (get("no_templates").empty())
set("no_templates", "0");
if (get("show_incompatible_presets").empty()) if (get("show_incompatible_presets").empty())
set("show_incompatible_presets", "0"); set("show_incompatible_presets", "0");
@ -665,6 +675,26 @@ std::string AppConfig::version_check_url() const
return from_settings.empty() ? VERSION_CHECK_URL : from_settings; return from_settings.empty() ? VERSION_CHECK_URL : from_settings;
} }
std::string AppConfig::index_archive_url() const
{
#if 0
// this code is for debug & testing purposes only - changed url wont get trough inner checks anyway.
auto from_settings = get("index_archive_url");
return from_settings.empty() ? INDEX_ARCHIVE_URL : from_settings;
#endif
return INDEX_ARCHIVE_URL;
}
std::string AppConfig::profile_folder_url() const
{
#if 0
// this code is for debug & testing purposes only - changed url wont get trough inner checks anyway.
auto from_settings = get("profile_folder_url");
return from_settings.empty() ? PROFILE_FOLDER_URL : from_settings;
#endif
return PROFILE_FOLDER_URL;
}
bool AppConfig::exists() bool AppConfig::exists()
{ {
return boost::filesystem::exists(config_path()); return boost::filesystem::exists(config_path());

View File

@ -139,6 +139,11 @@ public:
// Get the Slic3r version check url. // Get the Slic3r version check url.
// This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file. // This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file.
std::string version_check_url() const; std::string version_check_url() const;
// Get the Slic3r url to vendor index archive zip.
std::string index_archive_url() const;
// Get the Slic3r url to folder with vendor profile files.
std::string profile_folder_url() const;
// Returns the original Slic3r version found in the ini file before it was overwritten // Returns the original Slic3r version found in the ini file before it was overwritten
// by the current version // by the current version

View File

@ -573,6 +573,59 @@ inline static void rotate_back_skeletal_trapezoidation_graph_after_fix(SkeletalT
} }
} }
bool detect_voronoi_edge_intersecting_input_segment(const Geometry::VoronoiDiagram &voronoi_diagram, const std::vector<VoronoiUtils::Segment> &segments)
{
for (VoronoiUtils::vd_t::cell_type cell : voronoi_diagram.cells()) {
if (!cell.incident_edge())
continue; // Degenerated cell, there is no spoon
if (!cell.contains_segment())
continue; // Skip cells that don't contain segments.
const VoronoiUtils::Segment &source_segment = VoronoiUtils::getSourceSegment(cell, segments);
const Vec2d source_segment_from = source_segment.from().cast<double>();
const Vec2d source_segment_vec = source_segment.to().cast<double>() - source_segment_from;
Point start_source_point, end_source_point;
VoronoiUtils::vd_t::edge_type *begin_voronoi_edge = nullptr, *end_voronoi_edge = nullptr;
SkeletalTrapezoidation::computeSegmentCellRange(cell, start_source_point, end_source_point, begin_voronoi_edge, end_voronoi_edge, segments);
// All Voronoi vertices must be on left side of the source segment, otherwise Voronoi diagram is invalid.
// FIXME Lukas H.: Be aware that begin_voronoi_edge and end_voronoi_edge could be nullptr in some specific cases.
// It mostly happens when there is some missing Voronoi, for example, in GH issue #8846 (IssuesWithMysteriousPerimeters.3mf).
if (begin_voronoi_edge != nullptr && end_voronoi_edge != nullptr)
for (VoronoiUtils::vd_t::edge_type *edge = begin_voronoi_edge; edge != end_voronoi_edge; edge = edge->next())
if (const Vec2d edge_v1(edge->vertex1()->x(), edge->vertex1()->y()); Slic3r::cross2(source_segment_vec, edge_v1 - source_segment_from) < 0)
return true;
}
return false;
}
enum class VoronoiDiagramStatus {
NO_ISSUE_DETECTED,
MISSING_VORONOI_VERTEX,
NON_PLANAR_VORONOI_DIAGRAM,
VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT,
OTHER_TYPE_OF_VORONOI_DIAGRAM_DEGENERATION
};
// Try to detect cases when some Voronoi vertex is missing, when the Voronoi diagram
// is not planar or some Voronoi edge is intersecting input segment.
VoronoiDiagramStatus detect_voronoi_diagram_known_issues(const Geometry::VoronoiDiagram &voronoi_diagram,
const std::vector<SkeletalTrapezoidation::Segment> &segments)
{
if (const bool has_missing_voronoi_vertex = detect_missing_voronoi_vertex(voronoi_diagram, segments); has_missing_voronoi_vertex) {
return VoronoiDiagramStatus::MISSING_VORONOI_VERTEX;
} else if (const bool has_voronoi_edge_intersecting_input_segment = detect_voronoi_edge_intersecting_input_segment(voronoi_diagram, segments); has_voronoi_edge_intersecting_input_segment) {
// Detection if Voronoi edge is intersecting input segment detects at least one model in GH issue #8446.
return VoronoiDiagramStatus::VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT;
} else if (const bool is_voronoi_diagram_planar = Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segments); !is_voronoi_diagram_planar) {
// Detection of non-planar Voronoi diagram detects at least GH issues #8474, #8514 and #8446.
return VoronoiDiagramStatus::NON_PLANAR_VORONOI_DIAGRAM;
}
return VoronoiDiagramStatus::NO_ISSUE_DETECTED;
}
void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
{ {
#ifdef ARACHNE_DEBUG #ifdef ARACHNE_DEBUG
@ -614,36 +667,35 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
} }
#endif #endif
// Try to detect cases when some Voronoi vertex is missing and when // When any Voronoi vertex is missing, the Voronoi diagram is not planar, or some voronoi edge is
// the Voronoi diagram is not planar. // intersecting input segment, rotate the input polygon and try again.
// When any Voronoi vertex is missing, or the Voronoi diagram is not VoronoiDiagramStatus status = detect_voronoi_diagram_known_issues(voronoi_diagram, segments);
// planar, rotate the input polygon and try again.
const bool has_missing_voronoi_vertex = detect_missing_voronoi_vertex(voronoi_diagram, segments);
// Detection of non-planar Voronoi diagram detects at least GH issues #8474, #8514 and #8446.
const bool is_voronoi_diagram_planar = Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram);
const double fix_angle = PI / 6; const double fix_angle = PI / 6;
std::unordered_map<Point, Point, PointHash> vertex_mapping; std::unordered_map<Point, Point, PointHash> vertex_mapping;
// polys_copy is referenced through items stored in the std::vector segments. // polys_copy is referenced through items stored in the std::vector segments.
Polygons polys_copy = polys; Polygons polys_copy = polys;
if (has_missing_voronoi_vertex || !is_voronoi_diagram_planar) { if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED) {
if (has_missing_voronoi_vertex) if (status == VoronoiDiagramStatus::MISSING_VORONOI_VERTEX)
BOOST_LOG_TRIVIAL(warning) << "Detected missing Voronoi vertex, input polygons will be rotated back and forth."; BOOST_LOG_TRIVIAL(warning) << "Detected missing Voronoi vertex, input polygons will be rotated back and forth.";
else if (!is_voronoi_diagram_planar) else if (status == VoronoiDiagramStatus::NON_PLANAR_VORONOI_DIAGRAM)
BOOST_LOG_TRIVIAL(warning) << "Detected non-planar Voronoi diagram, input polygons will be rotated back and forth."; BOOST_LOG_TRIVIAL(warning) << "Detected non-planar Voronoi diagram, input polygons will be rotated back and forth.";
else if (status == VoronoiDiagramStatus::VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT)
BOOST_LOG_TRIVIAL(warning) << "Detected Voronoi edge intersecting input segment, input polygons will be rotated back and forth.";
vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle); vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle);
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments)); assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments));
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram)); assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segments));
assert(!detect_voronoi_edge_intersecting_input_segment(voronoi_diagram, segments));
if (detect_missing_voronoi_vertex(voronoi_diagram, segments)) if (detect_missing_voronoi_vertex(voronoi_diagram, segments))
BOOST_LOG_TRIVIAL(error) << "Detected missing Voronoi vertex even after the rotation of input."; BOOST_LOG_TRIVIAL(error) << "Detected missing Voronoi vertex even after the rotation of input.";
else if (!Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram)) else if (!Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segments))
BOOST_LOG_TRIVIAL(error) << "Detected non-planar Voronoi diagram even after the rotation of input."; BOOST_LOG_TRIVIAL(error) << "Detected non-planar Voronoi diagram even after the rotation of input.";
else if (detect_voronoi_edge_intersecting_input_segment(voronoi_diagram, segments))
BOOST_LOG_TRIVIAL(error) << "Detected Voronoi edge intersecting input segment even after the rotation of input.";
} }
bool degenerated_voronoi_diagram = has_missing_voronoi_vertex || !is_voronoi_diagram_planar;
process_voronoi_diagram: process_voronoi_diagram:
assert(this->graph.edges.empty() && this->graph.nodes.empty() && this->vd_edge_to_he_edge.empty() && this->vd_node_to_he_node.empty()); assert(this->graph.edges.empty() && this->graph.nodes.empty() && this->vd_edge_to_he_edge.empty() && this->vd_node_to_he_node.empty());
for (vd_t::cell_type cell : voronoi_diagram.cells()) { for (vd_t::cell_type cell : voronoi_diagram.cells()) {
@ -652,35 +704,35 @@ process_voronoi_diagram:
Point start_source_point; Point start_source_point;
Point end_source_point; Point end_source_point;
vd_t::edge_type* starting_vonoroi_edge = nullptr; vd_t::edge_type* starting_voronoi_edge = nullptr;
vd_t::edge_type* ending_vonoroi_edge = nullptr; vd_t::edge_type* ending_voronoi_edge = nullptr;
// Compute and store result in above variables // Compute and store result in above variables
if (cell.contains_point()) { if (cell.contains_point()) {
const bool keep_going = computePointCellRange(cell, start_source_point, end_source_point, starting_vonoroi_edge, ending_vonoroi_edge, segments); const bool keep_going = computePointCellRange(cell, start_source_point, end_source_point, starting_voronoi_edge, ending_voronoi_edge, segments);
if (!keep_going) if (!keep_going)
continue; continue;
} else { } else {
assert(cell.contains_segment()); assert(cell.contains_segment());
computeSegmentCellRange(cell, start_source_point, end_source_point, starting_vonoroi_edge, ending_vonoroi_edge, segments); computeSegmentCellRange(cell, start_source_point, end_source_point, starting_voronoi_edge, ending_voronoi_edge, segments);
} }
if (!starting_vonoroi_edge || !ending_vonoroi_edge) { if (!starting_voronoi_edge || !ending_voronoi_edge) {
assert(false && "Each cell should start / end in a polygon vertex"); assert(false && "Each cell should start / end in a polygon vertex");
continue; continue;
} }
// Copy start to end edge to graph // Copy start to end edge to graph
edge_t* prev_edge = nullptr; edge_t* prev_edge = nullptr;
assert(VoronoiUtils::p(starting_vonoroi_edge->vertex1()).x() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_vonoroi_edge->vertex1()).x() >= std::numeric_limits<coord_t>::lowest()); assert(VoronoiUtils::p(starting_voronoi_edge->vertex1()).x() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_voronoi_edge->vertex1()).x() >= std::numeric_limits<coord_t>::lowest());
assert(VoronoiUtils::p(starting_vonoroi_edge->vertex1()).y() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_vonoroi_edge->vertex1()).y() >= std::numeric_limits<coord_t>::lowest()); assert(VoronoiUtils::p(starting_voronoi_edge->vertex1()).y() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_voronoi_edge->vertex1()).y() >= std::numeric_limits<coord_t>::lowest());
transferEdge(start_source_point, VoronoiUtils::p(starting_vonoroi_edge->vertex1()).cast<coord_t>(), *starting_vonoroi_edge, prev_edge, start_source_point, end_source_point, segments); transferEdge(start_source_point, VoronoiUtils::p(starting_voronoi_edge->vertex1()).cast<coord_t>(), *starting_voronoi_edge, prev_edge, start_source_point, end_source_point, segments);
node_t* starting_node = vd_node_to_he_node[starting_vonoroi_edge->vertex0()]; node_t* starting_node = vd_node_to_he_node[starting_voronoi_edge->vertex0()];
starting_node->data.distance_to_boundary = 0; starting_node->data.distance_to_boundary = 0;
constexpr bool is_next_to_start_or_end = true; constexpr bool is_next_to_start_or_end = true;
graph.makeRib(prev_edge, start_source_point, end_source_point, is_next_to_start_or_end); graph.makeRib(prev_edge, start_source_point, end_source_point, is_next_to_start_or_end);
for (vd_t::edge_type* vd_edge = starting_vonoroi_edge->next(); vd_edge != ending_vonoroi_edge; vd_edge = vd_edge->next()) { for (vd_t::edge_type* vd_edge = starting_voronoi_edge->next(); vd_edge != ending_voronoi_edge; vd_edge = vd_edge->next()) {
assert(vd_edge->is_finite()); assert(vd_edge->is_finite());
assert(VoronoiUtils::p(vd_edge->vertex0()).x() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(vd_edge->vertex0()).x() >= std::numeric_limits<coord_t>::lowest()); assert(VoronoiUtils::p(vd_edge->vertex0()).x() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(vd_edge->vertex0()).x() >= std::numeric_limits<coord_t>::lowest());
@ -692,12 +744,12 @@ process_voronoi_diagram:
Point v2 = VoronoiUtils::p(vd_edge->vertex1()).cast<coord_t>(); Point v2 = VoronoiUtils::p(vd_edge->vertex1()).cast<coord_t>();
transferEdge(v1, v2, *vd_edge, prev_edge, start_source_point, end_source_point, segments); transferEdge(v1, v2, *vd_edge, prev_edge, start_source_point, end_source_point, segments);
graph.makeRib(prev_edge, start_source_point, end_source_point, vd_edge->next() == ending_vonoroi_edge); graph.makeRib(prev_edge, start_source_point, end_source_point, vd_edge->next() == ending_voronoi_edge);
} }
assert(VoronoiUtils::p(starting_vonoroi_edge->vertex0()).x() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_vonoroi_edge->vertex0()).x() >= std::numeric_limits<coord_t>::lowest()); assert(VoronoiUtils::p(starting_voronoi_edge->vertex0()).x() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_voronoi_edge->vertex0()).x() >= std::numeric_limits<coord_t>::lowest());
assert(VoronoiUtils::p(starting_vonoroi_edge->vertex0()).y() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_vonoroi_edge->vertex0()).y() >= std::numeric_limits<coord_t>::lowest()); assert(VoronoiUtils::p(starting_voronoi_edge->vertex0()).y() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_voronoi_edge->vertex0()).y() >= std::numeric_limits<coord_t>::lowest());
transferEdge(VoronoiUtils::p(ending_vonoroi_edge->vertex0()).cast<coord_t>(), end_source_point, *ending_vonoroi_edge, prev_edge, start_source_point, end_source_point, segments); transferEdge(VoronoiUtils::p(ending_voronoi_edge->vertex0()).cast<coord_t>(), end_source_point, *ending_voronoi_edge, prev_edge, start_source_point, end_source_point, segments);
prev_edge->to->data.distance_to_boundary = 0; prev_edge->to->data.distance_to_boundary = 0;
} }
@ -705,9 +757,9 @@ process_voronoi_diagram:
// When this degenerated Voronoi diagram is processed, the resulting half-edge structure contains some edges that don't have // When this degenerated Voronoi diagram is processed, the resulting half-edge structure contains some edges that don't have
// a twin edge. Based on this, we created a fast mechanism that detects those causes and tries to recompute the Voronoi // a twin edge. Based on this, we created a fast mechanism that detects those causes and tries to recompute the Voronoi
// diagram on slightly rotated input polygons that usually make the Voronoi generator generate a non-degenerated Voronoi diagram. // diagram on slightly rotated input polygons that usually make the Voronoi generator generate a non-degenerated Voronoi diagram.
if (!degenerated_voronoi_diagram && has_missing_twin_edge(this->graph)) { if (status == VoronoiDiagramStatus::NO_ISSUE_DETECTED && has_missing_twin_edge(this->graph)) {
BOOST_LOG_TRIVIAL(warning) << "Detected degenerated Voronoi diagram, input polygons will be rotated back and forth."; BOOST_LOG_TRIVIAL(warning) << "Detected degenerated Voronoi diagram, input polygons will be rotated back and forth.";
degenerated_voronoi_diagram = true; status = VoronoiDiagramStatus::OTHER_TYPE_OF_VORONOI_DIAGRAM_DEGENERATION;
vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle); vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle);
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments)); assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments));
@ -724,14 +776,14 @@ process_voronoi_diagram:
goto process_voronoi_diagram; goto process_voronoi_diagram;
} }
if (degenerated_voronoi_diagram) { if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED) {
assert(!has_missing_twin_edge(this->graph)); assert(!has_missing_twin_edge(this->graph));
if (has_missing_twin_edge(this->graph)) if (has_missing_twin_edge(this->graph))
BOOST_LOG_TRIVIAL(error) << "Detected degenerated Voronoi diagram even after the rotation of input."; BOOST_LOG_TRIVIAL(error) << "Detected degenerated Voronoi diagram even after the rotation of input.";
} }
if (degenerated_voronoi_diagram) if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED)
rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fix_angle, vertex_mapping); rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fix_angle, vertex_mapping);
#ifdef ARACHNE_DEBUG #ifdef ARACHNE_DEBUG
@ -742,7 +794,7 @@ process_voronoi_diagram:
graph.collapseSmallEdges(); graph.collapseSmallEdges();
// Set [incident_edge] the the first possible edge that way we can iterate over all reachable edges from node.incident_edge, // Set [incident_edge] the first possible edge that way we can iterate over all reachable edges from node.incident_edge,
// without needing to iterate backward // without needing to iterate backward
for (edge_t& edge : graph.edges) for (edge_t& edge : graph.edges)
if (!edge.prev) if (!edge.prev)

View File

@ -9,6 +9,7 @@
#include <memory> // smart pointers #include <memory> // smart pointers
#include <unordered_map> #include <unordered_map>
#include <utility> // pair #include <utility> // pair
#include <Arachne/utils/VoronoiUtils.hpp>
#include "utils/HalfEdgeGraph.hpp" #include "utils/HalfEdgeGraph.hpp"
#include "utils/PolygonsSegmentIndex.hpp" #include "utils/PolygonsSegmentIndex.hpp"
@ -229,7 +230,7 @@ protected:
* /return Whether the cell is inside of the polygon. If it's outside of the * /return Whether the cell is inside of the polygon. If it's outside of the
* polygon we should skip processing it altogether. * polygon we should skip processing it altogether.
*/ */
bool computePointCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector<Segment>& segments); static bool computePointCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector<Segment>& segments);
/*! /*!
* Compute the range of line segments that surround a cell of the skeletal * Compute the range of line segments that surround a cell of the skeletal
@ -255,7 +256,7 @@ protected:
* /return Whether the cell is inside of the polygon. If it's outside of the * /return Whether the cell is inside of the polygon. If it's outside of the
* polygon we should skip processing it altogether. * polygon we should skip processing it altogether.
*/ */
void computeSegmentCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector<Segment>& segments); static void computeSegmentCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector<Segment>& segments);
/*! /*!
* For VD cells associated with an input polygon vertex, we need to separate the node at the end and start of the cell into two * For VD cells associated with an input polygon vertex, we need to separate the node at the end and start of the cell into two
@ -597,6 +598,8 @@ protected:
* Genrate small segments for local maxima where the beading would only result in a single bead * Genrate small segments for local maxima where the beading would only result in a single bead
*/ */
void generateLocalMaximaSingleBeads(); void generateLocalMaximaSingleBeads();
friend bool detect_voronoi_edge_intersecting_input_segment(const Geometry::VoronoiDiagram &voronoi_diagram, const std::vector<VoronoiUtils::Segment> &segments);
}; };
} // namespace Slic3r::Arachne } // namespace Slic3r::Arachne

View File

@ -14,7 +14,7 @@
#include "../../../clipper/clipper_z.hpp" #include "../../../clipper/clipper_z.hpp"
namespace Slic3r { namespace Slic3r {
class ThickPolyline; struct ThickPolyline;
} }
namespace Slic3r::Arachne namespace Slic3r::Arachne

View File

@ -5,7 +5,7 @@
#include <optional> #include <optional>
#include <algorithm> #include <algorithm>
#include "libslic3r/SLA/SupportTreeUtils.hpp" #include "libslic3r/TriangleMesh.hpp"
namespace Slic3r { namespace branchingtree { namespace Slic3r { namespace branchingtree {
@ -76,18 +76,20 @@ void build_tree(PointCloud &nodes, Builder &builder)
switch (type) { switch (type) {
case BED: { case BED: {
closest_node.weight = w; closest_node.weight = w;
if (closest_it->dst_branching > nodes.properties().max_branch_length()) { double max_br_len = nodes.properties().max_branch_length();
auto hl_br_len = float(nodes.properties().max_branch_length()) / 2.f; if (closest_it->dst_branching > max_br_len) {
Node new_node {{node.pos.x(), node.pos.y(), node.pos.z() - hl_br_len}, node.Rmin}; std::optional<Vec3f> avo = builder.suggest_avoidance(node, max_br_len);
new_node.id = int(nodes.next_junction_id()); if (!avo)
new_node.weight = nodes.get(node_id).weight + hl_br_len; break;
Node new_node {*avo, node.Rmin};
new_node.weight = nodes.get(node_id).weight + (node.pos - *avo).norm();
new_node.left = node.id; new_node.left = node.id;
if ((routed = builder.add_bridge(node, new_node))) { if ((routed = builder.add_bridge(node, new_node))) {
size_t new_idx = nodes.insert_junction(new_node); size_t new_idx = nodes.insert_junction(new_node);
ptsqueue.push(new_idx); ptsqueue.push(new_idx);
} }
} } else if ((routed = builder.add_ground_bridge(node, closest_node))) {
else if ((routed = builder.add_ground_bridge(node, closest_node))) {
closest_node.left = closest_node.right = node_id; closest_node.left = closest_node.right = node_id;
nodes.get(closest_node_id) = closest_node; nodes.get(closest_node_id) = closest_node;
nodes.mark_unreachable(closest_node_id); nodes.mark_unreachable(closest_node_id);

View File

@ -5,7 +5,6 @@
#include <admesh/stl.h> #include <admesh/stl.h>
#include "libslic3r/ExPolygon.hpp" #include "libslic3r/ExPolygon.hpp"
#include "libslic3r/BoundingBox.hpp"
namespace Slic3r { namespace branchingtree { namespace Slic3r { namespace branchingtree {
@ -21,6 +20,7 @@ class Properties
ExPolygons m_bed_shape; ExPolygons m_bed_shape;
public: public:
// Maximum slope for bridges of the tree // Maximum slope for bridges of the tree
Properties &max_slope(double val) noexcept Properties &max_slope(double val) noexcept
{ {
@ -77,6 +77,11 @@ struct Node
{} {}
}; };
inline bool is_occupied(const Node &n)
{
return n.left != Node::ID_NONE && n.right != Node::ID_NONE;
}
// An output interface for the branching tree generator function. Consider each // An output interface for the branching tree generator function. Consider each
// method as a callback and implement the actions that need to be done. // method as a callback and implement the actions that need to be done.
class Builder class Builder
@ -100,6 +105,12 @@ public:
// Add an anchor bridge to the model body // Add an anchor bridge to the model body
virtual bool add_mesh_bridge(const Node &from, const Node &to) = 0; virtual bool add_mesh_bridge(const Node &from, const Node &to) = 0;
virtual std::optional<Vec3f> suggest_avoidance(const Node &from,
float max_bridge_len) const
{
return {};
}
// Report nodes that can not be routed to an endpoint (model or ground) // Report nodes that can not be routed to an endpoint (model or ground)
virtual void report_unroutable(const Node &j) = 0; virtual void report_unroutable(const Node &j) = 0;

View File

@ -1,82 +1,15 @@
#include "PointCloud.hpp" #include "PointCloud.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Tesselate.hpp" #include "libslic3r/Tesselate.hpp"
#include "libslic3r/SLA/SupportTreeUtils.hpp"
#include <igl/random_points_on_mesh.h> #include <igl/random_points_on_mesh.h>
namespace Slic3r { namespace branchingtree { namespace Slic3r { namespace branchingtree {
std::optional<Vec3f> find_merge_pt(const Vec3f &A, std::optional<Vec3f> find_merge_pt(const Vec3f &A, const Vec3f &B, float max_slope)
const Vec3f &B,
float critical_angle)
{ {
// The idea is that A and B both have their support cones. But searching return sla::find_merge_pt(A, B, max_slope);
// for the intersection of these support cones is difficult and its enough
// to reduce this problem to 2D and search for the intersection of two
// rays that merge somewhere between A and B. The 2D plane is a vertical
// slice of the 3D scene where the 2D Y axis is equal to the 3D Z axis and
// the 2D X axis is determined by the XY direction of the AB vector.
//
// Z^
// | A *
// | . . B *
// | . . . .
// | . . . .
// | . x .
// -------------------> XY
// Determine the transformation matrix for the 2D projection:
Vec3f diff = {B.x() - A.x(), B.y() - A.y(), 0.f};
Vec3f dir = diff.normalized(); // TODO: avoid normalization
Eigen::Matrix<float, 2, 3> tr2D;
tr2D.row(0) = Vec3f{dir.x(), dir.y(), dir.z()};
tr2D.row(1) = Vec3f{0.f, 0.f, 1.f};
// Transform the 2 vectors A and B into 2D vector 'a' and 'b'. Here we can
// omit 'a', pretend that its the origin and use BA as the vector b.
Vec2f b = tr2D * (B - A);
// Get the square sine of the ray emanating from 'a' towards 'b'. This ray might
// exceed the allowed angle but that is corrected subsequently.
// The sign of the original sine is also needed, hence b.y is multiplied by
// abs(b.y)
float b_sqn = b.squaredNorm();
float sin2sig_a = b_sqn > EPSILON ? (b.y() * std::abs(b.y())) / b_sqn : 0.f;
// sine2 from 'b' to 'a' is the opposite of sine2 from a to b
float sin2sig_b = -sin2sig_a;
// Derive the allowed angles from the given critical angle.
// critical_angle is measured from the horizontal X axis.
// The rays need to go downwards which corresponds to negative angles
float sincrit = std::sin(critical_angle); // sine of the critical angle
float sin2crit = -sincrit * sincrit; // signed sine squared
sin2sig_a = std::min(sin2sig_a, sin2crit); // Do the angle saturation of both rays
sin2sig_b = std::min(sin2sig_b, sin2crit); //
float sin2_a = std::abs(sin2sig_a); // Get cosine squared values
float sin2_b = std::abs(sin2sig_b);
float cos2_a = 1.f - sin2_a;
float cos2_b = 1.f - sin2_b;
// Derive the new direction vectors. This is by square rooting the sin2
// and cos2 values and restoring the original signs
Vec2f Da = {std::copysign(std::sqrt(cos2_a), b.x()), std::copysign(std::sqrt(sin2_a), sin2sig_a)};
Vec2f Db = {-std::copysign(std::sqrt(cos2_b), b.x()), std::copysign(std::sqrt(sin2_b), sin2sig_b)};
// Determine where two rays ([0, 0], Da), (b, Db) intersect.
// Based on
// https://stackoverflow.com/questions/27459080/given-two-points-and-two-direction-vectors-find-the-point-where-they-intersect
// One ray is emanating from (0, 0) so the formula is simplified
double t1 = (Db.y() * b.x() - b.y() * Db.x()) /
(Da.x() * Db.y() - Da.y() * Db.x());
Vec2f mp = t1 * Da;
Vec3f Mp = A + tr2D.transpose() * mp;
return t1 >= 0.f ? Mp : Vec3f{};
} }
void to_eigen_mesh(const indexed_triangle_set &its, void to_eigen_mesh(const indexed_triangle_set &its,
@ -141,8 +74,6 @@ std::vector<Node> sample_mesh(const indexed_triangle_set &its, double radius)
std::vector<Node> sample_bed(const ExPolygons &bed, float z, double radius) std::vector<Node> sample_bed(const ExPolygons &bed, float z, double radius)
{ {
std::vector<Vec3f> ret;
auto triangles = triangulate_expolygons_3d(bed, z); auto triangles = triangulate_expolygons_3d(bed, z);
indexed_triangle_set its; indexed_triangle_set its;
its.vertices.reserve(triangles.size()); its.vertices.reserve(triangles.size());
@ -199,6 +130,9 @@ PointCloud::PointCloud(std::vector<Node> meshpts,
for (size_t i = 0; i < m_leafs.size(); ++i) { for (size_t i = 0; i < m_leafs.size(); ++i) {
Node &n = m_leafs[i]; Node &n = m_leafs[i];
n.id = int(LEAFS_BEGIN + i); n.id = int(LEAFS_BEGIN + i);
n.left = Node::ID_NONE;
n.right = Node::ID_NONE;
m_ktree.insert({n.pos, n.id}); m_ktree.insert({n.pos, n.id});
} }
} }

View File

@ -5,7 +5,7 @@
#include "BranchingTree.hpp" #include "BranchingTree.hpp"
#include "libslic3r/Execution/Execution.hpp" //#include "libslic3r/Execution/Execution.hpp"
#include "libslic3r/MutablePriorityQueue.hpp" #include "libslic3r/MutablePriorityQueue.hpp"
#include "libslic3r/BoostAdapter.hpp" #include "libslic3r/BoostAdapter.hpp"
@ -78,14 +78,6 @@ private:
rtree<PointIndexEl, boost::geometry::index::rstar<16, 4> /* ? */> rtree<PointIndexEl, boost::geometry::index::rstar<16, 4> /* ? */>
m_ktree; m_ktree;
bool is_outside_support_cone(const Vec3f &supp, const Vec3f &pt) const
{
Vec3d D = (pt - supp).cast<double>();
double dot_sq = -D.z() * std::abs(-D.z());
return dot_sq < D.squaredNorm() * cos2bridge_slope;
}
template<class PC> template<class PC>
static auto *get_node(PC &&pc, size_t id) static auto *get_node(PC &&pc, size_t id)
{ {
@ -104,6 +96,14 @@ private:
public: public:
bool is_outside_support_cone(const Vec3f &supp, const Vec3f &pt) const
{
Vec3d D = (pt - supp).cast<double>();
double dot_sq = -D.z() * std::abs(-D.z());
return dot_sq < D.squaredNorm() * cos2bridge_slope;
}
static constexpr auto Unqueued = size_t(-1); static constexpr auto Unqueued = size_t(-1);
struct ZCompareFn struct ZCompareFn
@ -255,18 +255,42 @@ public:
} }
}; };
template<class Fn> constexpr bool IsTraverseFn = std::is_invocable_v<Fn, Node&>;
struct TraverseReturnT
{
bool to_left : 1; // if true, continue traversing to the left
bool to_right : 1; // if true, continue traversing to the right
};
template<class PC, class Fn> void traverse(PC &&pc, size_t root, Fn &&fn) template<class PC, class Fn> void traverse(PC &&pc, size_t root, Fn &&fn)
{ {
if (auto nodeptr = pc.find(root); nodeptr != nullptr) { if (auto nodeptr = pc.find(root); nodeptr != nullptr) {
auto &nroot = *nodeptr; auto &nroot = *nodeptr;
TraverseReturnT ret{true, true};
if constexpr (std::is_same_v<std::invoke_result_t<Fn, decltype(nroot)>, void>) {
// Our fn has no return value
fn(nroot); fn(nroot);
if (nroot.left >= 0) traverse(pc, nroot.left, fn); } else {
if (nroot.right >= 0) traverse(pc, nroot.right, fn); // Fn returns instructions about how to continue traversing
ret = fn(nroot);
}
if (ret.to_left && nroot.left >= 0)
traverse(pc, nroot.left, fn);
if (ret.to_right && nroot.right >= 0)
traverse(pc, nroot.right, fn);
} }
} }
void build_tree(PointCloud &pcloud, Builder &builder); void build_tree(PointCloud &pcloud, Builder &builder);
inline void build_tree(PointCloud &&pc, Builder &builder)
{
build_tree(pc, builder);
}
}} // namespace Slic3r::branchingtree }} // namespace Slic3r::branchingtree
#endif // POINTCLOUD_HPP #endif // POINTCLOUD_HPP

View File

@ -79,12 +79,11 @@ inline std::tuple<Vec2d, double> detect_bridging_direction(const Lines &floating
{ {
if (floating_edges.empty()) { if (floating_edges.empty()) {
// consider this area anchored from all sides, pick bridging direction that will likely yield shortest bridges // consider this area anchored from all sides, pick bridging direction that will likely yield shortest bridges
//use 3mm resolution (should be quite fast, and rough estimation should not cause any problems here) auto [pc1, pc2] = compute_principal_components(overhang_area);
auto [pc1, pc2] = compute_principal_components(overhang_area, 3.0); if (pc2 == Vec2f::Zero()) { // overhang may be smaller than resolution. In this case, any direction is ok
if (pc2 == Vec2d::Zero()) { // overhang may be smaller than resolution. In this case, any direction is ok
return {Vec2d{1.0,0.0}, 0.0}; return {Vec2d{1.0,0.0}, 0.0};
} else { } else {
return {pc2.normalized(), 0.0}; return {pc2.normalized().cast<double>(), 0.0};
} }
} }

View File

@ -490,7 +490,7 @@ static void make_inner_brim(const Print &print,
loops = union_pt_chained_outside_in(loops); loops = union_pt_chained_outside_in(loops);
std::reverse(loops.begin(), loops.end()); std::reverse(loops.begin(), loops.end());
extrusion_entities_append_loops(brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), extrusion_entities_append_loops(brim.entities, std::move(loops), ExtrusionRole::Skirt, float(flow.mm3_per_mm()),
float(flow.width()), float(print.skirt_first_layer_height())); float(flow.width()), float(print.skirt_first_layer_height()));
} }
@ -672,7 +672,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
if (i + 1 == j && first_path.size() > 3 && first_path.front().x() == first_path.back().x() && first_path.front().y() == first_path.back().y()) { if (i + 1 == j && first_path.size() > 3 && first_path.front().x() == first_path.back().x() && first_path.front().y() == first_path.back().y()) {
auto *loop = new ExtrusionLoop(); auto *loop = new ExtrusionLoop();
brim.entities.emplace_back(loop); brim.entities.emplace_back(loop);
loop->paths.emplace_back(erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height())); loop->paths.emplace_back(ExtrusionRole::Skirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
Points &points = loop->paths.front().polyline.points; Points &points = loop->paths.front().polyline.points;
points.reserve(first_path.size()); points.reserve(first_path.size());
for (const ClipperLib_Z::IntPoint &pt : first_path) for (const ClipperLib_Z::IntPoint &pt : first_path)
@ -683,7 +683,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
ExtrusionEntityCollection this_loop_trimmed; ExtrusionEntityCollection this_loop_trimmed;
this_loop_trimmed.entities.reserve(j - i); this_loop_trimmed.entities.reserve(j - i);
for (; i < j; ++ i) { for (; i < j; ++ i) {
this_loop_trimmed.entities.emplace_back(new ExtrusionPath(erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()))); this_loop_trimmed.entities.emplace_back(new ExtrusionPath(ExtrusionRole::Skirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height())));
const ClipperLib_Z::Path &path = *loops_trimmed_order[i].first; const ClipperLib_Z::Path &path = *loops_trimmed_order[i].first;
Points &points = dynamic_cast<ExtrusionPath*>(this_loop_trimmed.entities.back())->polyline.points; Points &points = dynamic_cast<ExtrusionPath*>(this_loop_trimmed.entities.back())->polyline.points;
points.reserve(path.size()); points.reserve(path.size());
@ -699,7 +699,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
} }
} }
} else { } else {
extrusion_entities_append_loops_and_paths(brim.entities, std::move(all_loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height())); extrusion_entities_append_loops_and_paths(brim.entities, std::move(all_loops), ExtrusionRole::Skirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
} }
make_inner_brim(print, top_level_objects_with_brim, bottom_layers_expolygons, brim); make_inner_brim(print, top_level_objects_with_brim, bottom_layers_expolygons, brim);

View File

@ -320,7 +320,7 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& vol
bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom) const bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom) const
{ {
auto move_valid = [](const GCodeProcessorResult::MoveVertex &move) { auto move_valid = [](const GCodeProcessorResult::MoveVertex &move) {
return move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.f && move.height != 0.f; return move.type == EMoveType::Extrude && move.extrusion_role != GCodeExtrusionRole::Custom && move.width != 0.f && move.height != 0.f;
}; };
static constexpr const double epsilon = BedEpsilon; static constexpr const double epsilon = BedEpsilon;

View File

@ -11,7 +11,7 @@ endif ()
set(OpenVDBUtils_SOURCES "") set(OpenVDBUtils_SOURCES "")
if (TARGET OpenVDB::openvdb) if (TARGET OpenVDB::openvdb)
set(OpenVDBUtils_SOURCES OpenVDBUtils.cpp OpenVDBUtils.hpp) set(OpenVDBUtils_SOURCES OpenVDBUtils.cpp OpenVDBUtils.hpp OpenVDBUtilsLegacy.hpp)
endif() endif()
set(SLIC3R_SOURCES set(SLIC3R_SOURCES
@ -24,6 +24,7 @@ set(SLIC3R_SOURCES
AABBMesh.cpp AABBMesh.cpp
Algorithm/RegionExpansion.cpp Algorithm/RegionExpansion.cpp
Algorithm/RegionExpansion.hpp Algorithm/RegionExpansion.hpp
AnyPtr.hpp
BoundingBox.cpp BoundingBox.cpp
BoundingBox.hpp BoundingBox.hpp
BridgeDetector.cpp BridgeDetector.cpp
@ -42,6 +43,13 @@ set(SLIC3R_SOURCES
Color.hpp Color.hpp
Config.cpp Config.cpp
Config.hpp Config.hpp
CSGMesh/CSGMesh.hpp
CSGMesh/SliceCSGMesh.hpp
CSGMesh/ModelToCSGMesh.hpp
CSGMesh/PerformCSGMeshBooleans.hpp
CSGMesh/VoxelizeCSGMesh.hpp
CSGMesh/TriangleMeshAdapter.hpp
CSGMesh/CSGMeshCopy.hpp
EdgeGrid.cpp EdgeGrid.cpp
EdgeGrid.hpp EdgeGrid.hpp
ElephantFootCompensation.cpp ElephantFootCompensation.cpp
@ -59,6 +67,8 @@ set(SLIC3R_SOURCES
ExtrusionEntity.hpp ExtrusionEntity.hpp
ExtrusionEntityCollection.cpp ExtrusionEntityCollection.cpp
ExtrusionEntityCollection.hpp ExtrusionEntityCollection.hpp
ExtrusionRole.cpp
ExtrusionRole.hpp
ExtrusionSimulator.cpp ExtrusionSimulator.cpp
ExtrusionSimulator.hpp ExtrusionSimulator.hpp
FileParserError.hpp FileParserError.hpp
@ -326,6 +336,7 @@ set(SLIC3R_SOURCES
SLA/SupportTreeMesher.hpp SLA/SupportTreeMesher.hpp
SLA/SupportTreeMesher.cpp SLA/SupportTreeMesher.cpp
SLA/SupportTreeUtils.hpp SLA/SupportTreeUtils.hpp
SLA/SupportTreeUtilsLegacy.hpp
SLA/SupportTreeBuilder.cpp SLA/SupportTreeBuilder.cpp
SLA/SupportTree.hpp SLA/SupportTree.hpp
SLA/SupportTree.cpp SLA/SupportTree.cpp

View File

@ -0,0 +1,86 @@
#ifndef CSGMESH_HPP
#define CSGMESH_HPP
#include <libslic3r/AnyPtr.hpp>
#include <admesh/stl.h>
namespace Slic3r { namespace csg {
// A CSGPartT should be an object that can provide at least a mesh + trafo and an
// associated csg operation. A collection of CSGPartT objects can then
// be interpreted as one model and used in various contexts. It can be assembled
// with CGAL or OpenVDB, rendered with OpenCSG or provided to a ray-tracer to
// deal with various parts of it according to the supported CSG types...
//
// A few simple templated interface functions are provided here and a default
// CSGPart class that implements the necessary means to be usable as a
// CSGPartT object.
// Supported CSG operation types
enum class CSGType { Union, Difference, Intersection };
// A CSG part can instruct the processing to push the sub-result until a new
// csg part with a pop instruction appears. This can be used to implement
// parentheses in a CSG expression represented by the collection of csg parts.
// A CSG part can not contain another CSG collection, only a mesh, this is why
// its easier to do this stacking instead of recursion in the data definition.
// CSGStackOp::Continue means no stack operation required.
// When a CSG part contains a Push instruction, it is expected that the CSG
// operation it contains refers to the whole collection spanning to the nearest
// part with a Pop instruction.
// e.g.:
// {
// CUBE1: { mesh: cube, op: Union, stack op: Continue },
// CUBE2: { mesh: cube, op: Difference, stack op: Push},
// CUBE3: { mesh: cube, op: Union, stack op: Pop}
// }
// is a collection of csg parts representing the expression CUBE1 - (CUBE2 + CUBE3)
enum class CSGStackOp { Push, Continue, Pop };
// Get the CSG operation of the part. Can be overriden for any type
template<class CSGPartT> CSGType get_operation(const CSGPartT &part)
{
return part.operation;
}
// Get the stack operation required by the CSG part.
template<class CSGPartT> CSGStackOp get_stack_operation(const CSGPartT &part)
{
return part.stack_operation;
}
// Get the mesh for the part. Can be overriden for any type
template<class CSGPartT>
const indexed_triangle_set *get_mesh(const CSGPartT &part)
{
return part.its_ptr.get();
}
// Get the transformation associated with the mesh inside a CSGPartT object.
// Can be overriden for any type.
template<class CSGPartT>
Transform3f get_transform(const CSGPartT &part)
{
return part.trafo;
}
// Default implementation
struct CSGPart {
AnyPtr<const indexed_triangle_set> its_ptr;
Transform3f trafo;
CSGType operation;
CSGStackOp stack_operation;
CSGPart(AnyPtr<const indexed_triangle_set> ptr = {},
CSGType op = CSGType::Union,
const Transform3f &tr = Transform3f::Identity())
: its_ptr{std::move(ptr)}
, operation{op}
, stack_operation{CSGStackOp::Continue}
, trafo{tr}
{}
};
}} // namespace Slic3r::csg
#endif // CSGMESH_HPP

View File

@ -0,0 +1,80 @@
#ifndef CSGMESHCOPY_HPP
#define CSGMESHCOPY_HPP
#include "CSGMesh.hpp"
namespace Slic3r { namespace csg {
// Copy a csg range but for the meshes, only copy the pointers. If the copy
// is made from a CSGPart compatible object, and the pointer is a shared one,
// it will be copied with reference counting.
template<class It, class OutIt>
void copy_csgrange_shallow(const Range<It> &csgrange, OutIt out)
{
for (const auto &part : csgrange) {
CSGPart cpy{{},
get_operation(part),
get_transform(part)};
cpy.stack_operation = get_stack_operation(part);
if constexpr (std::is_convertible_v<decltype(part), const CSGPart&>) {
if (auto shptr = part.its_ptr.get_shared_cpy()) {
cpy.its_ptr = shptr;
}
}
if (!cpy.its_ptr)
cpy.its_ptr = AnyPtr<const indexed_triangle_set>{get_mesh(part)};
*out = std::move(cpy);
++out;
}
}
// Copy the csg range, allocating new meshes
template<class It, class OutIt>
void copy_csgrange_deep(const Range<It> &csgrange, OutIt out)
{
for (const auto &part : csgrange) {
CSGPart cpy{{}, get_operation(part), get_transform(part)};
if (auto meshptr = get_mesh(part)) {
cpy.its_ptr = std::make_unique<const indexed_triangle_set>(*meshptr);
}
cpy.stack_operation = get_stack_operation(part);
*out = std::move(cpy);
++out;
}
}
template<class ItA, class ItB>
bool is_same(const Range<ItA> &A, const Range<ItB> &B)
{
bool ret = true;
size_t s = A.size();
if (B.size() != s)
ret = false;
size_t i = 0;
auto itA = A.begin();
auto itB = B.begin();
for (; ret && i < s; ++itA, ++itB, ++i) {
ret = ret &&
get_mesh(*itA) == get_mesh(*itB) &&
get_operation(*itA) == get_operation(*itB) &&
get_stack_operation(*itA) == get_stack_operation(*itB) &&
get_transform(*itA).isApprox(get_transform(*itB));
}
return ret;
}
}} // namespace Slic3r::csg
#endif // CSGCOPY_HPP

View File

@ -0,0 +1,88 @@
#ifndef MODELTOCSGMESH_HPP
#define MODELTOCSGMESH_HPP
#include "CSGMesh.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/SLA/Hollowing.hpp"
#include "libslic3r/MeshSplitImpl.hpp"
namespace Slic3r { namespace csg {
// Flags to select which parts to export from Model into a csg part collection.
// These flags can be chained with the | operator
enum ModelParts {
mpartsPositive = 1, // Include positive parts
mpartsNegative = 2, // Include negative parts
mpartsDrillHoles = 4, // Include drill holes
mpartsDoSplits = 8, // Split each splitable mesh and export as a union of csg parts
};
template<class OutIt>
void model_to_csgmesh(const ModelObject &mo,
const Transform3d &trafo, // Applies to all exported parts
OutIt out, // Output iterator
// values of ModelParts OR-ed
int parts_to_include = mpartsPositive
)
{
bool do_positives = parts_to_include & mpartsPositive;
bool do_negatives = parts_to_include & mpartsNegative;
bool do_drillholes = parts_to_include & mpartsDrillHoles;
bool do_splits = parts_to_include & mpartsDoSplits;
for (const ModelVolume *vol : mo.volumes) {
if (vol && vol->mesh_ptr() &&
((do_positives && vol->is_model_part()) ||
(do_negatives && vol->is_negative_volume()))) {
if (do_splits && its_is_splittable(vol->mesh().its)) {
CSGPart part_begin{{}, vol->is_model_part() ? CSGType::Union : CSGType::Difference};
part_begin.stack_operation = CSGStackOp::Push;
*out = std::move(part_begin);
++out;
its_split(vol->mesh().its, SplitOutputFn{[&out, &vol, &trafo](indexed_triangle_set &&its) {
if (its.empty())
return;
CSGPart part{std::make_unique<indexed_triangle_set>(std::move(its)),
CSGType::Union,
(trafo * vol->get_matrix()).cast<float>()};
*out = std::move(part);
++out;
}});
CSGPart part_end{{}};
part_end.stack_operation = CSGStackOp::Pop;
*out = std::move(part_end);
++out;
} else {
CSGPart part{&(vol->mesh().its),
vol->is_model_part() ? CSGType::Union : CSGType::Difference,
(trafo * vol->get_matrix()).cast<float>()};
*out = std::move(part);
++out;
}
}
}
if (do_drillholes) {
sla::DrainHoles drainholes = sla::transformed_drainhole_points(mo, trafo);
for (const sla::DrainHole &dhole : drainholes) {
CSGPart part{std::make_unique<const indexed_triangle_set>(
dhole.to_mesh()),
CSGType::Difference};
*out = std::move(part);
++out;
}
}
}
}} // namespace Slic3r::csg
#endif // MODELTOCSGMESH_HPP

View File

@ -0,0 +1,205 @@
#ifndef PERFORMCSGMESHBOOLEANS_HPP
#define PERFORMCSGMESHBOOLEANS_HPP
#include <stack>
#include <vector>
#include "CSGMesh.hpp"
#include "libslic3r/Execution/ExecutionTBB.hpp"
//#include "libslic3r/Execution/ExecutionSeq.hpp"
#include "libslic3r/MeshBoolean.hpp"
namespace Slic3r { namespace csg {
// This method can be overriden when a specific CSGPart type supports caching
// of the voxel grid
template<class CSGPartT>
MeshBoolean::cgal::CGALMeshPtr get_cgalmesh(const CSGPartT &csgpart)
{
const indexed_triangle_set *its = csg::get_mesh(csgpart);
indexed_triangle_set dummy;
if (!its)
its = &dummy;
MeshBoolean::cgal::CGALMeshPtr ret;
indexed_triangle_set m = *its;
auto tr = get_transform(csgpart);
its_transform(m, get_transform(csgpart), true);
try {
ret = MeshBoolean::cgal::triangle_mesh_to_cgal(m);
} catch (...) {
// errors are ignored, simply return null
ret = nullptr;
}
return ret;
}
namespace detail_cgal {
using MeshBoolean::cgal::CGALMeshPtr;
inline void perform_csg(CSGType op, CGALMeshPtr &dst, CGALMeshPtr &src)
{
if (!dst && op == CSGType::Union && src) {
dst = std::move(src);
return;
}
if (!dst || !src)
return;
switch (op) {
case CSGType::Union:
MeshBoolean::cgal::plus(*dst, *src);
break;
case CSGType::Difference:
MeshBoolean::cgal::minus(*dst, *src);
break;
case CSGType::Intersection:
MeshBoolean::cgal::intersect(*dst, *src);
break;
}
}
template<class Ex, class It>
std::vector<CGALMeshPtr> get_cgalptrs(Ex policy, const Range<It> &csgrange)
{
std::vector<CGALMeshPtr> ret(csgrange.size());
execution::for_each(policy, size_t(0), csgrange.size(),
[&csgrange, &ret](size_t i) {
auto it = csgrange.begin();
std::advance(it, i);
auto &csgpart = *it;
ret[i] = get_cgalmesh(csgpart);
});
return ret;
}
} // namespace detail
// Process the sequence of CSG parts with CGAL.
template<class It>
void perform_csgmesh_booleans(MeshBoolean::cgal::CGALMeshPtr &cgalm,
const Range<It> &csgrange)
{
using MeshBoolean::cgal::CGALMesh;
using MeshBoolean::cgal::CGALMeshPtr;
using namespace detail_cgal;
struct Frame {
CSGType op; CGALMeshPtr cgalptr;
explicit Frame(CSGType csgop = CSGType::Union)
: op{csgop}
, cgalptr{MeshBoolean::cgal::triangle_mesh_to_cgal(indexed_triangle_set{})}
{}
};
std::stack opstack{std::vector<Frame>{}};
opstack.push(Frame{});
std::vector<CGALMeshPtr> cgalmeshes = get_cgalptrs(ex_tbb, csgrange);
size_t csgidx = 0;
for (auto &csgpart : csgrange) {
auto op = get_operation(csgpart);
CGALMeshPtr &cgalptr = cgalmeshes[csgidx++];
if (get_stack_operation(csgpart) == CSGStackOp::Push) {
opstack.push(Frame{op});
op = CSGType::Union;
}
Frame *top = &opstack.top();
perform_csg(get_operation(csgpart), top->cgalptr, cgalptr);
if (get_stack_operation(csgpart) == CSGStackOp::Pop) {
CGALMeshPtr src = std::move(top->cgalptr);
auto popop = opstack.top().op;
opstack.pop();
CGALMeshPtr &dst = opstack.top().cgalptr;
perform_csg(popop, dst, src);
}
}
cgalm = std::move(opstack.top().cgalptr);
}
template<class It, class Visitor>
It check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
{
using namespace detail_cgal;
std::vector<CGALMeshPtr> cgalmeshes(csgrange.size());
auto check_part = [&csgrange, &cgalmeshes](size_t i)
{
auto it = csgrange.begin();
std::advance(it, i);
auto &csgpart = *it;
auto m = get_cgalmesh(csgpart);
// mesh can be nullptr if this is a stack push or pull
if (!get_mesh(csgpart) && get_stack_operation(csgpart) != CSGStackOp::Continue) {
cgalmeshes[i] = MeshBoolean::cgal::triangle_mesh_to_cgal(indexed_triangle_set{});
return;
}
try {
if (!m || MeshBoolean::cgal::empty(*m))
return;
if (!MeshBoolean::cgal::does_bound_a_volume(*m))
return;
if (MeshBoolean::cgal::does_self_intersect(*m))
return;
}
catch (...) { return; }
cgalmeshes[i] = std::move(m);
};
execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part);
It ret = csgrange.end();
for (size_t i = 0; i < csgrange.size(); ++i) {
if (!cgalmeshes[i]) {
auto it = csgrange.begin();
std::advance(it, i);
vfn(it);
if (ret == csgrange.end())
ret = it;
}
}
return ret;
}
template<class It>
It check_csgmesh_booleans(const Range<It> &csgrange)
{
return check_csgmesh_booleans(csgrange, [](auto &) {});
}
template<class It>
MeshBoolean::cgal::CGALMeshPtr perform_csgmesh_booleans(const Range<It> &csgparts)
{
auto ret = MeshBoolean::cgal::triangle_mesh_to_cgal(indexed_triangle_set{});
if (ret)
perform_csgmesh_booleans(ret, csgparts);
return ret;
}
} // namespace csg
} // namespace Slic3r
#endif // PERFORMCSGMESHBOOLEANS_HPP

View File

@ -0,0 +1,131 @@
#ifndef SLICECSGMESH_HPP
#define SLICECSGMESH_HPP
#include "CSGMesh.hpp"
#include <stack>
#include "libslic3r/TriangleMeshSlicer.hpp"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/Execution/ExecutionTBB.hpp"
namespace Slic3r { namespace csg {
namespace detail {
inline void merge_slices(csg::CSGType op, size_t i,
std::vector<ExPolygons> &target,
std::vector<ExPolygons> &source)
{
switch(op) {
case CSGType::Union:
for (ExPolygon &expoly : source[i])
target[i].emplace_back(std::move(expoly));
break;
case CSGType::Difference:
target[i] = diff_ex(target[i], source[i]);
break;
case CSGType::Intersection:
target[i] = intersection_ex(target[i], source[i]);
break;
}
}
inline void collect_nonempty_indices(csg::CSGType op,
const std::vector<float> &slicegrid,
const std::vector<ExPolygons> &slices,
std::vector<size_t> &indices)
{
indices.clear();
for (size_t i = 0; i < slicegrid.size(); ++i) {
if (op == CSGType::Intersection || !slices[i].empty())
indices.emplace_back(i);
}
}
} // namespace detail
template<class ItCSG>
std::vector<ExPolygons> slice_csgmesh_ex(
const Range<ItCSG> &csgrange,
const std::vector<float> &slicegrid,
const MeshSlicingParamsEx &params,
const std::function<void()> &throw_on_cancel = [] {})
{
using namespace detail;
struct Frame { CSGType op; std::vector<ExPolygons> slices; };
std::stack opstack{std::vector<Frame>{}};
MeshSlicingParamsEx params_cpy = params;
auto trafo = params.trafo;
auto nonempty_indices = reserve_vector<size_t>(slicegrid.size());
opstack.push({CSGType::Union, std::vector<ExPolygons>(slicegrid.size())});
for (const auto &csgpart : csgrange) {
const indexed_triangle_set *its = csg::get_mesh(csgpart);
auto op = get_operation(csgpart);
if (get_stack_operation(csgpart) == CSGStackOp::Push) {
opstack.push({op, std::vector<ExPolygons>(slicegrid.size())});
op = CSGType::Union;
}
Frame *top = &opstack.top();
if (its) {
params_cpy.trafo = trafo * csg::get_transform(csgpart).template cast<double>();
std::vector<ExPolygons> slices = slice_mesh_ex(*its,
slicegrid, params_cpy,
throw_on_cancel);
assert(slices.size() == slicegrid.size());
collect_nonempty_indices(op, slicegrid, slices, nonempty_indices);
execution::for_each(
ex_tbb, nonempty_indices.begin(), nonempty_indices.end(),
[op, &slices, &top](size_t i) {
merge_slices(op, i, top->slices, slices);
}, execution::max_concurrency(ex_tbb));
}
if (get_stack_operation(csgpart) == CSGStackOp::Pop) {
std::vector<ExPolygons> popslices = std::move(top->slices);
auto popop = opstack.top().op;
opstack.pop();
std::vector<ExPolygons> &prev_slices = opstack.top().slices;
collect_nonempty_indices(popop, slicegrid, popslices, nonempty_indices);
execution::for_each(
ex_tbb, nonempty_indices.begin(), nonempty_indices.end(),
[&popslices, &prev_slices, popop](size_t i) {
merge_slices(popop, i, prev_slices, popslices);
}, execution::max_concurrency(ex_tbb));
}
}
std::vector<ExPolygons> ret = std::move(opstack.top().slices);
// TODO: verify if this part can be omitted or not.
execution::for_each(ex_tbb, ret.begin(), ret.end(), [](ExPolygons &slice) {
auto it = std::remove_if(slice.begin(), slice.end(), [](const ExPolygon &p){
return p.area() < double(SCALED_EPSILON) * double(SCALED_EPSILON);
});
// Hopefully, ExPolygons are moved, not copied to new positions
// and that is cheap for expolygons
slice.erase(it, slice.end());
slice = union_ex(slice);
}, execution::max_concurrency(ex_tbb));
return ret;
}
}} // namespace Slic3r::csg
#endif // SLICECSGMESH_HPP

View File

@ -0,0 +1,95 @@
#ifndef TRIANGLEMESHADAPTER_HPP
#define TRIANGLEMESHADAPTER_HPP
#include "CSGMesh.hpp"
#include "libslic3r/TriangleMesh.hpp"
namespace Slic3r { namespace csg {
// Provide default overloads for indexed_triangle_set to be usable as a plain
// CSGPart with an implicit union operation
inline CSGType get_operation(const indexed_triangle_set &part)
{
return CSGType::Union;
}
inline CSGStackOp get_stack_operation(const indexed_triangle_set &part)
{
return CSGStackOp::Continue;
}
inline const indexed_triangle_set * get_mesh(const indexed_triangle_set &part)
{
return &part;
}
inline Transform3f get_transform(const indexed_triangle_set &part)
{
return Transform3f::Identity();
}
inline CSGType get_operation(const indexed_triangle_set *const part)
{
return CSGType::Union;
}
inline CSGStackOp get_stack_operation(const indexed_triangle_set *const part)
{
return CSGStackOp::Continue;
}
inline const indexed_triangle_set * get_mesh(const indexed_triangle_set *const part)
{
return part;
}
inline Transform3f get_transform(const indexed_triangle_set *const part)
{
return Transform3f::Identity();
}
inline CSGType get_operation(const TriangleMesh &part)
{
return CSGType::Union;
}
inline CSGStackOp get_stack_operation(const TriangleMesh &part)
{
return CSGStackOp::Continue;
}
inline const indexed_triangle_set * get_mesh(const TriangleMesh &part)
{
return &part.its;
}
inline Transform3f get_transform(const TriangleMesh &part)
{
return Transform3f::Identity();
}
inline CSGType get_operation(const TriangleMesh * const part)
{
return CSGType::Union;
}
inline CSGStackOp get_stack_operation(const TriangleMesh * const part)
{
return CSGStackOp::Continue;
}
inline const indexed_triangle_set * get_mesh(const TriangleMesh * const part)
{
return &part->its;
}
inline Transform3f get_transform(const TriangleMesh * const part)
{
return Transform3f::Identity();
}
}} // namespace Slic3r::csg
#endif // TRIANGLEMESHADAPTER_HPP

View File

@ -0,0 +1,116 @@
#ifndef VOXELIZECSGMESH_HPP
#define VOXELIZECSGMESH_HPP
#include <functional>
#include <stack>
#include "CSGMesh.hpp"
#include "libslic3r/OpenVDBUtils.hpp"
#include "libslic3r/Execution/ExecutionTBB.hpp"
namespace Slic3r { namespace csg {
using VoxelizeParams = MeshToGridParams;
// This method can be overriden when a specific CSGPart type supports caching
// of the voxel grid
template<class CSGPartT>
VoxelGridPtr get_voxelgrid(const CSGPartT &csgpart, VoxelizeParams params)
{
const indexed_triangle_set *its = csg::get_mesh(csgpart);
VoxelGridPtr ret;
params.trafo(params.trafo() * csg::get_transform(csgpart));
if (its)
ret = mesh_to_grid(*its, params);
return ret;
}
namespace detail {
inline void perform_csg(CSGType op, VoxelGridPtr &dst, VoxelGridPtr &src)
{
if (!dst || !src)
return;
switch (op) {
case CSGType::Union:
if (is_grid_empty(*dst) && !is_grid_empty(*src))
dst = clone(*src);
else
grid_union(*dst, *src);
break;
case CSGType::Difference:
grid_difference(*dst, *src);
break;
case CSGType::Intersection:
grid_intersection(*dst, *src);
break;
}
}
} // namespace detail
template<class It>
VoxelGridPtr voxelize_csgmesh(const Range<It> &csgrange,
const VoxelizeParams &params = {})
{
using namespace detail;
VoxelGridPtr ret;
std::vector<VoxelGridPtr> grids (csgrange.size());
execution::for_each(ex_tbb, size_t(0), csgrange.size(), [&](size_t csgidx) {
if (params.statusfn() && params.statusfn()(-1))
return;
auto it = csgrange.begin();
std::advance(it, csgidx);
auto &csgpart = *it;
grids[csgidx] = get_voxelgrid(csgpart, params);
}, execution::max_concurrency(ex_tbb));
size_t csgidx = 0;
struct Frame { CSGType op = CSGType::Union; VoxelGridPtr grid; };
std::stack opstack{std::vector<Frame>{}};
opstack.push({CSGType::Union, mesh_to_grid({}, params)});
for (auto &csgpart : csgrange) {
if (params.statusfn() && params.statusfn()(-1))
break;
auto &partgrid = grids[csgidx++];
auto op = get_operation(csgpart);
if (get_stack_operation(csgpart) == CSGStackOp::Push) {
opstack.push({op, mesh_to_grid({}, params)});
op = CSGType::Union;
}
Frame *top = &opstack.top();
perform_csg(get_operation(csgpart), top->grid, partgrid);
if (get_stack_operation(csgpart) == CSGStackOp::Pop) {
VoxelGridPtr popgrid = std::move(top->grid);
auto popop = opstack.top().op;
opstack.pop();
VoxelGridPtr &grid = opstack.top().grid;
perform_csg(popop, grid, popgrid);
}
}
ret = std::move(opstack.top().grid);
return ret;
}
}} // namespace Slic3r::csg
#endif // VOXELIZECSGMESH_HPP

View File

@ -615,7 +615,7 @@ public:
static double nil_value() { return std::numeric_limits<double>::quiet_NaN(); } static double nil_value() { return std::numeric_limits<double>::quiet_NaN(); }
// A scalar is nil, or all values of a vector are nil. // A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; } bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; }
bool is_nil(size_t idx) const override { return std::isnan(this->values[idx]); } bool is_nil(size_t idx) const override { return std::isnan(this->values[idx < values.size() ? idx : 0]); }
std::string serialize() const override std::string serialize() const override
{ {
@ -776,7 +776,7 @@ public:
static int nil_value() { return std::numeric_limits<int>::max(); } static int nil_value() { return std::numeric_limits<int>::max(); }
// A scalar is nil, or all values of a vector are nil. // A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } bool is_nil(size_t idx) const override { return values[idx < this->values.size() ? idx : 0] == nil_value(); }
std::string serialize() const override std::string serialize() const override
{ {
@ -1092,7 +1092,7 @@ public:
static FloatOrPercent nil_value() { return { std::numeric_limits<double>::quiet_NaN(), false }; } static FloatOrPercent nil_value() { return { std::numeric_limits<double>::quiet_NaN(), false }; }
// A scalar is nil, or all values of a vector are nil. // A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; } bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; }
bool is_nil(size_t idx) const override { return std::isnan(this->values[idx].value); } bool is_nil(size_t idx) const override { return std::isnan(this->values[idx < values.size() ? idx : 0].value); }
std::string serialize() const override std::string serialize() const override
{ {
@ -1404,7 +1404,7 @@ public:
static unsigned char nil_value() { return std::numeric_limits<unsigned char>::max(); } static unsigned char nil_value() { return std::numeric_limits<unsigned char>::max(); }
// A scalar is nil, or all values of a vector are nil. // A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); } bool is_nil(size_t idx) const override { return this->values[idx < values.size() ? idx : 0] == nil_value(); }
bool& get_at(size_t i) { bool& get_at(size_t i) {
assert(! this->values.empty()); assert(! this->values.empty());

View File

@ -768,6 +768,15 @@ void priv::set_skip_for_out_of_aoi(std::vector<bool> &skip_indicies,
point_normals[i] = {p1, normal}; point_normals[i] = {p1, normal};
} }
// check that projection is not left handed
// Fix for reflected projection
if (is_out_of(point_normals[2].first, point_normals[0])) {
// projection is reflected so normals are reflected
for (auto &pn : point_normals)
pn.second *= -1;
}
// same meaning as point normal // same meaning as point normal
IsOnSides is_on_sides(its.vertices.size(), {false,false,false,false}); IsOnSides is_on_sides(its.vertices.size(), {false,false,false,false});
@ -1614,9 +1623,9 @@ void priv::create_reduce_map(ReductionMap &reduction_map, const CutMesh &mesh)
Vec3d n1 = v_ab.cross(v_ae); Vec3d n1 = v_ab.cross(v_ae);
Vec3d n2 = v_ab.cross(v_al); Vec3d n2 = v_ab.cross(v_al);
// check that normal has same direction // check that normal has same direction
if ((n1.x() > 0 != n2.x() > 0) || if (((n1.x() > 0) != (n2.x() > 0)) ||
(n1.y() > 0 != n2.y() > 0) || ((n1.y() > 0) != (n2.y() > 0)) ||
(n1.z() > 0 != n2.z() > 0)) ((n1.z() > 0) != (n2.z() > 0)))
return; // this reduction will create CCW triangle return; // this reduction will create CCW triangle
} }

View File

@ -20,43 +20,224 @@
#include "libslic3r/BoundingBox.hpp" #include "libslic3r/BoundingBox.hpp"
using namespace Slic3r; using namespace Slic3r;
using namespace Emboss;
using fontinfo_opt = std::optional<stbtt_fontinfo>;
// for try approach to heal shape by Clipper::Closing
//#define HEAL_WITH_CLOSING
// functionality to remove all spikes from shape
//#define REMOVE_SPIKES
// do not expose out of this file stbtt_ data types // do not expose out of this file stbtt_ data types
namespace priv{ namespace priv{
using Polygon = Slic3r::Polygon;
bool is_valid(const Emboss::FontFile &font, unsigned int index); bool is_valid(const FontFile &font, unsigned int index);
std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0); fontinfo_opt load_font_info(const unsigned char *data, unsigned int index = 0);
std::optional<Emboss::Glyph> get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness); std::optional<Glyph> get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness);
// take glyph from cache // take glyph from cache
const Emboss::Glyph* get_glyph(int unicode, const Emboss::FontFile &font, const FontProp &font_prop, const Glyph* get_glyph(int unicode, const FontFile &font, const FontProp &font_prop,
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt); Glyphs &cache, fontinfo_opt &font_info_opt);
EmbossStyle create_style(std::wstring name, std::wstring path); EmbossStyle create_style(std::wstring name, std::wstring path);
// scale and convert float to int coordinate // scale and convert float to int coordinate
Point to_point(const stbtt__point &point); Point to_point(const stbtt__point &point);
// bad is contour smaller than 3 points
void remove_bad(Polygons &polygons);
void remove_bad(ExPolygons &expolygons);
// helpr for heal shape // helpr for heal shape
bool remove_same_neighbor(Slic3r::Points &points); // Return true when erase otherwise false
bool remove_same_neighbor(Slic3r::Polygons &polygons); bool remove_same_neighbor(Points &points);
bool remove_same_neighbor(Polygons &polygons);
bool remove_same_neighbor(ExPolygons &expolygons); bool remove_same_neighbor(ExPolygons &expolygons);
// Try to remove self intersection by subtracting rect 2x2 px
bool remove_self_intersections(ExPolygons &shape, unsigned max_iteration = 10);
ExPolygon create_bounding_rect(const ExPolygons &shape);
void remove_small_islands(ExPolygons &shape, double minimal_area);
// NOTE: expolygons can't contain same_neighbor // NOTE: expolygons can't contain same_neighbor
Points collect_close_points(const ExPolygons &expolygons, double distance = .6); Points collect_close_points(const ExPolygons &expolygons, double distance = .6);
// Heal duplicates points and self intersections
bool heal_dupl_inter(ExPolygons &shape, unsigned max_iteration);
// for debug purpose
void visualize_heal(const std::string& svg_filepath, const ExPolygons &expolygons);
const Points pts_2x2({Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1)}); const Points pts_2x2({Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1)});
const Points pts_3x3({Point(-1, -1), Point(1, -1), Point(1, 1), Point(-1, 1)}); const Points pts_3x3({Point(-1, -1), Point(1, -1), Point(1, 1), Point(-1, 1)});
struct SpikeDesc
{
// cosinus of max spike angle
double cos_angle; // speed up to skip acos
// Half of Wanted bevel size
double half_bevel;
/// <summary>
/// Calculate spike description
/// </summary>
/// <param name="bevel_size">Size of spike width after cut of the tip, has to be grater than 2.5</param>
/// <param name="pixel_spike_length">When spike has same or more pixels with width less than 1 pixel</param>
SpikeDesc(double bevel_size, double pixel_spike_length = 6)
{
// create min angle given by spike_length
// Use it as minimal height of 1 pixel base spike
double angle = 2. * atan2(pixel_spike_length, .5); // [rad]
cos_angle = std::fabs(cos(angle));
// When remove spike this angle is set.
// Value must be grater than min_angle
half_bevel = bevel_size / 2;
}
}; };
bool priv::is_valid(const Emboss::FontFile &font, unsigned int index) { // return TRUE when remove point. It could create polygon with 2 points.
bool remove_when_spike(Polygon &polygon, size_t index, const SpikeDesc &spike_desc);
void remove_spikes_in_duplicates(ExPolygons &expolygons, const Points &duplicates);
#ifdef REMOVE_SPIKES
// Remove long sharp corners aka spikes
// by adding points to bevel tip of spikes - Not printable parts
// Try to not modify long sides of spike and add points on it's side
void remove_spikes(Polygon &polygon, const SpikeDesc &spike_desc);
void remove_spikes(Polygons &polygons, const SpikeDesc &spike_desc);
void remove_spikes(ExPolygons &expolygons, const SpikeDesc &spike_desc);
#endif
};
bool priv::remove_when_spike(Polygon &polygon, size_t index, const SpikeDesc &spike_desc) {
std::optional<Point> add;
bool do_erase = false;
Points &pts = polygon.points;
{
size_t pts_size = pts.size();
if (pts_size < 3)
return false;
const Point &a = (index == 0) ? pts.back() : pts[index - 1];
const Point &b = pts[index];
const Point &c = (index == (pts_size - 1)) ? pts.front() : pts[index + 1];
// calc sides
Vec2d ba = (a - b).cast<double>();
Vec2d bc = (c - b).cast<double>();
double dot_product = ba.dot(bc);
// sqrt together after multiplication save one sqrt
double ba_size_sq = ba.squaredNorm();
double bc_size_sq = bc.squaredNorm();
double norm = sqrt(ba_size_sq * bc_size_sq);
double cos_angle = dot_product / norm;
// small angle are around 1 --> cos(0) = 1
if (cos_angle < spike_desc.cos_angle)
return false; // not a spike
// has to be in range <-1, 1>
// Due to preccission of floating point number could be sligtly out of range
if (cos_angle > 1.)
cos_angle = 1.;
// if (cos_angle < -1.)
// cos_angle = -1.;
// Current Spike angle
double angle = acos(cos_angle);
double wanted_size = spike_desc.half_bevel / cos(angle / 2.);
double wanted_size_sq = wanted_size * wanted_size;
bool is_ba_short = ba_size_sq < wanted_size_sq;
bool is_bc_short = bc_size_sq < wanted_size_sq;
auto a_side = [&b, &ba, &ba_size_sq, &wanted_size]() -> Point {
Vec2d ba_norm = ba / sqrt(ba_size_sq);
return b + (wanted_size * ba_norm).cast<coord_t>();
};
auto c_side = [&b, &bc, &bc_size_sq, &wanted_size]() -> Point {
Vec2d bc_norm = bc / sqrt(bc_size_sq);
return b + (wanted_size * bc_norm).cast<coord_t>();
};
if (is_ba_short && is_bc_short) {
// remove short spike
do_erase = true;
} else if (is_ba_short) {
// move point B on C-side
pts[index] = c_side();
} else if (is_bc_short) {
// move point B on A-side
pts[index] = a_side();
} else {
// move point B on C-side and add point on A-side(left - before)
pts[index] = c_side();
add = a_side();
if (*add == pts[index]) {
// should be very rare, when SpikeDesc has small base
// will be fixed by remove B point
add.reset();
do_erase = true;
}
}
}
if (do_erase) {
pts.erase(pts.begin() + index);
return true;
}
if (add.has_value())
pts.insert(pts.begin() + index, *add);
return false;
}
void priv::remove_spikes_in_duplicates(ExPolygons &expolygons, const Points &duplicates) {
auto check = [](Polygon &polygon, const Point &d) -> bool {
double spike_bevel = 1 / SHAPE_SCALE;
double spike_length = 5.;
const static SpikeDesc sd(spike_bevel, spike_length);
Points& pts = polygon.points;
bool exist_remove = false;
for (size_t i = 0; i < pts.size(); i++) {
if (pts[i] != d)
continue;
exist_remove |= remove_when_spike(polygon, i, sd);
}
return exist_remove && pts.size() < 3;
};
bool exist_remove = false;
for (ExPolygon &expolygon : expolygons) {
BoundingBox bb(to_points(expolygon.contour));
for (const Point &d : duplicates) {
if (!bb.contains(d))
continue;
exist_remove |= check(expolygon.contour, d);
for (Polygon &hole : expolygon.holes)
exist_remove |= check(hole, d);
}
}
if (exist_remove)
remove_bad(expolygons);
}
bool priv::is_valid(const FontFile &font, unsigned int index) {
if (font.data == nullptr) return false; if (font.data == nullptr) return false;
if (font.data->empty()) return false; if (font.data->empty()) return false;
if (index >= font.infos.size()) return false; if (index >= font.infos.size()) return false;
return true; return true;
} }
std::optional<stbtt_fontinfo> priv::load_font_info( fontinfo_opt priv::load_font_info(
const unsigned char *data, unsigned int index) const unsigned char *data, unsigned int index)
{ {
int font_offset = stbtt_GetFontOffsetForIndex(data, index); int font_offset = stbtt_GetFontOffsetForIndex(data, index);
@ -74,6 +255,23 @@ std::optional<stbtt_fontinfo> priv::load_font_info(
return font_info; return font_info;
} }
void priv::remove_bad(Polygons &polygons) {
polygons.erase(
std::remove_if(polygons.begin(), polygons.end(),
[](const Polygon &p) { return p.size() < 3; }),
polygons.end());
}
void priv::remove_bad(ExPolygons &expolygons) {
expolygons.erase(
std::remove_if(expolygons.begin(), expolygons.end(),
[](const ExPolygon &p) { return p.contour.size() < 3; }),
expolygons.end());
for (ExPolygon &expolygon : expolygons)
remove_bad(expolygon.holes);
}
bool priv::remove_same_neighbor(Slic3r::Points &points) bool priv::remove_same_neighbor(Slic3r::Points &points)
{ {
if (points.empty()) return false; if (points.empty()) return false;
@ -85,15 +283,15 @@ bool priv::remove_same_neighbor(Slic3r::Points &points)
return true; return true;
} }
bool priv::remove_same_neighbor(Slic3r::Polygons &polygons) { bool priv::remove_same_neighbor(Polygons &polygons) {
if (polygons.empty()) return false; if (polygons.empty()) return false;
bool exist = false; bool exist = false;
for (Slic3r::Polygon& polygon : polygons) for (Polygon& polygon : polygons)
exist |= remove_same_neighbor(polygon.points); exist |= remove_same_neighbor(polygon.points);
// remove empty polygons // remove empty polygons
polygons.erase( polygons.erase(
std::remove_if(polygons.begin(), polygons.end(), std::remove_if(polygons.begin(), polygons.end(),
[](const Slic3r::Polygon &p) { return p.empty(); }), [](const Polygon &p) { return p.empty(); }),
polygons.end()); polygons.end());
return exist; return exist;
} }
@ -104,19 +302,18 @@ bool priv::remove_same_neighbor(ExPolygons &expolygons) {
for (ExPolygon &expoly : expolygons) { for (ExPolygon &expoly : expolygons) {
exist |= remove_same_neighbor(expoly.contour.points); exist |= remove_same_neighbor(expoly.contour.points);
Polygons &holes = expoly.holes; Polygons &holes = expoly.holes;
for (Slic3r::Polygon &hole : holes) for (Polygon &hole : holes)
exist |= remove_same_neighbor(hole.points); exist |= remove_same_neighbor(hole.points);
// remove empy holes
holes.erase( holes.erase(
std::remove_if(holes.begin(), holes.end(), std::remove_if(holes.begin(), holes.end(),
[](const Slic3r::Polygon &p) { return p.empty(); }), [](const Polygon &p) { return p.size() < 3; }),
holes.end()); holes.end());
} }
// remove empty contours
expolygons.erase( // Removing of point could create polygon with less than 3 points
std::remove_if(expolygons.begin(), expolygons.end(), if (exist)
[](const ExPolygon &p) { return p.contour.empty(); }), remove_bad(expolygons);
expolygons.end());
return exist; return exist;
} }
@ -145,7 +342,7 @@ Points priv::collect_close_points(const ExPolygons &expolygons, double distance)
// do not doubled side point of segment // do not doubled side point of segment
const ExPolygonsIndex id = ids.cvt(index); const ExPolygonsIndex id = ids.cvt(index);
const ExPolygon &expoly = expolygons[id.expolygons_index]; const ExPolygon &expoly = expolygons[id.expolygons_index];
const Slic3r::Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()]; const Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
const Points &poly_pts = poly.points; const Points &poly_pts = poly.points;
const Point &line_a = poly_pts[id.point_index]; const Point &line_a = poly_pts[id.point_index];
const Point &line_b = (!ids.is_last_point(id)) ? poly_pts[id.point_index + 1] : poly_pts.front(); const Point &line_b = (!ids.is_last_point(id)) ? poly_pts[id.point_index + 1] : poly_pts.front();
@ -159,7 +356,7 @@ Points priv::collect_close_points(const ExPolygons &expolygons, double distance)
}; };
for (const ExPolygon &expoly : expolygons) { for (const ExPolygon &expoly : expolygons) {
collect_close(expoly.contour.points); collect_close(expoly.contour.points);
for (const Slic3r::Polygon &hole : expoly.holes) for (const Polygon &hole : expoly.holes)
collect_close(hole.points); collect_close(hole.points);
} }
if (res.empty()) return {}; if (res.empty()) return {};
@ -198,7 +395,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
// do not doubled side point of segment // do not doubled side point of segment
const ExPolygonsIndex id = ids.cvt(index); const ExPolygonsIndex id = ids.cvt(index);
const ExPolygon &expoly = expolygons[id.expolygons_index]; const ExPolygon &expoly = expolygons[id.expolygons_index];
const Slic3r::Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()]; const Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
const Points &poly_pts = poly.points; const Points &poly_pts = poly.points;
const Point &line_a = poly_pts[id.point_index]; const Point &line_a = poly_pts[id.point_index];
const Point &line_b = (!ids.is_last_point(id)) ? poly_pts[id.point_index + 1] : poly_pts.front(); const Point &line_b = (!ids.is_last_point(id)) ? poly_pts[id.point_index + 1] : poly_pts.front();
@ -213,7 +410,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
}; };
for (const ExPolygon &expoly : expolygons) { for (const ExPolygon &expoly : expolygons) {
check_points(expoly.contour.points); check_points(expoly.contour.points);
for (const Slic3r::Polygon &hole : expoly.holes) for (const Polygon &hole : expoly.holes)
check_points(hole.points); check_points(hole.points);
} }
@ -235,7 +432,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
ExPolygonsIndex id = ids.cvt(index); ExPolygonsIndex id = ids.cvt(index);
ExPolygon &expoly = expolygons[id.expolygons_index]; ExPolygon &expoly = expolygons[id.expolygons_index];
Slic3r::Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()]; Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
Points &pts = poly.points; Points &pts = poly.points;
size_t count = it2 - it; size_t count = it2 - it;
@ -272,7 +469,64 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
return true; return true;
} }
ExPolygons Emboss::heal_shape(const Polygons &shape) { bool priv::remove_self_intersections(ExPolygons &shape, unsigned max_iteration) {
if (shape.empty())
return true;
Pointfs intersections_f = intersection_points(shape);
if (intersections_f.empty())
return true;
// create loop permanent memory
Polygons holes;
Points intersections;
while (--max_iteration) {
// convert intersections into Points
assert(intersections.empty());
intersections.reserve(intersections_f.size());
std::transform(intersections_f.begin(), intersections_f.end(), std::back_inserter(intersections),
[](const Vec2d &p) { return Point(std::floor(p.x()), std::floor(p.y())); });
// intersections should be unique poits
std::sort(intersections.begin(), intersections.end());
auto it = std::unique(intersections.begin(), intersections.end());
intersections.erase(it, intersections.end());
assert(holes.empty());
holes.reserve(intersections.size());
// Fix self intersection in result by subtracting hole 2x2
for (const Point &p : intersections) {
Polygon hole(priv::pts_2x2);
hole.translate(p);
holes.push_back(hole);
}
// union overlapped holes
if (holes.size() > 1)
holes = Slic3r::union_(holes);
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
// TODO: find where diff ex could create same neighbor
priv::remove_same_neighbor(shape);
// find new intersections made by diff_ex
intersections_f = intersection_points(shape);
if (intersections_f.empty())
return true;
else {
// clear permanent vectors
holes.clear();
intersections.clear();
}
}
assert(max_iteration == 0);
assert(!intersections_f.empty());
return false;
}
ExPolygons Emboss::heal_shape(const Polygons &shape)
{
// When edit this code check that font 'ALIENATE.TTF' and glyph 'i' still work // When edit this code check that font 'ALIENATE.TTF' and glyph 'i' still work
// fix of self intersections // fix of self intersections
// http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/SimplifyPolygon.htm // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/SimplifyPolygon.htm
@ -280,14 +534,15 @@ ExPolygons Emboss::heal_shape(const Polygons &shape) {
const double clean_distance = 1.415; // little grater than sqrt(2) const double clean_distance = 1.415; // little grater than sqrt(2)
ClipperLib::CleanPolygons(paths, clean_distance); ClipperLib::CleanPolygons(paths, clean_distance);
Polygons polygons = to_polygons(paths); Polygons polygons = to_polygons(paths);
polygons.erase(std::remove_if(polygons.begin(), polygons.end(), [](const Polygon &p) { return p.size() < 3; }), polygons.end());
// Do not remove all duplicits but do it better way // Do not remove all duplicates but do it better way
// Overlap all duplicit points by rectangle 3x3 // Overlap all duplicit points by rectangle 3x3
Points duplicits = collect_duplicates(to_points(polygons)); Points duplicits = collect_duplicates(to_points(polygons));
if (!duplicits.empty()) { if (!duplicits.empty()) {
polygons.reserve(polygons.size() + duplicits.size()); polygons.reserve(polygons.size() + duplicits.size());
for (const Point &p : duplicits) { for (const Point &p : duplicits) {
Slic3r::Polygon rect_3x3(priv::pts_3x3); Polygon rect_3x3(priv::pts_3x3);
rect_3x3.translate(p); rect_3x3.translate(p);
polygons.push_back(rect_3x3); polygons.push_back(rect_3x3);
} }
@ -301,73 +556,133 @@ ExPolygons Emboss::heal_shape(const Polygons &shape) {
return res; return res;
} }
#include "libslic3r/SVG.hpp"
void priv::visualize_heal(const std::string &svg_filepath, const ExPolygons &expolygons) {
Points pts = to_points(expolygons);
BoundingBox bb(pts);
//double svg_scale = SHAPE_SCALE / unscale<double>(1.);
// bb.scale(svg_scale);
SVG svg(svg_filepath, bb);
svg.draw(expolygons);
Points duplicits = collect_duplicates(pts);
svg.draw(duplicits, "black", 7 / SHAPE_SCALE);
Pointfs intersections_f = intersection_points(expolygons);
Points intersections;
intersections.reserve(intersections_f.size());
std::transform(intersections_f.begin(), intersections_f.end(), std::back_inserter(intersections),
[](const Vec2d &p) { return p.cast<int>(); });
svg.draw(intersections, "red", 8 / SHAPE_SCALE);
}
bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration) bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
{
return priv::heal_dupl_inter(shape, max_iteration);
}
#ifndef HEAL_WITH_CLOSING
bool priv::heal_dupl_inter(ExPolygons &shape, unsigned max_iteration)
{ {
if (shape.empty()) return true; if (shape.empty()) return true;
Slic3r::Polygons holes; // create loop permanent memory
Polygons holes;
Points intersections;
while (--max_iteration) { while (--max_iteration) {
priv::remove_same_neighbor(shape); priv::remove_same_neighbor(shape);
Pointfs intersections_f = intersection_points(shape);
Pointfs intersections = intersection_points(shape); // convert intersections into Points
Points duplicits = collect_duplicates(to_points(shape)); assert(intersections.empty());
//Points close = priv::collect_close_points(shape, 1.); intersections.reserve(intersections_f.size());
if (intersections.empty() && duplicits.empty() /* && close.empty() */) break; std::transform(intersections_f.begin(), intersections_f.end(), std::back_inserter(intersections),
[](const Vec2d &p) { return Point(std::floor(p.x()), std::floor(p.y())); });
holes.clear(); // intersections should be unique poits
holes.reserve(intersections.size() + duplicits.size() /* + close.size()*/); std::sort(intersections.begin(), intersections.end());
auto it = std::unique(intersections.begin(), intersections.end());
intersections.erase(it, intersections.end());
Points duplicates = collect_duplicates(to_points(shape));
// duplicates are already uniqua and sorted
// Check whether shape is already healed
if (intersections.empty() && duplicates.empty())
return true;
assert(holes.empty());
holes.reserve(intersections.size() + duplicates.size());
remove_spikes_in_duplicates(shape, duplicates);
// Fix self intersection in result by subtracting hole 2x2 // Fix self intersection in result by subtracting hole 2x2
for (const Vec2d &p : intersections) { for (const Point &p : intersections) {
Slic3r::Polygon hole(priv::pts_2x2); Polygon hole(priv::pts_2x2);
Point tr(std::floor(p.x()), std::floor(p.y()));
hole.translate(tr);
holes.push_back(hole);
}
// fix duplicit points by hole 3x3 around duplicit point
for (const Point &p : duplicits) {
Slic3r::Polygon hole(priv::pts_3x3);
hole.translate(p); hole.translate(p);
holes.push_back(hole); holes.push_back(hole);
} }
// fix close points in simmilar way as duplicits // Fix duplicit points by hole 3x3 around duplicit point
//for (const Point &p : close) { for (const Point &p : duplicates) {
// Slic3r::Polygon hole(priv::pts_3x3); Polygon hole(priv::pts_3x3);
// hole.translate(p); hole.translate(p);
// holes.push_back(hole); holes.push_back(hole);
//} }
holes = Slic3r::union_(holes); holes = Slic3r::union_(holes);
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes); shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
// prepare for next loop
holes.clear();
intersections.clear();
} }
/* VISUALIZATION of BAD symbols for debug
{
double svg_scale = Emboss::SHAPE_SCALE / unscale<double>(1.);
BoundingBox bb(to_points(shape));
//bb.scale(svg_scale);
SVG svg("C:/data/temp/fix_self_intersection.svg", bb);
svg.draw(shape);
// svg.draw(polygons, "orange");
svg.draw(shape, "green");
svg.draw(duplicits, "lightgray", 13 / Emboss::SHAPE_SCALE); //priv::visualize_heal("C:/data/temp/heal.svg", shape);
Points duplicits3 = collect_duplicates(to_points(shape));
svg.draw(duplicits3, "black", 7 / Emboss::SHAPE_SCALE);
Pointfs pts2 = intersection_points(shape);
Points pts_i; pts_i.reserve(pts2.size());
for (auto p : pts2) pts_i.push_back(p.cast<int>());
svg.draw(pts_i, "red", 8 / Emboss::SHAPE_SCALE);
} //*/
if (max_iteration == 0) {
assert(false); assert(false);
shape = {priv::create_bounding_rect(shape)};
return false;
}
#else
bool priv::heal_dupl_inter(ExPolygons &shape, unsigned max_iteration)
{
priv::remove_same_neighbor(shape);
const float delta = 2.f;
const ClipperLib::JoinType joinType = ClipperLib::JoinType::jtRound;
// remove double points
while (max_iteration) {
--max_iteration;
// if(!priv::remove_self_intersections(shape, max_iteration)) break;
shape = Slic3r::union_ex(shape);
shape = Slic3r::closing_ex(shape, delta, joinType);
// double minimal_area = 1000;
// priv::remove_small_islands(shape, minimal_area);
// check that duplicates and intersections do NOT exists
Points duplicits = collect_duplicates(to_points(shape));
Pointfs intersections_f = intersection_points(shape);
if (duplicits.empty() && intersections_f.empty())
return true;
}
// priv::visualize_heal("C:/data/temp/heal.svg", shape);
assert(false);
shape = {priv::create_bounding_rect(shape)};
return false;
}
#endif // !HEAL_WITH_CLOSING
ExPolygon priv::create_bounding_rect(const ExPolygons &shape) {
BoundingBox bb = get_extents(shape); BoundingBox bb = get_extents(shape);
Point size = bb.size(); Point size = bb.size();
if (size.x() < 10) bb.max.x() += 10; if (size.x() < 10)
if (size.y() < 10) bb.max.y() += 10; bb.max.x() += 10;
if (size.y() < 10)
bb.max.y() += 10;
Polygon rect({// CCW Polygon rect({// CCW
bb.min, bb.min,
@ -381,17 +696,29 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
{bb.min.x() + offset.x(), bb.max.y() - offset.y()}, {bb.min.x() + offset.x(), bb.max.y() - offset.y()},
bb.max - offset, bb.max - offset,
{bb.max.x() - offset.x(), bb.min.y() + offset.y()}}); {bb.max.x() - offset.x(), bb.min.y() + offset.y()}});
// BAD symbol
shape = {ExPolygon(rect, hole)}; return ExPolygon(rect, hole);
return false;
} }
assert(intersection_points(shape).empty()); void priv::remove_small_islands(ExPolygons &expolygons, double minimal_area) {
assert(collect_duplicates(to_points(shape)).empty()); if (expolygons.empty())
return true; return;
// remove small expolygons contours
auto expoly_it = std::remove_if(expolygons.begin(), expolygons.end(),
[&minimal_area](const ExPolygon &p) { return p.contour.area() < minimal_area; });
expolygons.erase(expoly_it, expolygons.end());
// remove small holes in expolygons
for (ExPolygon &expoly : expolygons) {
Polygons& holes = expoly.holes;
auto it = std::remove_if(holes.begin(), holes.end(),
[&minimal_area](const Polygon &p) { return -p.area() < minimal_area; });
holes.erase(it, holes.end());
}
} }
std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness) std::optional<Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness)
{ {
int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter); int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter);
if (glyph_index == 0) { if (glyph_index == 0) {
@ -404,7 +731,7 @@ std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, in
return {}; return {};
} }
Emboss::Glyph glyph; Glyph glyph;
stbtt_GetGlyphHMetrics(&font_info, glyph_index, &glyph.advance_width, &glyph.left_side_bearing); stbtt_GetGlyphHMetrics(&font_info, glyph_index, &glyph.advance_width, &glyph.left_side_bearing);
stbtt_vertex *vertices; stbtt_vertex *vertices;
@ -454,12 +781,12 @@ std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, in
return glyph; return glyph;
} }
const Emboss::Glyph* priv::get_glyph( const Glyph* priv::get_glyph(
int unicode, int unicode,
const Emboss::FontFile & font, const FontFile & font,
const FontProp & font_prop, const FontProp & font_prop,
Emboss::Glyphs & cache, Glyphs & cache,
std::optional<stbtt_fontinfo> &font_info_opt) fontinfo_opt &font_info_opt)
{ {
// TODO: Use resolution by printer configuration, or add it into FontProp // TODO: Use resolution by printer configuration, or add it into FontProp
const float RESOLUTION = 0.0125f; // [in mm] const float RESOLUTION = 0.0125f; // [in mm]
@ -482,7 +809,7 @@ const Emboss::Glyph* priv::get_glyph(
// Fix for very small flatness because it create huge amount of points from curve // Fix for very small flatness because it create huge amount of points from curve
if (flatness < RESOLUTION) flatness = RESOLUTION; if (flatness < RESOLUTION) flatness = RESOLUTION;
std::optional<Emboss::Glyph> glyph_opt = std::optional<Glyph> glyph_opt =
priv::get_glyph(*font_info_opt, unicode, flatness); priv::get_glyph(*font_info_opt, unicode, flatness);
// IMPROVE: multiple loadig glyph without data // IMPROVE: multiple loadig glyph without data
@ -494,26 +821,26 @@ const Emboss::Glyph* priv::get_glyph(
// scale glyph size // scale glyph size
glyph_opt->advance_width = glyph_opt->advance_width =
static_cast<int>(glyph_opt->advance_width / Emboss::SHAPE_SCALE); static_cast<int>(glyph_opt->advance_width / SHAPE_SCALE);
glyph_opt->left_side_bearing = glyph_opt->left_side_bearing =
static_cast<int>(glyph_opt->left_side_bearing / Emboss::SHAPE_SCALE); static_cast<int>(glyph_opt->left_side_bearing / SHAPE_SCALE);
if (!glyph_opt->shape.empty()) { if (!glyph_opt->shape.empty()) {
if (font_prop.boldness.has_value()) { if (font_prop.boldness.has_value()) {
float delta = *font_prop.boldness / Emboss::SHAPE_SCALE / float delta = *font_prop.boldness / SHAPE_SCALE /
font_prop.size_in_mm; font_prop.size_in_mm;
glyph_opt->shape = Slic3r::union_ex(offset_ex(glyph_opt->shape, delta)); glyph_opt->shape = Slic3r::union_ex(offset_ex(glyph_opt->shape, delta));
} }
if (font_prop.skew.has_value()) { if (font_prop.skew.has_value()) {
const float &ratio = *font_prop.skew; const float &ratio = *font_prop.skew;
auto skew = [&ratio](Slic3r::Polygon &polygon) { auto skew = [&ratio](Polygon &polygon) {
for (Slic3r::Point &p : polygon.points) { for (Slic3r::Point &p : polygon.points) {
p.x() += p.y() * ratio; p.x() += p.y() * ratio;
} }
}; };
for (ExPolygon &expolygon : glyph_opt->shape) { for (ExPolygon &expolygon : glyph_opt->shape) {
skew(expolygon.contour); skew(expolygon.contour);
for (Slic3r::Polygon &hole : expolygon.holes) skew(hole); for (Polygon &hole : expolygon.holes) skew(hole);
} }
} }
} }
@ -529,8 +856,8 @@ EmbossStyle priv::create_style(std::wstring name, std::wstring path) {
} }
Point priv::to_point(const stbtt__point &point) { Point priv::to_point(const stbtt__point &point) {
return Point(static_cast<int>(std::round(point.x / Emboss::SHAPE_SCALE)), return Point(static_cast<int>(std::round(point.x / SHAPE_SCALE)),
static_cast<int>(std::round(point.y / Emboss::SHAPE_SCALE))); static_cast<int>(std::round(point.y / SHAPE_SCALE)));
} }
#ifdef _WIN32 #ifdef _WIN32
@ -738,7 +1065,7 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
} }
#endif #endif
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file( std::unique_ptr<FontFile> Emboss::create_font_file(
std::unique_ptr<std::vector<unsigned char>> data) std::unique_ptr<std::vector<unsigned char>> data)
{ {
int collection_size = stbtt_GetNumberOfFonts(data->data()); int collection_size = stbtt_GetNumberOfFonts(data->data());
@ -767,10 +1094,10 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(
infos.emplace_back(FontFile::Info{ascent, descent, linegap, units_per_em}); infos.emplace_back(FontFile::Info{ascent, descent, linegap, units_per_em});
} }
return std::make_unique<Emboss::FontFile>(std::move(data), std::move(infos)); return std::make_unique<FontFile>(std::move(data), std::move(infos));
} }
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(const char *file_path) std::unique_ptr<FontFile> Emboss::create_font_file(const char *file_path)
{ {
FILE *file = std::fopen(file_path, "rb"); FILE *file = std::fopen(file_path, "rb");
if (file == nullptr) { if (file == nullptr) {
@ -833,7 +1160,7 @@ static bool load_hfont(void* hfont, DWORD &dwTable, DWORD &dwOffset, size_t& siz
return true; return true;
} }
void * Emboss::can_load(HFONT hfont) void *Emboss::can_load(void *hfont)
{ {
DWORD dwTable=0, dwOffset=0; DWORD dwTable=0, dwOffset=0;
size_t size = 0; size_t size = 0;
@ -841,7 +1168,7 @@ void * Emboss::can_load(HFONT hfont)
return hfont; return hfont;
} }
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont) std::unique_ptr<FontFile> Emboss::create_font_file(void *hfont)
{ {
HDC hdc = ::CreateCompatibleDC(NULL); HDC hdc = ::CreateCompatibleDC(NULL);
if (hdc == NULL) { if (hdc == NULL) {
@ -868,7 +1195,7 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
} }
#endif // _WIN32 #endif // _WIN32
std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font, std::optional<Glyph> Emboss::letter2glyph(const FontFile &font,
unsigned int font_index, unsigned int font_index,
int letter, int letter,
float flatness) float flatness)
@ -885,7 +1212,7 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
std::function<bool()> was_canceled) std::function<bool()> was_canceled)
{ {
assert(font_with_cache.has_value()); assert(font_with_cache.has_value());
std::optional<stbtt_fontinfo> font_info_opt; fontinfo_opt font_info_opt;
Point cursor(0, 0); Point cursor(0, 0);
ExPolygons result; ExPolygons result;
const FontFile& font = *font_with_cache.font_file; const FontFile& font = *font_with_cache.font_file;
@ -893,7 +1220,7 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
*font_prop.collection_number : 0; *font_prop.collection_number : 0;
if (!priv::is_valid(font, font_index)) return {}; if (!priv::is_valid(font, font_index)) return {};
const FontFile::Info& info = font.infos[font_index]; const FontFile::Info& info = font.infos[font_index];
Emboss::Glyphs& cache = *font_with_cache.cache; Glyphs& cache = *font_with_cache.cache;
std::wstring ws = boost::nowide::widen(text); std::wstring ws = boost::nowide::widen(text);
for (wchar_t wc: ws){ for (wchar_t wc: ws){
if (wc == '\n') { if (wc == '\n') {
@ -953,7 +1280,7 @@ void Emboss::apply_transformation(const FontProp &font_prop,
bool Emboss::is_italic(const FontFile &font, unsigned int font_index) bool Emboss::is_italic(const FontFile &font, unsigned int font_index)
{ {
if (font_index >= font.infos.size()) return false; if (font_index >= font.infos.size()) return false;
std::optional<stbtt_fontinfo> font_info_opt = priv::load_font_info(font.data->data(), font_index); fontinfo_opt font_info_opt = priv::load_font_info(font.data->data(), font_index);
if (!font_info_opt.has_value()) return false; if (!font_info_opt.has_value()) return false;
stbtt_fontinfo *info = &(*font_info_opt); stbtt_fontinfo *info = &(*font_info_opt);
@ -1036,7 +1363,7 @@ double Emboss::get_shape_scale(const FontProp &fp, const FontFile &ff)
int unit_per_em = ff.infos[font_index].unit_per_em; int unit_per_em = ff.infos[font_index].unit_per_em;
double scale = fp.size_in_mm / unit_per_em; double scale = fp.size_in_mm / unit_per_em;
// Shape is scaled for store point coordinate as integer // Shape is scaled for store point coordinate as integer
return scale * Emboss::SHAPE_SCALE; return scale * SHAPE_SCALE;
} }
namespace priv { namespace priv {
@ -1055,7 +1382,7 @@ void add_quad(uint32_t i1,
indexed_triangle_set polygons2model_unique( indexed_triangle_set polygons2model_unique(
const ExPolygons &shape2d, const ExPolygons &shape2d,
const Emboss::IProjection &projection, const IProjection &projection,
const Points &points) const Points &points)
{ {
// CW order of triangle indices // CW order of triangle indices
@ -1091,7 +1418,7 @@ indexed_triangle_set polygons2model_unique(
// quads around - zig zag by triangles // quads around - zig zag by triangles
size_t polygon_offset = 0; size_t polygon_offset = 0;
auto add_quads = [&polygon_offset,&result, &count_point] auto add_quads = [&polygon_offset,&result, &count_point]
(const Slic3r::Polygon& polygon) { (const Polygon& polygon) {
uint32_t polygon_points = polygon.points.size(); uint32_t polygon_points = polygon.points.size();
// previous index // previous index
uint32_t prev = polygon_offset + polygon_points - 1; uint32_t prev = polygon_offset + polygon_points - 1;
@ -1105,7 +1432,7 @@ indexed_triangle_set polygons2model_unique(
for (const ExPolygon &expolygon : shape2d) { for (const ExPolygon &expolygon : shape2d) {
add_quads(expolygon.contour); add_quads(expolygon.contour);
for (const Slic3r::Polygon &hole : expolygon.holes) add_quads(hole); for (const Polygon &hole : expolygon.holes) add_quads(hole);
} }
return result; return result;
@ -1113,7 +1440,7 @@ indexed_triangle_set polygons2model_unique(
indexed_triangle_set polygons2model_duplicit( indexed_triangle_set polygons2model_duplicit(
const ExPolygons &shape2d, const ExPolygons &shape2d,
const Emboss::IProjection &projection, const IProjection &projection,
const Points &points, const Points &points,
const Points &duplicits) const Points &duplicits)
{ {
@ -1161,7 +1488,7 @@ indexed_triangle_set polygons2model_duplicit(
// quads around - zig zag by triangles // quads around - zig zag by triangles
size_t polygon_offset = 0; size_t polygon_offset = 0;
auto add_quads = [&polygon_offset, &result, count_point, &changes] auto add_quads = [&polygon_offset, &result, count_point, &changes]
(const Slic3r::Polygon &polygon) { (const Polygon &polygon) {
uint32_t polygon_points = polygon.points.size(); uint32_t polygon_points = polygon.points.size();
// previous index // previous index
uint32_t prev = changes[polygon_offset + polygon_points - 1]; uint32_t prev = changes[polygon_offset + polygon_points - 1];
@ -1176,7 +1503,7 @@ indexed_triangle_set polygons2model_duplicit(
for (const ExPolygon &expolygon : shape2d) { for (const ExPolygon &expolygon : shape2d) {
add_quads(expolygon.contour); add_quads(expolygon.contour);
for (const Slic3r::Polygon &hole : expolygon.holes) add_quads(hole); for (const Polygon &hole : expolygon.holes) add_quads(hole);
} }
return result; return result;
} }
@ -1292,3 +1619,160 @@ std::optional<Vec2d> Emboss::OrthoProject::unproject(const Vec3d &p, double *dep
if (depth != nullptr) *depth = pp.z(); if (depth != nullptr) *depth = pp.z();
return Vec2d(pp.x(), pp.y()); return Vec2d(pp.x(), pp.y());
} }
#ifdef REMOVE_SPIKES
#include <Geometry.hpp>
void priv::remove_spikes(Polygon &polygon, const SpikeDesc &spike_desc)
{
enum class Type {
add, // Move with point B on A-side and add new point on C-side
move, // Only move with point B
erase // left only points A and C without move
};
struct SpikeHeal
{
Type type;
size_t index;
Point b;
Point add;
};
using SpikeHeals = std::vector<SpikeHeal>;
SpikeHeals heals;
size_t count = polygon.size();
if (count < 3)
return;
const Point *ptr_a = &polygon[count - 2];
const Point *ptr_b = &polygon[count - 1];
for (const Point &c : polygon) {
const Point &a = *ptr_a;
const Point &b = *ptr_b;
ScopeGuard sg([&ptr_a, &ptr_b, &c]() {
// prepare for next loop
ptr_a = ptr_b;
ptr_b = &c;
});
// calc sides
Point ba = a - b;
Point bc = c - b;
Vec2d ba_f = ba.cast<double>();
Vec2d bc_f = bc.cast<double>();
double dot_product = ba_f.dot(bc_f);
// sqrt together after multiplication save one sqrt
double ba_size_sq = ba_f.squaredNorm();
double bc_size_sq = bc_f.squaredNorm();
double norm = sqrt(ba_size_sq * bc_size_sq);
double cos_angle = dot_product / norm;
// small angle are around 1 --> cos(0) = 1
if (cos_angle < spike_desc.cos_angle)
continue;
SpikeHeal heal;
heal.index = &b - &polygon.points.front();
// has to be in range <-1, 1>
// Due to preccission of floating point number could be sligtly out of range
if (cos_angle > 1.)
cos_angle = 1.;
if (cos_angle < -1.)
cos_angle = -1.;
// Current Spike angle
double angle = acos(cos_angle);
double wanted_size = spike_desc.half_bevel / cos(angle / 2.);
double wanted_size_sq = wanted_size * wanted_size;
bool is_ba_short = ba_size_sq < wanted_size_sq;
bool is_bc_short = bc_size_sq < wanted_size_sq;
auto a_side = [&b, &ba_f, &ba_size_sq, &wanted_size]() {
Vec2d ba_norm = ba_f / sqrt(ba_size_sq);
return b + (wanted_size * ba_norm).cast<coord_t>();
};
auto c_side = [&b, &bc_f, &bc_size_sq, &wanted_size]() {
Vec2d bc_norm = bc_f / sqrt(bc_size_sq);
return b + (wanted_size * bc_norm).cast<coord_t>();
};
if (is_ba_short && is_bc_short) {
// remove short spike
heal.type = Type::erase;
} else if (is_ba_short){
// move point B on C-side
heal.type = Type::move;
heal.b = c_side();
} else if (is_bc_short) {
// move point B on A-side
heal.type = Type::move;
heal.b = a_side();
} else {
// move point B on A-side and add point on C-side
heal.type = Type::add;
heal.b = a_side();
heal.add = c_side();
}
heals.push_back(heal);
}
if (heals.empty())
return;
// sort index from high to low
if (heals.front().index == (count - 1))
std::rotate(heals.begin(), heals.begin()+1, heals.end());
std::reverse(heals.begin(), heals.end());
int extend = 0;
int curr_extend = 0;
for (const SpikeHeal &h : heals)
switch (h.type) {
case Type::add:
++curr_extend;
if (extend < curr_extend)
extend = curr_extend;
break;
case Type::erase:
--curr_extend;
}
Points &pts = polygon.points;
if (extend > 0)
pts.reserve(pts.size() + extend);
for (const SpikeHeal &h : heals) {
switch (h.type) {
case Type::add:
pts[h.index] = h.b;
pts.insert(pts.begin() + h.index+1, h.add);
break;
case Type::erase:
pts.erase(pts.begin() + h.index);
break;
case Type::move:
pts[h.index] = h.b;
break;
default: break;
}
}
}
void priv::remove_spikes(Polygons &polygons, const SpikeDesc &spike_desc)
{
for (Polygon &polygon : polygons)
remove_spikes(polygon, spike_desc);
remove_bad(polygons);
}
void priv::remove_spikes(ExPolygons &expolygons, const SpikeDesc &spike_desc)
{
for (ExPolygon &expolygon : expolygons) {
remove_spikes(expolygon.contour, spike_desc);
remove_spikes(expolygon.holes, spike_desc);
}
remove_bad(expolygons);
}
#endif // REMOVE_SPIKES

View File

@ -128,10 +128,9 @@ namespace Emboss
// data = raw file data // data = raw file data
std::unique_ptr<FontFile> create_font_file(std::unique_ptr<std::vector<unsigned char>> data); std::unique_ptr<FontFile> create_font_file(std::unique_ptr<std::vector<unsigned char>> data);
#ifdef _WIN32 #ifdef _WIN32
// fix for unknown pointer HFONT // fix for unknown pointer HFONT is replaced with "void *"
using HFONT = void*; void * can_load(void* hfont);
void * can_load(HFONT hfont); std::unique_ptr<FontFile> create_font_file(void * hfont);
std::unique_ptr<FontFile> create_font_file(HFONT hfont);
#endif // _WIN32 #endif // _WIN32
/// <summary> /// <summary>
@ -155,9 +154,10 @@ namespace Emboss
ExPolygons text2shapes(FontFileWithCache &font, const char *text, const FontProp &font_prop, std::function<bool()> was_canceled = nullptr); ExPolygons text2shapes(FontFileWithCache &font, const char *text, const FontProp &font_prop, std::function<bool()> was_canceled = nullptr);
/// <summary> /// <summary>
/// Fix intersections and self intersections in polygons glyph shape /// Fix duplicit points and self intersections in polygons.
/// Also try to reduce amount of points and remove useless polygon parts
/// </summary> /// </summary>
/// <param name="shape">Input shape to heal</param> /// <param name="precision">Define wanted precision of shape after heal</param>
/// <returns>Healed shapes</returns> /// <returns>Healed shapes</returns>
ExPolygons heal_shape(const Polygons &shape); ExPolygons heal_shape(const Polygons &shape);

View File

@ -320,7 +320,9 @@ void ExPolygon::medial_axis(double min_width, double max_width, Polylines* polyl
{ {
ThickPolylines tp; ThickPolylines tp;
this->medial_axis(min_width, max_width, &tp); this->medial_axis(min_width, max_width, &tp);
polylines->insert(polylines->end(), tp.begin(), tp.end()); polylines->reserve(polylines->size() + tp.size());
for (auto &pl : tp)
polylines->emplace_back(pl.points);
} }
Lines ExPolygon::lines() const Lines ExPolygon::lines() const

View File

@ -32,8 +32,8 @@ public:
ExPolygon& operator=(const ExPolygon &other) = default; ExPolygon& operator=(const ExPolygon &other) = default;
ExPolygon& operator=(ExPolygon &&other) = default; ExPolygon& operator=(ExPolygon &&other) = default;
Polygon contour; Polygon contour; //CCW
Polygons holes; Polygons holes; //CW
void clear() { contour.points.clear(); holes.clear(); } void clear() { contour.points.clear(); holes.clear(); }
void scale(double factor); void scale(double factor);

View File

@ -53,7 +53,7 @@ public:
I to, I to,
const T &init, const T &init,
MergeFn &&mergefn, MergeFn &&mergefn,
AccessFn &&access, AccessFn &&accessfn,
size_t granularity = 1 size_t granularity = 1
) )
{ {
@ -61,7 +61,7 @@ public:
tbb::blocked_range{from, to, granularity}, init, tbb::blocked_range{from, to, granularity}, init,
[&](const auto &range, T subinit) { [&](const auto &range, T subinit) {
T acc = subinit; T acc = subinit;
loop_(range, [&](auto &i) { acc = mergefn(acc, access(i)); }); loop_(range, [&](auto &i) { acc = mergefn(acc, accessfn(i)); });
return acc; return acc;
}, },
std::forward<MergeFn>(mergefn)); std::forward<MergeFn>(mergefn));

View File

@ -8,8 +8,6 @@
#include <limits> #include <limits>
#include <sstream> #include <sstream>
#define L(s) (s)
namespace Slic3r { namespace Slic3r {
void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const
@ -52,7 +50,7 @@ void ExtrusionPath::polygons_covered_by_spacing(Polygons &out, const float scale
{ {
// Instantiating the Flow class to get the line spacing. // Instantiating the Flow class to get the line spacing.
// Don't know the nozzle diameter, setting to zero. It shall not matter it shall be optimized out by the compiler. // Don't know the nozzle diameter, setting to zero. It shall not matter it shall be optimized out by the compiler.
bool bridge = is_bridge(this->role()); bool bridge = this->role().is_bridge();
assert(! bridge || this->width == this->height); assert(! bridge || this->width == this->height);
auto flow = bridge ? Flow::bridging_flow(this->width, 0.f) : Flow(this->width, this->height, 0.f); auto flow = bridge ? Flow::bridging_flow(this->width, 0.f) : Flow(this->width, this->height, 0.f);
polygons_append(out, offset(this->polyline, 0.5f * float(flow.scaled_spacing()) + scaled_epsilon)); polygons_append(out, offset(this->polyline, 0.5f * float(flow.scaled_spacing()) + scaled_epsilon));
@ -210,7 +208,7 @@ ExtrusionLoop::ClosestPathPoint ExtrusionLoop::get_closest_path_and_point(const
out.segment_idx = foot_pt_.first; out.segment_idx = foot_pt_.first;
min2 = d2; min2 = d2;
} }
if (prefer_non_overhang && !is_bridge(path.role()) && d2 < min2_non_overhang) { if (prefer_non_overhang && ! path.role().is_bridge() && d2 < min2_non_overhang) {
best_non_overhang.foot_pt = foot_pt_.second; best_non_overhang.foot_pt = foot_pt_.second;
best_non_overhang.path_idx = &path - &this->paths.front(); best_non_overhang.path_idx = &path - &this->paths.front();
best_non_overhang.segment_idx = foot_pt_.first; best_non_overhang.segment_idx = foot_pt_.first;
@ -296,7 +294,7 @@ bool ExtrusionLoop::has_overhang_point(const Point &point) const
if (pos != -1) { if (pos != -1) {
// point belongs to this path // point belongs to this path
// we consider it overhang only if it's not an endpoint // we consider it overhang only if it's not an endpoint
return (is_bridge(path.role()) && pos > 0 && pos != (int)(path.polyline.points.size())-1); return (path.role().is_bridge() && pos > 0 && pos != int(path.polyline.points.size())-1);
} }
} }
return false; return false;
@ -322,65 +320,4 @@ double ExtrusionLoop::min_mm3_per_mm() const
return min_mm3_per_mm; return min_mm3_per_mm;
} }
std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
{
switch (role) {
case erNone : return L("Unknown");
case erPerimeter : return L("Perimeter");
case erExternalPerimeter : return L("External perimeter");
case erOverhangPerimeter : return L("Overhang perimeter");
case erInternalInfill : return L("Internal infill");
case erSolidInfill : return L("Solid infill");
case erTopSolidInfill : return L("Top solid infill");
case erIroning : return L("Ironing");
case erBridgeInfill : return L("Bridge infill");
case erGapFill : return L("Gap fill");
case erSkirt : return L("Skirt/Brim");
case erSupportMaterial : return L("Support material");
case erSupportMaterialInterface : return L("Support material interface");
case erWipeTower : return L("Wipe tower");
case erCustom : return L("Custom");
case erMixed : return L("Mixed");
default : assert(false);
}
return "";
}
ExtrusionRole ExtrusionEntity::string_to_role(const std::string_view role)
{
if (role == L("Perimeter"))
return erPerimeter;
else if (role == L("External perimeter"))
return erExternalPerimeter;
else if (role == L("Overhang perimeter"))
return erOverhangPerimeter;
else if (role == L("Internal infill"))
return erInternalInfill;
else if (role == L("Solid infill"))
return erSolidInfill;
else if (role == L("Top solid infill"))
return erTopSolidInfill;
else if (role == L("Ironing"))
return erIroning;
else if (role == L("Bridge infill"))
return erBridgeInfill;
else if (role == L("Gap fill"))
return erGapFill;
else if (role == L("Skirt") || role == L("Skirt/Brim")) // "Skirt" is for backward compatibility with 2.3.1 and earlier
return erSkirt;
else if (role == L("Support material"))
return erSupportMaterial;
else if (role == L("Support material interface"))
return erSupportMaterialInterface;
else if (role == L("Wipe tower"))
return erWipeTower;
else if (role == L("Custom"))
return erCustom;
else if (role == L("Mixed"))
return erMixed;
else
return erNone;
}
} }

View File

@ -2,6 +2,7 @@
#define slic3r_ExtrusionEntity_hpp_ #define slic3r_ExtrusionEntity_hpp_
#include "libslic3r.h" #include "libslic3r.h"
#include "ExtrusionRole.hpp"
#include "Polygon.hpp" #include "Polygon.hpp"
#include "Polyline.hpp" #include "Polyline.hpp"
@ -16,65 +17,6 @@ using ExPolygons = std::vector<ExPolygon>;
class ExtrusionEntityCollection; class ExtrusionEntityCollection;
class Extruder; class Extruder;
// Each ExtrusionRole value identifies a distinct set of { extruder, speed }
enum ExtrusionRole : uint8_t {
erNone,
erPerimeter,
erExternalPerimeter,
erOverhangPerimeter,
erInternalInfill,
erSolidInfill,
erTopSolidInfill,
erIroning,
erBridgeInfill,
erGapFill,
erSkirt,
erSupportMaterial,
erSupportMaterialInterface,
erWipeTower,
erCustom,
// Extrusion role for a collection with multiple extrusion roles.
erMixed,
erCount
};
// Special flags describing loop
enum ExtrusionLoopRole {
elrDefault,
elrContourInternalPerimeter,
elrSkirt,
};
inline bool is_perimeter(ExtrusionRole role)
{
return role == erPerimeter
|| role == erExternalPerimeter
|| role == erOverhangPerimeter;
}
inline bool is_infill(ExtrusionRole role)
{
return role == erBridgeInfill
|| role == erInternalInfill
|| role == erSolidInfill
|| role == erTopSolidInfill
|| role == erIroning;
}
inline bool is_solid_infill(ExtrusionRole role)
{
return role == erBridgeInfill
|| role == erSolidInfill
|| role == erTopSolidInfill
|| role == erIroning;
}
inline bool is_bridge(ExtrusionRole role) {
return role == erBridgeInfill
|| role == erOverhangPerimeter;
}
class ExtrusionEntity class ExtrusionEntity
{ {
public: public:
@ -108,9 +50,6 @@ public:
virtual Polylines as_polylines() const { Polylines dst; this->collect_polylines(dst); return dst; } virtual Polylines as_polylines() const { Polylines dst; this->collect_polylines(dst); return dst; }
virtual double length() const = 0; virtual double length() const = 0;
virtual double total_volume() const = 0; virtual double total_volume() const = 0;
static std::string role_to_string(ExtrusionRole role);
static ExtrusionRole string_to_role(const std::string_view role);
}; };
typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr; typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
@ -217,7 +156,7 @@ public:
size_t size() const { return this->paths.size(); } size_t size() const { return this->paths.size(); }
bool empty() const { return this->paths.empty(); } bool empty() const { return this->paths.empty(); }
double length() const override; double length() const override;
ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); } ExtrusionRole role() const override { return this->paths.empty() ? ExtrusionRole::None : this->paths.front().role(); }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override; void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override;
@ -279,7 +218,7 @@ public:
// Test, whether the point is extruded by a bridging flow. // Test, whether the point is extruded by a bridging flow.
// This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead. // This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead.
bool has_overhang_point(const Point &point) const; bool has_overhang_point(const Point &point) const;
ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); } ExtrusionRole role() const override { return this->paths.empty() ? ExtrusionRole::None : this->paths.front().role(); }
ExtrusionLoopRole loop_role() const { return m_loop_role; } ExtrusionLoopRole loop_role() const { return m_loop_role; }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
@ -304,8 +243,6 @@ public:
} }
double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; }
//static inline std::string role_to_string(ExtrusionLoopRole role);
#ifndef NDEBUG #ifndef NDEBUG
bool validate() const { bool validate() const {
assert(this->first_point() == this->paths.back().polyline.points.back()); assert(this->first_point() == this->paths.back().polyline.points.back());

View File

@ -8,7 +8,7 @@ namespace Slic3r {
void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role) void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role)
{ {
if (role != erMixed) { if (role != ExtrusionRole::Mixed) {
auto first = extrusion_entities.begin(); auto first = extrusion_entities.begin();
auto last = extrusion_entities.end(); auto last = extrusion_entities.end();
extrusion_entities.erase( extrusion_entities.erase(

View File

@ -54,10 +54,10 @@ public:
bool is_collection() const override { return true; } bool is_collection() const override { return true; }
ExtrusionRole role() const override { ExtrusionRole role() const override {
ExtrusionRole out = erNone; ExtrusionRole out{ ExtrusionRole::None };
for (const ExtrusionEntity *ee : entities) { for (const ExtrusionEntity *ee : entities) {
ExtrusionRole er = ee->role(); ExtrusionRole er = ee->role();
out = (out == erNone || out == er) ? er : erMixed; out = (out == ExtrusionRole::None || out == er) ? er : ExtrusionRole::Mixed;
} }
return out; return out;
} }
@ -96,8 +96,8 @@ public:
} }
void replace(size_t i, const ExtrusionEntity &entity); void replace(size_t i, const ExtrusionEntity &entity);
void remove(size_t i); void remove(size_t i);
static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed); static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = ExtrusionRole::Mixed);
ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = ExtrusionRole::Mixed) const
{ return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); } { return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); }
void reverse() override; void reverse() override;
const Point& first_point() const override { return this->entities.front()->first_point(); } const Point& first_point() const override { return this->entities.front()->first_point(); }

View File

@ -0,0 +1,91 @@
#include "ExtrusionRole.hpp"
#include <string>
#include <string_view>
#include <cassert>
#define L(s) (s)
namespace Slic3r {
// Convert a rich bitmask based ExtrusionRole to a less expressive ordinal GCodeExtrusionRole.
// GCodeExtrusionRole is to be serialized into G-code and deserialized by G-code viewer,
GCodeExtrusionRole extrusion_role_to_gcode_extrusion_role(ExtrusionRole role)
{
if (role == ExtrusionRole::None) return GCodeExtrusionRole::None;
if (role.is_perimeter()) {
return role.is_bridge() ? GCodeExtrusionRole::OverhangPerimeter :
role.is_external() ? GCodeExtrusionRole::ExternalPerimeter : GCodeExtrusionRole::Perimeter;
}
if (role == ExtrusionRole::InternalInfill) return GCodeExtrusionRole::InternalInfill;
if (role == ExtrusionRole::SolidInfill) return GCodeExtrusionRole::SolidInfill;
if (role == ExtrusionRole::TopSolidInfill) return GCodeExtrusionRole::TopSolidInfill;
if (role == ExtrusionRole::Ironing) return GCodeExtrusionRole::Ironing;
if (role == ExtrusionRole::BridgeInfill) return GCodeExtrusionRole::BridgeInfill;
if (role == ExtrusionRole::GapFill) return GCodeExtrusionRole::GapFill;
if (role == ExtrusionRole::Skirt) return GCodeExtrusionRole::Skirt;
if (role == ExtrusionRole::SupportMaterial) return GCodeExtrusionRole::SupportMaterial;
if (role == ExtrusionRole::SupportMaterialInterface) return GCodeExtrusionRole::SupportMaterialInterface;
if (role == ExtrusionRole::WipeTower) return GCodeExtrusionRole::WipeTower;
assert(false);
return GCodeExtrusionRole::None;
}
std::string gcode_extrusion_role_to_string(GCodeExtrusionRole role)
{
switch (role) {
case GCodeExtrusionRole::None : return L("Unknown");
case GCodeExtrusionRole::Perimeter : return L("Perimeter");
case GCodeExtrusionRole::ExternalPerimeter : return L("External perimeter");
case GCodeExtrusionRole::OverhangPerimeter : return L("Overhang perimeter");
case GCodeExtrusionRole::InternalInfill : return L("Internal infill");
case GCodeExtrusionRole::SolidInfill : return L("Solid infill");
case GCodeExtrusionRole::TopSolidInfill : return L("Top solid infill");
case GCodeExtrusionRole::Ironing : return L("Ironing");
case GCodeExtrusionRole::BridgeInfill : return L("Bridge infill");
case GCodeExtrusionRole::GapFill : return L("Gap fill");
case GCodeExtrusionRole::Skirt : return L("Skirt/Brim");
case GCodeExtrusionRole::SupportMaterial : return L("Support material");
case GCodeExtrusionRole::SupportMaterialInterface : return L("Support material interface");
case GCodeExtrusionRole::WipeTower : return L("Wipe tower");
case GCodeExtrusionRole::Custom : return L("Custom");
default : assert(false);
}
return {};
}
GCodeExtrusionRole string_to_gcode_extrusion_role(const std::string_view role)
{
if (role == L("Perimeter"))
return GCodeExtrusionRole::Perimeter;
else if (role == L("External perimeter"))
return GCodeExtrusionRole::ExternalPerimeter;
else if (role == L("Overhang perimeter"))
return GCodeExtrusionRole::OverhangPerimeter;
else if (role == L("Internal infill"))
return GCodeExtrusionRole::InternalInfill;
else if (role == L("Solid infill"))
return GCodeExtrusionRole::SolidInfill;
else if (role == L("Top solid infill"))
return GCodeExtrusionRole::TopSolidInfill;
else if (role == L("Ironing"))
return GCodeExtrusionRole::Ironing;
else if (role == L("Bridge infill"))
return GCodeExtrusionRole::BridgeInfill;
else if (role == L("Gap fill"))
return GCodeExtrusionRole::GapFill;
else if (role == L("Skirt") || role == L("Skirt/Brim")) // "Skirt" is for backward compatibility with 2.3.1 and earlier
return GCodeExtrusionRole::Skirt;
else if (role == L("Support material"))
return GCodeExtrusionRole::SupportMaterial;
else if (role == L("Support material interface"))
return GCodeExtrusionRole::SupportMaterialInterface;
else if (role == L("Wipe tower"))
return GCodeExtrusionRole::WipeTower;
else if (role == L("Custom"))
return GCodeExtrusionRole::Custom;
else
return GCodeExtrusionRole::None;
}
}

View File

@ -0,0 +1,128 @@
#ifndef slic3r_ExtrusionRole_hpp_
#define slic3r_ExtrusionRole_hpp_
#include "enum_bitmask.hpp"
#include <string>
#include <string_view>
namespace Slic3r {
enum class ExtrusionRoleModifier : uint16_t {
// 1) Extrusion types
// Perimeter (external, inner, ...)
Perimeter,
// Infill (top / bottom / solid inner / sparse inner / bridging inner ...)
Infill,
// Variable width extrusion
Thin,
// Support material extrusion
Support,
Skirt,
Wipe,
// 2) Extrusion modifiers
External,
Solid,
Ironing,
Bridge,
// 3) Special types
// Indicator that the extrusion role was mixed from multiple differing extrusion roles,
// for example from Support and SupportInterface.
Mixed,
// Stopper, there should be maximum 16 modifiers defined for uint16_t bit mask.
Count
};
// There should be maximum 16 modifiers defined for uint16_t bit mask.
static_assert(int(ExtrusionRoleModifier::Count) <= 16, "ExtrusionRoleModifier: there must be maximum 16 modifiers defined to fit a 16 bit bitmask");
using ExtrusionRoleModifiers = enum_bitmask<ExtrusionRoleModifier>;
ENABLE_ENUM_BITMASK_OPERATORS(ExtrusionRoleModifier);
struct ExtrusionRole : public ExtrusionRoleModifiers
{
constexpr ExtrusionRole(const ExtrusionRoleModifier bit) : ExtrusionRoleModifiers(bit) {}
constexpr ExtrusionRole(const ExtrusionRoleModifiers bits) : ExtrusionRoleModifiers(bits) {}
static constexpr const ExtrusionRoleModifiers None{};
// Internal perimeter, not bridging.
static constexpr const ExtrusionRoleModifiers Perimeter{ ExtrusionRoleModifier::Perimeter };
// External perimeter, not bridging.
static constexpr const ExtrusionRoleModifiers ExternalPerimeter{ ExtrusionRoleModifier::Perimeter | ExtrusionRoleModifier::External };
// Perimeter, bridging. To be or'ed with ExtrusionRoleModifier::External for external bridging perimeter.
static constexpr const ExtrusionRoleModifiers OverhangPerimeter{ ExtrusionRoleModifier::Perimeter | ExtrusionRoleModifier::Bridge };
// Sparse internal infill.
static constexpr const ExtrusionRoleModifiers InternalInfill{ ExtrusionRoleModifier::Infill };
// Solid internal infill.
static constexpr const ExtrusionRoleModifiers SolidInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid };
// Top solid infill (visible).
//FIXME why there is no bottom solid infill type?
static constexpr const ExtrusionRoleModifiers TopSolidInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::External };
// Ironing infill at the top surfaces.
static constexpr const ExtrusionRoleModifiers Ironing{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::Ironing | ExtrusionRoleModifier::External };
// Visible bridging infill at the bottom of an object.
static constexpr const ExtrusionRoleModifiers BridgeInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::Bridge | ExtrusionRoleModifier::External };
// static constexpr const ExtrusionRoleModifiers InternalBridgeInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::Bridge };
// Gap fill extrusion, currently used for any variable width extrusion: Thin walls outside of the outer extrusion,
// gap fill in between perimeters, gap fill between the inner perimeter and infill.
//FIXME revise GapFill and ThinWall types, split Gap Fill to Gap Fill and ThinWall.
static constexpr const ExtrusionRoleModifiers GapFill{ ExtrusionRoleModifier::Thin }; // | ExtrusionRoleModifier::External };
// static constexpr const ExtrusionRoleModifiers ThinWall{ ExtrusionRoleModifier::Thin };
static constexpr const ExtrusionRoleModifiers Skirt{ ExtrusionRoleModifier::Skirt };
// Support base material, printed with non-soluble plastic.
static constexpr const ExtrusionRoleModifiers SupportMaterial{ ExtrusionRoleModifier::Support };
// Support interface material, printed with soluble plastic.
static constexpr const ExtrusionRoleModifiers SupportMaterialInterface{ ExtrusionRoleModifier::Support | ExtrusionRoleModifier::External };
// Wipe tower material.
static constexpr const ExtrusionRoleModifiers WipeTower{ ExtrusionRoleModifier::Wipe };
// Extrusion role for a collection with multiple extrusion roles.
static constexpr const ExtrusionRoleModifiers Mixed{ ExtrusionRoleModifier::Mixed };
bool is_perimeter() const { return this->ExtrusionRoleModifiers::has(ExtrusionRoleModifier::Perimeter); }
bool is_external_perimeter() const { return this->is_perimeter() && this->is_external(); }
bool is_infill() const { return this->ExtrusionRoleModifiers::has(ExtrusionRoleModifier::Infill); }
bool is_solid_infill() const { return this->is_infill() && this->ExtrusionRoleModifiers::has(ExtrusionRoleModifier::Solid); }
bool is_external() const { return this->ExtrusionRoleModifiers::has(ExtrusionRoleModifier::External); }
bool is_bridge() const { return this->ExtrusionRoleModifiers::has(ExtrusionRoleModifier::Bridge); }
};
// Special flags describing loop
enum ExtrusionLoopRole {
elrDefault,
elrContourInternalPerimeter,
elrSkirt,
};
// Be careful when editing this list as many parts of the code depend
// on the values of these ordinars, for example
// GCodeViewer::Extrusion_Role_Colors
enum class GCodeExtrusionRole : uint8_t {
None,
Perimeter,
ExternalPerimeter,
OverhangPerimeter,
InternalInfill,
SolidInfill,
TopSolidInfill,
Ironing,
BridgeInfill,
GapFill,
Skirt,
SupportMaterial,
SupportMaterialInterface,
WipeTower,
// Custom (user defined) G-code block, for example start / end G-code.
Custom,
// Stopper to count number of enums.
Count
};
// Convert a rich bitmask based ExtrusionRole to a less expressive ordinal GCodeExtrusionRole.
// GCodeExtrusionRole is to be serialized into G-code and deserialized by G-code viewer,
GCodeExtrusionRole extrusion_role_to_gcode_extrusion_role(ExtrusionRole role);
std::string gcode_extrusion_role_to_string(GCodeExtrusionRole role);
GCodeExtrusionRole string_to_gcode_extrusion_role(const std::string_view role);
}
#endif // slic3r_ExtrusionRole_hpp_

View File

@ -54,7 +54,7 @@ struct SurfaceFillParams
Flow flow; Flow flow;
// For the output // For the output
ExtrusionRole extrusion_role = ExtrusionRole(0); ExtrusionRole extrusion_role{ ExtrusionRole::None };
// Various print settings? // Various print settings?
@ -83,8 +83,7 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(flow.height()); RETURN_COMPARE_NON_EQUAL(flow.height());
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter()); RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, bridge); RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, bridge);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role); return this->extrusion_role.lower(rhs.extrusion_role);
return false;
} }
bool operator==(const SurfaceFillParams &rhs) const { bool operator==(const SurfaceFillParams &rhs) const {
@ -152,11 +151,10 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.extrusion_role = params.extrusion_role =
is_bridge ? is_bridge ?
erBridgeInfill : ExtrusionRole::BridgeInfill :
(surface.is_solid() ? (surface.is_solid() ?
(surface.is_top() ? erTopSolidInfill : erSolidInfill) : (surface.is_top() ? ExtrusionRole::TopSolidInfill : ExtrusionRole::SolidInfill) :
//(surface.is_top() ? erTopSolidInfill : (surface.is_bottom()? erBottomSurface : erSolidInfill)) : ExtrusionRole::InternalInfill);
erInternalInfill);
params.bridge_angle = float(surface.bridge_angle); params.bridge_angle = float(surface.bridge_angle);
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value)); params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
@ -291,7 +289,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.extruder = layerm.region().extruder(frSolidInfill); params.extruder = layerm.region().extruder(frSolidInfill);
params.pattern = fill_type_monotonic(layerm.region().config().top_fill_pattern) ? ipMonotonic : ipRectilinear; params.pattern = fill_type_monotonic(layerm.region().config().top_fill_pattern) ? ipMonotonic : ipRectilinear;
params.density = 100.f; params.density = 100.f;
params.extrusion_role = erInternalInfill; params.extrusion_role = ExtrusionRole::InternalInfill;
params.angle = float(Geometry::deg2rad(layerm.region().config().fill_angle.value)); params.angle = float(Geometry::deg2rad(layerm.region().config().fill_angle.value));
// calculate the actual flow we'll be using for this infill // calculate the actual flow we'll be using for this infill
params.flow = layerm.flow(frSolidInfill); params.flow = layerm.flow(frSolidInfill);
@ -497,8 +495,11 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
f->print_config = &this->object()->print()->config(); f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config(); f->print_object_config = &this->object()->config();
if (surface_fill.params.pattern == ipLightning) if (surface_fill.params.pattern == ipLightning) {
dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator; auto *lf = dynamic_cast<FillLightning::Filler*>(f.get());
lf->generator = lightning_generator;
lf->num_raft_layers = this->object()->slicing_parameters().raft_layers();
}
if (surface_fill.params.pattern == ipEnsuring) { if (surface_fill.params.pattern == ipEnsuring) {
auto *fill_bounded_rectilinear = dynamic_cast<FillEnsuring *>(f.get()); auto *fill_bounded_rectilinear = dynamic_cast<FillEnsuring *>(f.get());
@ -835,7 +836,7 @@ void Layer::make_ironing()
eec->no_sort = true; eec->no_sort = true;
extrusion_entities_append_paths( extrusion_entities_append_paths(
eec->entities, std::move(polylines), eec->entities, std::move(polylines),
erIroning, ExtrusionRole::Ironing,
flow_mm3_per_mm, extrusion_width, float(extrusion_height)); flow_mm3_per_mm, extrusion_width, float(extrusion_height));
insert_fills_into_islands(*this, ironing_params.region_id, fill_begin, uint32_t(ironing_params.layerm->fills().size())); insert_fills_into_islands(*this, ironing_params.region_id, fill_begin, uint32_t(ironing_params.layerm->fills().size()));
} }

View File

@ -13,7 +13,7 @@ void Filler::_fill_surface_single(
ExPolygon expolygon, ExPolygon expolygon,
Polylines &polylines_out) Polylines &polylines_out)
{ {
const Layer &layer = generator->getTreesForLayer(this->layer_id); const Layer &layer = generator->getTreesForLayer(this->layer_id - this->num_raft_layers);
Polylines fill_lines = layer.convertToLines(to_polygons(expolygon), scaled<coord_t>(0.5 * this->spacing - this->overlap)); Polylines fill_lines = layer.convertToLines(to_polygons(expolygon), scaled<coord_t>(0.5 * this->spacing - this->overlap));
if (params.dont_connect() || fill_lines.size() <= 1) { if (params.dont_connect() || fill_lines.size() <= 1) {

View File

@ -22,6 +22,7 @@ public:
~Filler() override = default; ~Filler() override = default;
Generator *generator { nullptr }; Generator *generator { nullptr };
size_t num_raft_layers { 0 };
protected: protected:
Fill* clone() const override { return new Filler(*this); } Fill* clone() const override { return new Filler(*this); }

View File

@ -4,7 +4,7 @@
#include "libslic3r.h" #include "libslic3r.h"
#include "Config.hpp" #include "Config.hpp"
#include "Exception.hpp" #include "Exception.hpp"
#include "ExtrusionEntity.hpp" #include "ExtrusionRole.hpp"
namespace Slic3r { namespace Slic3r {

View File

@ -113,26 +113,19 @@ namespace Slic3r {
{ {
std::string gcode; std::string gcode;
// move to the nearest standby point unsigned int extruder_id = gcodegen.writer().extruder()->id();
if (!this->standby_points.empty()) { const ConfigOptionIntsNullable& filament_idle_temp = gcodegen.config().idle_temperature;
// get current position in print coordinates if (filament_idle_temp.is_nil(extruder_id)) {
Vec3d writer_pos = gcodegen.writer().get_position(); // There is no idle temperature defined in filament settings.
Point pos = Point::new_scale(writer_pos(0), writer_pos(1)); // Use the delta value from print config.
// find standby point
Point standby_point = nearest_point(this->standby_points, pos).first;
/* We don't call gcodegen.travel_to() because we don't need retraction (it was already
triggered by the caller) nor avoid_crossing_perimeters and also because the coordinates
of the destination point must not be transformed by origin nor current extruder offset. */
gcode += gcodegen.writer().travel_to_xy(unscale(standby_point),
"move to standby position");
}
if (gcodegen.config().standby_temperature_delta.value != 0) { if (gcodegen.config().standby_temperature_delta.value != 0) {
// we assume that heating is always slower than cooling, so no need to block // we assume that heating is always slower than cooling, so no need to block
gcode += gcodegen.writer().set_temperature gcode += gcodegen.writer().set_temperature
(this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, gcodegen.writer().extruder()->id()); (this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, extruder_id);
}
} else {
// Use the value from filament settings. That one is absolute, not delta.
gcode += gcodegen.writer().set_temperature(filament_idle_temp.get_at(extruder_id), false, extruder_id);
} }
return gcode; return gcode;
@ -145,10 +138,9 @@ namespace Slic3r {
std::string(); std::string();
} }
int int OozePrevention::_get_temp(const GCode& gcodegen) const
OozePrevention::_get_temp(GCode& gcodegen)
{ {
return (gcodegen.layer() != NULL && gcodegen.layer()->id() == 0) return (gcodegen.layer() == nullptr || gcodegen.layer()->id() == 0)
? gcodegen.config().first_layer_temperature.get_at(gcodegen.writer().extruder()->id()) ? gcodegen.config().first_layer_temperature.get_at(gcodegen.writer().extruder()->id())
: gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id()); : gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id());
} }
@ -238,92 +230,54 @@ namespace Slic3r {
std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation);
if (! tcr.priming) { double current_z = gcodegen.writer().get_position().z();
// Move over the wipe tower. if (z == -1.) // in case no specific z was provided, print at current_z pos
z = current_z;
const bool needs_toolchange = gcodegen.writer().need_toolchange(new_extruder_id);
const bool will_go_down = ! is_approx(z, current_z);
if (tcr.force_travel || ! needs_toolchange || (gcodegen.config().single_extruder_multi_material && ! tcr.priming)) {
// Move over the wipe tower. If this is not single-extruder MM, the first wipe tower move following the
// toolchange will travel there anyway (if there is a toolchange).
// FIXME: It would be better if the wipe tower set the force_travel flag for all toolchanges,
// then we could simplify the condition and make it more readable.
gcode += gcodegen.retract(); gcode += gcodegen.retract();
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
gcode += gcodegen.travel_to( gcode += gcodegen.travel_to(
wipe_tower_point_to_object_point(gcodegen, start_pos), wipe_tower_point_to_object_point(gcodegen, start_pos),
erMixed, ExtrusionRole::Mixed,
"Travel to a Wipe Tower"); "Travel to a Wipe Tower");
gcode += gcodegen.unretract(); gcode += gcodegen.unretract();
} }
double current_z = gcodegen.writer().get_position().z(); if (will_go_down) {
if (z == -1.) // in case no specific z was provided, print at current_z pos
z = current_z;
if (! is_approx(z, current_z)) {
gcode += gcodegen.writer().retract(); gcode += gcodegen.writer().retract();
gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer."); gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer.");
gcode += gcodegen.writer().unretract(); gcode += gcodegen.writer().unretract();
} }
// Process the end filament gcode.
std::string end_filament_gcode_str;
if (gcodegen.writer().extruder() != nullptr) {
// Process the custom end_filament_gcode in case of single_extruder_multi_material.
unsigned int old_extruder_id = gcodegen.writer().extruder()->id();
const std::string& end_filament_gcode = gcodegen.config().end_filament_gcode.get_at(old_extruder_id);
if (gcodegen.writer().extruder() != nullptr && !end_filament_gcode.empty()) {
end_filament_gcode_str = gcodegen.placeholder_parser_process("end_filament_gcode", end_filament_gcode, old_extruder_id);
check_add_eol(end_filament_gcode_str);
}
}
// Process the custom toolchange_gcode. If it is empty, provide a simple Tn command to change the filament.
// Otherwise, leave control to the user completely.
std::string toolchange_gcode_str; std::string toolchange_gcode_str;
const std::string& toolchange_gcode = gcodegen.config().toolchange_gcode.value; std::string deretraction_str;
if (! toolchange_gcode.empty()) { if (tcr.priming || (new_extruder_id >= 0 && needs_toolchange)) {
DynamicConfig config; if (gcodegen.config().single_extruder_multi_material)
int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1; gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines.
config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id)); toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z
config.set_key_value("next_extruder", new ConfigOptionInt((int)new_extruder_id)); if (gcodegen.config().wipe_tower)
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index)); deretraction_str = gcodegen.unretract();
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
config.set_key_value("toolchange_z", new ConfigOptionFloat(z));
config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z));
toolchange_gcode_str = gcodegen.placeholder_parser_process("toolchange_gcode", toolchange_gcode, new_extruder_id, &config);
check_add_eol(toolchange_gcode_str);
} }
std::string toolchange_command;
if (tcr.priming || (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id)))
toolchange_command = gcodegen.writer().toolchange(new_extruder_id);
if (!custom_gcode_changes_tool(toolchange_gcode_str, gcodegen.writer().toolchange_prefix(), new_extruder_id))
toolchange_gcode_str += toolchange_command;
else {
// We have informed the m_writer about the current extruder_id, we can ignore the generated G-code.
}
gcodegen.placeholder_parser().set("current_extruder", new_extruder_id);
// Process the start filament gcode.
std::string start_filament_gcode_str; // Insert the toolchange and deretraction gcode into the generated gcode.
const std::string& start_filament_gcode = gcodegen.config().start_filament_gcode.get_at(new_extruder_id);
if (!start_filament_gcode.empty()) {
// Process the start_filament_gcode for the active filament only.
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(gcodegen.writer().get_position()(2) - gcodegen.m_config.z_offset.value));
config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z));
config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
start_filament_gcode_str = gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
check_add_eol(start_filament_gcode_str);
}
// Insert the end filament, toolchange, and start filament gcode into the generated gcode.
DynamicConfig config;
config.set_key_value("end_filament_gcode", new ConfigOptionString(end_filament_gcode_str));
config.set_key_value("toolchange_gcode", new ConfigOptionString(toolchange_gcode_str)); config.set_key_value("toolchange_gcode", new ConfigOptionString(toolchange_gcode_str));
config.set_key_value("start_filament_gcode", new ConfigOptionString(start_filament_gcode_str)); config.set_key_value("deretraction_from_wipe_tower_generator", new ConfigOptionString(deretraction_str));
std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config); std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config);
unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode); unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
gcode += tcr_gcode; gcode += tcr_gcode;
check_add_eol(toolchange_gcode_str); check_add_eol(toolchange_gcode_str);
// A phony move to the end position at the wipe tower. // A phony move to the end position at the wipe tower.
gcodegen.writer().travel_to_xy(end_pos.cast<double>()); gcodegen.writer().travel_to_xy(end_pos.cast<double>());
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos)); gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
@ -740,7 +694,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
// Does the file exist? If so, we hope that it is still valid. // Does the file exist? If so, we hope that it is still valid.
{ {
PrintStateBase::StateWithTimeStamp state = print->step_state_with_timestamp(psGCodeExport); PrintStateBase::StateWithTimeStamp state = print->step_state_with_timestamp(psGCodeExport);
if (! state.enabled || (state.state == PrintStateBase::DONE && boost::filesystem::exists(boost::filesystem::path(path)))) if (! state.enabled || (state.is_done() && boost::filesystem::exists(boost::filesystem::path(path))))
return; return;
} }
@ -864,7 +818,7 @@ namespace DoExport {
auto min_mm3_per_mm_no_ironing = [](const ExtrusionEntityCollection& eec) -> double { auto min_mm3_per_mm_no_ironing = [](const ExtrusionEntityCollection& eec) -> double {
double min = std::numeric_limits<double>::max(); double min = std::numeric_limits<double>::max();
for (const ExtrusionEntity* ee : eec.entities) for (const ExtrusionEntity* ee : eec.entities)
if (ee->role() != erIroning) if (ee->role() != ExtrusionRole::Ironing)
min = std::min(min, ee->min_mm3_per_mm()); min = std::min(min, ee->min_mm3_per_mm());
return min; return min;
}; };
@ -898,34 +852,7 @@ namespace DoExport {
static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention) static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention)
{ {
// Calculate wiping points if needed ooze_prevention.enable = print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material;
if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) {
Points skirt_points;
for (const ExtrusionEntity *ee : print.skirt().entities)
for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths)
append(skirt_points, path.polyline.points);
if (! skirt_points.empty()) {
Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
Polygons skirts;
for (unsigned int extruder_id : print.extruders()) {
const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id);
Polygon s(outer_skirt);
s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1)));
skirts.emplace_back(std::move(s));
}
ooze_prevention.enable = true;
ooze_prevention.standby_points = offset(Slic3r::Geometry::convex_hull(skirts), float(scale_(3.))).front().equally_spaced_points(float(scale_(10.)));
#if 0
require "Slic3r/SVG.pm";
Slic3r::SVG::output(
"ooze_prevention.svg",
red_polygons => \@skirts,
polygons => [$outer_skirt],
points => $gcodegen->ooze_prevention->standby_points,
);
#endif
}
}
} }
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section. // Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
@ -1263,7 +1190,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_placeholder_parser.set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() })); m_placeholder_parser.set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
m_placeholder_parser.set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() })); m_placeholder_parser.set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
m_placeholder_parser.set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() })); m_placeholder_parser.set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
std::vector<unsigned char> is_extruder_used(print.config().nozzle_diameter.size(), 0);
for (unsigned int extruder_id : print.extruders())
is_extruder_used[extruder_id] = true;
m_placeholder_parser.set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
} }
// Enable ooze prevention if configured so.
DoExport::init_ooze_prevention(print, m_ooze_prevention);
std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id); std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id);
// Set bed temperature if the start G-code does not contain any bed temp control G-codes. // Set bed temperature if the start G-code does not contain any bed temp control G-codes.
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true); this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
@ -1271,7 +1207,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false); this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
// adds tag for processor // adds tag for processor
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), gcode_extrusion_role_to_string(GCodeExtrusionRole::Custom).c_str());
// Write the custom start G-code // Write the custom start G-code
file.writeln(start_gcode); file.writeln(start_gcode);
@ -1282,8 +1218,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// Set other general things. // Set other general things.
file.write(this->preamble()); file.write(this->preamble());
// Calculate wiping points if needed
DoExport::init_ooze_prevention(print, m_ooze_prevention);
print.throw_if_canceled(); print.throw_if_canceled();
// Collect custom seam data from all objects. // Collect custom seam data from all objects.
@ -1320,7 +1254,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
m_avoid_crossing_perimeters.use_external_mp_once(); m_avoid_crossing_perimeters.use_external_mp_once();
file.write(this->retract()); file.write(this->retract());
file.write(this->travel_to(Point(0, 0), erNone, "move to origin position for next object")); file.write(this->travel_to(Point(0, 0), ExtrusionRole::None, "move to origin position for next object"));
m_enable_cooling_markers = true; m_enable_cooling_markers = true;
// Disable motion planner when traveling to first object point. // Disable motion planner when traveling to first object point.
m_avoid_crossing_perimeters.disable_once(); m_avoid_crossing_perimeters.disable_once();
@ -1407,7 +1341,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
file.write(m_writer.set_fan(0)); file.write(m_writer.set_fan(0));
// adds tag for processor // adds tag for processor
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), gcode_extrusion_role_to_string(GCodeExtrusionRole::Custom).c_str());
// Process filament-specific gcode in extruder order. // Process filament-specific gcode in extruder order.
{ {
@ -1823,8 +1757,14 @@ void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Pr
// Set temperatures of all the printing extruders. // Set temperatures of all the printing extruders.
for (unsigned int tool_id : print.extruders()) { for (unsigned int tool_id : print.extruders()) {
int temp = print.config().first_layer_temperature.get_at(tool_id); int temp = print.config().first_layer_temperature.get_at(tool_id);
if (print.config().ooze_prevention.value)
if (print.config().ooze_prevention.value && tool_id != first_printing_extruder_id) {
if (print.config().idle_temperature.is_nil(tool_id))
temp += print.config().standby_temperature_delta.value; temp += print.config().standby_temperature_delta.value;
else
temp = print.config().idle_temperature.get_at(tool_id);
}
if (temp > 0) if (temp > 0)
file.write(m_writer.set_temperature(temp, wait, tool_id)); file.write(m_writer.set_temperature(temp, wait, tool_id));
} }
@ -2136,11 +2076,14 @@ LayerResult GCode::process_layer(
// Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent // Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
// first_layer_temperature vs. temperature settings. // first_layer_temperature vs. temperature settings.
for (const Extruder &extruder : m_writer.extruders()) { for (const Extruder &extruder : m_writer.extruders()) {
if (print.config().single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id()) if (print.config().single_extruder_multi_material.value || m_ooze_prevention.enable) {
// In single extruder multi material mode, set the temperature for the current extruder only. // In single extruder multi material mode, set the temperature for the current extruder only.
// The same applies when ooze prevention is enabled.
if (extruder.id() != m_writer.extruder()->id())
continue; continue;
}
int temperature = print.config().temperature.get_at(extruder.id()); int temperature = print.config().temperature.get_at(extruder.id());
if (temperature > 0 && temperature != print.config().first_layer_temperature.get_at(extruder.id())) if (temperature > 0 && (temperature != print.config().first_layer_temperature.get_at(extruder.id())))
gcode += m_writer.set_temperature(temperature, false, extruder.id()); gcode += m_writer.set_temperature(temperature, false, extruder.id());
} }
gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id)); gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id));
@ -2161,11 +2104,11 @@ LayerResult GCode::process_layer(
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) : Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) :
Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done); Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done);
if (this->config().avoid_curled_filament_during_travels) { if (this->config().avoid_crossing_curled_overhangs) {
m_avoid_curled_filaments.clear(); m_avoid_crossing_curled_overhangs.clear();
for (const ObjectLayerToPrint &layer_to_print : layers) { for (const ObjectLayerToPrint &layer_to_print : layers) {
m_avoid_curled_filaments.add_obstacles(layer_to_print.object_layer, Point(scaled(this->origin()))); m_avoid_crossing_curled_overhangs.add_obstacles(layer_to_print.object_layer, Point(scaled(this->origin())));
m_avoid_curled_filaments.add_obstacles(layer_to_print.support_layer, Point(scaled(this->origin()))); m_avoid_crossing_curled_overhangs.add_obstacles(layer_to_print.support_layer, Point(scaled(this->origin())));
} }
} }
@ -2182,7 +2125,7 @@ LayerResult GCode::process_layer(
// let analyzer tag generator aware of a role type change // let analyzer tag generator aware of a role type change
if (layer_tools.has_wipe_tower && m_wipe_tower) if (layer_tools.has_wipe_tower && m_wipe_tower)
m_last_processor_extrusion_role = erWipeTower; m_last_processor_extrusion_role = GCodeExtrusionRole::WipeTower;
if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) { if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
const std::pair<size_t, size_t> loops = loops_it->second; const std::pair<size_t, size_t> loops = loops_it->second;
@ -2305,8 +2248,8 @@ void GCode::process_layer_single_object(
if (! print_wipe_extrusions && layer_to_print.support_layer != nullptr) if (! print_wipe_extrusions && layer_to_print.support_layer != nullptr)
if (const SupportLayer &support_layer = *layer_to_print.support_layer; ! support_layer.support_fills.entities.empty()) { if (const SupportLayer &support_layer = *layer_to_print.support_layer; ! support_layer.support_fills.entities.empty()) {
ExtrusionRole role = support_layer.support_fills.role(); ExtrusionRole role = support_layer.support_fills.role();
bool has_support = role == erMixed || role == erSupportMaterial; bool has_support = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterial;
bool has_interface = role == erMixed || role == erSupportMaterialInterface; bool has_interface = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterialInterface;
// Extruder ID of the support base. -1 if "don't care". // Extruder ID of the support base. -1 if "don't care".
unsigned int support_extruder = print_object.config().support_material_extruder.value - 1; unsigned int support_extruder = print_object.config().support_material_extruder.value - 1;
// Shall the support be printed with the active extruder, preferably with non-soluble, to avoid tool changes? // Shall the support be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
@ -2340,8 +2283,8 @@ void GCode::process_layer_single_object(
m_layer = layer_to_print.support_layer; m_layer = layer_to_print.support_layer;
m_object_layer_over_raft = false; m_object_layer_over_raft = false;
gcode += this->extrude_support( gcode += this->extrude_support(
// support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths. // support_extrusion_role is ExtrusionRole::SupportMaterial, ExtrusionRole::SupportMaterialInterface or ExtrusionRole::Mixed for all extrusion paths.
support_layer.support_fills.chained_path_from(m_last_pos, has_support ? (has_interface ? erMixed : erSupportMaterial) : erSupportMaterialInterface)); support_layer.support_fills.chained_path_from(m_last_pos, has_support ? (has_interface ? ExtrusionRole::Mixed : ExtrusionRole::SupportMaterial) : ExtrusionRole::SupportMaterialInterface));
} }
} }
@ -2372,7 +2315,8 @@ void GCode::process_layer_single_object(
ExtrusionEntitiesPtr temp_fill_extrusions; ExtrusionEntitiesPtr temp_fill_extrusions;
if (const Layer *layer = layer_to_print.object_layer; layer) if (const Layer *layer = layer_to_print.object_layer; layer)
for (const LayerSlice &lslice : layer->lslices_ex) { for (size_t idx : layer->lslice_indices_sorted_by_print_order) {
const LayerSlice &lslice = layer->lslices_ex[idx];
auto extrude_infill_range = [&]( auto extrude_infill_range = [&](
const LayerRegion &layerm, const ExtrusionEntityCollection &fills, const LayerRegion &layerm, const ExtrusionEntityCollection &fills,
LayerExtrusionRanges::const_iterator it_fill_ranges_begin, LayerExtrusionRanges::const_iterator it_fill_ranges_end, bool ironing) { LayerExtrusionRanges::const_iterator it_fill_ranges_begin, LayerExtrusionRanges::const_iterator it_fill_ranges_end, bool ironing) {
@ -2385,7 +2329,7 @@ void GCode::process_layer_single_object(
for (uint32_t fill_id : *it_fill_range) { for (uint32_t fill_id : *it_fill_range) {
assert(dynamic_cast<ExtrusionEntityCollection*>(fills.entities[fill_id])); assert(dynamic_cast<ExtrusionEntityCollection*>(fills.entities[fill_id]));
if (auto *eec = static_cast<ExtrusionEntityCollection*>(fills.entities[fill_id]); if (auto *eec = static_cast<ExtrusionEntityCollection*>(fills.entities[fill_id]);
(eec->role() == erIroning) == ironing && shall_print_this_extrusion_collection(eec, region)) { (eec->role() == ExtrusionRole::Ironing) == ironing && shall_print_this_extrusion_collection(eec, region)) {
if (eec->can_reverse()) if (eec->can_reverse())
// Flatten the infill collection for better path planning. // Flatten the infill collection for better path planning.
for (auto *ee : eec->entities) for (auto *ee : eec->entities)
@ -2601,7 +2545,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
if (paths.empty()) return ""; if (paths.empty()) return "";
// apply the small perimeter speed // apply the small perimeter speed
if (is_perimeter(paths.front().role()) && loop.length() <= SMALL_PERIMETER_LENGTH && speed == -1) if (paths.front().role().is_perimeter() && loop.length() <= SMALL_PERIMETER_LENGTH && speed == -1)
speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
// extrude along the path // extrude along the path
@ -2618,7 +2562,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
m_wipe.path = paths.front().polyline; m_wipe.path = paths.front().polyline;
for (auto it = std::next(paths.begin()); it != paths.end(); ++it) { for (auto it = std::next(paths.begin()); it != paths.end(); ++it) {
if (is_bridge(it->role())) if (it->role().is_bridge())
break; // Don't perform a wipe on bridges. break; // Don't perform a wipe on bridges.
assert(it->polyline.points.size() >= 2); assert(it->polyline.points.size() >= 2);
@ -2631,7 +2575,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
} }
// make a little move inwards before leaving loop // make a little move inwards before leaving loop
if (paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { if (paths.back().role().is_external_perimeter() && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) {
// detect angle between last and first segment // detect angle between last and first segment
// the side depends on the original winding order of the polygon (left for contours, right for holes) // the side depends on the original winding order of the polygon (left for contours, right for holes)
//FIXME improve the algorithm in case the loop is tiny. //FIXME improve the algorithm in case the loop is tiny.
@ -2686,7 +2630,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s
m_wipe.path.reverse(); m_wipe.path.reverse();
for (auto it = std::next(multipath.paths.rbegin()); it != multipath.paths.rend(); ++it) { for (auto it = std::next(multipath.paths.rbegin()); it != multipath.paths.rend(); ++it) {
if (is_bridge(it->role())) if (it->role().is_bridge())
break; // Do not perform a wipe on bridges. break; // Do not perform a wipe on bridges.
assert(it->polyline.points.size() >= 2); assert(it->polyline.points.size() >= 2);
@ -2739,9 +2683,9 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
const double support_interface_speed = m_config.support_material_interface_speed.get_abs_value(support_speed); const double support_interface_speed = m_config.support_material_interface_speed.get_abs_value(support_speed);
for (const ExtrusionEntity *ee : support_fills.entities) { for (const ExtrusionEntity *ee : support_fills.entities) {
ExtrusionRole role = ee->role(); ExtrusionRole role = ee->role();
assert(role == erSupportMaterial || role == erSupportMaterialInterface); assert(role == ExtrusionRole::SupportMaterial || role == ExtrusionRole::SupportMaterialInterface);
const auto label = (role == erSupportMaterial) ? support_label : support_interface_label; const auto label = (role == ExtrusionRole::SupportMaterial) ? support_label : support_interface_label;
const double speed = (role == erSupportMaterial) ? support_speed : support_interface_speed; const double speed = (role == ExtrusionRole::SupportMaterial) ? support_speed : support_interface_speed;
const ExtrusionPath *path = dynamic_cast<const ExtrusionPath*>(ee); const ExtrusionPath *path = dynamic_cast<const ExtrusionPath*>(ee);
if (path) if (path)
gcode += this->extrude_path(*path, label, speed); gcode += this->extrude_path(*path, label, speed);
@ -2831,7 +2775,7 @@ void GCode::GCodeOutputStream::write_format(const char* format, ...)
std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view description, double speed) std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view description, double speed)
{ {
std::string gcode; std::string gcode;
const std::string_view description_bridge = is_bridge(path.role()) ? " (bridge)"sv : ""sv; const std::string_view description_bridge = path.role().is_bridge() ? " (bridge)"sv : ""sv;
// go to first point of extrusion path // go to first point of extrusion path
if (!m_last_pos_defined || m_last_pos != path.first_point()) { if (!m_last_pos_defined || m_last_pos != path.first_point()) {
@ -2852,11 +2796,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
acceleration = m_config.first_layer_acceleration.value; acceleration = m_config.first_layer_acceleration.value;
} else if (this->object_layer_over_raft() && m_config.first_layer_acceleration_over_raft.value > 0) { } else if (this->object_layer_over_raft() && m_config.first_layer_acceleration_over_raft.value > 0) {
acceleration = m_config.first_layer_acceleration_over_raft.value; acceleration = m_config.first_layer_acceleration_over_raft.value;
} else if (m_config.bridge_acceleration.value > 0 && is_bridge(path.role())) { } else if (m_config.bridge_acceleration.value > 0 && path.role().is_bridge()) {
acceleration = m_config.bridge_acceleration.value; acceleration = m_config.bridge_acceleration.value;
} else if (m_config.infill_acceleration.value > 0 && is_infill(path.role())) { } else if (m_config.infill_acceleration.value > 0 && path.role().is_infill()) {
acceleration = m_config.infill_acceleration.value; acceleration = m_config.infill_acceleration.value;
} else if (m_config.perimeter_acceleration.value > 0 && is_perimeter(path.role())) { } else if (m_config.perimeter_acceleration.value > 0 && path.role().is_perimeter()) {
acceleration = m_config.perimeter_acceleration.value; acceleration = m_config.perimeter_acceleration.value;
} else { } else {
acceleration = m_config.default_acceleration.value; acceleration = m_config.default_acceleration.value;
@ -2872,21 +2816,22 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
// set speed // set speed
if (speed == -1) { if (speed == -1) {
if (path.role() == erPerimeter) { if (path.role() == ExtrusionRole::Perimeter) {
speed = m_config.get_abs_value("perimeter_speed"); speed = m_config.get_abs_value("perimeter_speed");
} else if (path.role() == erExternalPerimeter) { } else if (path.role() == ExtrusionRole::ExternalPerimeter) {
speed = m_config.get_abs_value("external_perimeter_speed"); speed = m_config.get_abs_value("external_perimeter_speed");
} else if (path.role() == erOverhangPerimeter || path.role() == erBridgeInfill) { } else if (path.role().is_bridge()) {
assert(path.role().is_perimeter() || path.role() == ExtrusionRole::BridgeInfill);
speed = m_config.get_abs_value("bridge_speed"); speed = m_config.get_abs_value("bridge_speed");
} else if (path.role() == erInternalInfill) { } else if (path.role() == ExtrusionRole::InternalInfill) {
speed = m_config.get_abs_value("infill_speed"); speed = m_config.get_abs_value("infill_speed");
} else if (path.role() == erSolidInfill) { } else if (path.role() == ExtrusionRole::SolidInfill) {
speed = m_config.get_abs_value("solid_infill_speed"); speed = m_config.get_abs_value("solid_infill_speed");
} else if (path.role() == erTopSolidInfill) { } else if (path.role() == ExtrusionRole::TopSolidInfill) {
speed = m_config.get_abs_value("top_solid_infill_speed"); speed = m_config.get_abs_value("top_solid_infill_speed");
} else if (path.role() == erIroning) { } else if (path.role() == ExtrusionRole::Ironing) {
speed = m_config.get_abs_value("ironing_speed"); speed = m_config.get_abs_value("ironing_speed");
} else if (path.role() == erGapFill) { } else if (path.role() == ExtrusionRole::GapFill) {
speed = m_config.get_abs_value("gap_fill_speed"); speed = m_config.get_abs_value("gap_fill_speed");
} else { } else {
throw Slic3r::InvalidArgument("Invalid speed"); throw Slic3r::InvalidArgument("Invalid speed");
@ -2915,8 +2860,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
bool variable_speed = false; bool variable_speed = false;
std::vector<ProcessedPoint> new_points{}; std::vector<ProcessedPoint> new_points{};
if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && is_perimeter(path.role())) { if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && path.role().is_perimeter()) {
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_steepness_levels, new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_overlap_levels,
m_config.dynamic_overhang_speeds, m_config.dynamic_overhang_speeds,
m_config.get_abs_value("external_perimeter_speed"), speed); m_config.get_abs_value("external_perimeter_speed"), speed);
variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.speed != speed; }); variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.speed != speed; });
@ -2927,9 +2872,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
// extrude arc or line // extrude arc or line
if (m_enable_extrusion_role_markers) if (m_enable_extrusion_role_markers)
{ {
if (path.role() != m_last_extrusion_role) if (GCodeExtrusionRole role = extrusion_role_to_gcode_extrusion_role(path.role()); role != m_last_extrusion_role)
{ {
m_last_extrusion_role = path.role(); m_last_extrusion_role = role;
if (m_enable_extrusion_role_markers) if (m_enable_extrusion_role_markers)
{ {
char buf[32]; char buf[32];
@ -2941,14 +2886,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
// adds processor tags and updates processor tracking data // adds processor tags and updates processor tracking data
// PrusaMultiMaterial::Writer may generate GCodeProcessor::Height_Tag lines without updating m_last_height // PrusaMultiMaterial::Writer may generate GCodeProcessor::Height_Tag lines without updating m_last_height
// so, if the last role was erWipeTower we force export of GCodeProcessor::Height_Tag lines // so, if the last role was GCodeExtrusionRole::WipeTower we force export of GCodeProcessor::Height_Tag lines
bool last_was_wipe_tower = (m_last_processor_extrusion_role == erWipeTower); bool last_was_wipe_tower = (m_last_processor_extrusion_role == GCodeExtrusionRole::WipeTower);
assert(is_decimal_separator_point()); assert(is_decimal_separator_point());
if (path.role() != m_last_processor_extrusion_role) { if (GCodeExtrusionRole role = extrusion_role_to_gcode_extrusion_role(path.role()); role != m_last_processor_extrusion_role) {
m_last_processor_extrusion_role = path.role(); m_last_processor_extrusion_role = role;
char buf[64]; char buf[64];
sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str()); sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), gcode_extrusion_role_to_string(m_last_processor_extrusion_role).c_str());
gcode += buf; gcode += buf;
} }
@ -2975,11 +2920,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
std::string comment; std::string comment;
if (m_enable_cooling_markers) { if (m_enable_cooling_markers) {
if (is_bridge(path.role())) if (path.role().is_bridge())
gcode += ";_BRIDGE_FAN_START\n"; gcode += ";_BRIDGE_FAN_START\n";
else else
comment = ";_EXTRUDE_SET_SPEED"; comment = ";_EXTRUDE_SET_SPEED";
if (path.role() == erExternalPerimeter) if (path.role() == ExtrusionRole::ExternalPerimeter)
comment += ";_EXTERNAL_PERIMETER"; comment += ";_EXTERNAL_PERIMETER";
} }
@ -3026,7 +2971,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
} }
if (m_enable_cooling_markers) if (m_enable_cooling_markers)
gcode += is_bridge(path.role()) ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n"; gcode += path.role().is_bridge() ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n";
this->set_last_pos(path.last_point()); this->set_last_pos(path.last_point());
return gcode; return gcode;
@ -3040,13 +2985,13 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
this->origin in order to get G-code coordinates. */ this->origin in order to get G-code coordinates. */
Polyline travel { this->last_pos(), point }; Polyline travel { this->last_pos(), point };
if (this->config().avoid_curled_filament_during_travels) { if (this->config().avoid_crossing_curled_overhangs) {
if (m_config.avoid_crossing_perimeters) { if (m_config.avoid_crossing_perimeters) {
BOOST_LOG_TRIVIAL(warning) BOOST_LOG_TRIVIAL(warning)
<< "Option >avoid curled filament during travels< is not compatible with avoid crossing perimeters and it will be ignored!"; << "Option >avoid crossing curled overhangs< is not compatible with avoid crossing perimeters and it will be ignored!";
} else { } else {
Point scaled_origin = Point(scaled(this->origin())); Point scaled_origin = Point(scaled(this->origin()));
travel = m_avoid_curled_filaments.find_path(this->last_pos() + scaled_origin, point + scaled_origin); travel = m_avoid_crossing_curled_overhangs.find_path(this->last_pos() + scaled_origin, point + scaled_origin);
travel.translate(-scaled_origin); travel.translate(-scaled_origin);
} }
} }
@ -3112,7 +3057,7 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
return false; return false;
} }
if (role == erSupportMaterial) if (role == ExtrusionRole::SupportMaterial)
if (const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(m_layer); if (const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(m_layer);
support_layer != nullptr && ! support_layer->support_islands_bboxes.empty()) { support_layer != nullptr && ! support_layer->support_islands_bboxes.empty()) {
BoundingBox bbox_travel = get_extents(travel); BoundingBox bbox_travel = get_extents(travel);
@ -3185,6 +3130,9 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
if (! start_filament_gcode.empty()) { if (! start_filament_gcode.empty()) {
// Process the start_filament_gcode for the filament. // Process the start_filament_gcode for the filament.
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value));
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id))); config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config); gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
check_add_eol(gcode); check_add_eol(gcode);
@ -3200,8 +3148,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
m_wipe.reset_path(); m_wipe.reset_path();
if (m_writer.extruder() != nullptr) { if (m_writer.extruder() != nullptr) {
// Process the custom end_filament_gcode. set_extruder() is only called if there is no wipe tower // Process the custom end_filament_gcode.
// so it should not be injected twice.
unsigned int old_extruder_id = m_writer.extruder()->id(); unsigned int old_extruder_id = m_writer.extruder()->id();
const std::string &end_filament_gcode = m_config.end_filament_gcode.get_at(old_extruder_id); const std::string &end_filament_gcode = m_config.end_filament_gcode.get_at(old_extruder_id);
if (! end_filament_gcode.empty()) { if (! end_filament_gcode.empty()) {
@ -3211,8 +3158,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
} }
// If ooze prevention is enabled, park current extruder in the nearest // If ooze prevention is enabled, set current extruder to the standby temperature.
// standby point and set it to the standby temperature.
if (m_ooze_prevention.enable && m_writer.extruder() != nullptr) if (m_ooze_prevention.enable && m_writer.extruder() != nullptr)
gcode += m_ooze_prevention.pre_toolchange(*this); gcode += m_ooze_prevention.pre_toolchange(*this);
@ -3256,6 +3202,9 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
if (! start_filament_gcode.empty()) { if (! start_filament_gcode.empty()) {
// Process the start_filament_gcode for the new filament. // Process the start_filament_gcode for the new filament.
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value));
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id))); config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config); gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
check_add_eol(gcode); check_add_eol(gcode);

View File

@ -39,14 +39,13 @@ struct PrintInstance;
class OozePrevention { class OozePrevention {
public: public:
bool enable; bool enable;
Points standby_points;
OozePrevention() : enable(false) {} OozePrevention() : enable(false) {}
std::string pre_toolchange(GCode &gcodegen); std::string pre_toolchange(GCode &gcodegen);
std::string post_toolchange(GCode &gcodegen); std::string post_toolchange(GCode &gcodegen);
private: private:
int _get_temp(GCode &gcodegen); int _get_temp(const GCode &gcodegen) const;
}; };
class Wipe { class Wipe {
@ -137,14 +136,14 @@ public:
m_enable_loop_clipping(true), m_enable_loop_clipping(true),
m_enable_cooling_markers(false), m_enable_cooling_markers(false),
m_enable_extrusion_role_markers(false), m_enable_extrusion_role_markers(false),
m_last_processor_extrusion_role(erNone), m_last_processor_extrusion_role(GCodeExtrusionRole::None),
m_layer_count(0), m_layer_count(0),
m_layer_index(-1), m_layer_index(-1),
m_layer(nullptr), m_layer(nullptr),
m_object_layer_over_raft(false), m_object_layer_over_raft(false),
m_volumetric_speed(0), m_volumetric_speed(0),
m_last_pos_defined(false), m_last_pos_defined(false),
m_last_extrusion_role(erNone), m_last_extrusion_role(GCodeExtrusionRole::None),
m_last_width(0.0f), m_last_width(0.0f),
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_last_mm3_per_mm(0.0), m_last_mm3_per_mm(0.0),
@ -326,7 +325,7 @@ private:
std::string extrude_support(const ExtrusionEntityCollection &support_fills); std::string extrude_support(const ExtrusionEntityCollection &support_fills);
std::string travel_to(const Point &point, ExtrusionRole role, std::string comment); std::string travel_to(const Point &point, ExtrusionRole role, std::string comment);
bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone); bool needs_retraction(const Polyline &travel, ExtrusionRole role = ExtrusionRole::None);
std::string retract(bool toolchange = false); std::string retract(bool toolchange = false);
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
std::string set_extruder(unsigned int extruder_id, double print_z); std::string set_extruder(unsigned int extruder_id, double print_z);
@ -352,7 +351,7 @@ private:
OozePrevention m_ooze_prevention; OozePrevention m_ooze_prevention;
Wipe m_wipe; Wipe m_wipe;
AvoidCrossingPerimeters m_avoid_crossing_perimeters; AvoidCrossingPerimeters m_avoid_crossing_perimeters;
JPSPathFinder m_avoid_curled_filaments; JPSPathFinder m_avoid_crossing_curled_overhangs;
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters; RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters;
bool m_enable_loop_clipping; bool m_enable_loop_clipping;
// If enabled, the G-code generator will put following comments at the ends // If enabled, the G-code generator will put following comments at the ends
@ -363,7 +362,7 @@ private:
// The Pressure Equalizer removes the markers from the final G-code. // The Pressure Equalizer removes the markers from the final G-code.
bool m_enable_extrusion_role_markers; bool m_enable_extrusion_role_markers;
// Keeps track of the last extrusion role passed to the processor // Keeps track of the last extrusion role passed to the processor
ExtrusionRole m_last_processor_extrusion_role; GCodeExtrusionRole m_last_processor_extrusion_role;
// How many times will change_layer() be called? // How many times will change_layer() be called?
// change_layer() will update the progress bar. // change_layer() will update the progress bar.
unsigned int m_layer_count; unsigned int m_layer_count;
@ -376,7 +375,7 @@ private:
bool m_object_layer_over_raft; bool m_object_layer_over_raft;
double m_volumetric_speed; double m_volumetric_speed;
// Support for the extrusion role markers. Which marker is active? // Support for the extrusion role markers. Which marker is active?
ExtrusionRole m_last_extrusion_role; GCodeExtrusionRole m_last_extrusion_role;
// Support for G-Code Processor // Support for G-Code Processor
float m_last_height{ 0.0f }; float m_last_height{ 0.0f };
float m_last_layer_z{ 0.0f }; float m_last_layer_z{ 0.0f };

View File

@ -39,9 +39,9 @@ public:
void add_point(float distance, float angle) void add_point(float distance, float angle)
{ {
total_distance += distance; total_distance += distance;
total_curvature += std::abs(angle); total_curvature += angle;
distances.push_back(distance); distances.push_back(distance);
angles.push_back(std::abs(angle)); angles.push_back(angle);
while (distances.size() > 1 && total_distance > window_size) { while (distances.size() > 1 && total_distance > window_size) {
total_distance -= distances.front(); total_distance -= distances.front();
@ -53,8 +53,6 @@ public:
float get_curvature() const float get_curvature() const
{ {
if (total_distance < EPSILON) { return 0.0; }
return total_curvature / window_size; return total_curvature / window_size;
} }
@ -69,24 +67,33 @@ public:
class CurvatureEstimator class CurvatureEstimator
{ {
static const size_t sliders_count = 2; static const size_t sliders_count = 3;
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.5}, {3.0}}; SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.0},{4.0}, {10.0}};
public: public:
void add_point(float distance, float angle) void add_point(float distance, float angle)
{ {
if (distance < EPSILON) return; if (distance < EPSILON)
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.add_point(distance, angle); } return;
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
slider.add_point(distance, angle);
}
} }
float get_curvature() float get_curvature()
{ {
float max_curvature = std::numeric_limits<float>::min(); float max_curvature = 0.0f;
for (const SlidingWindowCurvatureAccumulator &slider : sliders) { max_curvature = std::max(max_curvature, slider.get_curvature()); } for (const SlidingWindowCurvatureAccumulator &slider : sliders) {
if (abs(slider.get_curvature()) > abs(max_curvature)) {
max_curvature = slider.get_curvature();
}
}
return max_curvature; return max_curvature;
} }
void reset() void reset()
{ {
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.reset(); } for (SlidingWindowCurvatureAccumulator &slider : sliders) {
slider.reset();
}
} }
}; };
@ -102,45 +109,47 @@ struct ExtendedPoint
float curvature; float curvature;
}; };
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_ONLY, bool CONCAVITY_RESETS_CURVATURE, typename P, typename L> template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename P, typename L>
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &extrusion_points, std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &input_points,
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer, const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
float flow_width) float flow_width,
float max_line_length = -1.0f)
{ {
if (extrusion_points.empty()) return {}; using AABBScalar = typename AABBTreeLines::LinesDistancer<L>::Scalar;
float boundary_offset = PREV_LAYER_BOUNDARY_ONLY ? 0.5 * flow_width : 0.0f; if (input_points.empty())
return {};
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
CurvatureEstimator cestim; CurvatureEstimator cestim;
float min_malformation_dist = 0.55 * flow_width;
std::vector<ExtendedPoint> points;
points.reserve(extrusion_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); }; auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
std::vector<ExtendedPoint> points;
points.reserve(input_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
{ {
ExtendedPoint start_point{maybe_unscale(extrusion_points.front())}; ExtendedPoint start_point{maybe_unscale(input_points.front())};
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(start_point.position); auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
start_point.distance = distance + boundary_offset; start_point.distance = distance + boundary_offset;
start_point.nearest_prev_layer_line = nearest_line; start_point.nearest_prev_layer_line = nearest_line;
points.push_back(start_point); points.push_back(start_point);
} }
for (size_t i = 1; i < extrusion_points.size(); i++) { for (size_t i = 1; i < input_points.size(); i++) {
ExtendedPoint next_point{maybe_unscale(extrusion_points[i])}; ExtendedPoint next_point{maybe_unscale(input_points[i])};
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(next_point.position); auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
next_point.distance = distance + boundary_offset; next_point.distance = distance + boundary_offset;
next_point.nearest_prev_layer_line = nearest_line; next_point.nearest_prev_layer_line = nearest_line;
if (ADD_INTERSECTIONS && if (ADD_INTERSECTIONS &&
((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) { ((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) {
const ExtendedPoint &prev_point = points.back(); const ExtendedPoint &prev_point = points.back();
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position, next_point.position}); auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position.cast<AABBScalar>(), next_point.position.cast<AABBScalar>()});
for (const auto &intersection : intersections) { for (const auto &intersection : intersections) {
points.emplace_back(intersection, boundary_offset); points.emplace_back(intersection.first.template cast<double>(), boundary_offset, intersection.second);
} }
} }
points.push_back(next_point); points.push_back(next_point);
} }
if (PREV_LAYER_BOUNDARY_ONLY && ADD_INTERSECTIONS) { if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) {
std::vector<ExtendedPoint> new_points; std::vector<ExtendedPoint> new_points;
new_points.reserve(points.size()*2); new_points.reserve(points.size()*2);
new_points.push_back(points.front()); new_points.push_back(points.front());
@ -159,19 +168,42 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
if (t0 < 1.0) { if (t0 < 1.0) {
auto p0 = curr.position + t0 * (next.position - curr.position); auto p0 = curr.position + t0 * (next.position - curr.position);
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.signed_distance_from_lines_extra(p0); auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p0.cast<AABBScalar>());
new_points.push_back(ExtendedPoint{p0, float(p0_dist + boundary_offset), p0_near_l}); new_points.push_back(ExtendedPoint{p0, float(p0_dist + boundary_offset), p0_near_l});
} }
if (t1 > 0.0) { if (t1 > 0.0) {
auto p1 = curr.position + t1 * (next.position - curr.position); auto p1 = curr.position + t1 * (next.position - curr.position);
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.signed_distance_from_lines_extra(p1); auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p1.cast<AABBScalar>());
new_points.push_back(ExtendedPoint{p1, float(p1_dist + boundary_offset), p1_near_l}); new_points.push_back(ExtendedPoint{p1, float(p1_dist + boundary_offset), p1_near_l});
} }
} }
} }
new_points.push_back(next); new_points.push_back(next);
} }
points = std::move(new_points); points = new_points;
}
if (max_line_length > 0) {
std::vector<ExtendedPoint> new_points;
new_points.reserve(points.size()*2);
{
for (size_t i = 0; i + 1 < points.size(); i++) {
const ExtendedPoint &curr = points[i];
const ExtendedPoint &next = points[i + 1];
new_points.push_back(curr);
double len = (next.position - curr.position).squaredNorm();
double t = sqrt((max_line_length * max_line_length) / len);
size_t new_point_count = 1.0 / t;
for (size_t j = 1; j < new_point_count + 1; j++) {
Vec2d pos = curr.position * (1.0 - j * t) + next.position * (j * t);
auto [p_dist, p_near_l,
p_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(pos.cast<AABBScalar>());
new_points.push_back(ExtendedPoint{pos, float(p_dist + boundary_offset), p_near_l});
}
}
new_points.push_back(points.back());
}
points = new_points;
} }
for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) { for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) {
@ -194,10 +226,8 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
float distance = (prev.position - a.position).norm(); float distance = (prev.position - a.position).norm();
float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position); float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position);
cestim.add_point(distance, alfa); cestim.add_point(distance, alfa);
if (CONCAVITY_RESETS_CURVATURE && alfa < 0.0) { cestim.reset(); }
} }
if (a.distance < min_malformation_dist) { cestim.reset(); }
a.curvature = cestim.get_curvature(); a.curvature = cestim.get_curvature();
} }
@ -241,10 +271,23 @@ public:
speed_sections.push_back({distance, speed}); speed_sections.push_back({distance, speed});
} }
std::sort(speed_sections.begin(), speed_sections.end(), std::sort(speed_sections.begin(), speed_sections.end(),
[](const std::pair<float, float> &a, const std::pair<float, float> &b) { return a.first < b.first; }); [](const std::pair<float, float> &a, const std::pair<float, float> &b) {
if (a.first == b.first) {
return a.second > b.second;
}
return a.first < b.first; });
std::pair<float, float> last_section{INFINITY, 0};
for (auto &section : speed_sections) {
if (section.first == last_section.first) {
section.second = last_section.second;
} else {
last_section = section;
}
}
std::vector<ExtendedPoint> extended_points = std::vector<ExtendedPoint> extended_points =
estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width); estimate_points_properties<true, true, true, true>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
std::vector<ProcessedPoint> processed_points; std::vector<ProcessedPoint> processed_points;
processed_points.reserve(extended_points.size()); processed_points.reserve(extended_points.size());

View File

@ -415,7 +415,7 @@ void GCodeProcessor::UsedFilaments::process_role_cache(const GCodeProcessor* pro
filament.first = role_cache / s * 0.001; filament.first = role_cache / s * 0.001;
filament.second = role_cache * processor->m_result.filament_densities[processor->m_extruder_id] * 0.001; filament.second = role_cache * processor->m_result.filament_densities[processor->m_extruder_id] * 0.001;
ExtrusionRole active_role = processor->m_extrusion_role; GCodeExtrusionRole active_role = processor->m_extrusion_role;
if (filaments_per_role.find(active_role) != filaments_per_role.end()) { if (filaments_per_role.find(active_role) != filaments_per_role.end()) {
filaments_per_role[active_role].first += filament.first; filaments_per_role[active_role].first += filament.first;
filaments_per_role[active_role].second += filament.second; filaments_per_role[active_role].second += filament.second;
@ -942,7 +942,7 @@ void GCodeProcessor::reset()
m_fan_speed = 0.0f; m_fan_speed = 0.0f;
m_z_offset = 0.0f; m_z_offset = 0.0f;
m_extrusion_role = erNone; m_extrusion_role = GCodeExtrusionRole::None;
m_extruder_id = 0; m_extruder_id = 0;
m_extruder_colors.resize(MIN_EXTRUDERS_COUNT); m_extruder_colors.resize(MIN_EXTRUDERS_COUNT);
for (size_t i = 0; i < MIN_EXTRUDERS_COUNT; ++i) { for (size_t i = 0; i < MIN_EXTRUDERS_COUNT; ++i) {
@ -1170,14 +1170,14 @@ std::vector<std::pair<EMoveType, float>> GCodeProcessor::get_moves_time(PrintEst
return ret; return ret;
} }
std::vector<std::pair<ExtrusionRole, float>> GCodeProcessor::get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const std::vector<std::pair<GCodeExtrusionRole, float>> GCodeProcessor::get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const
{ {
std::vector<std::pair<ExtrusionRole, float>> ret; std::vector<std::pair<GCodeExtrusionRole, float>> ret;
if (mode < PrintEstimatedStatistics::ETimeMode::Count) { if (mode < PrintEstimatedStatistics::ETimeMode::Count) {
for (size_t i = 0; i < m_time_processor.machines[static_cast<size_t>(mode)].roles_time.size(); ++i) { for (size_t i = 0; i < m_time_processor.machines[static_cast<size_t>(mode)].roles_time.size(); ++i) {
float time = m_time_processor.machines[static_cast<size_t>(mode)].roles_time[i]; float time = m_time_processor.machines[static_cast<size_t>(mode)].roles_time[i];
if (time > 0.0f) if (time > 0.0f)
ret.push_back({ static_cast<ExtrusionRole>(i), time }); ret.push_back({ static_cast<GCodeExtrusionRole>(i), time });
} }
} }
return ret; return ret;
@ -1645,8 +1645,8 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
// extrusion role tag // extrusion role tag
if (boost::starts_with(comment, reserved_tag(ETags::Role))) { if (boost::starts_with(comment, reserved_tag(ETags::Role))) {
set_extrusion_role(ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length()))); set_extrusion_role(string_to_gcode_extrusion_role(comment.substr(reserved_tag(ETags::Role).length())));
if (m_extrusion_role == erExternalPerimeter) if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
m_seams_detector.activate(true); m_seams_detector.activate(true);
return; return;
} }
@ -1827,27 +1827,27 @@ bool GCodeProcessor::process_cura_tags(const std::string_view comment)
if (pos != comment.npos) { if (pos != comment.npos) {
const std::string_view type = comment.substr(pos + tag.length()); const std::string_view type = comment.substr(pos + tag.length());
if (type == "SKIRT") if (type == "SKIRT")
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
else if (type == "WALL-OUTER") else if (type == "WALL-OUTER")
set_extrusion_role(erExternalPerimeter); set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
else if (type == "WALL-INNER") else if (type == "WALL-INNER")
set_extrusion_role(erPerimeter); set_extrusion_role(GCodeExtrusionRole::Perimeter);
else if (type == "SKIN") else if (type == "SKIN")
set_extrusion_role(erSolidInfill); set_extrusion_role(GCodeExtrusionRole::SolidInfill);
else if (type == "FILL") else if (type == "FILL")
set_extrusion_role(erInternalInfill); set_extrusion_role(GCodeExtrusionRole::InternalInfill);
else if (type == "SUPPORT") else if (type == "SUPPORT")
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
else if (type == "SUPPORT-INTERFACE") else if (type == "SUPPORT-INTERFACE")
set_extrusion_role(erSupportMaterialInterface); set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
else if (type == "PRIME-TOWER") else if (type == "PRIME-TOWER")
set_extrusion_role(erWipeTower); set_extrusion_role(GCodeExtrusionRole::WipeTower);
else { else {
set_extrusion_role(erNone); set_extrusion_role(GCodeExtrusionRole::None);
BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type; BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type;
} }
if (m_extrusion_role == erExternalPerimeter) if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
m_seams_detector.activate(true); m_seams_detector.activate(true);
return true; return true;
@ -1906,14 +1906,14 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
// ; skirt // ; skirt
pos = cmt.find(" skirt"); pos = cmt.find(" skirt");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
return true; return true;
} }
// ; outer perimeter // ; outer perimeter
pos = cmt.find(" outer perimeter"); pos = cmt.find(" outer perimeter");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erExternalPerimeter); set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
m_seams_detector.activate(true); m_seams_detector.activate(true);
return true; return true;
} }
@ -1921,77 +1921,77 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
// ; inner perimeter // ; inner perimeter
pos = cmt.find(" inner perimeter"); pos = cmt.find(" inner perimeter");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erPerimeter); set_extrusion_role(GCodeExtrusionRole::Perimeter);
return true; return true;
} }
// ; gap fill // ; gap fill
pos = cmt.find(" gap fill"); pos = cmt.find(" gap fill");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erGapFill); set_extrusion_role(GCodeExtrusionRole::GapFill);
return true; return true;
} }
// ; infill // ; infill
pos = cmt.find(" infill"); pos = cmt.find(" infill");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erInternalInfill); set_extrusion_role(GCodeExtrusionRole::InternalInfill);
return true; return true;
} }
// ; solid layer // ; solid layer
pos = cmt.find(" solid layer"); pos = cmt.find(" solid layer");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSolidInfill); set_extrusion_role(GCodeExtrusionRole::SolidInfill);
return true; return true;
} }
// ; bridge // ; bridge
pos = cmt.find(" bridge"); pos = cmt.find(" bridge");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erBridgeInfill); set_extrusion_role(GCodeExtrusionRole::BridgeInfill);
return true; return true;
} }
// ; support // ; support
pos = cmt.find(" support"); pos = cmt.find(" support");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
return true; return true;
} }
// ; dense support // ; dense support
pos = cmt.find(" dense support"); pos = cmt.find(" dense support");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSupportMaterialInterface); set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
return true; return true;
} }
// ; prime pillar // ; prime pillar
pos = cmt.find(" prime pillar"); pos = cmt.find(" prime pillar");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erWipeTower); set_extrusion_role(GCodeExtrusionRole::WipeTower);
return true; return true;
} }
// ; ooze shield // ; ooze shield
pos = cmt.find(" ooze shield"); pos = cmt.find(" ooze shield");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); // Missing mapping set_extrusion_role(GCodeExtrusionRole::None); // Missing mapping
return true; return true;
} }
// ; raft // ; raft
pos = cmt.find(" raft"); pos = cmt.find(" raft");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
return true; return true;
} }
// ; internal single extrusion // ; internal single extrusion
pos = cmt.find(" internal single extrusion"); pos = cmt.find(" internal single extrusion");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); // Missing mapping set_extrusion_role(GCodeExtrusionRole::None); // Missing mapping
return true; return true;
} }
@ -2043,33 +2043,33 @@ bool GCodeProcessor::process_craftware_tags(const std::string_view comment)
if (pos != comment.npos) { if (pos != comment.npos) {
const std::string_view type = comment.substr(pos + tag.length()); const std::string_view type = comment.substr(pos + tag.length());
if (type == "Skirt") if (type == "Skirt")
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
else if (type == "Perimeter") else if (type == "Perimeter")
set_extrusion_role(erExternalPerimeter); set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
else if (type == "HShell") else if (type == "HShell")
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
else if (type == "InnerHair") else if (type == "InnerHair")
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
else if (type == "Loop") else if (type == "Loop")
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
else if (type == "Infill") else if (type == "Infill")
set_extrusion_role(erInternalInfill); set_extrusion_role(GCodeExtrusionRole::InternalInfill);
else if (type == "Raft") else if (type == "Raft")
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
else if (type == "Support") else if (type == "Support")
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
else if (type == "SupportTouch") else if (type == "SupportTouch")
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
else if (type == "SoftSupport") else if (type == "SoftSupport")
set_extrusion_role(erSupportMaterialInterface); set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
else if (type == "Pillar") else if (type == "Pillar")
set_extrusion_role(erWipeTower); set_extrusion_role(GCodeExtrusionRole::WipeTower);
else { else {
set_extrusion_role(erNone); set_extrusion_role(GCodeExtrusionRole::None);
BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type; BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type;
} }
if (m_extrusion_role == erExternalPerimeter) if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
m_seams_detector.activate(true); m_seams_detector.activate(true);
return true; return true;
@ -2093,25 +2093,25 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
if (pos != comment.npos) { if (pos != comment.npos) {
const std::string_view type = comment.substr(pos + tag.length()); const std::string_view type = comment.substr(pos + tag.length());
if (type == "RAFT") if (type == "RAFT")
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
else if (type == "WALL-OUTER") else if (type == "WALL-OUTER")
set_extrusion_role(erExternalPerimeter); set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
else if (type == "WALL-INNER") else if (type == "WALL-INNER")
set_extrusion_role(erPerimeter); set_extrusion_role(GCodeExtrusionRole::Perimeter);
else if (type == "SOLID-FILL") else if (type == "SOLID-FILL")
set_extrusion_role(erSolidInfill); set_extrusion_role(GCodeExtrusionRole::SolidInfill);
else if (type == "FILL") else if (type == "FILL")
set_extrusion_role(erInternalInfill); set_extrusion_role(GCodeExtrusionRole::InternalInfill);
else if (type == "BRIDGE") else if (type == "BRIDGE")
set_extrusion_role(erBridgeInfill); set_extrusion_role(GCodeExtrusionRole::BridgeInfill);
else if (type == "SUPPORT") else if (type == "SUPPORT")
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
else { else {
set_extrusion_role(erNone); set_extrusion_role(GCodeExtrusionRole::None);
BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type; BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type;
} }
if (m_extrusion_role == erExternalPerimeter) if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
m_seams_detector.activate(true); m_seams_detector.activate(true);
return true; return true;
@ -2153,35 +2153,35 @@ bool GCodeProcessor::process_kissslicer_tags(const std::string_view comment)
// ; 'Raft Path' // ; 'Raft Path'
size_t pos = comment.find(" 'Raft Path'"); size_t pos = comment.find(" 'Raft Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
return true; return true;
} }
// ; 'Support Interface Path' // ; 'Support Interface Path'
pos = comment.find(" 'Support Interface Path'"); pos = comment.find(" 'Support Interface Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSupportMaterialInterface); set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
return true; return true;
} }
// ; 'Travel/Ironing Path' // ; 'Travel/Ironing Path'
pos = comment.find(" 'Travel/Ironing Path'"); pos = comment.find(" 'Travel/Ironing Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erIroning); set_extrusion_role(GCodeExtrusionRole::Ironing);
return true; return true;
} }
// ; 'Support (may Stack) Path' // ; 'Support (may Stack) Path'
pos = comment.find(" 'Support (may Stack) Path'"); pos = comment.find(" 'Support (may Stack) Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
return true; return true;
} }
// ; 'Perimeter Path' // ; 'Perimeter Path'
pos = comment.find(" 'Perimeter Path'"); pos = comment.find(" 'Perimeter Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erExternalPerimeter); set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
m_seams_detector.activate(true); m_seams_detector.activate(true);
return true; return true;
} }
@ -2189,56 +2189,56 @@ bool GCodeProcessor::process_kissslicer_tags(const std::string_view comment)
// ; 'Pillar Path' // ; 'Pillar Path'
pos = comment.find(" 'Pillar Path'"); pos = comment.find(" 'Pillar Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true; return true;
} }
// ; 'Destring/Wipe/Jump Path' // ; 'Destring/Wipe/Jump Path'
pos = comment.find(" 'Destring/Wipe/Jump Path'"); pos = comment.find(" 'Destring/Wipe/Jump Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true; return true;
} }
// ; 'Prime Pillar Path' // ; 'Prime Pillar Path'
pos = comment.find(" 'Prime Pillar Path'"); pos = comment.find(" 'Prime Pillar Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true; return true;
} }
// ; 'Loop Path' // ; 'Loop Path'
pos = comment.find(" 'Loop Path'"); pos = comment.find(" 'Loop Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true; return true;
} }
// ; 'Crown Path' // ; 'Crown Path'
pos = comment.find(" 'Crown Path'"); pos = comment.find(" 'Crown Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true; return true;
} }
// ; 'Solid Path' // ; 'Solid Path'
pos = comment.find(" 'Solid Path'"); pos = comment.find(" 'Solid Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erNone); set_extrusion_role(GCodeExtrusionRole::None);
return true; return true;
} }
// ; 'Stacked Sparse Infill Path' // ; 'Stacked Sparse Infill Path'
pos = comment.find(" 'Stacked Sparse Infill Path'"); pos = comment.find(" 'Stacked Sparse Infill Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erInternalInfill); set_extrusion_role(GCodeExtrusionRole::InternalInfill);
return true; return true;
} }
// ; 'Sparse Infill Path' // ; 'Sparse Infill Path'
pos = comment.find(" 'Sparse Infill Path'"); pos = comment.find(" 'Sparse Infill Path'");
if (pos == 0) { if (pos == 0) {
set_extrusion_role(erSolidInfill); set_extrusion_role(GCodeExtrusionRole::SolidInfill);
return true; return true;
} }
@ -2263,45 +2263,45 @@ bool GCodeProcessor::process_bambustudio_tags(const std::string_view comment)
if (pos != comment.npos) { if (pos != comment.npos) {
const std::string_view type = comment.substr(pos + tag.length()); const std::string_view type = comment.substr(pos + tag.length());
if (type == "Custom") if (type == "Custom")
set_extrusion_role(erCustom); set_extrusion_role(GCodeExtrusionRole::Custom);
else if (type == "Inner wall") else if (type == "Inner wall")
set_extrusion_role(erPerimeter); set_extrusion_role(GCodeExtrusionRole::Perimeter);
else if (type == "Outer wall") else if (type == "Outer wall")
set_extrusion_role(erExternalPerimeter); set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
else if (type == "Overhang wall") else if (type == "Overhang wall")
set_extrusion_role(erOverhangPerimeter); set_extrusion_role(GCodeExtrusionRole::OverhangPerimeter);
else if (type == "Gap infill") else if (type == "Gap infill")
set_extrusion_role(erGapFill); set_extrusion_role(GCodeExtrusionRole::GapFill);
else if (type == "Bridge") else if (type == "Bridge")
set_extrusion_role(erBridgeInfill); set_extrusion_role(GCodeExtrusionRole::BridgeInfill);
else if (type == "Sparse infill") else if (type == "Sparse infill")
set_extrusion_role(erInternalInfill); set_extrusion_role(GCodeExtrusionRole::InternalInfill);
else if (type == "Internal solid infill") else if (type == "Internal solid infill")
set_extrusion_role(erSolidInfill); set_extrusion_role(GCodeExtrusionRole::SolidInfill);
else if (type == "Top surface") else if (type == "Top surface")
set_extrusion_role(erTopSolidInfill); set_extrusion_role(GCodeExtrusionRole::TopSolidInfill);
else if (type == "Bottom surface") else if (type == "Bottom surface")
set_extrusion_role(erNone); set_extrusion_role(GCodeExtrusionRole::None);
else if (type == "Ironing") else if (type == "Ironing")
set_extrusion_role(erIroning); set_extrusion_role(GCodeExtrusionRole::Ironing);
else if (type == "Skirt") else if (type == "Skirt")
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
else if (type == "Brim") else if (type == "Brim")
set_extrusion_role(erSkirt); set_extrusion_role(GCodeExtrusionRole::Skirt);
else if (type == "Support") else if (type == "Support")
set_extrusion_role(erSupportMaterial); set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
else if (type == "Support interface") else if (type == "Support interface")
set_extrusion_role(erSupportMaterialInterface); set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
else if (type == "Support transition") else if (type == "Support transition")
set_extrusion_role(erNone); set_extrusion_role(GCodeExtrusionRole::None);
else if (type == "Prime tower") else if (type == "Prime tower")
set_extrusion_role(erWipeTower); set_extrusion_role(GCodeExtrusionRole::WipeTower);
else { else {
set_extrusion_role(erNone); set_extrusion_role(GCodeExtrusionRole::None);
BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type; BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type;
} }
if (m_extrusion_role == erExternalPerimeter) if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
m_seams_detector.activate(true); m_seams_detector.activate(true);
return true; return true;
@ -2405,7 +2405,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_height == 0.0f) if (m_height == 0.0f)
m_height = DEFAULT_TOOLPATH_HEIGHT; m_height = DEFAULT_TOOLPATH_HEIGHT;
if (m_end_position[Z] == 0.0f || (m_extrusion_role == erCustom && m_layer_id == 0)) if (m_end_position[Z] == 0.0f || (m_extrusion_role == GCodeExtrusionRole::Custom && m_layer_id == 0))
m_end_position[Z] = m_height; m_end_position[Z] = m_height;
if (line.comment() != INTERNAL_G2G3_TAG) if (line.comment() != INTERNAL_G2G3_TAG)
@ -2418,10 +2418,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_forced_width > 0.0f) if (m_forced_width > 0.0f)
m_width = m_forced_width; m_width = m_forced_width;
else if (m_extrusion_role == erExternalPerimeter) else if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
// cross section: rectangle // cross section: rectangle
m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height); m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height);
else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erNone) else if (m_extrusion_role == GCodeExtrusionRole::BridgeInfill || m_extrusion_role == GCodeExtrusionRole::None)
// cross section: circle // cross section: circle
m_width = static_cast<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz); m_width = static_cast<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
else else
@ -2605,10 +2605,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_seams_detector.is_active()) { if (m_seams_detector.is_active()) {
// check for seam starting vertex // check for seam starting vertex
if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) if (type == EMoveType::Extrude && m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter && !m_seams_detector.has_first_vertex())
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]);
// check for seam ending vertex and store the resulting move // check for seam ending vertex and store the resulting move
else if ((type != EMoveType::Extrude || (m_extrusion_role != erExternalPerimeter && m_extrusion_role != erOverhangPerimeter)) && m_seams_detector.has_first_vertex()) { else if ((type != EMoveType::Extrude || (m_extrusion_role != GCodeExtrusionRole::ExternalPerimeter && m_extrusion_role != GCodeExtrusionRole::OverhangPerimeter)) && m_seams_detector.has_first_vertex()) {
auto set_end_position = [this](const Vec3f& pos) { auto set_end_position = [this](const Vec3f& pos) {
m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z(); m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z();
}; };
@ -2627,7 +2627,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
m_seams_detector.activate(false); m_seams_detector.activate(false);
} }
} }
else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) { else if (type == EMoveType::Extrude && m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter) {
m_seams_detector.activate(true); m_seams_detector.activate(true);
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]);
} }
@ -3771,7 +3771,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type, bool internal_only)
} }
} }
void GCodeProcessor::set_extrusion_role(ExtrusionRole role) void GCodeProcessor::set_extrusion_role(GCodeExtrusionRole role)
{ {
m_used_filaments.process_role_cache(this); m_used_filaments.process_role_cache(this);
m_extrusion_role = role; m_extrusion_role = role;

View File

@ -3,7 +3,7 @@
#include "libslic3r/GCodeReader.hpp" #include "libslic3r/GCodeReader.hpp"
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionRole.hpp"
#include "libslic3r/PrintConfig.hpp" #include "libslic3r/PrintConfig.hpp"
#include "libslic3r/CustomGCode.hpp" #include "libslic3r/CustomGCode.hpp"
@ -47,7 +47,7 @@ namespace Slic3r {
float travel_time; float travel_time;
std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> custom_gcode_times; std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> custom_gcode_times;
std::vector<std::pair<EMoveType, float>> moves_times; std::vector<std::pair<EMoveType, float>> moves_times;
std::vector<std::pair<ExtrusionRole, float>> roles_times; std::vector<std::pair<GCodeExtrusionRole, float>> roles_times;
std::vector<float> layers_times; std::vector<float> layers_times;
void reset() { void reset() {
@ -62,7 +62,7 @@ namespace Slic3r {
std::vector<double> volumes_per_color_change; std::vector<double> volumes_per_color_change;
std::map<size_t, double> volumes_per_extruder; std::map<size_t, double> volumes_per_extruder;
std::map<ExtrusionRole, std::pair<double, double>> used_filaments_per_role; std::map<GCodeExtrusionRole, std::pair<double, double>> used_filaments_per_role;
std::map<size_t, double> cost_per_extruder; std::map<size_t, double> cost_per_extruder;
std::array<Mode, static_cast<size_t>(ETimeMode::Count)> modes; std::array<Mode, static_cast<size_t>(ETimeMode::Count)> modes;
@ -99,7 +99,7 @@ namespace Slic3r {
{ {
unsigned int gcode_id{ 0 }; unsigned int gcode_id{ 0 };
EMoveType type{ EMoveType::Noop }; EMoveType type{ EMoveType::Noop };
ExtrusionRole extrusion_role{ erNone }; GCodeExtrusionRole extrusion_role{ GCodeExtrusionRole::None };
unsigned char extruder_id{ 0 }; unsigned char extruder_id{ 0 };
unsigned char cp_color_id{ 0 }; unsigned char cp_color_id{ 0 };
Vec3f position{ Vec3f::Zero() }; // mm Vec3f position{ Vec3f::Zero() }; // mm
@ -238,7 +238,7 @@ namespace Slic3r {
}; };
EMoveType move_type{ EMoveType::Noop }; EMoveType move_type{ EMoveType::Noop };
ExtrusionRole role{ erNone }; GCodeExtrusionRole role{ GCodeExtrusionRole::None };
unsigned int g1_line_id{ 0 }; unsigned int g1_line_id{ 0 };
unsigned int layer_id{ 0 }; unsigned int layer_id{ 0 };
float distance{ 0.0f }; // mm float distance{ 0.0f }; // mm
@ -310,7 +310,7 @@ namespace Slic3r {
std::vector<TimeBlock> blocks; std::vector<TimeBlock> blocks;
std::vector<G1LinesCacheItem> g1_times_cache; std::vector<G1LinesCacheItem> g1_times_cache;
std::array<float, static_cast<size_t>(EMoveType::Count)> moves_time; std::array<float, static_cast<size_t>(EMoveType::Count)> moves_time;
std::array<float, static_cast<size_t>(ExtrusionRole::erCount)> roles_time; std::array<float, static_cast<size_t>(GCodeExtrusionRole::Count)> roles_time;
std::vector<float> layers_time; std::vector<float> layers_time;
void reset(); void reset();
@ -360,7 +360,7 @@ namespace Slic3r {
std::map<size_t, double> volumes_per_extruder; std::map<size_t, double> volumes_per_extruder;
double role_cache; double role_cache;
std::map<ExtrusionRole, std::pair<double, double>> filaments_per_role; // ExtrusionRole -> (m, g) std::map<GCodeExtrusionRole, std::pair<double, double>> filaments_per_role; // ExtrusionRole -> (m, g)
void reset(); void reset();
@ -441,7 +441,7 @@ namespace Slic3r {
{ {
float value; float value;
float tag_value; float tag_value;
ExtrusionRole role; GCodeExtrusionRole role;
}; };
std::string type; std::string type;
@ -454,8 +454,8 @@ namespace Slic3r {
: type(type), threshold(threshold) : type(type), threshold(threshold)
{} {}
void update(float value, ExtrusionRole role) { void update(float value, GCodeExtrusionRole role) {
if (role != erCustom) { if (role != GCodeExtrusionRole::Custom) {
++count; ++count;
if (last_tag_value != 0.0f) { if (last_tag_value != 0.0f) {
if (std::abs(value - last_tag_value) / last_tag_value > threshold) if (std::abs(value - last_tag_value) / last_tag_value > threshold)
@ -539,7 +539,7 @@ namespace Slic3r {
float m_mm3_per_mm; float m_mm3_per_mm;
float m_fan_speed; // percentage float m_fan_speed; // percentage
float m_z_offset; // mm float m_z_offset; // mm
ExtrusionRole m_extrusion_role; GCodeExtrusionRole m_extrusion_role;
unsigned char m_extruder_id; unsigned char m_extruder_id;
ExtruderColors m_extruder_colors; ExtruderColors m_extruder_colors;
ExtruderTemps m_extruder_temps; ExtruderTemps m_extruder_temps;
@ -620,7 +620,7 @@ namespace Slic3r {
std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const; std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const;
std::vector<std::pair<EMoveType, float>> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector<std::pair<EMoveType, float>> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::vector<std::pair<ExtrusionRole, float>> get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector<std::pair<GCodeExtrusionRole, float>> get_roles_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::vector<float> get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const; std::vector<float> get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const;
private: private:
@ -757,7 +757,7 @@ namespace Slic3r {
void store_move_vertex(EMoveType type, bool internal_only = false); void store_move_vertex(EMoveType type, bool internal_only = false);
void set_extrusion_role(ExtrusionRole role); void set_extrusion_role(GCodeExtrusionRole role);
float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const; float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;
float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const; float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;

View File

@ -37,7 +37,7 @@ PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_use_
m_current_extruder = 0; m_current_extruder = 0;
// Zero the position of the XYZE axes + the current feed // Zero the position of the XYZE axes + the current feed
memset(m_current_pos, 0, sizeof(float) * 5); memset(m_current_pos, 0, sizeof(float) * 5);
m_current_extrusion_role = erNone; m_current_extrusion_role = GCodeExtrusionRole::None;
// Expect the first command to fill the nozzle (deretract). // Expect the first command to fill the nozzle (deretract).
m_retracted = true; m_retracted = true;
@ -60,9 +60,9 @@ PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_use_
} }
// Don't regulate the pressure before and after gap-fill and ironing. // Don't regulate the pressure before and after gap-fill and ironing.
for (const ExtrusionRole er : {erGapFill, erIroning}) { for (const GCodeExtrusionRole er : {GCodeExtrusionRole::GapFill, GCodeExtrusionRole::Ironing}) {
m_max_volumetric_extrusion_rate_slopes[er].negative = 0; m_max_volumetric_extrusion_rate_slopes[size_t(er)].negative = 0;
m_max_volumetric_extrusion_rate_slopes[er].positive = 0; m_max_volumetric_extrusion_rate_slopes[size_t(er)].positive = 0;
} }
opened_extrude_set_speed_block = false; opened_extrude_set_speed_block = false;
@ -185,7 +185,7 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo
if (strncmp(line, EXTRUSION_ROLE_TAG.data(), EXTRUSION_ROLE_TAG.length()) == 0) { if (strncmp(line, EXTRUSION_ROLE_TAG.data(), EXTRUSION_ROLE_TAG.length()) == 0) {
line += EXTRUSION_ROLE_TAG.length(); line += EXTRUSION_ROLE_TAG.length();
int role = atoi(line); int role = atoi(line);
m_current_extrusion_role = ExtrusionRole(role); m_current_extrusion_role = GCodeExtrusionRole(role);
#ifdef PRESSURE_EQUALIZER_DEBUG #ifdef PRESSURE_EQUALIZER_DEBUG
++line_idx; ++line_idx;
#endif #endif
@ -367,7 +367,16 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo
case 'T': case 'T':
{ {
// Activate an extruder head. // Activate an extruder head.
int new_extruder = parse_int(line); int new_extruder = -1;
try {
new_extruder = parse_int(line);
} catch (Slic3r::InvalidArgument &) {
// Ignore invalid GCodes starting with T.
eatws(line);
break;
}
assert(new_extruder != -1);
if (new_extruder != int(m_current_extruder)) { if (new_extruder != int(m_current_extruder)) {
m_current_extruder = new_extruder; m_current_extruder = new_extruder;
m_retracted = true; m_retracted = true;
@ -510,9 +519,9 @@ void PressureEqualizer::adjust_volumetric_rate()
// Nothing to do, the last move is not extruding. // Nothing to do, the last move is not extruding.
return; return;
std::array<float, erCount> feedrate_per_extrusion_role{}; std::array<float, size_t(GCodeExtrusionRole::Count)> feedrate_per_extrusion_role{};
feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max()); feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
feedrate_per_extrusion_role[m_gcode_lines[line_idx].extrusion_role] = m_gcode_lines[line_idx].volumetric_extrusion_rate_start; feedrate_per_extrusion_role[int(m_gcode_lines[line_idx].extrusion_role)] = m_gcode_lines[line_idx].volumetric_extrusion_rate_start;
while (line_idx != fist_line_idx) { while (line_idx != fist_line_idx) {
size_t idx_prev = line_idx - 1; size_t idx_prev = line_idx - 1;
@ -520,7 +529,7 @@ void PressureEqualizer::adjust_volumetric_rate()
if (!m_gcode_lines[idx_prev].extruding()) if (!m_gcode_lines[idx_prev].extruding())
break; break;
// Don't decelerate before ironing and gap-fill. // Don't decelerate before ironing and gap-fill.
if (m_gcode_lines[line_idx].extrusion_role == erIroning || m_gcode_lines[line_idx].extrusion_role == erGapFill) { if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing || m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::GapFill) {
line_idx = idx_prev; line_idx = idx_prev;
continue; continue;
} }
@ -530,23 +539,23 @@ void PressureEqualizer::adjust_volumetric_rate()
line_idx = idx_prev; line_idx = idx_prev;
GCodeLine &line = m_gcode_lines[line_idx]; GCodeLine &line = m_gcode_lines[line_idx];
for (size_t iRole = 1; iRole < erCount; ++ iRole) { for (size_t iRole = 1; iRole < size_t(GCodeExtrusionRole::Count); ++ iRole) {
const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].negative; const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].negative;
if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max()) if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
continue; // The negative rate is unlimited or the rate for ExtrusionRole iRole is unlimited. continue; // The negative rate is unlimited or the rate for GCodeExtrusionRole iRole is unlimited.
float rate_end = feedrate_per_extrusion_role[iRole]; float rate_end = feedrate_per_extrusion_role[iRole];
if (iRole == line.extrusion_role && rate_succ < rate_end) if (iRole == size_t(line.extrusion_role) && rate_succ < rate_end)
// Limit by the succeeding volumetric flow rate. // Limit by the succeeding volumetric flow rate.
rate_end = rate_succ; rate_end = rate_succ;
if (!line.adjustable_flow || line.extrusion_role == erExternalPerimeter || line.extrusion_role == erGapFill || line.extrusion_role == erBridgeInfill || line.extrusion_role == erIroning) { if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter || line.extrusion_role == GCodeExtrusionRole::GapFill || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) {
rate_end = line.volumetric_extrusion_rate_end; rate_end = line.volumetric_extrusion_rate_end;
} else if (line.volumetric_extrusion_rate_end > rate_end) { } else if (line.volumetric_extrusion_rate_end > rate_end) {
line.volumetric_extrusion_rate_end = rate_end; line.volumetric_extrusion_rate_end = rate_end;
line.max_volumetric_extrusion_rate_slope_negative = rate_slope; line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
line.modified = true; line.modified = true;
} else if (iRole == line.extrusion_role) { } else if (iRole == size_t(line.extrusion_role)) {
rate_end = line.volumetric_extrusion_rate_end; rate_end = line.volumetric_extrusion_rate_end;
} else { } else {
// Use the original, 'floating' extrusion rate as a starting point for the limiter. // Use the original, 'floating' extrusion rate as a starting point for the limiter.
@ -564,13 +573,13 @@ void PressureEqualizer::adjust_volumetric_rate()
} }
// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_start : rate_start; // feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_start : rate_start;
// Don't store feed rate for ironing and gap-fill. // Don't store feed rate for ironing and gap-fill.
if (line.extrusion_role != erIroning && line.extrusion_role != erGapFill) if (line.extrusion_role != GCodeExtrusionRole::Ironing && line.extrusion_role != GCodeExtrusionRole::GapFill)
feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_start; feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_start;
} }
} }
feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max()); feedrate_per_extrusion_role.fill(std::numeric_limits<float>::max());
feedrate_per_extrusion_role[m_gcode_lines[line_idx].extrusion_role] = m_gcode_lines[line_idx].volumetric_extrusion_rate_end; feedrate_per_extrusion_role[size_t(m_gcode_lines[line_idx].extrusion_role)] = m_gcode_lines[line_idx].volumetric_extrusion_rate_end;
assert(m_gcode_lines[line_idx].extruding()); assert(m_gcode_lines[line_idx].extruding());
while (line_idx != last_line_idx) { while (line_idx != last_line_idx) {
@ -579,7 +588,7 @@ void PressureEqualizer::adjust_volumetric_rate()
if (!m_gcode_lines[idx_next].extruding()) if (!m_gcode_lines[idx_next].extruding())
break; break;
// Don't accelerate after ironing and gap-fill. // Don't accelerate after ironing and gap-fill.
if (m_gcode_lines[line_idx].extrusion_role == erIroning || m_gcode_lines[line_idx].extrusion_role == erGapFill) { if (m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::Ironing || m_gcode_lines[line_idx].extrusion_role == GCodeExtrusionRole::GapFill) {
line_idx = idx_next; line_idx = idx_next;
continue; continue;
} }
@ -588,21 +597,21 @@ void PressureEqualizer::adjust_volumetric_rate()
line_idx = idx_next; line_idx = idx_next;
GCodeLine &line = m_gcode_lines[line_idx]; GCodeLine &line = m_gcode_lines[line_idx];
for (size_t iRole = 1; iRole < erCount; ++ iRole) { for (size_t iRole = 1; iRole < size_t(GCodeExtrusionRole::Count); ++ iRole) {
const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].positive; const float &rate_slope = m_max_volumetric_extrusion_rate_slopes[iRole].positive;
if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max()) if (rate_slope == 0 || feedrate_per_extrusion_role[iRole] == std::numeric_limits<float>::max())
continue; // The positive rate is unlimited or the rate for ExtrusionRole iRole is unlimited. continue; // The positive rate is unlimited or the rate for GCodeExtrusionRole iRole is unlimited.
float rate_start = feedrate_per_extrusion_role[iRole]; float rate_start = feedrate_per_extrusion_role[iRole];
if (!line.adjustable_flow || line.extrusion_role == erExternalPerimeter || line.extrusion_role == erGapFill || line.extrusion_role == erBridgeInfill || line.extrusion_role == erIroning) { if (!line.adjustable_flow || line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter || line.extrusion_role == GCodeExtrusionRole::GapFill || line.extrusion_role == GCodeExtrusionRole::BridgeInfill || line.extrusion_role == GCodeExtrusionRole::Ironing) {
rate_start = line.volumetric_extrusion_rate_start; rate_start = line.volumetric_extrusion_rate_start;
} else if (iRole == line.extrusion_role && rate_prec < rate_start) } else if (iRole == size_t(line.extrusion_role) && rate_prec < rate_start)
rate_start = rate_prec; rate_start = rate_prec;
if (line.volumetric_extrusion_rate_start > rate_start) { if (line.volumetric_extrusion_rate_start > rate_start) {
line.volumetric_extrusion_rate_start = rate_start; line.volumetric_extrusion_rate_start = rate_start;
line.max_volumetric_extrusion_rate_slope_positive = rate_slope; line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
line.modified = true; line.modified = true;
} else if (iRole == line.extrusion_role) { } else if (iRole == size_t(line.extrusion_role)) {
rate_start = line.volumetric_extrusion_rate_start; rate_start = line.volumetric_extrusion_rate_start;
} else { } else {
// Use the original, 'floating' extrusion rate as a starting point for the limiter. // Use the original, 'floating' extrusion rate as a starting point for the limiter.
@ -620,7 +629,7 @@ void PressureEqualizer::adjust_volumetric_rate()
} }
// feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_end : rate_end; // feedrate_per_extrusion_role[iRole] = (iRole == line.extrusion_role) ? line.volumetric_extrusion_rate_end : rate_end;
// Don't store feed rate for ironing and gap-fill. // Don't store feed rate for ironing and gap-fill.
if (line.extrusion_role != erIroning && line.extrusion_role != erGapFill) if (line.extrusion_role != GCodeExtrusionRole::Ironing && line.extrusion_role != GCodeExtrusionRole::GapFill)
feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_end; feedrate_per_extrusion_role[iRole] = line.volumetric_extrusion_rate_end;
} }
} }
@ -704,7 +713,7 @@ void PressureEqualizer::push_line_to_output(const size_t line_idx, const float n
GCodeG1Formatter feedrate_formatter; GCodeG1Formatter feedrate_formatter;
feedrate_formatter.emit_f(new_feedrate); feedrate_formatter.emit_f(new_feedrate);
feedrate_formatter.emit_string(std::string(EXTRUDE_SET_SPEED_TAG.data(), EXTRUDE_SET_SPEED_TAG.length())); feedrate_formatter.emit_string(std::string(EXTRUDE_SET_SPEED_TAG.data(), EXTRUDE_SET_SPEED_TAG.length()));
if (line.extrusion_role == erExternalPerimeter) if (line.extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
feedrate_formatter.emit_string(std::string(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG.length())); feedrate_formatter.emit_string(std::string(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG.length()));
push_to_output(feedrate_formatter); push_to_output(feedrate_formatter);

View File

@ -3,7 +3,7 @@
#include "../libslic3r.h" #include "../libslic3r.h"
#include "../PrintConfig.hpp" #include "../PrintConfig.hpp"
#include "../ExtrusionEntity.hpp" #include "../ExtrusionRole.hpp"
#include <queue> #include <queue>
@ -65,7 +65,7 @@ private:
float positive; float positive;
float negative; float negative;
}; };
ExtrusionRateSlope m_max_volumetric_extrusion_rate_slopes[erCount]; ExtrusionRateSlope m_max_volumetric_extrusion_rate_slopes[size_t(GCodeExtrusionRole::Count)];
float m_max_volumetric_extrusion_rate_slope_positive; float m_max_volumetric_extrusion_rate_slope_positive;
float m_max_volumetric_extrusion_rate_slope_negative; float m_max_volumetric_extrusion_rate_slope_negative;
@ -77,7 +77,7 @@ private:
// X,Y,Z,E,F // X,Y,Z,E,F
float m_current_pos[5]; float m_current_pos[5];
size_t m_current_extruder; size_t m_current_extruder;
ExtrusionRole m_current_extrusion_role; GCodeExtrusionRole m_current_extrusion_role;
bool m_retracted; bool m_retracted;
bool m_use_relative_e_distances; bool m_use_relative_e_distances;
@ -149,7 +149,7 @@ private:
// Index of the active extruder. // Index of the active extruder.
size_t extruder_id; size_t extruder_id;
// Extrusion role of this segment. // Extrusion role of this segment.
ExtrusionRole extrusion_role; GCodeExtrusionRole extrusion_role;
// Current volumetric extrusion rate. // Current volumetric extrusion rate.
float volumetric_extrusion_rate; float volumetric_extrusion_rate;

View File

@ -407,13 +407,13 @@ Polygons extract_perimeter_polygons(const Layer *layer, std::vector<const LayerR
ExtrusionRole role = perimeter->role(); ExtrusionRole role = perimeter->role();
if (perimeter->is_loop()) { if (perimeter->is_loop()) {
for (const ExtrusionPath &path : static_cast<const ExtrusionLoop*>(perimeter)->paths) { for (const ExtrusionPath &path : static_cast<const ExtrusionLoop*>(perimeter)->paths) {
if (path.role() == ExtrusionRole::erExternalPerimeter) { if (path.role() == ExtrusionRole::ExternalPerimeter) {
role = ExtrusionRole::erExternalPerimeter; role = ExtrusionRole::ExternalPerimeter;
} }
} }
} }
if (role == ExtrusionRole::erExternalPerimeter) { if (role == ExtrusionRole::ExternalPerimeter) {
Points p; Points p;
perimeter->collect_points(p); perimeter->collect_points(p);
polygons.emplace_back(std::move(p)); polygons.emplace_back(std::move(p));
@ -1071,7 +1071,7 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
for (SeamCandidate &perimeter_point : layers[layer_idx].points) { for (SeamCandidate &perimeter_point : layers[layer_idx].points) {
Vec2f point = Vec2f { perimeter_point.position.head<2>() }; Vec2f point = Vec2f { perimeter_point.position.head<2>() };
if (prev_layer_distancer.get() != nullptr) { if (prev_layer_distancer.get() != nullptr) {
perimeter_point.overhang = prev_layer_distancer->signed_distance_from_lines(point.cast<double>()) perimeter_point.overhang = prev_layer_distancer->distance_from_lines<true>(point.cast<double>())
+ 0.6f * perimeter_point.perimeter.flow_width + 0.6f * perimeter_point.perimeter.flow_width
- tan(SeamPlacer::overhang_angle_threshold) - tan(SeamPlacer::overhang_angle_threshold)
* po->layers()[layer_idx]->height; * po->layers()[layer_idx]->height;
@ -1080,7 +1080,7 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
} }
if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam) if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam)
perimeter_point.embedded_distance = current_layer_distancer->signed_distance_from_lines(point.cast<double>()) perimeter_point.embedded_distance = current_layer_distancer->distance_from_lines<true>(point.cast<double>())
+ 0.6f * perimeter_point.perimeter.flow_width; + 0.6f * perimeter_point.perimeter.flow_width;
} }
} }
@ -1548,7 +1548,7 @@ void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool extern
Point seam_point = Point::new_scale(seam_position.x(), seam_position.y()); Point seam_point = Point::new_scale(seam_position.x(), seam_position.y());
if (loop.role() == ExtrusionRole::erPerimeter) { //Hopefully inner perimeter if (loop.role() == ExtrusionRole::Perimeter) { //Hopefully inner perimeter
const SeamCandidate &perimeter_point = layer_perimeters.points[seam_index]; const SeamCandidate &perimeter_point = layer_perimeters.points[seam_index];
ExtrusionLoop::ClosestPathPoint projected_point = loop.get_closest_path_and_point(seam_point, false); ExtrusionLoop::ClosestPathPoint projected_point = loop.get_closest_path_and_point(seam_point, false);
// determine depth of the seam point. // determine depth of the seam point.

View File

@ -63,11 +63,11 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
assert(region.config().infill_extruder.value > 0); assert(region.config().infill_extruder.value > 0);
assert(region.config().solid_infill_extruder.value > 0); assert(region.config().solid_infill_extruder.value > 0);
// 1 based extruder ID. // 1 based extruder ID.
unsigned int extruder = ((this->extruder_override == 0) ? unsigned int extruder = this->extruder_override == 0 ?
(is_infill(extrusions.role()) ? (extrusions.role().is_infill() ?
(is_solid_infill(extrusions.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) : (extrusions.entities.front()->role().is_solid_infill() ? region.config().solid_infill_extruder : region.config().infill_extruder) :
region.config().perimeter_extruder.value) : region.config().perimeter_extruder.value) :
this->extruder_override); this->extruder_override;
return (extruder == 0) ? 0 : extruder - 1; return (extruder == 0) ? 0 : extruder - 1;
} }
@ -197,7 +197,7 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
if (object.config().wipe_into_objects) if (object.config().wipe_into_objects)
return true; return true;
if (!region.config().wipe_into_infill || eec.role() != erInternalInfill) if (!region.config().wipe_into_infill || eec.role() != ExtrusionRole::InternalInfill)
return false; return false;
return true; return true;
@ -210,8 +210,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
for (auto support_layer : object.support_layers()) { for (auto support_layer : object.support_layers()) {
LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z); LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z);
ExtrusionRole role = support_layer->support_fills.role(); ExtrusionRole role = support_layer->support_fills.role();
bool has_support = role == erMixed || role == erSupportMaterial; bool has_support = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterial;
bool has_interface = role == erMixed || role == erSupportMaterialInterface; bool has_interface = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterialInterface;
unsigned int extruder_support = object.config().support_material_extruder.value; unsigned int extruder_support = object.config().support_material_extruder.value;
unsigned int extruder_interface = object.config().support_material_interface_extruder.value; unsigned int extruder_interface = object.config().support_material_interface_extruder.value;
if (has_support) if (has_support)
@ -266,10 +266,10 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
for (const ExtrusionEntity *ee : layerm->fills()) { for (const ExtrusionEntity *ee : layerm->fills()) {
// fill represents infill extrusions of a single island. // fill represents infill extrusions of a single island.
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee); const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
ExtrusionRole role = fill->entities.empty() ? erNone : fill->entities.front()->role(); ExtrusionRole role = fill->entities.empty() ? ExtrusionRole::None : fill->entities.front()->role();
if (is_solid_infill(role)) if (role.is_solid_infill())
has_solid_infill = true; has_solid_infill = true;
else if (role != erNone) else if (role != ExtrusionRole::None)
has_infill = true; has_infill = true;
if (m_print_config_ptr) { if (m_print_config_ptr) {

View File

@ -37,7 +37,7 @@ public:
// adds tag for analyzer: // adds tag for analyzer:
std::ostringstream str; std::ostringstream str;
str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) << m_layer_height << "\n"; // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) << m_layer_height << "\n"; // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role) << ExtrusionEntity::role_to_string(erWipeTower) << "\n"; str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role) << gcode_extrusion_role_to_string(GCodeExtrusionRole::WipeTower) << "\n";
m_gcode += str.str(); m_gcode += str.str();
change_analyzer_line_width(line_width); change_analyzer_line_width(line_width);
} }
@ -71,6 +71,8 @@ public:
return *this; return *this;
} }
WipeTowerWriter& set_position(const Vec2f &pos) { m_current_pos = pos; return *this; }
WipeTowerWriter& set_initial_tool(size_t tool) { m_current_tool = tool; return *this; } WipeTowerWriter& set_initial_tool(size_t tool) { m_current_tool = tool; return *this; }
WipeTowerWriter& set_z(float z) WipeTowerWriter& set_z(float z)
@ -806,6 +808,8 @@ void WipeTower::toolchange_Unload(
const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness
const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm
const Vec2f ramming_start_pos = Vec2f(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f);
writer.append("; CP TOOLCHANGE UNLOAD\n") writer.append("; CP TOOLCHANGE UNLOAD\n")
.change_analyzer_line_width(line_width); .change_analyzer_line_width(line_width);
@ -814,10 +818,12 @@ void WipeTower::toolchange_Unload(
float remaining = xr - xl ; // keeps track of distance to the next turnaround float remaining = xr - xl ; // keeps track of distance to the next turnaround
float e_done = 0; // measures E move done from each segment float e_done = 0; // measures E move done from each segment
writer.travel(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f ); // move to starting position if (m_semm)
writer.travel(ramming_start_pos); // move to starting position
else
writer.set_position(ramming_start_pos);
// if the ending point of the ram would end up in mid air, align it with the end of the wipe tower: // if the ending point of the ram would end up in mid air, align it with the end of the wipe tower:
if (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion )) { if (m_semm && (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion ))) {
// this is y of the center of previous sparse infill border // this is y of the center of previous sparse infill border
float sparse_beginning_y = 0.f; float sparse_beginning_y = 0.f;
@ -849,7 +855,7 @@ void WipeTower::toolchange_Unload(
writer.disable_linear_advance(); writer.disable_linear_advance();
// now the ramming itself: // now the ramming itself:
while (i < m_filpar[m_current_tool].ramming_speed.size()) while (m_semm && i < m_filpar[m_current_tool].ramming_speed.size())
{ {
const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * 0.25f, line_width, m_layer_height); const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * 0.25f, line_width, m_layer_height);
const float e = m_filpar[m_current_tool].ramming_speed[i] * 0.25f / filament_area(); // transform volume per sec to E move; const float e = m_filpar[m_current_tool].ramming_speed[i] * 0.25f / filament_area(); // transform volume per sec to E move;
@ -898,7 +904,7 @@ void WipeTower::toolchange_Unload(
// Cooling: // Cooling:
const int& number_of_moves = m_filpar[m_current_tool].cooling_moves; const int& number_of_moves = m_filpar[m_current_tool].cooling_moves;
if (number_of_moves > 0) { if (m_semm && number_of_moves > 0) {
const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed; const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed;
const float& final_speed = m_filpar[m_current_tool].cooling_final_speed; const float& final_speed = m_filpar[m_current_tool].cooling_final_speed;
@ -916,14 +922,20 @@ void WipeTower::toolchange_Unload(
} }
} }
if (m_semm) {
// let's wait is necessary: // let's wait is necessary:
writer.wait(m_filpar[m_current_tool].delay); writer.wait(m_filpar[m_current_tool].delay);
// we should be at the beginning of the cooling tube again - let's move to parking position: // we should be at the beginning of the cooling tube again - let's move to parking position:
writer.retract(-m_cooling_tube_length/2.f+m_parking_pos_retraction-m_cooling_tube_retraction, 2000); writer.retract(-m_cooling_tube_length/2.f+m_parking_pos_retraction-m_cooling_tube_retraction, 2000);
}
// this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start: // this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start:
// the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material // the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material
writer.travel(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing-m_perimeter_width) / 2.f + m_perimeter_width, 2400.f); Vec2f pos = Vec2f(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing-m_perimeter_width) / 2.f + m_perimeter_width);
if (m_semm)
writer.travel(pos, 2400.f);
else
writer.set_position(pos);
writer.resume_preview() writer.resume_preview()
.flush_planner_queue(); .flush_planner_queue();
@ -941,7 +953,7 @@ void WipeTower::toolchange_Change(
// This is where we want to place the custom gcodes. We will use placeholders for this. // This is where we want to place the custom gcodes. We will use placeholders for this.
// These will be substituted by the actual gcodes when the gcode is generated. // These will be substituted by the actual gcodes when the gcode is generated.
writer.append("[end_filament_gcode]\n"); //writer.append("[end_filament_gcode]\n");
writer.append("[toolchange_gcode]\n"); writer.append("[toolchange_gcode]\n");
// Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc) // Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc)
@ -952,11 +964,12 @@ void WipeTower::toolchange_Change(
.append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x()) .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x())
+ " Y" + Slic3r::float_to_string_decimal_point(current_pos.y()) + " Y" + Slic3r::float_to_string_decimal_point(current_pos.y())
+ never_skip_tag() + "\n"); + never_skip_tag() + "\n");
writer.append("[deretraction_from_wipe_tower_generator]");
// The toolchange Tn command will be inserted later, only in case that the user does // The toolchange Tn command will be inserted later, only in case that the user does
// not provide a custom toolchange gcode. // not provide a custom toolchange gcode.
writer.set_tool(new_tool); // This outputs nothing, the writer just needs to know the tool has changed. writer.set_tool(new_tool); // This outputs nothing, the writer just needs to know the tool has changed.
writer.append("[start_filament_gcode]\n"); //writer.append("[start_filament_gcode]\n");
writer.flush_planner_queue(); writer.flush_planner_queue();
m_current_tool = new_tool; m_current_tool = new_tool;
@ -1374,8 +1387,10 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
layer_result.emplace_back(std::move(finish_layer_tcr)); layer_result.emplace_back(std::move(finish_layer_tcr));
} }
else { else {
if (idx == -1) if (idx == -1) {
layer_result[0] = merge_tcr(finish_layer_tcr, layer_result[0]); layer_result[0] = merge_tcr(finish_layer_tcr, layer_result[0]);
layer_result[0].force_travel = true;
}
else else
layer_result[idx] = merge_tcr(layer_result[idx], finish_layer_tcr); layer_result[idx] = merge_tcr(layer_result[idx], finish_layer_tcr);
} }

View File

@ -82,6 +82,8 @@ public:
} }
return e_length; return e_length;
} }
bool force_travel = false;
}; };
struct box_coordinates struct box_coordinates
@ -290,7 +292,6 @@ private:
// Extruder specific parameters. // Extruder specific parameters.
std::vector<FilamentParameters> m_filpar; std::vector<FilamentParameters> m_filpar;
// State of the wipe tower generator. // State of the wipe tower generator.
unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics. unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics. unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.

View File

@ -728,7 +728,7 @@ void Transformation::reset_skew()
const double average_scale = std::cbrt(scale(0, 0) * scale(1, 1) * scale(2, 2)); const double average_scale = std::cbrt(scale(0, 0) * scale(1, 1) * scale(2, 2));
scale(0, 0) = average_scale; scale(0, 0) = is_left_handed() ? -average_scale : average_scale;
scale(1, 1) = average_scale; scale(1, 1) = average_scale;
scale(2, 2) = average_scale; scale(2, 2) = average_scale;
@ -872,18 +872,15 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot
} }
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_to)
{ {
const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); auto m = trafo_to.linear() * trafo_from.linear().inverse();
const Vec3d& axis = angle_axis.axis(); assert(std::abs(m.determinant() - 1) < EPSILON);
const double angle = angle_axis.angle(); Vec3d vx = m * Vec3d(1., 0., 0);
#ifndef NDEBUG // Verify that the linear part of rotation from trafo_from to trafo_to rotates around Z and is unity.
if (std::abs(angle) > 1e-8) { assert(std::abs(std::hypot(vx.x(), vx.y()) - 1.) < 1e-5);
assert(std::abs(axis.x()) < 1e-8); assert(std::abs(vx.z()) < 1e-5);
assert(std::abs(axis.y()) < 1e-8); return atan2(vx.y(), vx.x());
}
#endif /* NDEBUG */
return (axis.z() < 0) ? -angle : angle;
} }
}} // namespace Slic3r::Geometry }} // namespace Slic3r::Geometry

View File

@ -470,8 +470,7 @@ public:
Transform3d get_mirror_matrix() const; Transform3d get_mirror_matrix() const;
bool is_left_handed() const { bool is_left_handed() const {
const Vec3d mirror = get_mirror(); return m_matrix.linear().determinant() < 0;
return mirror.x() * mirror.y() * mirror.z() < 0.0;
} }
#else #else
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; } bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
@ -547,7 +546,7 @@ extern Transform3d transform3d_from_string(const std::string& transform_str);
extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to);
// Rotation by Z to align rot_xyz_from to rot_xyz_to. // Rotation by Z to align rot_xyz_from to rot_xyz_to.
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); extern double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_to);
// Is the angle close to a multiple of 90 degrees? // Is the angle close to a multiple of 90 degrees?
inline bool is_rotation_ninety_degrees(double a) inline bool is_rotation_ninety_degrees(double a)

View File

@ -495,6 +495,7 @@ void MedialAxis::build(ThickPolylines* polylines)
polyline.width.emplace_back(seed_edge_data.width_end); polyline.width.emplace_back(seed_edge_data.width_end);
// Grow the polyline in a forward direction. // Grow the polyline in a forward direction.
this->process_edge_neighbors(&*seed_edge, &polyline); this->process_edge_neighbors(&*seed_edge, &polyline);
assert(polyline.width.size() == polyline.points.size() * 2 - 2);
// Grow the polyline in a backward direction. // Grow the polyline in a backward direction.
reverse_polyline.clear(); reverse_polyline.clear();
@ -502,7 +503,6 @@ void MedialAxis::build(ThickPolylines* polylines)
polyline.points.insert(polyline.points.begin(), reverse_polyline.points.rbegin(), reverse_polyline.points.rend()); polyline.points.insert(polyline.points.begin(), reverse_polyline.points.rbegin(), reverse_polyline.points.rend());
polyline.width.insert(polyline.width.begin(), reverse_polyline.width.rbegin(), reverse_polyline.width.rend()); polyline.width.insert(polyline.width.begin(), reverse_polyline.width.rbegin(), reverse_polyline.width.rend());
polyline.endpoints.first = reverse_polyline.endpoints.second; polyline.endpoints.first = reverse_polyline.endpoints.second;
assert(polyline.width.size() == polyline.points.size() * 2 - 2); assert(polyline.width.size() == polyline.points.size() * 2 - 2);
// Prevent loop endpoints from being extended. // Prevent loop endpoints from being extended.
@ -535,7 +535,9 @@ void MedialAxis::build(Polylines* polylines)
{ {
ThickPolylines tp; ThickPolylines tp;
this->build(&tp); this->build(&tp);
polylines->insert(polylines->end(), tp.begin(), tp.end()); polylines->reserve(polylines->size() + tp.size());
for (auto &pl : tp)
polylines->emplace_back(pl.points);
} }
void MedialAxis::process_edge_neighbors(const VD::edge_type *edge, ThickPolyline* polyline) void MedialAxis::process_edge_neighbors(const VD::edge_type *edge, ThickPolyline* polyline)

View File

@ -8,17 +8,135 @@
#include "VoronoiUtilsCgal.hpp" #include "VoronoiUtilsCgal.hpp"
using VD = Slic3r::Geometry::VoronoiDiagram; using VD = Slic3r::Geometry::VoronoiDiagram;
using namespace Slic3r::Arachne;
namespace Slic3r::Geometry { namespace Slic3r::Geometry {
using CGAL_Point = CGAL::Exact_predicates_exact_constructions_kernel::Point_2; // The tangent vector of the parabola is computed based on the Proof of the reflective property.
using CGAL_Segment = CGAL::Arr_segment_traits_2<CGAL::Exact_predicates_exact_constructions_kernel>::Curve_2; // https://en.wikipedia.org/wiki/Parabola#Proof_of_the_reflective_property
// https://math.stackexchange.com/q/2439647/2439663#comment5039739_2439663
namespace impl {
using K = CGAL::Simple_cartesian<double>;
using FK = CGAL::Simple_cartesian<CGAL::Interval_nt_advanced>;
using EK = CGAL::Simple_cartesian<CGAL::MP_Float>;
using C2E = CGAL::Cartesian_converter<K, EK>;
using C2F = CGAL::Cartesian_converter<K, FK>;
class Epick : public CGAL::Filtered_kernel_adaptor<CGAL::Type_equality_wrapper<K::Base<Epick>::Type, Epick>, true> {};
inline static CGAL_Point to_cgal_point(const VD::vertex_type &pt) { return {pt.x(), pt.y()}; } template<typename K>
inline typename K::Vector_2 calculate_parabolic_tangent_vector(
// Test point on the parabola, where the tangent will be calculated.
const typename K::Point_2 &p,
// Focus point of the parabola.
const typename K::Point_2 &f,
// Points of a directrix of the parabola.
const typename K::Point_2 &u,
const typename K::Point_2 &v,
// On which side of the parabolic segment endpoints the focus point is, which determines the orientation of the tangent.
const typename K::Orientation &tangent_orientation)
{
using RT = typename K::RT;
using Vector_2 = typename K::Vector_2;
const Vector_2 directrix_vec = v - u;
const RT directrix_vec_sqr_length = CGAL::scalar_product(directrix_vec, directrix_vec);
Vector_2 focus_vec = (f - u) * directrix_vec_sqr_length - directrix_vec * CGAL::scalar_product(directrix_vec, p - u);
Vector_2 tangent_vec = focus_vec.perpendicular(tangent_orientation);
return tangent_vec;
}
template<typename K> struct ParabolicTangentToSegmentOrientationPredicate
{
using Point_2 = typename K::Point_2;
using Vector_2 = typename K::Vector_2;
using Orientation = typename K::Orientation;
using result_type = typename K::Orientation;
result_type operator()(
// Test point on the parabola, where the tangent will be calculated.
const Point_2 &p,
// End of the linear segment (p, q), for which orientation towards the tangent to parabola will be evaluated.
const Point_2 &q,
// Focus point of the parabola.
const Point_2 &f,
// Points of a directrix of the parabola.
const Point_2 &u,
const Point_2 &v,
// On which side of the parabolic segment endpoints the focus point is, which determines the orientation of the tangent.
const Orientation &tangent_orientation) const
{
assert(tangent_orientation == CGAL::Orientation::LEFT_TURN || tangent_orientation == CGAL::Orientation::RIGHT_TURN);
Vector_2 tangent_vec = calculate_parabolic_tangent_vector<K>(p, f, u, v, tangent_orientation);
Vector_2 linear_vec = q - p;
return CGAL::sign(tangent_vec.x() * linear_vec.y() - tangent_vec.y() * linear_vec.x());
}
};
template<typename K> struct ParabolicTangentToParabolicTangentOrientationPredicate
{
using Point_2 = typename K::Point_2;
using Vector_2 = typename K::Vector_2;
using Orientation = typename K::Orientation;
using result_type = typename K::Orientation;
result_type operator()(
// Common point on both parabolas, where the tangent will be calculated.
const Point_2 &p,
// Focus point of the first parabola.
const Point_2 &f_0,
// Points of a directrix of the first parabola.
const Point_2 &u_0,
const Point_2 &v_0,
// On which side of the parabolic segment endpoints the focus point is, which determines the orientation of the tangent.
const Orientation &tangent_orientation_0,
// Focus point of the second parabola.
const Point_2 &f_1,
// Points of a directrix of the second parabola.
const Point_2 &u_1,
const Point_2 &v_1,
// On which side of the parabolic segment endpoints the focus point is, which determines the orientation of the tangent.
const Orientation &tangent_orientation_1) const
{
assert(tangent_orientation_0 == CGAL::Orientation::LEFT_TURN || tangent_orientation_0 == CGAL::Orientation::RIGHT_TURN);
assert(tangent_orientation_1 == CGAL::Orientation::LEFT_TURN || tangent_orientation_1 == CGAL::Orientation::RIGHT_TURN);
Vector_2 tangent_vec_0 = calculate_parabolic_tangent_vector<K>(p, f_0, u_0, v_0, tangent_orientation_0);
Vector_2 tangent_vec_1 = calculate_parabolic_tangent_vector<K>(p, f_1, u_1, v_1, tangent_orientation_1);
return CGAL::sign(tangent_vec_0.x() * tangent_vec_1.y() - tangent_vec_0.y() * tangent_vec_1.x());
}
};
using ParabolicTangentToSegmentOrientationPredicateFiltered = CGAL::Filtered_predicate<ParabolicTangentToSegmentOrientationPredicate<EK>, ParabolicTangentToSegmentOrientationPredicate<FK>, C2E, C2F>;
using ParabolicTangentToParabolicTangentOrientationPredicateFiltered = CGAL::Filtered_predicate<ParabolicTangentToParabolicTangentOrientationPredicate<EK>, ParabolicTangentToParabolicTangentOrientationPredicate<FK>, C2E, C2F>;
} // namespace impl
using ParabolicTangentToSegmentOrientation = impl::ParabolicTangentToSegmentOrientationPredicateFiltered;
using ParabolicTangentToParabolicTangentOrientation = impl::ParabolicTangentToParabolicTangentOrientationPredicateFiltered;
using CGAL_Point = impl::K::Point_2;
inline static CGAL_Point to_cgal_point(const VD::vertex_type *pt) { return {pt->x(), pt->y()}; }
inline static CGAL_Point to_cgal_point(const Point &pt) { return {pt.x(), pt.y()}; }
inline static CGAL_Point to_cgal_point(const Vec2d &pt) { return {pt.x(), pt.y()}; }
inline static Linef make_linef(const VD::edge_type &edge)
{
const VD::vertex_type *v0 = edge.vertex0();
const VD::vertex_type *v1 = edge.vertex1();
return {Vec2d(v0->x(), v0->y()), Vec2d(v1->x(), v1->y())};
}
inline static bool is_equal(const VD::vertex_type &first, const VD::vertex_type &second) { return first.x() == second.x() && first.y() == second.y(); }
// FIXME Lukas H.: Also includes parabolic segments. // FIXME Lukas H.: Also includes parabolic segments.
bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_diagram) bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_diagram)
{ {
using CGAL_Point = CGAL::Exact_predicates_exact_constructions_kernel::Point_2;
using CGAL_Segment = CGAL::Arr_segment_traits_2<CGAL::Exact_predicates_exact_constructions_kernel>::Curve_2;
auto to_cgal_point = [](const VD::vertex_type &pt) -> CGAL_Point { return {pt.x(), pt.y()}; };
assert(std::all_of(voronoi_diagram.edges().cbegin(), voronoi_diagram.edges().cend(), assert(std::all_of(voronoi_diagram.edges().cbegin(), voronoi_diagram.edges().cend(),
[](const VD::edge_type &edge) { return edge.color() == 0; })); [](const VD::edge_type &edge) { return edge.color() == 0; }));
@ -30,7 +148,7 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_
continue; continue;
if (edge.is_finite() && edge.is_linear() && edge.vertex0() != nullptr && edge.vertex1() != nullptr && if (edge.is_finite() && edge.is_linear() && edge.vertex0() != nullptr && edge.vertex1() != nullptr &&
Arachne::VoronoiUtils::is_finite(*edge.vertex0()) && Arachne::VoronoiUtils::is_finite(*edge.vertex1())) { VoronoiUtils::is_finite(*edge.vertex0()) && VoronoiUtils::is_finite(*edge.vertex1())) {
segments.emplace_back(to_cgal_point(*edge.vertex0()), to_cgal_point(*edge.vertex1())); segments.emplace_back(to_cgal_point(*edge.vertex0()), to_cgal_point(*edge.vertex1()));
edge.color(1); edge.color(1);
assert(edge.twin() != nullptr); assert(edge.twin() != nullptr);
@ -46,37 +164,101 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_
return intersections_pt.empty(); return intersections_pt.empty();
} }
static bool check_if_three_vectors_are_ccw(const CGAL_Point &common_pt, const CGAL_Point &pt_1, const CGAL_Point &pt_2, const CGAL_Point &test_pt) { struct ParabolicSegment
CGAL::Orientation orientation = CGAL::orientation(common_pt, pt_1, pt_2); {
const Point focus;
const Line directrix;
// Two points on the parabola;
const Linef segment;
// Indicate if focus point is on the left side or right side relative to parabolic segment endpoints.
const CGAL::Orientation is_focus_on_left;
};
inline static ParabolicSegment get_parabolic_segment(const VD::edge_type &edge, const std::vector<VoronoiUtils::Segment> &segments)
{
assert(edge.is_curved());
const VD::cell_type *left_cell = edge.cell();
const VD::cell_type *right_cell = edge.twin()->cell();
const Point focus_pt = VoronoiUtils::getSourcePoint(*(left_cell->contains_point() ? left_cell : right_cell), segments);
const VoronoiUtils::Segment &directrix = VoronoiUtils::getSourceSegment(*(left_cell->contains_point() ? right_cell : left_cell), segments);
CGAL::Orientation focus_side = CGAL::opposite(CGAL::orientation(to_cgal_point(edge.vertex0()), to_cgal_point(edge.vertex1()), to_cgal_point(focus_pt)));
assert(focus_side == CGAL::Orientation::LEFT_TURN || focus_side == CGAL::Orientation::RIGHT_TURN);
return {focus_pt, Line(directrix.from(), directrix.to()), make_linef(edge), focus_side};
}
inline static CGAL::Orientation orientation_of_two_edges(const VD::edge_type &edge_a, const VD::edge_type &edge_b, const std::vector<VoronoiUtils::Segment> &segments) {
assert(is_equal(*edge_a.vertex0(), *edge_b.vertex0()));
CGAL::Orientation orientation;
if (edge_a.is_linear() && edge_b.is_linear()) {
orientation = CGAL::orientation(to_cgal_point(edge_a.vertex0()), to_cgal_point(edge_a.vertex1()), to_cgal_point(edge_b.vertex1()));
} else if (edge_a.is_curved() && edge_b.is_curved()) {
const ParabolicSegment parabolic_a = get_parabolic_segment(edge_a, segments);
const ParabolicSegment parabolic_b = get_parabolic_segment(edge_b, segments);
orientation = ParabolicTangentToParabolicTangentOrientation{}(to_cgal_point(parabolic_a.segment.a),
to_cgal_point(parabolic_a.focus),
to_cgal_point(parabolic_a.directrix.a),
to_cgal_point(parabolic_a.directrix.b),
parabolic_a.is_focus_on_left,
to_cgal_point(parabolic_b.focus),
to_cgal_point(parabolic_b.directrix.a),
to_cgal_point(parabolic_b.directrix.b),
parabolic_b.is_focus_on_left);
return orientation;
} else {
assert(edge_a.is_curved() != edge_b.is_curved());
const VD::edge_type &linear_edge = edge_a.is_curved() ? edge_b : edge_a;
const VD::edge_type &parabolic_edge = edge_a.is_curved() ? edge_a : edge_b;
const ParabolicSegment parabolic = get_parabolic_segment(parabolic_edge, segments);
orientation = ParabolicTangentToSegmentOrientation{}(to_cgal_point(parabolic.segment.a), to_cgal_point(linear_edge.vertex1()),
to_cgal_point(parabolic.focus),
to_cgal_point(parabolic.directrix.a),
to_cgal_point(parabolic.directrix.b),
parabolic.is_focus_on_left);
if (edge_b.is_curved())
orientation = CGAL::opposite(orientation);
}
return orientation;
}
static bool check_if_three_edges_are_ccw(const VD::edge_type &first, const VD::edge_type &second, const VD::edge_type &third, const std::vector<VoronoiUtils::Segment> &segments)
{
assert(is_equal(*first.vertex0(), *second.vertex0()) && is_equal(*second.vertex0(), *third.vertex0()));
CGAL::Orientation orientation = orientation_of_two_edges(first, second, segments);
if (orientation == CGAL::Orientation::COLLINEAR) { if (orientation == CGAL::Orientation::COLLINEAR) {
// The first two edges are collinear, so the third edge must be on the right side on the first of them. // The first two edges are collinear, so the third edge must be on the right side on the first of them.
return CGAL::orientation(common_pt, pt_1, test_pt) == CGAL::Orientation::RIGHT_TURN; return orientation_of_two_edges(first, third, segments) == CGAL::Orientation::RIGHT_TURN;
} else if (orientation == CGAL::Orientation::LEFT_TURN) { } else if (orientation == CGAL::Orientation::LEFT_TURN) {
// CCW oriented angle between vectors (common_pt, pt1) and (common_pt, pt2) is bellow PI. // CCW oriented angle between vectors (common_pt, pt1) and (common_pt, pt2) is bellow PI.
// So we need to check if test_pt isn't between them. // So we need to check if test_pt isn't between them.
CGAL::Orientation orientation1 = CGAL::orientation(common_pt, pt_1, test_pt); CGAL::Orientation orientation1 = orientation_of_two_edges(first, third, segments);
CGAL::Orientation orientation2 = CGAL::orientation(common_pt, pt_2, test_pt); CGAL::Orientation orientation2 = orientation_of_two_edges(second, third, segments);
return (orientation1 != CGAL::Orientation::LEFT_TURN || orientation2 != CGAL::Orientation::RIGHT_TURN); return (orientation1 != CGAL::Orientation::LEFT_TURN || orientation2 != CGAL::Orientation::RIGHT_TURN);
} else { } else {
assert(orientation == CGAL::Orientation::RIGHT_TURN); assert(orientation == CGAL::Orientation::RIGHT_TURN);
// CCW oriented angle between vectors (common_pt, pt1) and (common_pt, pt2) is upper PI. // CCW oriented angle between vectors (common_pt, pt1) and (common_pt, pt2) is upper PI.
// So we need to check if test_pt is between them. // So we need to check if test_pt is between them.
CGAL::Orientation orientation1 = CGAL::orientation(common_pt, pt_1, test_pt); CGAL::Orientation orientation1 = orientation_of_two_edges(first, third, segments);
CGAL::Orientation orientation2 = CGAL::orientation(common_pt, pt_2, test_pt); CGAL::Orientation orientation2 = orientation_of_two_edges(second, third, segments);
return (orientation1 == CGAL::Orientation::RIGHT_TURN || orientation2 == CGAL::Orientation::LEFT_TURN); return (orientation1 == CGAL::Orientation::RIGHT_TURN || orientation2 == CGAL::Orientation::LEFT_TURN);
} }
} }
bool VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(const VoronoiDiagram &voronoi_diagram) bool VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(const VoronoiDiagram &voronoi_diagram, const std::vector<VoronoiUtils::Segment> &segments)
{ {
for (const VD::vertex_type &vertex : voronoi_diagram.vertices()) { for (const VD::vertex_type &vertex : voronoi_diagram.vertices()) {
std::vector<const VD::edge_type *> edges; std::vector<const VD::edge_type *> edges;
const VD::edge_type *edge = vertex.incident_edge(); const VD::edge_type *edge = vertex.incident_edge();
do { do {
// FIXME Lukas H.: Also process parabolic segments. if (edge->is_finite() && edge->vertex0() != nullptr && edge->vertex1() != nullptr &&
if (edge->is_finite() && edge->is_linear() && edge->vertex0() != nullptr && edge->vertex1() != nullptr && VoronoiUtils::is_finite(*edge->vertex0()) && VoronoiUtils::is_finite(*edge->vertex1()))
Arachne::VoronoiUtils::is_finite(*edge->vertex0()) && Arachne::VoronoiUtils::is_finite(*edge->vertex1()))
edges.emplace_back(edge); edges.emplace_back(edge);
edge = edge->rot_next(); edge = edge->rot_next();
@ -89,8 +271,7 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(const VoronoiDiagram &vor
const Geometry::VoronoiDiagram::edge_type *curr_edge = *edge_it; const Geometry::VoronoiDiagram::edge_type *curr_edge = *edge_it;
const Geometry::VoronoiDiagram::edge_type *next_edge = std::next(edge_it) == edges.end() ? edges.front() : *std::next(edge_it); const Geometry::VoronoiDiagram::edge_type *next_edge = std::next(edge_it) == edges.end() ? edges.front() : *std::next(edge_it);
if (!check_if_three_vectors_are_ccw(to_cgal_point(*prev_edge->vertex0()), to_cgal_point(*prev_edge->vertex1()), if (!check_if_three_edges_are_ccw(*prev_edge, *curr_edge, *next_edge, segments))
to_cgal_point(*curr_edge->vertex1()), to_cgal_point(*next_edge->vertex1())))
return false; return false;
} }
} }
@ -99,5 +280,4 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(const VoronoiDiagram &vor
return true; return true;
} }
} // namespace Slic3r::Geometry } // namespace Slic3r::Geometry

View File

@ -2,6 +2,7 @@
#define slic3r_VoronoiUtilsCgal_hpp_ #define slic3r_VoronoiUtilsCgal_hpp_
#include "Voronoi.hpp" #include "Voronoi.hpp"
#include "../Arachne/utils/VoronoiUtils.hpp"
namespace Slic3r::Geometry { namespace Slic3r::Geometry {
class VoronoiDiagram; class VoronoiDiagram;
@ -13,7 +14,7 @@ public:
static bool is_voronoi_diagram_planar_intersection(const VoronoiDiagram &voronoi_diagram); static bool is_voronoi_diagram_planar_intersection(const VoronoiDiagram &voronoi_diagram);
// Check if the Voronoi diagram is planar using verification that all neighboring edges are ordered CCW for each vertex. // Check if the Voronoi diagram is planar using verification that all neighboring edges are ordered CCW for each vertex.
static bool is_voronoi_diagram_planar_angle(const VoronoiDiagram &voronoi_diagram); static bool is_voronoi_diagram_planar_angle(const VoronoiDiagram &voronoi_diagram, const std::vector<Arachne::VoronoiUtils::Segment> &segments);
}; };
} // namespace Slic3r::Geometry } // namespace Slic3r::Geometry

View File

@ -37,6 +37,7 @@ LayerRegion* Layer::add_region(const PrintRegion *print_region)
// merge all regions' slices to get islands // merge all regions' slices to get islands
void Layer::make_slices() void Layer::make_slices()
{
{ {
ExPolygons slices; ExPolygons slices;
if (m_regions.size() == 1) { if (m_regions.size() == 1) {
@ -48,22 +49,26 @@ void Layer::make_slices()
polygons_append(slices_p, to_polygons(layerm->slices().surfaces)); polygons_append(slices_p, to_polygons(layerm->slices().surfaces));
slices = union_safety_offset_ex(slices_p); slices = union_safety_offset_ex(slices_p);
} }
// lslices are sorted by topological order from outside to inside from the clipper union used above
this->lslices = slices;
}
this->lslices.clear(); // prepare lslices ordered by print order
this->lslices.reserve(slices.size()); this->lslice_indices_sorted_by_print_order.clear();
this->lslice_indices_sorted_by_print_order.reserve(lslices.size());
// prepare ordering points // prepare ordering points
Points ordering_points; Points ordering_points;
ordering_points.reserve(slices.size()); ordering_points.reserve( this->lslices.size());
for (const ExPolygon &ex : slices) for (const ExPolygon &ex : this->lslices)
ordering_points.push_back(ex.contour.first_point()); ordering_points.push_back(ex.contour.first_point());
// sort slices // sort slices
std::vector<Points::size_type> order = chain_points(ordering_points); std::vector<Points::size_type> order = chain_points(ordering_points);
// populate slices vector // populate slices vector
for (size_t i : order) for (size_t i : order) {
this->lslices.emplace_back(std::move(slices[i])); this->lslice_indices_sorted_by_print_order.emplace_back(i);
}
} }
// used by Layer::build_up_down_graph() // used by Layer::build_up_down_graph()
@ -465,16 +470,19 @@ void Layer::make_perimeters()
} else { } else {
SurfaceCollection new_slices; SurfaceCollection new_slices;
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence. // Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
LayerRegion *layerm_config = m_regions[layer_region_ids.front()]; uint32_t region_id_config = layer_region_ids.front();
LayerRegion* layerm_config = m_regions[region_id_config];
{ {
// Merge slices (surfaces) according to number of extra perimeters. // Merge slices (surfaces) according to number of extra perimeters.
for (uint32_t region_id : layer_region_ids) { for (uint32_t region_id : layer_region_ids) {
LayerRegion &layerm = *m_regions[region_id]; LayerRegion &layerm = *m_regions[region_id];
for (const Surface &surface : layerm.slices()) for (const Surface &surface : layerm.slices())
surfaces_to_merge.emplace_back(&surface); surfaces_to_merge.emplace_back(&surface);
if (layerm.region().config().fill_density > layerm_config->region().config().fill_density) if (layerm.region().config().fill_density > layerm_config->region().config().fill_density) {
region_id_config = region_id;
layerm_config = &layerm; layerm_config = &layerm;
} }
}
std::sort(surfaces_to_merge.begin(), surfaces_to_merge.end(), [](const Surface *l, const Surface *r){ return l->extra_perimeters < r->extra_perimeters; }); std::sort(surfaces_to_merge.begin(), surfaces_to_merge.end(), [](const Surface *l, const Surface *r){ return l->extra_perimeters < r->extra_perimeters; });
for (size_t i = 0; i < surfaces_to_merge.size();) { for (size_t i = 0; i < surfaces_to_merge.size();) {
size_t j = i; size_t j = i;
@ -493,7 +501,7 @@ void Layer::make_perimeters()
} }
// make perimeters // make perimeters
layerm_config->make_perimeters(new_slices, perimeter_and_gapfill_ranges, fill_expolygons, fill_expolygons_ranges); layerm_config->make_perimeters(new_slices, perimeter_and_gapfill_ranges, fill_expolygons, fill_expolygons_ranges);
this->sort_perimeters_into_islands(new_slices, region_id, perimeter_and_gapfill_ranges, std::move(fill_expolygons), fill_expolygons_ranges, layer_region_ids); this->sort_perimeters_into_islands(new_slices, region_id_config, perimeter_and_gapfill_ranges, std::move(fill_expolygons), fill_expolygons_ranges, layer_region_ids);
} }
} }
} }
@ -533,19 +541,43 @@ void Layer::sort_perimeters_into_islands(
const std::pair<ExtrusionRange, ExtrusionRange> &extrusions = perimeter_and_gapfill_ranges[islice]; const std::pair<ExtrusionRange, ExtrusionRange> &extrusions = perimeter_and_gapfill_ranges[islice];
Point sample; Point sample;
bool sample_set = false; bool sample_set = false;
if (! extrusions.first.empty()) { // Take a sample deep inside its island if available. Infills are usually quite far from the island boundary.
sample = this_layer_region.perimeters().entities[*extrusions.first.begin()]->first_point();
sample_set = true;
} else if (! extrusions.second.empty()) {
sample = this_layer_region.thin_fills().entities[*extrusions.second.begin()]->first_point();
sample_set = true;
} else {
for (uint32_t iexpoly : fill_expolygons_ranges[islice]) for (uint32_t iexpoly : fill_expolygons_ranges[islice])
if (const ExPolygon &expoly = fill_expolygons[iexpoly]; ! expoly.empty()) { if (const ExPolygon &expoly = fill_expolygons[iexpoly]; ! expoly.empty()) {
sample = expoly.contour.points.front(); sample = expoly.contour.points.front();
sample_set = true; sample_set = true;
break; break;
} }
if (! sample_set) {
// If there is no infill, take a sample of some inner perimeter.
for (uint32_t iperimeter : extrusions.first) {
const ExtrusionEntity &ee = *this_layer_region.perimeters().entities[iperimeter];
if (ee.is_collection()) {
for (const ExtrusionEntity *ee2 : dynamic_cast<const ExtrusionEntityCollection&>(ee).entities)
if (! ee2->role().is_external()) {
sample = ee2->first_point();
sample_set = true;
goto loop_end;
}
} else if (! ee.role().is_external()) {
sample = ee.first_point();
sample_set = true;
break;
}
}
loop_end:
if (! sample_set) {
if (! extrusions.second.empty()) {
// If there is no inner perimeter, take a sample of some gap fill extrusion.
sample = this_layer_region.thin_fills().entities[*extrusions.second.begin()]->first_point();
sample_set = true;
}
if (! sample_set && ! extrusions.first.empty()) {
// As a last resort, take a sample of some external perimeter.
sample = this_layer_region.perimeters().entities[*extrusions.first.begin()]->first_point();
sample_set = true;
}
}
} }
// There may be a valid empty island. // There may be a valid empty island.
// assert(sample_set); // assert(sample_set);
@ -694,9 +726,20 @@ void Layer::sort_perimeters_into_islands(
perimeter_slices_queue.pop_back(); perimeter_slices_queue.pop_back();
break; break;
} }
// If anything fails to be sorted in using exact fit, try to find a closest island. if (! perimeter_slices_queue.empty()) {
// If the slice sample was not fitted into any slice using exact fit, try to find a closest island as a last resort.
// This should be a rare event especially if the sample point was taken from infill or inner perimeter,
// however we may land here for external perimeter only islands with fuzzy skin applied.
// Check whether fuzzy skin was enabled and adjust the bounding box accordingly.
const PrintConfig &print_config = this->object()->print()->config();
const PrintRegionConfig &region_config = this_layer_region.region().config();
const auto bbox_eps = scaled<coord_t>(
EPSILON + print_config.gcode_resolution.value +
(region_config.fuzzy_skin.value == FuzzySkinType::None ? 0. : region_config.fuzzy_skin_thickness.value
//FIXME it looks as if Arachne could extend open lines by fuzzy_skin_point_dist, which does not seem right.
+ region_config.fuzzy_skin_point_dist.value));
auto point_inside_surface_dist2 = auto point_inside_surface_dist2 =
[&lslices = this->lslices, &lslices_ex = this->lslices_ex, bbox_eps = scaled<coord_t>(this->object()->print()->config().gcode_resolution.value) + SCALED_EPSILON] [&lslices = this->lslices, &lslices_ex = this->lslices_ex, bbox_eps]
(const size_t lslice_idx, const Point &point) { (const size_t lslice_idx, const Point &point) {
const BoundingBox &bbox = lslices_ex[lslice_idx].bbox; const BoundingBox &bbox = lslices_ex[lslice_idx].bbox;
return return
@ -717,6 +760,7 @@ void Layer::sort_perimeters_into_islands(
insert_into_island(lslice_idx_min, it_source_slice->first); insert_into_island(lslice_idx_min, it_source_slice->first);
} }
} }
}
void Layer::export_region_slices_to_svg(const char *path) const void Layer::export_region_slices_to_svg(const char *path) const
{ {

Some files were not shown because too many files have changed in this diff Show More