Merge remote-tracking branch 'remotes/origin/master' into vb_ensurovani
This commit is contained in:
commit
001358cbba
9
deps/NanoSVG/NanoSVG.cmake
vendored
9
deps/NanoSVG/NanoSVG.cmake
vendored
@ -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
|
||||
URL https://github.com/memononen/nanosvg/archive/4c8f0139b62c6e7faa3b67ce1fbe6e63590ed148.zip
|
||||
URL_HASH SHA256=584e084af1a75bf633f79753ce2f6f6ec8686002ca27f35f1037c25675fecfb6
|
||||
URL https://github.com/fltk/nanosvg/archive/abcd277ea45e9098bed752cf9c6875b533c0892f.zip
|
||||
URL_HASH SHA256=e859938fbaee4b351bd8a8b3d3c7a75b40c36885ce00b73faa1ce0b98aa0ad34
|
||||
)
|
4
deps/wxWidgets/wxWidgets.cmake
vendored
4
deps/wxWidgets/wxWidgets.cmake
vendored
@ -13,8 +13,8 @@ if (UNIX AND NOT APPLE) # wxWidgets will not use char as the underlying type for
|
||||
endif()
|
||||
|
||||
prusaslicer_add_cmake_project(wxWidgets
|
||||
URL https://github.com/prusa3d/wxWidgets/archive/34b524f8d5134a40a90d93a16360d533af2676ae.zip
|
||||
URL_HASH SHA256=e76ca0dd998905c4dbb86f41f264e6e0468504dc2398f7e7e3bba8dc37de2f45
|
||||
URL https://github.com/prusa3d/wxWidgets/archive/4fd2120c913c20c3bb66ee9d01d8ff5087a8b90a.zip
|
||||
URL_HASH SHA256=5b59e8b4dccf73e109c6588f6a69bcfe4e02e930af53c43d5d1329c1f3d83ec9
|
||||
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG dep_NanoSVG
|
||||
CMAKE_ARGS
|
||||
-DwxBUILD_PRECOMP=ON
|
||||
|
@ -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.
|
||||
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:]
|
||||
#text =
|
||||
#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
@ -9,19 +9,26 @@ src/slic3r/GUI/ConfigSnapshotDialog.cpp
|
||||
src/slic3r/GUI/ConfigWizard.cpp
|
||||
src/slic3r/GUI/DesktopIntegrationDialog.cpp
|
||||
src/slic3r/GUI/DoubleSlider.cpp
|
||||
src/slic3r/GUI/Downloader.cpp
|
||||
src/slic3r/GUI/DownloaderFileGet.cpp
|
||||
src/slic3r/GUI/ExtraRenderers.cpp
|
||||
src/slic3r/GUI/ExtruderSequenceDialog.cpp
|
||||
src/slic3r/GUI/Field.cpp
|
||||
src/slic3r/GUI/FileArchiveDialog.cpp
|
||||
src/slic3r/GUI/FirmwareDialog.cpp
|
||||
src/slic3r/GUI/GalleryDialog.cpp
|
||||
src/slic3r/GUI/GCodeViewer.cpp
|
||||
src/slic3r/GUI/GLCanvas3D.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
|
||||
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.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoFlatten.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.hpp
|
||||
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/GLGizmoSlaSupports.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
|
||||
src/slic3r/GUI/GUI.cpp
|
||||
@ -48,8 +54,7 @@ src/slic3r/GUI/HintNotification.cpp
|
||||
src/slic3r/GUI/ImGuiWrapper.cpp
|
||||
src/slic3r/GUI/Jobs/ArrangeJob.cpp
|
||||
src/slic3r/GUI/Jobs/FillBedJob.cpp
|
||||
src/slic3r/GUI/Jobs/Job.cpp
|
||||
src/slic3r/GUI/Jobs/PlaterJob.cpp
|
||||
src/slic3r/GUI/Jobs/EmbossJob.cpp
|
||||
src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
|
||||
src/slic3r/GUI/Jobs/RotoptimizeJob.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
2
resources/profiles/BIQU.idx
Normal file
2
resources/profiles/BIQU.idx
Normal file
@ -0,0 +1,2 @@
|
||||
min_slic3r_version = 2.6.0-alpha1
|
||||
0.1.0 Initial version
|
437
resources/profiles/BIQU.ini
Normal file
437
resources/profiles/BIQU.ini
Normal 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*
|
BIN
resources/profiles/BIQU/BIQUBX_thumbnail.png
Normal file
BIN
resources/profiles/BIQU/BIQUBX_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
resources/profiles/BIQU/BX_Bed.stl
Normal file
BIN
resources/profiles/BIQU/BX_Bed.stl
Normal file
Binary file not shown.
BIN
resources/profiles/BIQU/BX_Texture.png
Normal file
BIN
resources/profiles/BIQU/BX_Texture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
@ -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
|
||||
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.1 Added Ender 3 Neo and Ender 3 S1 Plus. Various updates.
|
||||
0.2.0 Added alternative nozzle support
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = Creality
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 0.2.2
|
||||
config_version = 0.2.6
|
||||
# Where to get the updates from?
|
||||
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%
|
||||
@ -131,14 +131,14 @@ 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:ENDER5PRO]
|
||||
#name = Creality Ender-5 Pro
|
||||
#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:ENDER5PRO]
|
||||
name = Creality Ender-5 Pro
|
||||
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:ENDER5PLUS]
|
||||
name = Creality Ender-5 Plus
|
||||
@ -149,6 +149,15 @@ bed_model = ender5plus_bed.stl
|
||||
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
|
||||
|
||||
[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]
|
||||
name = Creality Ender-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
|
||||
# not make it into the user interface.
|
||||
|
||||
@ -416,8 +447,8 @@ external_fill_pattern = rectilinear
|
||||
external_perimeters_first = 0
|
||||
external_perimeter_speed = 25
|
||||
extra_perimeters = 0
|
||||
extruder_clearance_height = 34
|
||||
extruder_clearance_radius = 47
|
||||
extruder_clearance_height = 25
|
||||
extruder_clearance_radius = 55
|
||||
fill_angle = 45
|
||||
fill_density = 15%
|
||||
fill_pattern = grid
|
||||
@ -425,6 +456,7 @@ first_layer_height = 0.2
|
||||
first_layer_speed = 20
|
||||
gap_fill_speed = 30
|
||||
gcode_comments = 0
|
||||
gcode_label_objects = 1
|
||||
infill_every_layers = 1
|
||||
infill_extruder = 1
|
||||
infill_first = 0
|
||||
@ -489,7 +521,62 @@ wipe_tower_x = 170
|
||||
wipe_tower_y = 140
|
||||
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*]
|
||||
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]
|
||||
inherits = *0.08mm*; *0.3nozzle*
|
||||
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]
|
||||
inherits = *0.20mm*; *0.3nozzle*
|
||||
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]
|
||||
inherits = *0.24mm*; *0.4nozzle*
|
||||
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]
|
||||
inherits = *0.28mm*; *0.4nozzle*
|
||||
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]
|
||||
inherits = *0.36mm*; *0.5nozzle*
|
||||
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]
|
||||
inherits = *0.44mm*; *0.6nozzle*
|
||||
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:
|
||||
# https://www.thingiverse.com/thing:2615842
|
||||
# Pay particular attention to bridging, overhangs and retractions.
|
||||
@ -830,6 +1167,26 @@ bridge_fan_speed = 30
|
||||
top_fan_speed = 0
|
||||
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]
|
||||
inherits = *PLA*
|
||||
renamed_from = "Generic PLA @ENDER3"
|
||||
@ -1109,6 +1466,50 @@ filament_cost = 16.99
|
||||
filament_density = 1.24
|
||||
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
|
||||
@ -1165,7 +1566,7 @@ wipe = 1
|
||||
z_offset = 0
|
||||
printer_model =
|
||||
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
|
||||
|
||||
# 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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[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
|
||||
[printer:*pauseprint*]
|
||||
@ -1238,7 +1639,7 @@ retract_before_wipe = 0%
|
||||
[printer:*0.3nozzle*]
|
||||
nozzle_diameter = 0.3
|
||||
printer_variant = 0.3
|
||||
min_layer_height = 0.08
|
||||
min_layer_height = 0.06
|
||||
max_layer_height = 0.24
|
||||
retract_lift_above = 0.2
|
||||
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*]
|
||||
nozzle_diameter = 0.4
|
||||
printer_variant = 0.4
|
||||
min_layer_height = 0.08
|
||||
min_layer_height = 0.06
|
||||
max_layer_height = 0.32
|
||||
retract_lift_above = 0.2
|
||||
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
|
||||
max_print_height = 270
|
||||
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)]
|
||||
inherits = *ENDER3S1*; *0.3nozzle*
|
||||
@ -1427,7 +1828,7 @@ inherits = *common*; *storedabl*; *spriteextruder*; *pauseprint*
|
||||
bed_shape = 5x0,215x0,215x220,5x220
|
||||
max_print_height = 270
|
||||
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)]
|
||||
inherits = *ENDER3S1PRO*; *0.3nozzle*
|
||||
@ -1449,7 +1850,7 @@ inherits = *common*; *storedabl*; *spriteextruder*; *pauseprint*
|
||||
bed_shape = 5x5,295x5,295x295,5x295
|
||||
max_print_height = 300
|
||||
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)]
|
||||
inherits = *ENDER3S1PLUS*; *0.3nozzle*
|
||||
@ -1554,26 +1955,26 @@ inherits = *ENDER5*; *0.6nozzle*
|
||||
|
||||
|
||||
|
||||
#[printer:*ENDER5PRO*]
|
||||
#inherits = *common*; *bowdencapricorn*; *descendingz*
|
||||
#bed_shape = 5x2.5,225x2.5,225x222.5,5x222.5
|
||||
#max_print_height = 300
|
||||
#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
|
||||
#machine_max_acceleration_e = 1000
|
||||
#machine_max_feedrate_z = 5
|
||||
#
|
||||
#[printer:Creality Ender-5 Pro (0.3 mm nozzle)]
|
||||
#inherits = *ENDER5PRO*; *0.3nozzle*
|
||||
#
|
||||
#[printer:Creality Ender-5 Pro (0.4 mm nozzle)]
|
||||
#inherits = *ENDER5PRO*; *0.4nozzle*
|
||||
#
|
||||
#[printer:Creality Ender-5 Pro (0.5 mm nozzle)]
|
||||
#inherits = *ENDER5PRO*; *0.5nozzle*
|
||||
#
|
||||
#[printer:Creality Ender-5 Pro (0.6 mm nozzle)]
|
||||
#inherits = *ENDER5PRO*; *0.6nozzle*
|
||||
[printer:*ENDER5PRO*]
|
||||
inherits = *common*; *bowdencapricorn*; *descendingz*
|
||||
bed_shape = 5x2.5,225x2.5,225x222.5,5x222.5
|
||||
max_print_height = 300
|
||||
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
|
||||
machine_max_acceleration_e = 1000
|
||||
machine_max_feedrate_z = 5
|
||||
|
||||
[printer:Creality Ender-5 Pro (0.3 mm nozzle)]
|
||||
inherits = *ENDER5PRO*; *0.3nozzle*
|
||||
|
||||
[printer:Creality Ender-5 Pro (0.4 mm nozzle)]
|
||||
inherits = *ENDER5PRO*; *0.4nozzle*
|
||||
|
||||
[printer:Creality Ender-5 Pro (0.5 mm nozzle)]
|
||||
inherits = *ENDER5PRO*; *0.5nozzle*
|
||||
|
||||
[printer:Creality Ender-5 Pro (0.6 mm nozzle)]
|
||||
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*]
|
||||
inherits = *common*; *bowden*; *descendingz*
|
||||
bed_shape = 5x5,255x5,255x255,5x255
|
||||
max_print_height = 400
|
||||
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)]
|
||||
inherits = *ENDER6*; *0.3nozzle*
|
||||
@ -1630,7 +2052,7 @@ inherits = *common*; *bowden*; *descendingz*
|
||||
bed_shape = 5x5,245x5,245x245,5x245
|
||||
max_print_height = 300
|
||||
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)]
|
||||
inherits = *ENDER7*; *0.3nozzle*
|
||||
@ -1805,7 +2227,7 @@ inherits = *common*; *slowabl*; *spriteextruder*
|
||||
bed_shape = 5x5,295x5,295x295,5x295
|
||||
max_print_height = 400
|
||||
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)]
|
||||
inherits = *CR10SMARTPRO*; *0.3nozzle*
|
||||
@ -2130,7 +2552,7 @@ inherits = *common*; *directdriveextruder*; *descendingz*
|
||||
bed_shape = 5x5,275x5,275x255,5x255
|
||||
max_print_height = 310
|
||||
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)]
|
||||
inherits = *SERMOOND1*; *0.3nozzle*
|
||||
@ -2144,3 +2566,45 @@ inherits = *SERMOOND1*; *0.5nozzle*
|
||||
|
||||
[printer:Creality Sermoon-D1 (0.6 mm nozzle)]
|
||||
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*
|
||||
|
BIN
resources/profiles/Creality/SERMOONV1PRO_thumbnail.png
Normal file
BIN
resources/profiles/Creality/SERMOONV1PRO_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
@ -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
|
||||
1.0.1 Decreased bed size to 220x220.
|
||||
1.0.0 Initial version
|
||||
|
@ -6,7 +6,7 @@
|
||||
name = Elegoo
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.0.1
|
||||
config_version = 1.0.2
|
||||
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,
|
||||
@ -58,6 +58,33 @@ bed_model =
|
||||
bed_texture =
|
||||
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]
|
||||
name = Elegoo Neptune-X
|
||||
variants = 0.4
|
||||
@ -428,26 +455,9 @@ retract_length = 5
|
||||
retract_speed = 60
|
||||
deretract_speed = 40
|
||||
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
|
||||
|
||||
|
||||
# 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
|
||||
[printer:*dualextruder*]
|
||||
single_extruder_multi_material = 1
|
||||
@ -473,7 +483,7 @@ retract_restart_extra = 0,0
|
||||
retract_restart_extra_toolchange = 0,0
|
||||
retract_speed = 60,60
|
||||
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
|
||||
|
||||
# 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*
|
||||
retract_length = 6,6
|
||||
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]
|
||||
inherits = Elegoo Neptune-2
|
||||
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]
|
||||
inherits = Elegoo Neptune-2
|
||||
max_print_height = 300
|
||||
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]
|
||||
inherits = Elegoo Neptune-2
|
||||
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_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]
|
||||
inherits = Elegoo Neptune-2
|
||||
bed_shape = 0x0,210x0,210x210,0x210
|
||||
max_print_height = 200
|
||||
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
|
||||
|
||||
|
BIN
resources/profiles/Elegoo/NEPTUNE3MAX_thumbnail.png
Normal file
BIN
resources/profiles/Elegoo/NEPTUNE3MAX_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
resources/profiles/Elegoo/NEPTUNE3PLUS_thumbnail.png
Normal file
BIN
resources/profiles/Elegoo/NEPTUNE3PLUS_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
BIN
resources/profiles/Elegoo/NEPTUNE3PRO_thumbnail.png
Normal file
BIN
resources/profiles/Elegoo/NEPTUNE3PRO_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
@ -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
|
||||
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.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.
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = Prusa Research
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.5.4
|
||||
config_version = 1.6.0-alpha0
|
||||
# Where to get the updates from?
|
||||
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%
|
||||
@ -173,7 +173,7 @@ infill_extruder = 1
|
||||
infill_extrusion_width = 0.45
|
||||
infill_first = 0
|
||||
infill_only_where_needed = 0
|
||||
infill_overlap = 25%
|
||||
infill_overlap = 10%
|
||||
interface_shells = 0
|
||||
max_print_speed = 100
|
||||
max_volumetric_extrusion_rate_slope_negative = 0
|
||||
@ -184,7 +184,7 @@ notes =
|
||||
overhangs = 1
|
||||
only_retract_when_crossing_perimeters = 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
|
||||
perimeter_extruder = 1
|
||||
perimeter_extrusion_width = 0.45
|
||||
@ -248,6 +248,8 @@ wall_transition_filter_deviation = 25%
|
||||
wall_transition_length = 0.4
|
||||
wall_distribution_count = 1
|
||||
min_bead_width = 85%
|
||||
enable_dynamic_overhang_speeds = 1
|
||||
top_fill_pattern = monotoniclines
|
||||
|
||||
[print:*MK3*]
|
||||
fill_pattern = grid
|
||||
@ -289,7 +291,7 @@ support_material_interface_spacing = 0.15
|
||||
support_material_spacing = 1
|
||||
support_material_xy_spacing = 150%
|
||||
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
|
||||
bridge_flow_ratio = 1
|
||||
bridge_speed = 20
|
||||
@ -299,6 +301,8 @@ wall_transition_filter_deviation = 25%
|
||||
wall_transition_length = 0.25
|
||||
wall_distribution_count = 1
|
||||
min_bead_width = 85%
|
||||
infill_overlap = 10%
|
||||
dynamic_overhang_speeds[0] = 20,20,15,15
|
||||
|
||||
[print:*0.25nozzleMK3*]
|
||||
inherits = *0.25nozzle*
|
||||
@ -340,7 +344,7 @@ support_material_extrusion_width = 0.55
|
||||
support_material_contact_distance = 0.15
|
||||
support_material_xy_spacing = 80%
|
||||
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
|
||||
top_solid_min_thickness = 0.9
|
||||
bottom_solid_min_thickness = 0.6
|
||||
@ -352,6 +356,7 @@ wall_transition_filter_deviation = 25%
|
||||
wall_transition_length = 0.6
|
||||
wall_distribution_count = 1
|
||||
min_bead_width = 85%
|
||||
infill_overlap = 15%
|
||||
|
||||
[print:*0.6nozzleMK3*]
|
||||
inherits = *0.6nozzle*
|
||||
@ -390,7 +395,7 @@ support_material_interface_speed = 100%
|
||||
support_material_spacing = 2
|
||||
support_material_xy_spacing = 80%
|
||||
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_density = 15%
|
||||
infill_anchor_max = 20
|
||||
@ -399,7 +404,7 @@ bottom_solid_layers = 3
|
||||
skirt_distance = 3
|
||||
skirt_height = 2
|
||||
first_layer_height = 0.3
|
||||
infill_overlap = 30%
|
||||
infill_overlap = 15%
|
||||
bridge_speed = 22
|
||||
gap_fill_speed = 30
|
||||
bridge_flow_ratio = 0.9
|
||||
@ -4065,7 +4070,6 @@ inherits = *FLEX*
|
||||
filament_vendor = Eolas Prints
|
||||
filament_cost = 34.99
|
||||
filament_density = 1.21
|
||||
filament_spool_weight = 1000
|
||||
filament_colour = #4D9398
|
||||
filament_max_volumetric_speed = 1.2
|
||||
temperature = 235
|
||||
@ -4495,6 +4499,8 @@ filament_soluble = 1
|
||||
filament_type = PVB
|
||||
filament_colour = #FFFF6F
|
||||
filament_spool_weight = 201
|
||||
bed_temperature = 75
|
||||
first_layer_bed_temperature = 75
|
||||
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"
|
||||
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_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]
|
||||
inherits = *common 0.025*
|
||||
exposure_time = 6
|
||||
@ -5957,6 +5971,14 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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]
|
||||
inherits = *common 0.025*
|
||||
exposure_time = 7
|
||||
@ -5981,6 +6003,22 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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
|
||||
|
||||
[sla_material:Prusa Orange Tough @0.025]
|
||||
@ -6432,6 +6470,14 @@ material_type = Tough
|
||||
material_vendor = BlueCast
|
||||
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]
|
||||
inherits = *common 0.05*
|
||||
exposure_time = 10
|
||||
@ -6938,6 +6984,14 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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]
|
||||
inherits = *common 0.05*
|
||||
exposure_time = 8
|
||||
@ -6962,6 +7016,22 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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
|
||||
|
||||
[sla_material:Prusa Beige Tough @0.05]
|
||||
@ -7252,6 +7322,14 @@ material_type = Tough
|
||||
material_vendor = BlueCast
|
||||
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]
|
||||
inherits = *common 0.1*
|
||||
exposure_time = 10
|
||||
@ -7286,6 +7364,14 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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]
|
||||
inherits = *common 0.1*
|
||||
exposure_time = 13
|
||||
@ -7374,6 +7460,22 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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
|
||||
|
||||
[sla_material:Prusa Orange Tough @0.1]
|
||||
@ -7590,6 +7692,14 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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]
|
||||
inherits = *0.025_sl1s*
|
||||
exposure_time = 3.5
|
||||
@ -7615,6 +7725,24 @@ material_vendor = Prusa Polymers
|
||||
material_colour = #ECDE05
|
||||
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
|
||||
|
||||
[sla_material:Prusa Orange Tough @0.025 SL1S]
|
||||
@ -8042,6 +8170,14 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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]
|
||||
inherits = *0.05_sl1s*
|
||||
exposure_time = 4
|
||||
@ -8067,6 +8203,24 @@ material_vendor = Prusa Polymers
|
||||
material_colour = #ECDE05
|
||||
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
|
||||
|
||||
[sla_material:Prusa Orange Tough @0.05 SL1S]
|
||||
@ -8798,6 +8952,14 @@ material_type = Tough
|
||||
material_vendor = Prusa Polymers
|
||||
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]
|
||||
inherits = *0.1_sl1s*
|
||||
exposure_time = 5
|
||||
@ -8823,6 +8985,24 @@ material_vendor = Prusa Polymers
|
||||
material_colour = #ECDE05
|
||||
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
|
||||
|
||||
[sla_material:Prusa Orange Tough @0.1 SL1S]
|
||||
@ -9312,6 +9492,8 @@ printer_model = MK2.5
|
||||
remaining_times = 1
|
||||
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
|
||||
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]
|
||||
inherits = Original Prusa i3 MK2S 0.25 nozzle
|
||||
@ -9319,6 +9501,8 @@ printer_model = MK2.5
|
||||
remaining_times = 1
|
||||
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
|
||||
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]
|
||||
inherits = Original Prusa i3 MK2S 0.6 nozzle
|
||||
@ -9327,6 +9511,8 @@ remaining_times = 1
|
||||
machine_max_jerk_e = 4.5
|
||||
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
|
||||
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]
|
||||
inherits = Original Prusa i3 MK2S 0.6 nozzle
|
||||
@ -9342,9 +9528,11 @@ retract_lift = 0.25
|
||||
remaining_times = 1
|
||||
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
|
||||
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_filament_profile = Prusament PLA @0.8 nozzle
|
||||
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
|
||||
thumbnails = 160x120
|
||||
|
||||
[printer:Original Prusa i3 MK2.5 MMU2 Single]
|
||||
inherits = *25mm2*
|
||||
@ -9379,7 +9567,7 @@ single_extruder_multi_material = 1
|
||||
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
|
||||
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
|
||||
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]
|
||||
inherits = Original Prusa i3 MK2.5
|
||||
@ -9406,7 +9594,7 @@ default_print_profile = 0.15mm OPTIMAL @MK2.5
|
||||
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
|
||||
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]
|
||||
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
|
||||
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
|
||||
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]
|
||||
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]
|
||||
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_extruding = 1250,1250
|
||||
machine_max_acceleration_retracting = 1250,1250
|
||||
@ -9659,7 +9847,7 @@ inherits = *mm2*
|
||||
single_extruder_multi_material = 0
|
||||
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}
|
||||
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]
|
||||
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
|
||||
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}
|
||||
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]
|
||||
inherits = *mm2s*
|
||||
@ -9715,7 +9903,7 @@ renamed_from = "Original Prusa i3 MK3S MMU2S Single"
|
||||
single_extruder_multi_material = 0
|
||||
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}
|
||||
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]
|
||||
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
|
||||
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}
|
||||
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
|
||||
|
||||
@ -9883,7 +10071,7 @@ retract_layer_change = 1
|
||||
silent_mode = 0
|
||||
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
|
||||
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
|
||||
extruder_colour =
|
||||
color_change_gcode = M600
|
||||
|
2
resources/profiles/Templates.idx
Normal file
2
resources/profiles/Templates.idx
Normal file
@ -0,0 +1,2 @@
|
||||
min_slic3r_version = 2.6.0-alpha0
|
||||
1.0.0 Initial
|
2144
resources/profiles/Templates.ini
Normal file
2144
resources/profiles/Templates.ini
Normal file
File diff suppressed because it is too large
Load Diff
17
resources/shaders/110/gouraud_light_clip.fs
Normal file
17
resources/shaders/110/gouraud_light_clip.fs
Normal 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);
|
||||
}
|
54
resources/shaders/110/gouraud_light_clip.vs
Normal file
54
resources/shaders/110/gouraud_light_clip.vs
Normal 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);
|
||||
}
|
19
resources/shaders/140/gouraud_light_clip.fs
Normal file
19
resources/shaders/140/gouraud_light_clip.fs
Normal 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);
|
||||
}
|
54
resources/shaders/140/gouraud_light_clip.vs
Normal file
54
resources/shaders/140/gouraud_light_clip.vs
Normal 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);
|
||||
}
|
19
resources/shaders/ES/gouraud_light_clip.fs
Normal file
19
resources/shaders/ES/gouraud_light_clip.fs
Normal 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);
|
||||
}
|
54
resources/shaders/ES/gouraud_light_clip.vs
Normal file
54
resources/shaders/ES/gouraud_light_clip.vs
Normal 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);
|
||||
}
|
@ -242,13 +242,14 @@ int wmain(int argc, wchar_t **argv)
|
||||
#ifdef SLIC3R_GUI
|
||||
// Here one may push some additional parameters based on the wrapper type.
|
||||
bool force_mesa = false;
|
||||
bool force_hw = false;
|
||||
#endif /* SLIC3R_GUI */
|
||||
for (int i = 1; i < argc; ++ i) {
|
||||
#ifdef SLIC3R_GUI
|
||||
if (wcscmp(argv[i], L"--sw-renderer") == 0)
|
||||
force_mesa = true;
|
||||
else if (wcscmp(argv[i], L"--no-sw-renderer") == 0)
|
||||
force_mesa = false;
|
||||
force_hw = true;
|
||||
#endif /* SLIC3R_GUI */
|
||||
argv_extended.emplace_back(argv[i]);
|
||||
}
|
||||
@ -261,7 +262,7 @@ int wmain(int argc, wchar_t **argv)
|
||||
force_mesa ||
|
||||
// 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.
|
||||
::GetSystemMetrics(SM_REMOTESESSION) ||
|
||||
(::GetSystemMetrics(SM_REMOTESESSION) && !force_hw) ||
|
||||
// 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);
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
@ -68,9 +68,6 @@ public:
|
||||
|
||||
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
|
||||
m_aabb->init(*m_tm, calculate_epsilon);
|
||||
}
|
||||
@ -97,7 +94,6 @@ AABBMesh::~AABBMesh() {}
|
||||
|
||||
AABBMesh::AABBMesh(const AABBMesh &other)
|
||||
: m_tm(other.m_tm)
|
||||
, m_ground_level(other.m_ground_level)
|
||||
, m_aabb(new AABBImpl(*other.m_aabb))
|
||||
, m_vfidx{other.m_vfidx}
|
||||
, m_fnidx{other.m_fnidx}
|
||||
@ -106,7 +102,6 @@ AABBMesh::AABBMesh(const AABBMesh &other)
|
||||
AABBMesh &AABBMesh::operator=(const AABBMesh &other)
|
||||
{
|
||||
m_tm = other.m_tm;
|
||||
m_ground_level = other.m_ground_level;
|
||||
m_aabb.reset(new AABBImpl(*other.m_aabb));
|
||||
m_vfidx = other.m_vfidx;
|
||||
m_fnidx = other.m_fnidx;
|
||||
|
@ -28,7 +28,6 @@ class AABBMesh {
|
||||
class AABBImpl;
|
||||
|
||||
const indexed_triangle_set* m_tm;
|
||||
double m_ground_level = 0/*, m_gnd_offset = 0*/;
|
||||
|
||||
std::unique_ptr<AABBImpl> m_aabb;
|
||||
VertexFaceIndex m_vfidx; // vertex-face index
|
||||
@ -57,10 +56,6 @@ public:
|
||||
|
||||
~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<Vec3i>& indices() const;
|
||||
const Vec3f& vertices(size_t idx) const;
|
||||
@ -72,9 +67,9 @@ public:
|
||||
double m_t = infty();
|
||||
int m_face_id = -1;
|
||||
const AABBMesh *m_mesh = nullptr;
|
||||
Vec3d m_dir;
|
||||
Vec3d m_source;
|
||||
Vec3d m_normal;
|
||||
Vec3d m_dir = Vec3d::Zero();
|
||||
Vec3d m_source = Vec3d::Zero();
|
||||
Vec3d m_normal = Vec3d::Zero();
|
||||
friend class AABBMesh;
|
||||
|
||||
// A valid object of this class can only be obtained from
|
||||
|
@ -117,7 +117,7 @@ inline std::tuple<int, int> coordinate_aligned_ray_hit_count(size_t
|
||||
}
|
||||
|
||||
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 std::vector<LineType> &lines,
|
||||
const LineType &line,
|
||||
@ -128,7 +128,7 @@ inline std::vector<VectorType> get_intersections_with_line(size_t
|
||||
if (node.is_leaf()) {
|
||||
VectorType 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 {
|
||||
return {};
|
||||
}
|
||||
@ -140,17 +140,17 @@ inline std::vector<VectorType> get_intersections_with_line(size_t
|
||||
assert(node_left.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)) {
|
||||
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines,
|
||||
line, line_bb);
|
||||
std::vector<std::pair<VectorType, size_t>> intersections =
|
||||
get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines, line, line_bb);
|
||||
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||
}
|
||||
|
||||
if (node_right.bbox.intersects(line_bb)) {
|
||||
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines,
|
||||
line, line_bb);
|
||||
std::vector<std::pair<VectorType, size_t>> intersections =
|
||||
get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines, line, line_bb);
|
||||
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||
}
|
||||
|
||||
@ -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>
|
||||
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);
|
||||
line_bb.extend(line.b);
|
||||
|
||||
@ -274,15 +278,16 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
|
||||
using Floating =
|
||||
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{};
|
||||
for (const VectorType &p : intersections) {
|
||||
points_with_sq_distance.emplace_back((p - line.a).template cast<Floating>().squaredNorm(), p);
|
||||
std::vector<std::pair<Floating, std::pair<VectorType, size_t>>> points_with_sq_distance{};
|
||||
for (const auto &p : intersections) {
|
||||
points_with_sq_distance.emplace_back((p.first - line.a).template cast<Floating>().squaredNorm(), p);
|
||||
}
|
||||
std::sort(points_with_sq_distance.begin(), points_with_sq_distance.end(),
|
||||
[](const std::pair<Floating, VectorType> &left, std::pair<Floating, VectorType> &right) {
|
||||
return left.first < right.first;
|
||||
});
|
||||
for (size_t i = 0; i < points_with_sq_distance.size(); i++) { intersections[i] = points_with_sq_distance[i].second; }
|
||||
[](const std::pair<Floating, std::pair<VectorType, size_t>> &left,
|
||||
std::pair<Floating, std::pair<VectorType, size_t>> &right) { return left.first < right.first; });
|
||||
for (size_t i = 0; i < points_with_sq_distance.size(); i++) {
|
||||
intersections[i] = points_with_sq_distance[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
return intersections;
|
||||
@ -290,10 +295,11 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
|
||||
|
||||
template<typename LineType> class LinesDistancer
|
||||
{
|
||||
private:
|
||||
std::vector<LineType> lines;
|
||||
public:
|
||||
using Scalar = typename LineType::Scalar;
|
||||
using Floating = typename std::conditional<std::is_floating_point<Scalar>::value, Scalar, double>::type;
|
||||
private:
|
||||
std::vector<LineType> lines;
|
||||
AABBTreeIndirect::Tree<2, Scalar> tree;
|
||||
|
||||
public:
|
||||
@ -313,23 +319,29 @@ public:
|
||||
int outside(const Vec<2, Scalar> &point) const { return point_outside_closed_contours(lines, tree, point); }
|
||||
|
||||
// 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);
|
||||
Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero();
|
||||
Vec<2, Floating> p = point.template cast<Floating>();
|
||||
auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out);
|
||||
|
||||
if (distance < 0) { return {std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out}; }
|
||||
if (distance < 0) {
|
||||
return {std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out};
|
||||
}
|
||||
distance = sqrt(distance);
|
||||
|
||||
if (SIGNED_DISTANCE) {
|
||||
distance *= outside(point);
|
||||
}
|
||||
|
||||
return {distance, nearest_line_index_out, nearest_point_out};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -338,7 +350,7 @@ public:
|
||||
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);
|
||||
}
|
||||
|
130
src/libslic3r/AnyPtr.hpp
Normal file
130
src/libslic3r/AnyPtr.hpp
Normal 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
|
@ -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.
|
||||
// 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.
|
||||
//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";
|
||||
// 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.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_MATERIALS = "sla_materials";
|
||||
@ -61,6 +66,9 @@ void AppConfig::set_defaults()
|
||||
// Disable background processing by default as it is not stable.
|
||||
if (get("background_processing").empty())
|
||||
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.
|
||||
// By default, Prusa has the controller hidden.
|
||||
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 (get("no_defaults").empty())
|
||||
set("no_defaults", "1");
|
||||
if (get("no_templates").empty())
|
||||
set("no_templates", "0");
|
||||
if (get("show_incompatible_presets").empty())
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return boost::filesystem::exists(config_path());
|
||||
|
@ -139,6 +139,11 @@ public:
|
||||
// Get the Slic3r version check url.
|
||||
// This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file.
|
||||
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
|
||||
// by the current version
|
||||
|
@ -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)
|
||||
{
|
||||
#ifdef ARACHNE_DEBUG
|
||||
@ -614,36 +667,35 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try to detect cases when some Voronoi vertex is missing and when
|
||||
// the Voronoi diagram is not planar.
|
||||
// When any Voronoi vertex is missing, or the Voronoi diagram is not
|
||||
// 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);
|
||||
// When any Voronoi vertex is missing, the Voronoi diagram is not planar, or some voronoi edge is
|
||||
// intersecting input segment, rotate the input polygon and try again.
|
||||
VoronoiDiagramStatus status = detect_voronoi_diagram_known_issues(voronoi_diagram, segments);
|
||||
const double fix_angle = PI / 6;
|
||||
|
||||
std::unordered_map<Point, Point, PointHash> vertex_mapping;
|
||||
// polys_copy is referenced through items stored in the std::vector segments.
|
||||
Polygons polys_copy = polys;
|
||||
if (has_missing_voronoi_vertex || !is_voronoi_diagram_planar) {
|
||||
if (has_missing_voronoi_vertex)
|
||||
if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED) {
|
||||
if (status == VoronoiDiagramStatus::MISSING_VORONOI_VERTEX)
|
||||
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.";
|
||||
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);
|
||||
|
||||
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))
|
||||
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.";
|
||||
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:
|
||||
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()) {
|
||||
@ -652,35 +704,35 @@ process_voronoi_diagram:
|
||||
|
||||
Point start_source_point;
|
||||
Point end_source_point;
|
||||
vd_t::edge_type* starting_vonoroi_edge = nullptr;
|
||||
vd_t::edge_type* ending_vonoroi_edge = nullptr;
|
||||
vd_t::edge_type* starting_voronoi_edge = nullptr;
|
||||
vd_t::edge_type* ending_voronoi_edge = nullptr;
|
||||
// Compute and store result in above variables
|
||||
|
||||
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)
|
||||
continue;
|
||||
} else {
|
||||
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");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy start to end edge to graph
|
||||
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_vonoroi_edge->vertex1()).y() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_vonoroi_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);
|
||||
node_t* starting_node = vd_node_to_he_node[starting_vonoroi_edge->vertex0()];
|
||||
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_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_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_voronoi_edge->vertex0()];
|
||||
starting_node->data.distance_to_boundary = 0;
|
||||
|
||||
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);
|
||||
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(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>();
|
||||
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_vonoroi_edge->vertex0()).y() <= std::numeric_limits<coord_t>::max() && VoronoiUtils::p(starting_vonoroi_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);
|
||||
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_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_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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
// 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.
|
||||
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.";
|
||||
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);
|
||||
|
||||
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments));
|
||||
@ -724,14 +776,14 @@ process_voronoi_diagram:
|
||||
goto process_voronoi_diagram;
|
||||
}
|
||||
|
||||
if (degenerated_voronoi_diagram) {
|
||||
if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED) {
|
||||
assert(!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.";
|
||||
}
|
||||
|
||||
if (degenerated_voronoi_diagram)
|
||||
if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED)
|
||||
rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fix_angle, vertex_mapping);
|
||||
|
||||
#ifdef ARACHNE_DEBUG
|
||||
@ -742,7 +794,7 @@ process_voronoi_diagram:
|
||||
|
||||
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
|
||||
for (edge_t& edge : graph.edges)
|
||||
if (!edge.prev)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <memory> // smart pointers
|
||||
#include <unordered_map>
|
||||
#include <utility> // pair
|
||||
#include <Arachne/utils/VoronoiUtils.hpp>
|
||||
|
||||
#include "utils/HalfEdgeGraph.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
|
||||
* 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
|
||||
@ -255,7 +256,7 @@ protected:
|
||||
* /return Whether the cell is inside of the polygon. If it's outside of the
|
||||
* 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
|
||||
@ -597,6 +598,8 @@ protected:
|
||||
* Genrate small segments for local maxima where the beading would only result in a single bead
|
||||
*/
|
||||
void generateLocalMaximaSingleBeads();
|
||||
|
||||
friend bool detect_voronoi_edge_intersecting_input_segment(const Geometry::VoronoiDiagram &voronoi_diagram, const std::vector<VoronoiUtils::Segment> &segments);
|
||||
};
|
||||
|
||||
} // namespace Slic3r::Arachne
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "../../../clipper/clipper_z.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
class ThickPolyline;
|
||||
struct ThickPolyline;
|
||||
}
|
||||
|
||||
namespace Slic3r::Arachne
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
|
||||
#include "libslic3r/SLA/SupportTreeUtils.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
namespace Slic3r { namespace branchingtree {
|
||||
|
||||
@ -76,18 +76,20 @@ void build_tree(PointCloud &nodes, Builder &builder)
|
||||
switch (type) {
|
||||
case BED: {
|
||||
closest_node.weight = w;
|
||||
if (closest_it->dst_branching > nodes.properties().max_branch_length()) {
|
||||
auto hl_br_len = float(nodes.properties().max_branch_length()) / 2.f;
|
||||
Node new_node {{node.pos.x(), node.pos.y(), node.pos.z() - hl_br_len}, node.Rmin};
|
||||
new_node.id = int(nodes.next_junction_id());
|
||||
new_node.weight = nodes.get(node_id).weight + hl_br_len;
|
||||
double max_br_len = nodes.properties().max_branch_length();
|
||||
if (closest_it->dst_branching > max_br_len) {
|
||||
std::optional<Vec3f> avo = builder.suggest_avoidance(node, max_br_len);
|
||||
if (!avo)
|
||||
break;
|
||||
|
||||
Node new_node {*avo, node.Rmin};
|
||||
new_node.weight = nodes.get(node_id).weight + (node.pos - *avo).norm();
|
||||
new_node.left = node.id;
|
||||
if ((routed = builder.add_bridge(node, new_node))) {
|
||||
size_t new_idx = nodes.insert_junction(new_node);
|
||||
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;
|
||||
nodes.get(closest_node_id) = closest_node;
|
||||
nodes.mark_unreachable(closest_node_id);
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <admesh/stl.h>
|
||||
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
|
||||
namespace Slic3r { namespace branchingtree {
|
||||
|
||||
@ -21,6 +20,7 @@ class Properties
|
||||
ExPolygons m_bed_shape;
|
||||
|
||||
public:
|
||||
|
||||
// Maximum slope for bridges of the tree
|
||||
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
|
||||
// method as a callback and implement the actions that need to be done.
|
||||
class Builder
|
||||
@ -100,6 +105,12 @@ public:
|
||||
// Add an anchor bridge to the model body
|
||||
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)
|
||||
virtual void report_unroutable(const Node &j) = 0;
|
||||
|
||||
|
@ -1,82 +1,15 @@
|
||||
#include "PointCloud.hpp"
|
||||
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/Tesselate.hpp"
|
||||
#include "libslic3r/SLA/SupportTreeUtils.hpp"
|
||||
|
||||
#include <igl/random_points_on_mesh.h>
|
||||
|
||||
namespace Slic3r { namespace branchingtree {
|
||||
|
||||
std::optional<Vec3f> find_merge_pt(const Vec3f &A,
|
||||
const Vec3f &B,
|
||||
float critical_angle)
|
||||
std::optional<Vec3f> find_merge_pt(const Vec3f &A, const Vec3f &B, float max_slope)
|
||||
{
|
||||
// The idea is that A and B both have their support cones. But searching
|
||||
// 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{};
|
||||
return sla::find_merge_pt(A, B, max_slope);
|
||||
}
|
||||
|
||||
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<Vec3f> ret;
|
||||
|
||||
auto triangles = triangulate_expolygons_3d(bed, z);
|
||||
indexed_triangle_set its;
|
||||
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) {
|
||||
Node &n = m_leafs[i];
|
||||
n.id = int(LEAFS_BEGIN + i);
|
||||
n.left = Node::ID_NONE;
|
||||
n.right = Node::ID_NONE;
|
||||
|
||||
m_ktree.insert({n.pos, n.id});
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "BranchingTree.hpp"
|
||||
|
||||
#include "libslic3r/Execution/Execution.hpp"
|
||||
//#include "libslic3r/Execution/Execution.hpp"
|
||||
#include "libslic3r/MutablePriorityQueue.hpp"
|
||||
|
||||
#include "libslic3r/BoostAdapter.hpp"
|
||||
@ -78,14 +78,6 @@ private:
|
||||
rtree<PointIndexEl, boost::geometry::index::rstar<16, 4> /* ? */>
|
||||
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>
|
||||
static auto *get_node(PC &&pc, size_t id)
|
||||
{
|
||||
@ -104,6 +96,14 @@ private:
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
if (auto nodeptr = pc.find(root); nodeptr != nullptr) {
|
||||
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);
|
||||
if (nroot.left >= 0) traverse(pc, nroot.left, fn);
|
||||
if (nroot.right >= 0) traverse(pc, nroot.right, fn);
|
||||
} else {
|
||||
// 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);
|
||||
|
||||
inline void build_tree(PointCloud &&pc, Builder &builder)
|
||||
{
|
||||
build_tree(pc, builder);
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::branchingtree
|
||||
|
||||
#endif // POINTCLOUD_HPP
|
||||
|
@ -79,12 +79,11 @@ inline std::tuple<Vec2d, double> detect_bridging_direction(const Lines &floating
|
||||
{
|
||||
if (floating_edges.empty()) {
|
||||
// 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, 3.0);
|
||||
if (pc2 == Vec2d::Zero()) { // overhang may be smaller than resolution. In this case, any direction is ok
|
||||
auto [pc1, pc2] = compute_principal_components(overhang_area);
|
||||
if (pc2 == Vec2f::Zero()) { // overhang may be smaller than resolution. In this case, any direction is ok
|
||||
return {Vec2d{1.0,0.0}, 0.0};
|
||||
} else {
|
||||
return {pc2.normalized(), 0.0};
|
||||
return {pc2.normalized().cast<double>(), 0.0};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,7 +490,7 @@ static void make_inner_brim(const Print &print,
|
||||
|
||||
loops = union_pt_chained_outside_in(loops);
|
||||
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()));
|
||||
}
|
||||
|
||||
@ -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()) {
|
||||
auto *loop = new ExtrusionLoop();
|
||||
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.reserve(first_path.size());
|
||||
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;
|
||||
this_loop_trimmed.entities.reserve(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;
|
||||
Points &points = dynamic_cast<ExtrusionPath*>(this_loop_trimmed.entities.back())->polyline.points;
|
||||
points.reserve(path.size());
|
||||
@ -699,7 +699,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
|
@ -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
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -11,7 +11,7 @@ endif ()
|
||||
|
||||
set(OpenVDBUtils_SOURCES "")
|
||||
if (TARGET OpenVDB::openvdb)
|
||||
set(OpenVDBUtils_SOURCES OpenVDBUtils.cpp OpenVDBUtils.hpp)
|
||||
set(OpenVDBUtils_SOURCES OpenVDBUtils.cpp OpenVDBUtils.hpp OpenVDBUtilsLegacy.hpp)
|
||||
endif()
|
||||
|
||||
set(SLIC3R_SOURCES
|
||||
@ -24,6 +24,7 @@ set(SLIC3R_SOURCES
|
||||
AABBMesh.cpp
|
||||
Algorithm/RegionExpansion.cpp
|
||||
Algorithm/RegionExpansion.hpp
|
||||
AnyPtr.hpp
|
||||
BoundingBox.cpp
|
||||
BoundingBox.hpp
|
||||
BridgeDetector.cpp
|
||||
@ -42,6 +43,13 @@ set(SLIC3R_SOURCES
|
||||
Color.hpp
|
||||
Config.cpp
|
||||
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.hpp
|
||||
ElephantFootCompensation.cpp
|
||||
@ -59,6 +67,8 @@ set(SLIC3R_SOURCES
|
||||
ExtrusionEntity.hpp
|
||||
ExtrusionEntityCollection.cpp
|
||||
ExtrusionEntityCollection.hpp
|
||||
ExtrusionRole.cpp
|
||||
ExtrusionRole.hpp
|
||||
ExtrusionSimulator.cpp
|
||||
ExtrusionSimulator.hpp
|
||||
FileParserError.hpp
|
||||
@ -326,6 +336,7 @@ set(SLIC3R_SOURCES
|
||||
SLA/SupportTreeMesher.hpp
|
||||
SLA/SupportTreeMesher.cpp
|
||||
SLA/SupportTreeUtils.hpp
|
||||
SLA/SupportTreeUtilsLegacy.hpp
|
||||
SLA/SupportTreeBuilder.cpp
|
||||
SLA/SupportTree.hpp
|
||||
SLA/SupportTree.cpp
|
||||
|
86
src/libslic3r/CSGMesh/CSGMesh.hpp
Normal file
86
src/libslic3r/CSGMesh/CSGMesh.hpp
Normal 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
|
80
src/libslic3r/CSGMesh/CSGMeshCopy.hpp
Normal file
80
src/libslic3r/CSGMesh/CSGMeshCopy.hpp
Normal 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
|
88
src/libslic3r/CSGMesh/ModelToCSGMesh.hpp
Normal file
88
src/libslic3r/CSGMesh/ModelToCSGMesh.hpp
Normal 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
|
205
src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp
Normal file
205
src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp
Normal 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
|
131
src/libslic3r/CSGMesh/SliceCSGMesh.hpp
Normal file
131
src/libslic3r/CSGMesh/SliceCSGMesh.hpp
Normal 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 ¶ms,
|
||||
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
|
95
src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp
Normal file
95
src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp
Normal 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 ∂
|
||||
}
|
||||
|
||||
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
|
116
src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp
Normal file
116
src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp
Normal 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 ¶ms = {})
|
||||
{
|
||||
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
|
@ -615,7 +615,7 @@ public:
|
||||
static double nil_value() { return std::numeric_limits<double>::quiet_NaN(); }
|
||||
// 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(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
|
||||
{
|
||||
@ -776,7 +776,7 @@ public:
|
||||
static int nil_value() { return std::numeric_limits<int>::max(); }
|
||||
// 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(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
|
||||
{
|
||||
@ -1092,7 +1092,7 @@ public:
|
||||
static FloatOrPercent nil_value() { return { std::numeric_limits<double>::quiet_NaN(), false }; }
|
||||
// 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(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
|
||||
{
|
||||
@ -1404,7 +1404,7 @@ public:
|
||||
static unsigned char nil_value() { return std::numeric_limits<unsigned char>::max(); }
|
||||
// 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(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) {
|
||||
assert(! this->values.empty());
|
||||
|
@ -768,6 +768,15 @@ void priv::set_skip_for_out_of_aoi(std::vector<bool> &skip_indicies,
|
||||
|
||||
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
|
||||
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 n2 = v_ab.cross(v_al);
|
||||
// check that normal has same direction
|
||||
if ((n1.x() > 0 != n2.x() > 0) ||
|
||||
(n1.y() > 0 != n2.y() > 0) ||
|
||||
(n1.z() > 0 != n2.z() > 0))
|
||||
if (((n1.x() > 0) != (n2.x() > 0)) ||
|
||||
((n1.y() > 0) != (n2.y() > 0)) ||
|
||||
((n1.z() > 0) != (n2.z() > 0)))
|
||||
return; // this reduction will create CCW triangle
|
||||
}
|
||||
|
||||
|
@ -20,43 +20,224 @@
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
|
||||
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
|
||||
namespace priv{
|
||||
|
||||
bool is_valid(const Emboss::FontFile &font, unsigned int index);
|
||||
std::optional<stbtt_fontinfo> 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);
|
||||
using Polygon = Slic3r::Polygon;
|
||||
bool is_valid(const FontFile &font, unsigned int index);
|
||||
fontinfo_opt load_font_info(const unsigned char *data, unsigned int index = 0);
|
||||
std::optional<Glyph> get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness);
|
||||
|
||||
// take glyph from cache
|
||||
const Emboss::Glyph* get_glyph(int unicode, const Emboss::FontFile &font, const FontProp &font_prop,
|
||||
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt);
|
||||
const Glyph* get_glyph(int unicode, const FontFile &font, const FontProp &font_prop,
|
||||
Glyphs &cache, fontinfo_opt &font_info_opt);
|
||||
|
||||
EmbossStyle create_style(std::wstring name, std::wstring path);
|
||||
|
||||
// scale and convert float to int coordinate
|
||||
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
|
||||
bool remove_same_neighbor(Slic3r::Points &points);
|
||||
bool remove_same_neighbor(Slic3r::Polygons &polygons);
|
||||
// Return true when erase otherwise false
|
||||
bool remove_same_neighbor(Points &points);
|
||||
bool remove_same_neighbor(Polygons &polygons);
|
||||
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
|
||||
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_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->empty()) return false;
|
||||
if (index >= font.infos.size()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<stbtt_fontinfo> priv::load_font_info(
|
||||
fontinfo_opt priv::load_font_info(
|
||||
const unsigned char *data, unsigned int index)
|
||||
{
|
||||
int font_offset = stbtt_GetFontOffsetForIndex(data, index);
|
||||
@ -74,6 +255,23 @@ std::optional<stbtt_fontinfo> priv::load_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)
|
||||
{
|
||||
if (points.empty()) return false;
|
||||
@ -85,15 +283,15 @@ bool priv::remove_same_neighbor(Slic3r::Points &points)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool priv::remove_same_neighbor(Slic3r::Polygons &polygons) {
|
||||
bool priv::remove_same_neighbor(Polygons &polygons) {
|
||||
if (polygons.empty()) return false;
|
||||
bool exist = false;
|
||||
for (Slic3r::Polygon& polygon : polygons)
|
||||
for (Polygon& polygon : polygons)
|
||||
exist |= remove_same_neighbor(polygon.points);
|
||||
// remove empty polygons
|
||||
polygons.erase(
|
||||
std::remove_if(polygons.begin(), polygons.end(),
|
||||
[](const Slic3r::Polygon &p) { return p.empty(); }),
|
||||
[](const Polygon &p) { return p.empty(); }),
|
||||
polygons.end());
|
||||
return exist;
|
||||
}
|
||||
@ -104,19 +302,18 @@ bool priv::remove_same_neighbor(ExPolygons &expolygons) {
|
||||
for (ExPolygon &expoly : expolygons) {
|
||||
exist |= remove_same_neighbor(expoly.contour.points);
|
||||
Polygons &holes = expoly.holes;
|
||||
for (Slic3r::Polygon &hole : holes)
|
||||
for (Polygon &hole : holes)
|
||||
exist |= remove_same_neighbor(hole.points);
|
||||
// remove empy holes
|
||||
holes.erase(
|
||||
std::remove_if(holes.begin(), holes.end(),
|
||||
[](const Slic3r::Polygon &p) { return p.empty(); }),
|
||||
[](const Polygon &p) { return p.size() < 3; }),
|
||||
holes.end());
|
||||
}
|
||||
// remove empty contours
|
||||
expolygons.erase(
|
||||
std::remove_if(expolygons.begin(), expolygons.end(),
|
||||
[](const ExPolygon &p) { return p.contour.empty(); }),
|
||||
expolygons.end());
|
||||
|
||||
// Removing of point could create polygon with less than 3 points
|
||||
if (exist)
|
||||
remove_bad(expolygons);
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
@ -145,7 +342,7 @@ Points priv::collect_close_points(const ExPolygons &expolygons, double distance)
|
||||
// do not doubled side point of segment
|
||||
const ExPolygonsIndex id = ids.cvt(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 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();
|
||||
@ -159,7 +356,7 @@ Points priv::collect_close_points(const ExPolygons &expolygons, double distance)
|
||||
};
|
||||
for (const ExPolygon &expoly : expolygons) {
|
||||
collect_close(expoly.contour.points);
|
||||
for (const Slic3r::Polygon &hole : expoly.holes)
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
collect_close(hole.points);
|
||||
}
|
||||
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
|
||||
const ExPolygonsIndex id = ids.cvt(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 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();
|
||||
@ -213,7 +410,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
|
||||
};
|
||||
for (const ExPolygon &expoly : expolygons) {
|
||||
check_points(expoly.contour.points);
|
||||
for (const Slic3r::Polygon &hole : expoly.holes)
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
check_points(hole.points);
|
||||
}
|
||||
|
||||
@ -235,7 +432,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
|
||||
|
||||
ExPolygonsIndex id = ids.cvt(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;
|
||||
size_t count = it2 - it;
|
||||
|
||||
@ -272,7 +469,64 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
|
||||
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
|
||||
// fix of self intersections
|
||||
// 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)
|
||||
ClipperLib::CleanPolygons(paths, clean_distance);
|
||||
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
|
||||
Points duplicits = collect_duplicates(to_points(polygons));
|
||||
if (!duplicits.empty()) {
|
||||
polygons.reserve(polygons.size() + duplicits.size());
|
||||
for (const Point &p : duplicits) {
|
||||
Slic3r::Polygon rect_3x3(priv::pts_3x3);
|
||||
Polygon rect_3x3(priv::pts_3x3);
|
||||
rect_3x3.translate(p);
|
||||
polygons.push_back(rect_3x3);
|
||||
}
|
||||
@ -301,73 +556,133 @@ ExPolygons Emboss::heal_shape(const Polygons &shape) {
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
Slic3r::Polygons holes;
|
||||
// create loop permanent memory
|
||||
Polygons holes;
|
||||
Points intersections;
|
||||
while (--max_iteration) {
|
||||
priv::remove_same_neighbor(shape);
|
||||
Pointfs intersections_f = intersection_points(shape);
|
||||
|
||||
Pointfs intersections = intersection_points(shape);
|
||||
Points duplicits = collect_duplicates(to_points(shape));
|
||||
//Points close = priv::collect_close_points(shape, 1.);
|
||||
if (intersections.empty() && duplicits.empty() /* && close.empty() */) break;
|
||||
// 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())); });
|
||||
|
||||
holes.clear();
|
||||
holes.reserve(intersections.size() + duplicits.size() /* + close.size()*/);
|
||||
// intersections should be unique poits
|
||||
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
|
||||
for (const Vec2d &p : intersections) {
|
||||
Slic3r::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);
|
||||
for (const Point &p : intersections) {
|
||||
Polygon hole(priv::pts_2x2);
|
||||
hole.translate(p);
|
||||
holes.push_back(hole);
|
||||
}
|
||||
|
||||
// fix close points in simmilar way as duplicits
|
||||
//for (const Point &p : close) {
|
||||
// Slic3r::Polygon hole(priv::pts_3x3);
|
||||
// hole.translate(p);
|
||||
// holes.push_back(hole);
|
||||
//}
|
||||
// Fix duplicit points by hole 3x3 around duplicit point
|
||||
for (const Point &p : duplicates) {
|
||||
Polygon hole(priv::pts_3x3);
|
||||
hole.translate(p);
|
||||
holes.push_back(hole);
|
||||
}
|
||||
|
||||
holes = Slic3r::union_(holes);
|
||||
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);
|
||||
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) {
|
||||
//priv::visualize_heal("C:/data/temp/heal.svg", shape);
|
||||
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);
|
||||
Point size = bb.size();
|
||||
if (size.x() < 10) bb.max.x() += 10;
|
||||
if (size.y() < 10) bb.max.y() += 10;
|
||||
if (size.x() < 10)
|
||||
bb.max.x() += 10;
|
||||
if (size.y() < 10)
|
||||
bb.max.y() += 10;
|
||||
|
||||
Polygon rect({// CCW
|
||||
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.max - offset,
|
||||
{bb.max.x() - offset.x(), bb.min.y() + offset.y()}});
|
||||
// BAD symbol
|
||||
shape = {ExPolygon(rect, hole)};
|
||||
return false;
|
||||
|
||||
return ExPolygon(rect, hole);
|
||||
}
|
||||
|
||||
assert(intersection_points(shape).empty());
|
||||
assert(collect_duplicates(to_points(shape)).empty());
|
||||
return true;
|
||||
void priv::remove_small_islands(ExPolygons &expolygons, double minimal_area) {
|
||||
if (expolygons.empty())
|
||||
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);
|
||||
if (glyph_index == 0) {
|
||||
@ -404,7 +731,7 @@ std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, in
|
||||
return {};
|
||||
}
|
||||
|
||||
Emboss::Glyph glyph;
|
||||
Glyph glyph;
|
||||
stbtt_GetGlyphHMetrics(&font_info, glyph_index, &glyph.advance_width, &glyph.left_side_bearing);
|
||||
|
||||
stbtt_vertex *vertices;
|
||||
@ -454,12 +781,12 @@ std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, in
|
||||
return glyph;
|
||||
}
|
||||
|
||||
const Emboss::Glyph* priv::get_glyph(
|
||||
const Glyph* priv::get_glyph(
|
||||
int unicode,
|
||||
const Emboss::FontFile & font,
|
||||
const FontFile & font,
|
||||
const FontProp & font_prop,
|
||||
Emboss::Glyphs & cache,
|
||||
std::optional<stbtt_fontinfo> &font_info_opt)
|
||||
Glyphs & cache,
|
||||
fontinfo_opt &font_info_opt)
|
||||
{
|
||||
// TODO: Use resolution by printer configuration, or add it into FontProp
|
||||
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
|
||||
if (flatness < RESOLUTION) flatness = RESOLUTION;
|
||||
|
||||
std::optional<Emboss::Glyph> glyph_opt =
|
||||
std::optional<Glyph> glyph_opt =
|
||||
priv::get_glyph(*font_info_opt, unicode, flatness);
|
||||
|
||||
// IMPROVE: multiple loadig glyph without data
|
||||
@ -494,26 +821,26 @@ const Emboss::Glyph* priv::get_glyph(
|
||||
|
||||
// scale glyph size
|
||||
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 =
|
||||
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 (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;
|
||||
glyph_opt->shape = Slic3r::union_ex(offset_ex(glyph_opt->shape, delta));
|
||||
}
|
||||
if (font_prop.skew.has_value()) {
|
||||
const float &ratio = *font_prop.skew;
|
||||
auto skew = [&ratio](Slic3r::Polygon &polygon) {
|
||||
auto skew = [&ratio](Polygon &polygon) {
|
||||
for (Slic3r::Point &p : polygon.points) {
|
||||
p.x() += p.y() * ratio;
|
||||
}
|
||||
};
|
||||
for (ExPolygon &expolygon : glyph_opt->shape) {
|
||||
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) {
|
||||
return Point(static_cast<int>(std::round(point.x / Emboss::SHAPE_SCALE)),
|
||||
static_cast<int>(std::round(point.y / Emboss::SHAPE_SCALE)));
|
||||
return Point(static_cast<int>(std::round(point.x / SHAPE_SCALE)),
|
||||
static_cast<int>(std::round(point.y / SHAPE_SCALE)));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -738,7 +1065,7 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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});
|
||||
}
|
||||
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");
|
||||
if (file == nullptr) {
|
||||
@ -833,7 +1160,7 @@ static bool load_hfont(void* hfont, DWORD &dwTable, DWORD &dwOffset, size_t& siz
|
||||
return true;
|
||||
}
|
||||
|
||||
void * Emboss::can_load(HFONT hfont)
|
||||
void *Emboss::can_load(void *hfont)
|
||||
{
|
||||
DWORD dwTable=0, dwOffset=0;
|
||||
size_t size = 0;
|
||||
@ -841,7 +1168,7 @@ void * Emboss::can_load(HFONT 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);
|
||||
if (hdc == NULL) {
|
||||
@ -868,7 +1195,7 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font,
|
||||
std::optional<Glyph> Emboss::letter2glyph(const FontFile &font,
|
||||
unsigned int font_index,
|
||||
int letter,
|
||||
float flatness)
|
||||
@ -885,7 +1212,7 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
|
||||
std::function<bool()> was_canceled)
|
||||
{
|
||||
assert(font_with_cache.has_value());
|
||||
std::optional<stbtt_fontinfo> font_info_opt;
|
||||
fontinfo_opt font_info_opt;
|
||||
Point cursor(0, 0);
|
||||
ExPolygons result;
|
||||
const FontFile& font = *font_with_cache.font_file;
|
||||
@ -893,7 +1220,7 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
|
||||
*font_prop.collection_number : 0;
|
||||
if (!priv::is_valid(font, font_index)) return {};
|
||||
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);
|
||||
for (wchar_t wc: ws){
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
double scale = fp.size_in_mm / unit_per_em;
|
||||
// Shape is scaled for store point coordinate as integer
|
||||
return scale * Emboss::SHAPE_SCALE;
|
||||
return scale * SHAPE_SCALE;
|
||||
}
|
||||
|
||||
namespace priv {
|
||||
@ -1055,7 +1382,7 @@ void add_quad(uint32_t i1,
|
||||
|
||||
indexed_triangle_set polygons2model_unique(
|
||||
const ExPolygons &shape2d,
|
||||
const Emboss::IProjection &projection,
|
||||
const IProjection &projection,
|
||||
const Points &points)
|
||||
{
|
||||
// CW order of triangle indices
|
||||
@ -1091,7 +1418,7 @@ indexed_triangle_set polygons2model_unique(
|
||||
// quads around - zig zag by triangles
|
||||
size_t polygon_offset = 0;
|
||||
auto add_quads = [&polygon_offset,&result, &count_point]
|
||||
(const Slic3r::Polygon& polygon) {
|
||||
(const Polygon& polygon) {
|
||||
uint32_t polygon_points = polygon.points.size();
|
||||
// previous index
|
||||
uint32_t prev = polygon_offset + polygon_points - 1;
|
||||
@ -1105,7 +1432,7 @@ indexed_triangle_set polygons2model_unique(
|
||||
|
||||
for (const ExPolygon &expolygon : shape2d) {
|
||||
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;
|
||||
@ -1113,7 +1440,7 @@ indexed_triangle_set polygons2model_unique(
|
||||
|
||||
indexed_triangle_set polygons2model_duplicit(
|
||||
const ExPolygons &shape2d,
|
||||
const Emboss::IProjection &projection,
|
||||
const IProjection &projection,
|
||||
const Points &points,
|
||||
const Points &duplicits)
|
||||
{
|
||||
@ -1161,7 +1488,7 @@ indexed_triangle_set polygons2model_duplicit(
|
||||
// quads around - zig zag by triangles
|
||||
size_t polygon_offset = 0;
|
||||
auto add_quads = [&polygon_offset, &result, count_point, &changes]
|
||||
(const Slic3r::Polygon &polygon) {
|
||||
(const Polygon &polygon) {
|
||||
uint32_t polygon_points = polygon.points.size();
|
||||
// previous index
|
||||
uint32_t prev = changes[polygon_offset + polygon_points - 1];
|
||||
@ -1176,7 +1503,7 @@ indexed_triangle_set polygons2model_duplicit(
|
||||
|
||||
for (const ExPolygon &expolygon : shape2d) {
|
||||
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;
|
||||
}
|
||||
@ -1292,3 +1619,160 @@ std::optional<Vec2d> Emboss::OrthoProject::unproject(const Vec3d &p, double *dep
|
||||
if (depth != nullptr) *depth = pp.z();
|
||||
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
|
@ -128,10 +128,9 @@ namespace Emboss
|
||||
// data = raw file data
|
||||
std::unique_ptr<FontFile> create_font_file(std::unique_ptr<std::vector<unsigned char>> data);
|
||||
#ifdef _WIN32
|
||||
// fix for unknown pointer HFONT
|
||||
using HFONT = void*;
|
||||
void * can_load(HFONT hfont);
|
||||
std::unique_ptr<FontFile> create_font_file(HFONT hfont);
|
||||
// fix for unknown pointer HFONT is replaced with "void *"
|
||||
void * can_load(void* hfont);
|
||||
std::unique_ptr<FontFile> create_font_file(void * hfont);
|
||||
#endif // _WIN32
|
||||
|
||||
/// <summary>
|
||||
@ -155,9 +154,10 @@ namespace Emboss
|
||||
ExPolygons text2shapes(FontFileWithCache &font, const char *text, const FontProp &font_prop, std::function<bool()> was_canceled = nullptr);
|
||||
|
||||
/// <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>
|
||||
/// <param name="shape">Input shape to heal</param>
|
||||
/// <param name="precision">Define wanted precision of shape after heal</param>
|
||||
/// <returns>Healed shapes</returns>
|
||||
ExPolygons heal_shape(const Polygons &shape);
|
||||
|
||||
|
@ -320,7 +320,9 @@ void ExPolygon::medial_axis(double min_width, double max_width, Polylines* polyl
|
||||
{
|
||||
ThickPolylines 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
|
||||
|
@ -32,8 +32,8 @@ public:
|
||||
ExPolygon& operator=(const ExPolygon &other) = default;
|
||||
ExPolygon& operator=(ExPolygon &&other) = default;
|
||||
|
||||
Polygon contour;
|
||||
Polygons holes;
|
||||
Polygon contour; //CCW
|
||||
Polygons holes; //CW
|
||||
|
||||
void clear() { contour.points.clear(); holes.clear(); }
|
||||
void scale(double factor);
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
I to,
|
||||
const T &init,
|
||||
MergeFn &&mergefn,
|
||||
AccessFn &&access,
|
||||
AccessFn &&accessfn,
|
||||
size_t granularity = 1
|
||||
)
|
||||
{
|
||||
@ -61,7 +61,7 @@ public:
|
||||
tbb::blocked_range{from, to, granularity}, init,
|
||||
[&](const auto &range, T subinit) {
|
||||
T acc = subinit;
|
||||
loop_(range, [&](auto &i) { acc = mergefn(acc, access(i)); });
|
||||
loop_(range, [&](auto &i) { acc = mergefn(acc, accessfn(i)); });
|
||||
return acc;
|
||||
},
|
||||
std::forward<MergeFn>(mergefn));
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#define L(s) (s)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
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.
|
||||
// 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);
|
||||
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));
|
||||
@ -210,7 +208,7 @@ ExtrusionLoop::ClosestPathPoint ExtrusionLoop::get_closest_path_and_point(const
|
||||
out.segment_idx = foot_pt_.first;
|
||||
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.path_idx = &path - &this->paths.front();
|
||||
best_non_overhang.segment_idx = foot_pt_.first;
|
||||
@ -296,7 +294,7 @@ bool ExtrusionLoop::has_overhang_point(const Point &point) const
|
||||
if (pos != -1) {
|
||||
// point belongs to this path
|
||||
// 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;
|
||||
@ -322,65 +320,4 @@ double ExtrusionLoop::min_mm3_per_mm() const
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define slic3r_ExtrusionEntity_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include "ExtrusionRole.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
|
||||
@ -16,65 +17,6 @@ using ExPolygons = std::vector<ExPolygon>;
|
||||
class ExtrusionEntityCollection;
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -108,9 +50,6 @@ public:
|
||||
virtual Polylines as_polylines() const { Polylines dst; this->collect_polylines(dst); return dst; }
|
||||
virtual double length() 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;
|
||||
@ -217,7 +156,7 @@ public:
|
||||
size_t size() const { return this->paths.size(); }
|
||||
bool empty() const { return this->paths.empty(); }
|
||||
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.
|
||||
// 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;
|
||||
@ -279,7 +218,7 @@ public:
|
||||
// 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.
|
||||
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; }
|
||||
// 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.
|
||||
@ -304,8 +243,6 @@ public:
|
||||
}
|
||||
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
|
||||
bool validate() const {
|
||||
assert(this->first_point() == this->paths.back().polyline.points.back());
|
||||
|
@ -8,7 +8,7 @@ namespace Slic3r {
|
||||
|
||||
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 last = extrusion_entities.end();
|
||||
extrusion_entities.erase(
|
||||
|
@ -54,10 +54,10 @@ public:
|
||||
|
||||
bool is_collection() const override { return true; }
|
||||
ExtrusionRole role() const override {
|
||||
ExtrusionRole out = erNone;
|
||||
ExtrusionRole out{ ExtrusionRole::None };
|
||||
for (const ExtrusionEntity *ee : entities) {
|
||||
ExtrusionRole er = ee->role();
|
||||
out = (out == erNone || out == er) ? er : erMixed;
|
||||
out = (out == ExtrusionRole::None || out == er) ? er : ExtrusionRole::Mixed;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@ -96,8 +96,8 @@ public:
|
||||
}
|
||||
void replace(size_t i, const ExtrusionEntity &entity);
|
||||
void remove(size_t i);
|
||||
static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed);
|
||||
ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const
|
||||
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 = ExtrusionRole::Mixed) const
|
||||
{ return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); }
|
||||
void reverse() override;
|
||||
const Point& first_point() const override { return this->entities.front()->first_point(); }
|
||||
|
91
src/libslic3r/ExtrusionRole.cpp
Normal file
91
src/libslic3r/ExtrusionRole.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
128
src/libslic3r/ExtrusionRole.hpp
Normal file
128
src/libslic3r/ExtrusionRole.hpp
Normal 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_
|
@ -54,7 +54,7 @@ struct SurfaceFillParams
|
||||
Flow flow;
|
||||
|
||||
// For the output
|
||||
ExtrusionRole extrusion_role = ExtrusionRole(0);
|
||||
ExtrusionRole extrusion_role{ ExtrusionRole::None };
|
||||
|
||||
// Various print settings?
|
||||
|
||||
@ -83,8 +83,7 @@ struct SurfaceFillParams
|
||||
RETURN_COMPARE_NON_EQUAL(flow.height());
|
||||
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, bridge);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role);
|
||||
return false;
|
||||
return this->extrusion_role.lower(rhs.extrusion_role);
|
||||
}
|
||||
|
||||
bool operator==(const SurfaceFillParams &rhs) const {
|
||||
@ -152,11 +151,10 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
|
||||
params.extrusion_role =
|
||||
is_bridge ?
|
||||
erBridgeInfill :
|
||||
ExtrusionRole::BridgeInfill :
|
||||
(surface.is_solid() ?
|
||||
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
|
||||
//(surface.is_top() ? erTopSolidInfill : (surface.is_bottom()? erBottomSurface : erSolidInfill)) :
|
||||
erInternalInfill);
|
||||
(surface.is_top() ? ExtrusionRole::TopSolidInfill : ExtrusionRole::SolidInfill) :
|
||||
ExtrusionRole::InternalInfill);
|
||||
params.bridge_angle = float(surface.bridge_angle);
|
||||
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.pattern = fill_type_monotonic(layerm.region().config().top_fill_pattern) ? ipMonotonic : ipRectilinear;
|
||||
params.density = 100.f;
|
||||
params.extrusion_role = erInternalInfill;
|
||||
params.extrusion_role = ExtrusionRole::InternalInfill;
|
||||
params.angle = float(Geometry::deg2rad(layerm.region().config().fill_angle.value));
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
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_object_config = &this->object()->config();
|
||||
|
||||
if (surface_fill.params.pattern == ipLightning)
|
||||
dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator;
|
||||
if (surface_fill.params.pattern == ipLightning) {
|
||||
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) {
|
||||
auto *fill_bounded_rectilinear = dynamic_cast<FillEnsuring *>(f.get());
|
||||
@ -835,7 +836,7 @@ void Layer::make_ironing()
|
||||
eec->no_sort = true;
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, std::move(polylines),
|
||||
erIroning,
|
||||
ExtrusionRole::Ironing,
|
||||
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()));
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ void Filler::_fill_surface_single(
|
||||
ExPolygon expolygon,
|
||||
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));
|
||||
|
||||
if (params.dont_connect() || fill_lines.size() <= 1) {
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
~Filler() override = default;
|
||||
|
||||
Generator *generator { nullptr };
|
||||
size_t num_raft_layers { 0 };
|
||||
protected:
|
||||
Fill* clone() const override { return new Filler(*this); }
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "libslic3r.h"
|
||||
#include "Config.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "ExtrusionRole.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -113,26 +113,19 @@ namespace Slic3r {
|
||||
{
|
||||
std::string gcode;
|
||||
|
||||
// move to the nearest standby point
|
||||
if (!this->standby_points.empty()) {
|
||||
// get current position in print coordinates
|
||||
Vec3d writer_pos = gcodegen.writer().get_position();
|
||||
Point pos = Point::new_scale(writer_pos(0), writer_pos(1));
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
unsigned int extruder_id = gcodegen.writer().extruder()->id();
|
||||
const ConfigOptionIntsNullable& filament_idle_temp = gcodegen.config().idle_temperature;
|
||||
if (filament_idle_temp.is_nil(extruder_id)) {
|
||||
// There is no idle temperature defined in filament settings.
|
||||
// Use the delta value from print config.
|
||||
if (gcodegen.config().standby_temperature_delta.value != 0) {
|
||||
// we assume that heating is always slower than cooling, so no need to block
|
||||
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;
|
||||
@ -145,10 +138,9 @@ namespace Slic3r {
|
||||
std::string();
|
||||
}
|
||||
|
||||
int
|
||||
OozePrevention::_get_temp(GCode& gcodegen)
|
||||
int OozePrevention::_get_temp(const GCode& gcodegen) const
|
||||
{
|
||||
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().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);
|
||||
|
||||
if (! tcr.priming) {
|
||||
// Move over the wipe tower.
|
||||
double current_z = gcodegen.writer().get_position().z();
|
||||
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();
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
gcode += gcodegen.travel_to(
|
||||
wipe_tower_point_to_object_point(gcodegen, start_pos),
|
||||
erMixed,
|
||||
ExtrusionRole::Mixed,
|
||||
"Travel to a Wipe Tower");
|
||||
gcode += gcodegen.unretract();
|
||||
}
|
||||
|
||||
double current_z = gcodegen.writer().get_position().z();
|
||||
if (z == -1.) // in case no specific z was provided, print at current_z pos
|
||||
z = current_z;
|
||||
if (! is_approx(z, current_z)) {
|
||||
if (will_go_down) {
|
||||
gcode += gcodegen.writer().retract();
|
||||
gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer.");
|
||||
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;
|
||||
const std::string& toolchange_gcode = gcodegen.config().toolchange_gcode.value;
|
||||
if (! toolchange_gcode.empty()) {
|
||||
DynamicConfig config;
|
||||
int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1;
|
||||
config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id));
|
||||
config.set_key_value("next_extruder", new ConfigOptionInt((int)new_extruder_id));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||
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 deretraction_str;
|
||||
if (tcr.priming || (new_extruder_id >= 0 && needs_toolchange)) {
|
||||
if (gcodegen.config().single_extruder_multi_material)
|
||||
gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines.
|
||||
toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z
|
||||
if (gcodegen.config().wipe_tower)
|
||||
deretraction_str = gcodegen.unretract();
|
||||
}
|
||||
|
||||
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;
|
||||
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.
|
||||
|
||||
// Insert the toolchange and deretraction gcode into the generated gcode.
|
||||
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("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);
|
||||
unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
|
||||
gcode += tcr_gcode;
|
||||
check_add_eol(toolchange_gcode_str);
|
||||
|
||||
|
||||
// A phony move to the end position at the wipe tower.
|
||||
gcodegen.writer().travel_to_xy(end_pos.cast<double>());
|
||||
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.
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -864,7 +818,7 @@ namespace DoExport {
|
||||
auto min_mm3_per_mm_no_ironing = [](const ExtrusionEntityCollection& eec) -> double {
|
||||
double min = std::numeric_limits<double>::max();
|
||||
for (const ExtrusionEntity* ee : eec.entities)
|
||||
if (ee->role() != erIroning)
|
||||
if (ee->role() != ExtrusionRole::Ironing)
|
||||
min = std::min(min, ee->min_mm3_per_mm());
|
||||
return min;
|
||||
};
|
||||
@ -898,34 +852,7 @@ namespace DoExport {
|
||||
|
||||
static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention)
|
||||
{
|
||||
// Calculate wiping points if needed
|
||||
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
|
||||
}
|
||||
}
|
||||
ooze_prevention.enable = print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material;
|
||||
}
|
||||
|
||||
// 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_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() }));
|
||||
|
||||
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);
|
||||
// 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);
|
||||
@ -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);
|
||||
|
||||
// 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
|
||||
file.writeln(start_gcode);
|
||||
@ -1282,8 +1218,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// Set other general things.
|
||||
file.write(this->preamble());
|
||||
|
||||
// Calculate wiping points if needed
|
||||
DoExport::init_ooze_prevention(print, m_ooze_prevention);
|
||||
print.throw_if_canceled();
|
||||
|
||||
// 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_avoid_crossing_perimeters.use_external_mp_once();
|
||||
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;
|
||||
// Disable motion planner when traveling to first object point.
|
||||
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));
|
||||
|
||||
// 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.
|
||||
{
|
||||
@ -1823,8 +1757,14 @@ void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Pr
|
||||
// Set temperatures of all the printing extruders.
|
||||
for (unsigned int tool_id : print.extruders()) {
|
||||
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;
|
||||
else
|
||||
temp = print.config().idle_temperature.get_at(tool_id);
|
||||
}
|
||||
|
||||
if (temp > 0)
|
||||
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
|
||||
// first_layer_temperature vs. temperature settings.
|
||||
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.
|
||||
// The same applies when ooze prevention is enabled.
|
||||
if (extruder.id() != m_writer.extruder()->id())
|
||||
continue;
|
||||
}
|
||||
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_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_other_layers(print, layer_tools, m_skirt_done);
|
||||
|
||||
if (this->config().avoid_curled_filament_during_travels) {
|
||||
m_avoid_curled_filaments.clear();
|
||||
if (this->config().avoid_crossing_curled_overhangs) {
|
||||
m_avoid_crossing_curled_overhangs.clear();
|
||||
for (const ObjectLayerToPrint &layer_to_print : layers) {
|
||||
m_avoid_curled_filaments.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.object_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
|
||||
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()) {
|
||||
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 (const SupportLayer &support_layer = *layer_to_print.support_layer; ! support_layer.support_fills.entities.empty()) {
|
||||
ExtrusionRole role = support_layer.support_fills.role();
|
||||
bool has_support = role == erMixed || role == erSupportMaterial;
|
||||
bool has_interface = role == erMixed || role == erSupportMaterialInterface;
|
||||
bool has_support = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterial;
|
||||
bool has_interface = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterialInterface;
|
||||
// Extruder ID of the support base. -1 if "don't care".
|
||||
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?
|
||||
@ -2340,8 +2283,8 @@ void GCode::process_layer_single_object(
|
||||
m_layer = layer_to_print.support_layer;
|
||||
m_object_layer_over_raft = false;
|
||||
gcode += this->extrude_support(
|
||||
// support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths.
|
||||
support_layer.support_fills.chained_path_from(m_last_pos, has_support ? (has_interface ? erMixed : erSupportMaterial) : erSupportMaterialInterface));
|
||||
// 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 ? ExtrusionRole::Mixed : ExtrusionRole::SupportMaterial) : ExtrusionRole::SupportMaterialInterface));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2372,7 +2315,8 @@ void GCode::process_layer_single_object(
|
||||
|
||||
ExtrusionEntitiesPtr temp_fill_extrusions;
|
||||
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 = [&](
|
||||
const LayerRegion &layerm, const ExtrusionEntityCollection &fills,
|
||||
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) {
|
||||
assert(dynamic_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())
|
||||
// Flatten the infill collection for better path planning.
|
||||
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 "";
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
// 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.
|
||||
@ -2686,7 +2630,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s
|
||||
m_wipe.path.reverse();
|
||||
|
||||
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.
|
||||
|
||||
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);
|
||||
for (const ExtrusionEntity *ee : support_fills.entities) {
|
||||
ExtrusionRole role = ee->role();
|
||||
assert(role == erSupportMaterial || role == erSupportMaterialInterface);
|
||||
const auto label = (role == erSupportMaterial) ? support_label : support_interface_label;
|
||||
const double speed = (role == erSupportMaterial) ? support_speed : support_interface_speed;
|
||||
assert(role == ExtrusionRole::SupportMaterial || role == ExtrusionRole::SupportMaterialInterface);
|
||||
const auto label = (role == ExtrusionRole::SupportMaterial) ? support_label : support_interface_label;
|
||||
const double speed = (role == ExtrusionRole::SupportMaterial) ? support_speed : support_interface_speed;
|
||||
const ExtrusionPath *path = dynamic_cast<const ExtrusionPath*>(ee);
|
||||
if (path)
|
||||
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;
|
||||
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
|
||||
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;
|
||||
} 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;
|
||||
} 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;
|
||||
} 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;
|
||||
} 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;
|
||||
} else {
|
||||
acceleration = m_config.default_acceleration.value;
|
||||
@ -2872,21 +2816,22 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
|
||||
// set speed
|
||||
if (speed == -1) {
|
||||
if (path.role() == erPerimeter) {
|
||||
if (path.role() == ExtrusionRole::Perimeter) {
|
||||
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");
|
||||
} 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");
|
||||
} else if (path.role() == erInternalInfill) {
|
||||
} else if (path.role() == ExtrusionRole::InternalInfill) {
|
||||
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");
|
||||
} else if (path.role() == erTopSolidInfill) {
|
||||
} else if (path.role() == ExtrusionRole::TopSolidInfill) {
|
||||
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");
|
||||
} else if (path.role() == erGapFill) {
|
||||
} else if (path.role() == ExtrusionRole::GapFill) {
|
||||
speed = m_config.get_abs_value("gap_fill_speed");
|
||||
} else {
|
||||
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;
|
||||
std::vector<ProcessedPoint> new_points{};
|
||||
if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && is_perimeter(path.role())) {
|
||||
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_steepness_levels,
|
||||
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_overlap_levels,
|
||||
m_config.dynamic_overhang_speeds,
|
||||
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; });
|
||||
@ -2927,9 +2872,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
// extrude arc or line
|
||||
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)
|
||||
{
|
||||
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
|
||||
// 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
|
||||
bool last_was_wipe_tower = (m_last_processor_extrusion_role == erWipeTower);
|
||||
// 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 == GCodeExtrusionRole::WipeTower);
|
||||
assert(is_decimal_separator_point());
|
||||
|
||||
if (path.role() != m_last_processor_extrusion_role) {
|
||||
m_last_processor_extrusion_role = path.role();
|
||||
if (GCodeExtrusionRole role = extrusion_role_to_gcode_extrusion_role(path.role()); role != m_last_processor_extrusion_role) {
|
||||
m_last_processor_extrusion_role = role;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2975,11 +2920,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
|
||||
std::string comment;
|
||||
if (m_enable_cooling_markers) {
|
||||
if (is_bridge(path.role()))
|
||||
if (path.role().is_bridge())
|
||||
gcode += ";_BRIDGE_FAN_START\n";
|
||||
else
|
||||
comment = ";_EXTRUDE_SET_SPEED";
|
||||
if (path.role() == erExternalPerimeter)
|
||||
if (path.role() == ExtrusionRole::ExternalPerimeter)
|
||||
comment += ";_EXTERNAL_PERIMETER";
|
||||
}
|
||||
|
||||
@ -3026,7 +2971,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
}
|
||||
|
||||
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());
|
||||
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. */
|
||||
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) {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -3112,7 +3057,7 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (role == erSupportMaterial)
|
||||
if (role == ExtrusionRole::SupportMaterial)
|
||||
if (const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(m_layer);
|
||||
support_layer != nullptr && ! support_layer->support_islands_bboxes.empty()) {
|
||||
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()) {
|
||||
// Process the start_filament_gcode for the filament.
|
||||
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)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
@ -3200,8 +3148,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
m_wipe.reset_path();
|
||||
|
||||
if (m_writer.extruder() != nullptr) {
|
||||
// Process the custom end_filament_gcode. set_extruder() is only called if there is no wipe tower
|
||||
// so it should not be injected twice.
|
||||
// Process the custom end_filament_gcode.
|
||||
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);
|
||||
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
|
||||
// standby point and set it to the standby temperature.
|
||||
// If ooze prevention is enabled, set current extruder to the standby temperature.
|
||||
if (m_ooze_prevention.enable && m_writer.extruder() != nullptr)
|
||||
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()) {
|
||||
// Process the start_filament_gcode for the new filament.
|
||||
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)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
|
@ -39,14 +39,13 @@ struct PrintInstance;
|
||||
class OozePrevention {
|
||||
public:
|
||||
bool enable;
|
||||
Points standby_points;
|
||||
|
||||
OozePrevention() : enable(false) {}
|
||||
std::string pre_toolchange(GCode &gcodegen);
|
||||
std::string post_toolchange(GCode &gcodegen);
|
||||
|
||||
private:
|
||||
int _get_temp(GCode &gcodegen);
|
||||
int _get_temp(const GCode &gcodegen) const;
|
||||
};
|
||||
|
||||
class Wipe {
|
||||
@ -137,14 +136,14 @@ public:
|
||||
m_enable_loop_clipping(true),
|
||||
m_enable_cooling_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_index(-1),
|
||||
m_layer(nullptr),
|
||||
m_object_layer_over_raft(false),
|
||||
m_volumetric_speed(0),
|
||||
m_last_pos_defined(false),
|
||||
m_last_extrusion_role(erNone),
|
||||
m_last_extrusion_role(GCodeExtrusionRole::None),
|
||||
m_last_width(0.0f),
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
m_last_mm3_per_mm(0.0),
|
||||
@ -326,7 +325,7 @@ private:
|
||||
std::string extrude_support(const ExtrusionEntityCollection &support_fills);
|
||||
|
||||
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 unretract() { return m_writer.unlift() + m_writer.unretract(); }
|
||||
std::string set_extruder(unsigned int extruder_id, double print_z);
|
||||
@ -352,7 +351,7 @@ private:
|
||||
OozePrevention m_ooze_prevention;
|
||||
Wipe m_wipe;
|
||||
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
||||
JPSPathFinder m_avoid_curled_filaments;
|
||||
JPSPathFinder m_avoid_crossing_curled_overhangs;
|
||||
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters;
|
||||
bool m_enable_loop_clipping;
|
||||
// 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.
|
||||
bool m_enable_extrusion_role_markers;
|
||||
// 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?
|
||||
// change_layer() will update the progress bar.
|
||||
unsigned int m_layer_count;
|
||||
@ -376,7 +375,7 @@ private:
|
||||
bool m_object_layer_over_raft;
|
||||
double m_volumetric_speed;
|
||||
// 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
|
||||
float m_last_height{ 0.0f };
|
||||
float m_last_layer_z{ 0.0f };
|
||||
|
@ -39,9 +39,9 @@ public:
|
||||
void add_point(float distance, float angle)
|
||||
{
|
||||
total_distance += distance;
|
||||
total_curvature += std::abs(angle);
|
||||
total_curvature += angle;
|
||||
distances.push_back(distance);
|
||||
angles.push_back(std::abs(angle));
|
||||
angles.push_back(angle);
|
||||
|
||||
while (distances.size() > 1 && total_distance > window_size) {
|
||||
total_distance -= distances.front();
|
||||
@ -53,8 +53,6 @@ public:
|
||||
|
||||
float get_curvature() const
|
||||
{
|
||||
if (total_distance < EPSILON) { return 0.0; }
|
||||
|
||||
return total_curvature / window_size;
|
||||
}
|
||||
|
||||
@ -69,24 +67,33 @@ public:
|
||||
|
||||
class CurvatureEstimator
|
||||
{
|
||||
static const size_t sliders_count = 2;
|
||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.5}, {3.0}};
|
||||
static const size_t sliders_count = 3;
|
||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.0},{4.0}, {10.0}};
|
||||
|
||||
public:
|
||||
void add_point(float distance, float angle)
|
||||
{
|
||||
if (distance < EPSILON) return;
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.add_point(distance, angle); }
|
||||
if (distance < EPSILON)
|
||||
return;
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||
slider.add_point(distance, angle);
|
||||
}
|
||||
}
|
||||
float get_curvature()
|
||||
{
|
||||
float max_curvature = std::numeric_limits<float>::min();
|
||||
for (const SlidingWindowCurvatureAccumulator &slider : sliders) { max_curvature = std::max(max_curvature, slider.get_curvature()); }
|
||||
float max_curvature = 0.0f;
|
||||
for (const SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||
if (abs(slider.get_curvature()) > abs(max_curvature)) {
|
||||
max_curvature = slider.get_curvature();
|
||||
}
|
||||
}
|
||||
return max_curvature;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.reset(); }
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||
slider.reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -102,45 +109,47 @@ struct ExtendedPoint
|
||||
float curvature;
|
||||
};
|
||||
|
||||
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_ONLY, bool CONCAVITY_RESETS_CURVATURE, typename P, typename L>
|
||||
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &extrusion_points,
|
||||
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename P, typename L>
|
||||
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &input_points,
|
||||
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
|
||||
float flow_width)
|
||||
float flow_width,
|
||||
float max_line_length = -1.0f)
|
||||
{
|
||||
if (extrusion_points.empty()) return {};
|
||||
float boundary_offset = PREV_LAYER_BOUNDARY_ONLY ? 0.5 * flow_width : 0.0f;
|
||||
using AABBScalar = typename AABBTreeLines::LinesDistancer<L>::Scalar;
|
||||
if (input_points.empty())
|
||||
return {};
|
||||
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
|
||||
CurvatureEstimator cestim;
|
||||
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>(); };
|
||||
|
||||
std::vector<ExtendedPoint> points;
|
||||
points.reserve(input_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
|
||||
|
||||
{
|
||||
ExtendedPoint start_point{maybe_unscale(extrusion_points.front())};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(start_point.position);
|
||||
ExtendedPoint start_point{maybe_unscale(input_points.front())};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
|
||||
start_point.distance = distance + boundary_offset;
|
||||
start_point.nearest_prev_layer_line = nearest_line;
|
||||
points.push_back(start_point);
|
||||
}
|
||||
for (size_t i = 1; i < extrusion_points.size(); i++) {
|
||||
ExtendedPoint next_point{maybe_unscale(extrusion_points[i])};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(next_point.position);
|
||||
for (size_t i = 1; i < input_points.size(); i++) {
|
||||
ExtendedPoint next_point{maybe_unscale(input_points[i])};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
|
||||
next_point.distance = distance + boundary_offset;
|
||||
next_point.nearest_prev_layer_line = nearest_line;
|
||||
|
||||
if (ADD_INTERSECTIONS &&
|
||||
((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) {
|
||||
const ExtendedPoint &prev_point = points.back();
|
||||
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position, 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) {
|
||||
points.emplace_back(intersection, boundary_offset);
|
||||
points.emplace_back(intersection.first.template cast<double>(), boundary_offset, intersection.second);
|
||||
}
|
||||
}
|
||||
points.push_back(next_point);
|
||||
}
|
||||
|
||||
if (PREV_LAYER_BOUNDARY_ONLY && ADD_INTERSECTIONS) {
|
||||
if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) {
|
||||
std::vector<ExtendedPoint> new_points;
|
||||
new_points.reserve(points.size()*2);
|
||||
new_points.push_back(points.front());
|
||||
@ -159,19 +168,42 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
|
||||
|
||||
if (t0 < 1.0) {
|
||||
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});
|
||||
}
|
||||
if (t1 > 0.0) {
|
||||
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(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) {
|
||||
@ -194,10 +226,8 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
|
||||
float distance = (prev.position - a.position).norm();
|
||||
float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position);
|
||||
cestim.add_point(distance, alfa);
|
||||
if (CONCAVITY_RESETS_CURVATURE && alfa < 0.0) { cestim.reset(); }
|
||||
}
|
||||
|
||||
if (a.distance < min_malformation_dist) { cestim.reset(); }
|
||||
a.curvature = cestim.get_curvature();
|
||||
}
|
||||
|
||||
@ -241,10 +271,23 @@ public:
|
||||
speed_sections.push_back({distance, speed});
|
||||
}
|
||||
std::sort(speed_sections.begin(), speed_sections.end(),
|
||||
[](const std::pair<float, float> &a, const std::pair<float, float> &b) { 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 §ion : speed_sections) {
|
||||
if (section.first == last_section.first) {
|
||||
section.second = last_section.second;
|
||||
} else {
|
||||
last_section = section;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ExtendedPoint> extended_points =
|
||||
estimate_points_properties<true, true, true, 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;
|
||||
processed_points.reserve(extended_points.size());
|
||||
|
@ -415,7 +415,7 @@ void GCodeProcessor::UsedFilaments::process_role_cache(const GCodeProcessor* pro
|
||||
filament.first = role_cache / s * 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()) {
|
||||
filaments_per_role[active_role].first += filament.first;
|
||||
filaments_per_role[active_role].second += filament.second;
|
||||
@ -942,7 +942,7 @@ void GCodeProcessor::reset()
|
||||
m_fan_speed = 0.0f;
|
||||
m_z_offset = 0.0f;
|
||||
|
||||
m_extrusion_role = erNone;
|
||||
m_extrusion_role = GCodeExtrusionRole::None;
|
||||
m_extruder_id = 0;
|
||||
m_extruder_colors.resize(MIN_EXTRUDERS_COUNT);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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];
|
||||
if (time > 0.0f)
|
||||
ret.push_back({ static_cast<ExtrusionRole>(i), time });
|
||||
ret.push_back({ static_cast<GCodeExtrusionRole>(i), time });
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -1645,8 +1645,8 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
|
||||
|
||||
// extrusion role tag
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Role))) {
|
||||
set_extrusion_role(ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length())));
|
||||
if (m_extrusion_role == erExternalPerimeter)
|
||||
set_extrusion_role(string_to_gcode_extrusion_role(comment.substr(reserved_tag(ETags::Role).length())));
|
||||
if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
|
||||
m_seams_detector.activate(true);
|
||||
return;
|
||||
}
|
||||
@ -1827,27 +1827,27 @@ bool GCodeProcessor::process_cura_tags(const std::string_view comment)
|
||||
if (pos != comment.npos) {
|
||||
const std::string_view type = comment.substr(pos + tag.length());
|
||||
if (type == "SKIRT")
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
else if (type == "WALL-OUTER")
|
||||
set_extrusion_role(erExternalPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
|
||||
else if (type == "WALL-INNER")
|
||||
set_extrusion_role(erPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::Perimeter);
|
||||
else if (type == "SKIN")
|
||||
set_extrusion_role(erSolidInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::SolidInfill);
|
||||
else if (type == "FILL")
|
||||
set_extrusion_role(erInternalInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::InternalInfill);
|
||||
else if (type == "SUPPORT")
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
else if (type == "SUPPORT-INTERFACE")
|
||||
set_extrusion_role(erSupportMaterialInterface);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
|
||||
else if (type == "PRIME-TOWER")
|
||||
set_extrusion_role(erWipeTower);
|
||||
set_extrusion_role(GCodeExtrusionRole::WipeTower);
|
||||
else {
|
||||
set_extrusion_role(erNone);
|
||||
set_extrusion_role(GCodeExtrusionRole::None);
|
||||
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);
|
||||
|
||||
return true;
|
||||
@ -1906,14 +1906,14 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
|
||||
// ; skirt
|
||||
pos = cmt.find(" skirt");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; outer perimeter
|
||||
pos = cmt.find(" outer perimeter");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erExternalPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
|
||||
m_seams_detector.activate(true);
|
||||
return true;
|
||||
}
|
||||
@ -1921,77 +1921,77 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
|
||||
// ; inner perimeter
|
||||
pos = cmt.find(" inner perimeter");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::Perimeter);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; gap fill
|
||||
pos = cmt.find(" gap fill");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erGapFill);
|
||||
set_extrusion_role(GCodeExtrusionRole::GapFill);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; infill
|
||||
pos = cmt.find(" infill");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erInternalInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::InternalInfill);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; solid layer
|
||||
pos = cmt.find(" solid layer");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSolidInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::SolidInfill);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; bridge
|
||||
pos = cmt.find(" bridge");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erBridgeInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::BridgeInfill);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; support
|
||||
pos = cmt.find(" support");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; dense support
|
||||
pos = cmt.find(" dense support");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSupportMaterialInterface);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; prime pillar
|
||||
pos = cmt.find(" prime pillar");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erWipeTower);
|
||||
set_extrusion_role(GCodeExtrusionRole::WipeTower);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; ooze shield
|
||||
pos = cmt.find(" ooze shield");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone); // Missing mapping
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // Missing mapping
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; raft
|
||||
pos = cmt.find(" raft");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; internal single extrusion
|
||||
pos = cmt.find(" internal single extrusion");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone); // Missing mapping
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // Missing mapping
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2043,33 +2043,33 @@ bool GCodeProcessor::process_craftware_tags(const std::string_view comment)
|
||||
if (pos != comment.npos) {
|
||||
const std::string_view type = comment.substr(pos + tag.length());
|
||||
if (type == "Skirt")
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
else if (type == "Perimeter")
|
||||
set_extrusion_role(erExternalPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
|
||||
else if (type == "HShell")
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
else if (type == "InnerHair")
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
else if (type == "Loop")
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
else if (type == "Infill")
|
||||
set_extrusion_role(erInternalInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::InternalInfill);
|
||||
else if (type == "Raft")
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
else if (type == "Support")
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
else if (type == "SupportTouch")
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
else if (type == "SoftSupport")
|
||||
set_extrusion_role(erSupportMaterialInterface);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
|
||||
else if (type == "Pillar")
|
||||
set_extrusion_role(erWipeTower);
|
||||
set_extrusion_role(GCodeExtrusionRole::WipeTower);
|
||||
else {
|
||||
set_extrusion_role(erNone);
|
||||
set_extrusion_role(GCodeExtrusionRole::None);
|
||||
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);
|
||||
|
||||
return true;
|
||||
@ -2093,25 +2093,25 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
|
||||
if (pos != comment.npos) {
|
||||
const std::string_view type = comment.substr(pos + tag.length());
|
||||
if (type == "RAFT")
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
else if (type == "WALL-OUTER")
|
||||
set_extrusion_role(erExternalPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
|
||||
else if (type == "WALL-INNER")
|
||||
set_extrusion_role(erPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::Perimeter);
|
||||
else if (type == "SOLID-FILL")
|
||||
set_extrusion_role(erSolidInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::SolidInfill);
|
||||
else if (type == "FILL")
|
||||
set_extrusion_role(erInternalInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::InternalInfill);
|
||||
else if (type == "BRIDGE")
|
||||
set_extrusion_role(erBridgeInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::BridgeInfill);
|
||||
else if (type == "SUPPORT")
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
else {
|
||||
set_extrusion_role(erNone);
|
||||
set_extrusion_role(GCodeExtrusionRole::None);
|
||||
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);
|
||||
|
||||
return true;
|
||||
@ -2153,35 +2153,35 @@ bool GCodeProcessor::process_kissslicer_tags(const std::string_view comment)
|
||||
// ; 'Raft Path'
|
||||
size_t pos = comment.find(" 'Raft Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Support Interface Path'
|
||||
pos = comment.find(" 'Support Interface Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSupportMaterialInterface);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Travel/Ironing Path'
|
||||
pos = comment.find(" 'Travel/Ironing Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erIroning);
|
||||
set_extrusion_role(GCodeExtrusionRole::Ironing);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Support (may Stack) Path'
|
||||
pos = comment.find(" 'Support (may Stack) Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Perimeter Path'
|
||||
pos = comment.find(" 'Perimeter Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erExternalPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
|
||||
m_seams_detector.activate(true);
|
||||
return true;
|
||||
}
|
||||
@ -2189,56 +2189,56 @@ bool GCodeProcessor::process_kissslicer_tags(const std::string_view comment)
|
||||
// ; 'Pillar Path'
|
||||
pos = comment.find(" 'Pillar Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Destring/Wipe/Jump Path'
|
||||
pos = comment.find(" 'Destring/Wipe/Jump Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Prime Pillar Path'
|
||||
pos = comment.find(" 'Prime Pillar Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Loop Path'
|
||||
pos = comment.find(" 'Loop Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Crown Path'
|
||||
pos = comment.find(" 'Crown Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
set_extrusion_role(GCodeExtrusionRole::None); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Solid Path'
|
||||
pos = comment.find(" 'Solid Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erNone);
|
||||
set_extrusion_role(GCodeExtrusionRole::None);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Stacked Sparse Infill Path'
|
||||
pos = comment.find(" 'Stacked Sparse Infill Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erInternalInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::InternalInfill);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ; 'Sparse Infill Path'
|
||||
pos = comment.find(" 'Sparse Infill Path'");
|
||||
if (pos == 0) {
|
||||
set_extrusion_role(erSolidInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::SolidInfill);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2263,45 +2263,45 @@ bool GCodeProcessor::process_bambustudio_tags(const std::string_view comment)
|
||||
if (pos != comment.npos) {
|
||||
const std::string_view type = comment.substr(pos + tag.length());
|
||||
if (type == "Custom")
|
||||
set_extrusion_role(erCustom);
|
||||
set_extrusion_role(GCodeExtrusionRole::Custom);
|
||||
else if (type == "Inner wall")
|
||||
set_extrusion_role(erPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::Perimeter);
|
||||
else if (type == "Outer wall")
|
||||
set_extrusion_role(erExternalPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::ExternalPerimeter);
|
||||
else if (type == "Overhang wall")
|
||||
set_extrusion_role(erOverhangPerimeter);
|
||||
set_extrusion_role(GCodeExtrusionRole::OverhangPerimeter);
|
||||
else if (type == "Gap infill")
|
||||
set_extrusion_role(erGapFill);
|
||||
set_extrusion_role(GCodeExtrusionRole::GapFill);
|
||||
else if (type == "Bridge")
|
||||
set_extrusion_role(erBridgeInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::BridgeInfill);
|
||||
else if (type == "Sparse infill")
|
||||
set_extrusion_role(erInternalInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::InternalInfill);
|
||||
else if (type == "Internal solid infill")
|
||||
set_extrusion_role(erSolidInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::SolidInfill);
|
||||
else if (type == "Top surface")
|
||||
set_extrusion_role(erTopSolidInfill);
|
||||
set_extrusion_role(GCodeExtrusionRole::TopSolidInfill);
|
||||
else if (type == "Bottom surface")
|
||||
set_extrusion_role(erNone);
|
||||
set_extrusion_role(GCodeExtrusionRole::None);
|
||||
else if (type == "Ironing")
|
||||
set_extrusion_role(erIroning);
|
||||
set_extrusion_role(GCodeExtrusionRole::Ironing);
|
||||
else if (type == "Skirt")
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
else if (type == "Brim")
|
||||
set_extrusion_role(erSkirt);
|
||||
set_extrusion_role(GCodeExtrusionRole::Skirt);
|
||||
else if (type == "Support")
|
||||
set_extrusion_role(erSupportMaterial);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterial);
|
||||
else if (type == "Support interface")
|
||||
set_extrusion_role(erSupportMaterialInterface);
|
||||
set_extrusion_role(GCodeExtrusionRole::SupportMaterialInterface);
|
||||
else if (type == "Support transition")
|
||||
set_extrusion_role(erNone);
|
||||
set_extrusion_role(GCodeExtrusionRole::None);
|
||||
else if (type == "Prime tower")
|
||||
set_extrusion_role(erWipeTower);
|
||||
set_extrusion_role(GCodeExtrusionRole::WipeTower);
|
||||
else {
|
||||
set_extrusion_role(erNone);
|
||||
set_extrusion_role(GCodeExtrusionRole::None);
|
||||
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);
|
||||
|
||||
return true;
|
||||
@ -2405,7 +2405,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
||||
if (m_height == 0.0f)
|
||||
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;
|
||||
|
||||
if (line.comment() != INTERNAL_G2G3_TAG)
|
||||
@ -2418,10 +2418,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
||||
|
||||
if (m_forced_width > 0.0f)
|
||||
m_width = m_forced_width;
|
||||
else if (m_extrusion_role == erExternalPerimeter)
|
||||
else if (m_extrusion_role == GCodeExtrusionRole::ExternalPerimeter)
|
||||
// cross section: rectangle
|
||||
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
|
||||
m_width = static_cast<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
|
||||
else
|
||||
@ -2605,10 +2605,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
||||
|
||||
if (m_seams_detector.is_active()) {
|
||||
// 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]);
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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.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_extrusion_role = role;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/ExtrusionRole.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
|
||||
@ -47,7 +47,7 @@ namespace Slic3r {
|
||||
float travel_time;
|
||||
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<ExtrusionRole, float>> roles_times;
|
||||
std::vector<std::pair<GCodeExtrusionRole, float>> roles_times;
|
||||
std::vector<float> layers_times;
|
||||
|
||||
void reset() {
|
||||
@ -62,7 +62,7 @@ namespace Slic3r {
|
||||
|
||||
std::vector<double> volumes_per_color_change;
|
||||
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::array<Mode, static_cast<size_t>(ETimeMode::Count)> modes;
|
||||
@ -99,7 +99,7 @@ namespace Slic3r {
|
||||
{
|
||||
unsigned int gcode_id{ 0 };
|
||||
EMoveType type{ EMoveType::Noop };
|
||||
ExtrusionRole extrusion_role{ erNone };
|
||||
GCodeExtrusionRole extrusion_role{ GCodeExtrusionRole::None };
|
||||
unsigned char extruder_id{ 0 };
|
||||
unsigned char cp_color_id{ 0 };
|
||||
Vec3f position{ Vec3f::Zero() }; // mm
|
||||
@ -238,7 +238,7 @@ namespace Slic3r {
|
||||
};
|
||||
|
||||
EMoveType move_type{ EMoveType::Noop };
|
||||
ExtrusionRole role{ erNone };
|
||||
GCodeExtrusionRole role{ GCodeExtrusionRole::None };
|
||||
unsigned int g1_line_id{ 0 };
|
||||
unsigned int layer_id{ 0 };
|
||||
float distance{ 0.0f }; // mm
|
||||
@ -310,7 +310,7 @@ namespace Slic3r {
|
||||
std::vector<TimeBlock> blocks;
|
||||
std::vector<G1LinesCacheItem> g1_times_cache;
|
||||
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;
|
||||
|
||||
void reset();
|
||||
@ -360,7 +360,7 @@ namespace Slic3r {
|
||||
std::map<size_t, double> volumes_per_extruder;
|
||||
|
||||
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();
|
||||
|
||||
@ -441,7 +441,7 @@ namespace Slic3r {
|
||||
{
|
||||
float value;
|
||||
float tag_value;
|
||||
ExtrusionRole role;
|
||||
GCodeExtrusionRole role;
|
||||
};
|
||||
|
||||
std::string type;
|
||||
@ -454,8 +454,8 @@ namespace Slic3r {
|
||||
: type(type), threshold(threshold)
|
||||
{}
|
||||
|
||||
void update(float value, ExtrusionRole role) {
|
||||
if (role != erCustom) {
|
||||
void update(float value, GCodeExtrusionRole role) {
|
||||
if (role != GCodeExtrusionRole::Custom) {
|
||||
++count;
|
||||
if (last_tag_value != 0.0f) {
|
||||
if (std::abs(value - last_tag_value) / last_tag_value > threshold)
|
||||
@ -539,7 +539,7 @@ namespace Slic3r {
|
||||
float m_mm3_per_mm;
|
||||
float m_fan_speed; // percentage
|
||||
float m_z_offset; // mm
|
||||
ExtrusionRole m_extrusion_role;
|
||||
GCodeExtrusionRole m_extrusion_role;
|
||||
unsigned char m_extruder_id;
|
||||
ExtruderColors m_extruder_colors;
|
||||
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<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;
|
||||
|
||||
private:
|
||||
@ -757,7 +757,7 @@ namespace Slic3r {
|
||||
|
||||
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_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;
|
||||
|
@ -37,7 +37,7 @@ PressureEqualizer::PressureEqualizer(const Slic3r::GCodeConfig &config) : m_use_
|
||||
m_current_extruder = 0;
|
||||
// Zero the position of the XYZE axes + the current feed
|
||||
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).
|
||||
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.
|
||||
for (const ExtrusionRole er : {erGapFill, erIroning}) {
|
||||
m_max_volumetric_extrusion_rate_slopes[er].negative = 0;
|
||||
m_max_volumetric_extrusion_rate_slopes[er].positive = 0;
|
||||
for (const GCodeExtrusionRole er : {GCodeExtrusionRole::GapFill, GCodeExtrusionRole::Ironing}) {
|
||||
m_max_volumetric_extrusion_rate_slopes[size_t(er)].negative = 0;
|
||||
m_max_volumetric_extrusion_rate_slopes[size_t(er)].positive = 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
line += EXTRUSION_ROLE_TAG.length();
|
||||
int role = atoi(line);
|
||||
m_current_extrusion_role = ExtrusionRole(role);
|
||||
m_current_extrusion_role = GCodeExtrusionRole(role);
|
||||
#ifdef PRESSURE_EQUALIZER_DEBUG
|
||||
++line_idx;
|
||||
#endif
|
||||
@ -367,7 +367,16 @@ bool PressureEqualizer::process_line(const char *line, const char *line_end, GCo
|
||||
case 'T':
|
||||
{
|
||||
// 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)) {
|
||||
m_current_extruder = new_extruder;
|
||||
m_retracted = true;
|
||||
@ -510,9 +519,9 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||
// Nothing to do, the last move is not extruding.
|
||||
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[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) {
|
||||
size_t idx_prev = line_idx - 1;
|
||||
@ -520,7 +529,7 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||
if (!m_gcode_lines[idx_prev].extruding())
|
||||
break;
|
||||
// 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;
|
||||
continue;
|
||||
}
|
||||
@ -530,23 +539,23 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||
line_idx = idx_prev;
|
||||
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;
|
||||
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];
|
||||
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.
|
||||
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;
|
||||
} else if (line.volumetric_extrusion_rate_end > rate_end) {
|
||||
line.volumetric_extrusion_rate_end = rate_end;
|
||||
line.max_volumetric_extrusion_rate_slope_negative = rate_slope;
|
||||
line.modified = true;
|
||||
} else if (iRole == line.extrusion_role) {
|
||||
} else if (iRole == size_t(line.extrusion_role)) {
|
||||
rate_end = line.volumetric_extrusion_rate_end;
|
||||
} else {
|
||||
// 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;
|
||||
// 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.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());
|
||||
while (line_idx != last_line_idx) {
|
||||
@ -579,7 +588,7 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||
if (!m_gcode_lines[idx_next].extruding())
|
||||
break;
|
||||
// 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;
|
||||
continue;
|
||||
}
|
||||
@ -588,21 +597,21 @@ void PressureEqualizer::adjust_volumetric_rate()
|
||||
line_idx = idx_next;
|
||||
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;
|
||||
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];
|
||||
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;
|
||||
} 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;
|
||||
if (line.volumetric_extrusion_rate_start > rate_start) {
|
||||
line.volumetric_extrusion_rate_start = rate_start;
|
||||
line.max_volumetric_extrusion_rate_slope_positive = rate_slope;
|
||||
line.modified = true;
|
||||
} else if (iRole == line.extrusion_role) {
|
||||
} else if (iRole == size_t(line.extrusion_role)) {
|
||||
rate_start = line.volumetric_extrusion_rate_start;
|
||||
} else {
|
||||
// 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;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -704,7 +713,7 @@ void PressureEqualizer::push_line_to_output(const size_t line_idx, const float n
|
||||
GCodeG1Formatter feedrate_formatter;
|
||||
feedrate_formatter.emit_f(new_feedrate);
|
||||
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()));
|
||||
push_to_output(feedrate_formatter);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../ExtrusionEntity.hpp"
|
||||
#include "../ExtrusionRole.hpp"
|
||||
|
||||
#include <queue>
|
||||
|
||||
@ -65,7 +65,7 @@ private:
|
||||
float positive;
|
||||
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_negative;
|
||||
|
||||
@ -77,7 +77,7 @@ private:
|
||||
// X,Y,Z,E,F
|
||||
float m_current_pos[5];
|
||||
size_t m_current_extruder;
|
||||
ExtrusionRole m_current_extrusion_role;
|
||||
GCodeExtrusionRole m_current_extrusion_role;
|
||||
bool m_retracted;
|
||||
bool m_use_relative_e_distances;
|
||||
|
||||
@ -149,7 +149,7 @@ private:
|
||||
// Index of the active extruder.
|
||||
size_t extruder_id;
|
||||
// Extrusion role of this segment.
|
||||
ExtrusionRole extrusion_role;
|
||||
GCodeExtrusionRole extrusion_role;
|
||||
|
||||
// Current volumetric extrusion rate.
|
||||
float volumetric_extrusion_rate;
|
||||
|
@ -407,13 +407,13 @@ Polygons extract_perimeter_polygons(const Layer *layer, std::vector<const LayerR
|
||||
ExtrusionRole role = perimeter->role();
|
||||
if (perimeter->is_loop()) {
|
||||
for (const ExtrusionPath &path : static_cast<const ExtrusionLoop*>(perimeter)->paths) {
|
||||
if (path.role() == ExtrusionRole::erExternalPerimeter) {
|
||||
role = ExtrusionRole::erExternalPerimeter;
|
||||
if (path.role() == ExtrusionRole::ExternalPerimeter) {
|
||||
role = ExtrusionRole::ExternalPerimeter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (role == ExtrusionRole::erExternalPerimeter) {
|
||||
if (role == ExtrusionRole::ExternalPerimeter) {
|
||||
Points p;
|
||||
perimeter->collect_points(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) {
|
||||
Vec2f point = Vec2f { perimeter_point.position.head<2>() };
|
||||
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
|
||||
- tan(SeamPlacer::overhang_angle_threshold)
|
||||
* 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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
|
||||
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];
|
||||
ExtrusionLoop::ClosestPathPoint projected_point = loop.get_closest_path_and_point(seam_point, false);
|
||||
// determine depth of the seam point.
|
||||
|
@ -63,11 +63,11 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
|
||||
assert(region.config().infill_extruder.value > 0);
|
||||
assert(region.config().solid_infill_extruder.value > 0);
|
||||
// 1 based extruder ID.
|
||||
unsigned int extruder = ((this->extruder_override == 0) ?
|
||||
(is_infill(extrusions.role()) ?
|
||||
(is_solid_infill(extrusions.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) :
|
||||
unsigned int extruder = this->extruder_override == 0 ?
|
||||
(extrusions.role().is_infill() ?
|
||||
(extrusions.entities.front()->role().is_solid_infill() ? region.config().solid_infill_extruder : region.config().infill_extruder) :
|
||||
region.config().perimeter_extruder.value) :
|
||||
this->extruder_override);
|
||||
this->extruder_override;
|
||||
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)
|
||||
return true;
|
||||
|
||||
if (!region.config().wipe_into_infill || eec.role() != erInternalInfill)
|
||||
if (!region.config().wipe_into_infill || eec.role() != ExtrusionRole::InternalInfill)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -210,8 +210,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
for (auto support_layer : object.support_layers()) {
|
||||
LayerTools &layer_tools = this->tools_for_layer(support_layer->print_z);
|
||||
ExtrusionRole role = support_layer->support_fills.role();
|
||||
bool has_support = role == erMixed || role == erSupportMaterial;
|
||||
bool has_interface = role == erMixed || role == erSupportMaterialInterface;
|
||||
bool has_support = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterial;
|
||||
bool has_interface = role == ExtrusionRole::Mixed || role == ExtrusionRole::SupportMaterialInterface;
|
||||
unsigned int extruder_support = object.config().support_material_extruder.value;
|
||||
unsigned int extruder_interface = object.config().support_material_interface_extruder.value;
|
||||
if (has_support)
|
||||
@ -266,10 +266,10 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
for (const ExtrusionEntity *ee : layerm->fills()) {
|
||||
// fill represents infill extrusions of a single island.
|
||||
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
ExtrusionRole role = fill->entities.empty() ? erNone : fill->entities.front()->role();
|
||||
if (is_solid_infill(role))
|
||||
ExtrusionRole role = fill->entities.empty() ? ExtrusionRole::None : fill->entities.front()->role();
|
||||
if (role.is_solid_infill())
|
||||
has_solid_infill = true;
|
||||
else if (role != erNone)
|
||||
else if (role != ExtrusionRole::None)
|
||||
has_infill = true;
|
||||
|
||||
if (m_print_config_ptr) {
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
// adds tag for analyzer:
|
||||
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::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();
|
||||
change_analyzer_line_width(line_width);
|
||||
}
|
||||
@ -71,6 +71,8 @@ public:
|
||||
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_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 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")
|
||||
.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 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 (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
|
||||
float sparse_beginning_y = 0.f;
|
||||
@ -849,7 +855,7 @@ void WipeTower::toolchange_Unload(
|
||||
writer.disable_linear_advance();
|
||||
|
||||
// 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 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:
|
||||
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& 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:
|
||||
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:
|
||||
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:
|
||||
// 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()
|
||||
.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.
|
||||
// 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");
|
||||
|
||||
// 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())
|
||||
+ " Y" + Slic3r::float_to_string_decimal_point(current_pos.y())
|
||||
+ 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
|
||||
// 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.append("[start_filament_gcode]\n");
|
||||
//writer.append("[start_filament_gcode]\n");
|
||||
|
||||
writer.flush_planner_queue();
|
||||
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));
|
||||
}
|
||||
else {
|
||||
if (idx == -1)
|
||||
if (idx == -1) {
|
||||
layer_result[0] = merge_tcr(finish_layer_tcr, layer_result[0]);
|
||||
layer_result[0].force_travel = true;
|
||||
}
|
||||
else
|
||||
layer_result[idx] = merge_tcr(layer_result[idx], finish_layer_tcr);
|
||||
}
|
||||
|
@ -82,6 +82,8 @@ public:
|
||||
}
|
||||
return e_length;
|
||||
}
|
||||
|
||||
bool force_travel = false;
|
||||
};
|
||||
|
||||
struct box_coordinates
|
||||
@ -290,7 +292,6 @@ private:
|
||||
// Extruder specific parameters.
|
||||
std::vector<FilamentParameters> m_filpar;
|
||||
|
||||
|
||||
// State of the wipe tower generator.
|
||||
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.
|
||||
|
@ -728,7 +728,7 @@ void Transformation::reset_skew()
|
||||
|
||||
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(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.
|
||||
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));
|
||||
const Vec3d& axis = angle_axis.axis();
|
||||
const double angle = angle_axis.angle();
|
||||
#ifndef NDEBUG
|
||||
if (std::abs(angle) > 1e-8) {
|
||||
assert(std::abs(axis.x()) < 1e-8);
|
||||
assert(std::abs(axis.y()) < 1e-8);
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
return (axis.z() < 0) ? -angle : angle;
|
||||
auto m = trafo_to.linear() * trafo_from.linear().inverse();
|
||||
assert(std::abs(m.determinant() - 1) < EPSILON);
|
||||
Vec3d vx = m * Vec3d(1., 0., 0);
|
||||
// Verify that the linear part of rotation from trafo_from to trafo_to rotates around Z and is unity.
|
||||
assert(std::abs(std::hypot(vx.x(), vx.y()) - 1.) < 1e-5);
|
||||
assert(std::abs(vx.z()) < 1e-5);
|
||||
return atan2(vx.y(), vx.x());
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::Geometry
|
||||
|
@ -470,8 +470,7 @@ public:
|
||||
Transform3d get_mirror_matrix() const;
|
||||
|
||||
bool is_left_handed() const {
|
||||
const Vec3d mirror = get_mirror();
|
||||
return mirror.x() * mirror.y() * mirror.z() < 0.0;
|
||||
return m_matrix.linear().determinant() < 0;
|
||||
}
|
||||
#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; }
|
||||
@ -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);
|
||||
// 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.
|
||||
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?
|
||||
inline bool is_rotation_ninety_degrees(double a)
|
||||
|
@ -495,6 +495,7 @@ void MedialAxis::build(ThickPolylines* polylines)
|
||||
polyline.width.emplace_back(seed_edge_data.width_end);
|
||||
// Grow the polyline in a forward direction.
|
||||
this->process_edge_neighbors(&*seed_edge, &polyline);
|
||||
assert(polyline.width.size() == polyline.points.size() * 2 - 2);
|
||||
|
||||
// Grow the polyline in a backward direction.
|
||||
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.width.insert(polyline.width.begin(), reverse_polyline.width.rbegin(), reverse_polyline.width.rend());
|
||||
polyline.endpoints.first = reverse_polyline.endpoints.second;
|
||||
|
||||
assert(polyline.width.size() == polyline.points.size() * 2 - 2);
|
||||
|
||||
// Prevent loop endpoints from being extended.
|
||||
@ -535,7 +535,9 @@ void MedialAxis::build(Polylines* polylines)
|
||||
{
|
||||
ThickPolylines 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)
|
||||
|
@ -8,17 +8,135 @@
|
||||
#include "VoronoiUtilsCgal.hpp"
|
||||
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
using namespace Slic3r::Arachne;
|
||||
|
||||
namespace Slic3r::Geometry {
|
||||
|
||||
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;
|
||||
// The tangent vector of the parabola is computed based on the Proof of the reflective property.
|
||||
// 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.
|
||||
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(),
|
||||
[](const VD::edge_type &edge) { return edge.color() == 0; }));
|
||||
|
||||
@ -30,7 +148,7 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_
|
||||
continue;
|
||||
|
||||
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()));
|
||||
edge.color(1);
|
||||
assert(edge.twin() != nullptr);
|
||||
@ -46,37 +164,101 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_
|
||||
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) {
|
||||
CGAL::Orientation orientation = CGAL::orientation(common_pt, pt_1, pt_2);
|
||||
struct ParabolicSegment
|
||||
{
|
||||
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 ¶bolic_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) {
|
||||
// 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) {
|
||||
// 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.
|
||||
CGAL::Orientation orientation1 = CGAL::orientation(common_pt, pt_1, test_pt);
|
||||
CGAL::Orientation orientation2 = CGAL::orientation(common_pt, pt_2, test_pt);
|
||||
CGAL::Orientation orientation1 = orientation_of_two_edges(first, third, segments);
|
||||
CGAL::Orientation orientation2 = orientation_of_two_edges(second, third, segments);
|
||||
return (orientation1 != CGAL::Orientation::LEFT_TURN || orientation2 != CGAL::Orientation::RIGHT_TURN);
|
||||
} else {
|
||||
assert(orientation == CGAL::Orientation::RIGHT_TURN);
|
||||
// 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.
|
||||
CGAL::Orientation orientation1 = CGAL::orientation(common_pt, pt_1, test_pt);
|
||||
CGAL::Orientation orientation2 = CGAL::orientation(common_pt, pt_2, test_pt);
|
||||
CGAL::Orientation orientation1 = orientation_of_two_edges(first, third, segments);
|
||||
CGAL::Orientation orientation2 = orientation_of_two_edges(second, third, segments);
|
||||
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()) {
|
||||
std::vector<const VD::edge_type *> edges;
|
||||
const VD::edge_type *edge = vertex.incident_edge();
|
||||
|
||||
do {
|
||||
// FIXME Lukas H.: Also process parabolic segments.
|
||||
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()))
|
||||
if (edge->is_finite() && edge->vertex0() != nullptr && edge->vertex1() != nullptr &&
|
||||
VoronoiUtils::is_finite(*edge->vertex0()) && VoronoiUtils::is_finite(*edge->vertex1()))
|
||||
edges.emplace_back(edge);
|
||||
|
||||
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 *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()),
|
||||
to_cgal_point(*curr_edge->vertex1()), to_cgal_point(*next_edge->vertex1())))
|
||||
if (!check_if_three_edges_are_ccw(*prev_edge, *curr_edge, *next_edge, segments))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -99,5 +280,4 @@ bool VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(const VoronoiDiagram &vor
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Slic3r::Geometry
|
@ -2,6 +2,7 @@
|
||||
#define slic3r_VoronoiUtilsCgal_hpp_
|
||||
|
||||
#include "Voronoi.hpp"
|
||||
#include "../Arachne/utils/VoronoiUtils.hpp"
|
||||
|
||||
namespace Slic3r::Geometry {
|
||||
class VoronoiDiagram;
|
||||
@ -13,7 +14,7 @@ public:
|
||||
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.
|
||||
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
|
||||
|
@ -37,6 +37,7 @@ LayerRegion* Layer::add_region(const PrintRegion *print_region)
|
||||
|
||||
// merge all regions' slices to get islands
|
||||
void Layer::make_slices()
|
||||
{
|
||||
{
|
||||
ExPolygons slices;
|
||||
if (m_regions.size() == 1) {
|
||||
@ -48,22 +49,26 @@ void Layer::make_slices()
|
||||
polygons_append(slices_p, to_polygons(layerm->slices().surfaces));
|
||||
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();
|
||||
this->lslices.reserve(slices.size());
|
||||
|
||||
// prepare lslices ordered by print order
|
||||
this->lslice_indices_sorted_by_print_order.clear();
|
||||
this->lslice_indices_sorted_by_print_order.reserve(lslices.size());
|
||||
// prepare ordering points
|
||||
Points ordering_points;
|
||||
ordering_points.reserve(slices.size());
|
||||
for (const ExPolygon &ex : slices)
|
||||
ordering_points.reserve( this->lslices.size());
|
||||
for (const ExPolygon &ex : this->lslices)
|
||||
ordering_points.push_back(ex.contour.first_point());
|
||||
|
||||
// sort slices
|
||||
std::vector<Points::size_type> order = chain_points(ordering_points);
|
||||
|
||||
// populate slices vector
|
||||
for (size_t i : order)
|
||||
this->lslices.emplace_back(std::move(slices[i]));
|
||||
for (size_t i : order) {
|
||||
this->lslice_indices_sorted_by_print_order.emplace_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// used by Layer::build_up_down_graph()
|
||||
@ -465,16 +470,19 @@ void Layer::make_perimeters()
|
||||
} else {
|
||||
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.
|
||||
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.
|
||||
for (uint32_t region_id : layer_region_ids) {
|
||||
LayerRegion &layerm = *m_regions[region_id];
|
||||
for (const Surface &surface : layerm.slices())
|
||||
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;
|
||||
}
|
||||
}
|
||||
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();) {
|
||||
size_t j = i;
|
||||
@ -493,7 +501,7 @@ void Layer::make_perimeters()
|
||||
}
|
||||
// make perimeters
|
||||
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];
|
||||
Point sample;
|
||||
bool sample_set = false;
|
||||
if (! extrusions.first.empty()) {
|
||||
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 {
|
||||
// Take a sample deep inside its island if available. Infills are usually quite far from the island boundary.
|
||||
for (uint32_t iexpoly : fill_expolygons_ranges[islice])
|
||||
if (const ExPolygon &expoly = fill_expolygons[iexpoly]; ! expoly.empty()) {
|
||||
sample = expoly.contour.points.front();
|
||||
sample_set = true;
|
||||
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.
|
||||
// assert(sample_set);
|
||||
@ -694,9 +726,20 @@ void Layer::sort_perimeters_into_islands(
|
||||
perimeter_slices_queue.pop_back();
|
||||
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 ®ion_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 =
|
||||
[&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 BoundingBox &bbox = lslices_ex[lslice_idx].bbox;
|
||||
return
|
||||
@ -717,6 +760,7 @@ void Layer::sort_perimeters_into_islands(
|
||||
insert_into_island(lslice_idx_min, it_source_slice->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
Loading…
Reference in New Issue
Block a user