Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate into et_show_sla_supports

This commit is contained in:
enricoturri1966 2023-03-20 14:35:02 +01:00
commit 997e731c41
18 changed files with 549 additions and 379 deletions

View File

@ -1,3 +1,5 @@
min_slic3r_version = 2.6.0-alpha4
1.1.1 Initial official version
1.0.1 Initial Version
min_slic3r_version = 2.6.0-alpha1 min_slic3r_version = 2.6.0-alpha1
1.0.1 Disabled thick bridges.
1.0.0 Initial Version 1.0.0 Initial Version

View File

@ -1,14 +1,14 @@
# Print profiles for the AnkerMake printers. # Print profiles for the AnkerMake printers.
# https://github.com/prusa3d/PrusaSlicer/pull/9075 by @just-trey
[vendor] [vendor]
# Vendor name will be shown by the Config Wizard. # Vendor name will be shown by the Config Wizard.
name = Anker name = AnkerMake
# Configuration version of this file. Config file will only be installed, if the config_version differs. # Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.0.1 config_version = 1.1.1
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anker/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anker/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
# The printer models will be shown by the Configuration Wizard in this order, # The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install. # also the first model installed & the first nozzle installed will be activated after install.
@ -20,8 +20,9 @@ variants = 0.4
technology = FFF technology = FFF
family = AnkerMake family = AnkerMake
bed_model = M5-bed.stl bed_model = M5-bed.stl
bed_texture = M5-texture.svg bed_texture = M5-texture_v2.svg
default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER thumbnail = M5_thumbnail_v2.png
default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER;
# All presets starting with asterisk, for example *common*, are intermediate and they will # All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface. # not make it into the user interface.
@ -31,8 +32,8 @@ default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER;
avoid_crossing_perimeters = 0 avoid_crossing_perimeters = 0
bridge_acceleration = 2500 bridge_acceleration = 2500
bridge_angle = 0 bridge_angle = 0
bridge_flow_ratio = 0.95 bridge_flow_ratio = 1
bridge_speed = 150 bridge_speed = 50
brim_separation = 0.1 brim_separation = 0.1
brim_type = outer_only brim_type = outer_only
brim_width = 0 brim_width = 0
@ -40,32 +41,36 @@ clip_multipart_objects = 1
complete_objects = 0 complete_objects = 0
default_acceleration = 2500 default_acceleration = 2500
dont_support_bridges = 1 dont_support_bridges = 1
elefant_foot_compensation = 0.1 elefant_foot_compensation = 0.2
ensure_vertical_shell_thickness = 1 ensure_vertical_shell_thickness = 1
external_perimeter_speed = 150 external_perimeter_speed = 150
external_perimeters_first = 0 external_perimeters_first = 0
extra_perimeters = 0 extra_perimeters = 0
extruder_clearance_height = 30 extruder_clearance_height = 30
extruder_clearance_radius = 45 extruder_clearance_radius = 45
extrusion_width = 0.4
external_perimeter_extrusion_width = 0.44
fill_angle = 45 fill_angle = 45
fill_density = 15% fill_density = 10%
fill_pattern = cubic fill_pattern = grid
first_layer_acceleration = 2500 first_layer_acceleration = 2500
first_layer_acceleration_over_raft = 0 first_layer_acceleration_over_raft = 0
first_layer_extrusion_width = 200% first_layer_extrusion_width = 0.4
first_layer_speed = 50% first_layer_speed = 50%
first_layer_speed_over_raft = 30 first_layer_speed_over_raft = 30
gap_fill_enabled = 1 gap_fill_enabled = 1
gap_fill_speed = 150 gap_fill_speed = 150
gcode_comments = 0 gcode_comments = 0
infill_acceleration = 2500 infill_acceleration = 2500
infill_anchor = 600% infill_anchor = 2.5
infill_anchor_max = 50 infill_anchor_max = 12
infill_every_layers = 1 infill_every_layers = 1
infill_extruder = 1 infill_extruder = 1
infill_first = 0 infill_first = 0
infill_extrusion_width = 0.4
infill_only_where_needed = 0 infill_only_where_needed = 0
infill_overlap = 23% infill_overlap = 10%
infill_speed = 250 infill_speed = 250
interface_shells = 0 interface_shells = 0
max_print_speed = 250 max_print_speed = 250
@ -76,18 +81,18 @@ min_skirt_length = 4
notes = notes =
only_retract_when_crossing_perimeters = 0 only_retract_when_crossing_perimeters = 0
ooze_prevention = 0 ooze_prevention = 0
output_filename_format = {input_filename_base}_{digits(layer_height,1,2)}mm_{filament_type[0]}_{printer_model}.gcode output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}.gcode
overhangs = 1 overhangs = 1
perimeter_acceleration = 2500 perimeter_acceleration = 2500
perimeter_extruder = 1 perimeter_extruder = 1
perimeter_extrusion_width = 0 perimeter_extrusion_width = 0.4
perimeter_generator = arachne perimeter_generator = classic
perimeter_speed = 250 perimeter_speed = 250
perimeters = 3 perimeters = 3
post_process = post_process =
print_settings_id = print_settings_id =
raft_layers = 0 raft_layers = 0
resolution = 0 resolution = 0.01
seam_position = aligned seam_position = aligned
single_extruder_multi_material_priming = 0 single_extruder_multi_material_priming = 0
skirt_distance = 3 skirt_distance = 3
@ -97,32 +102,37 @@ small_perimeter_speed = 150
solid_infill_below_area = 0 solid_infill_below_area = 0
solid_infill_every_layers = 0 solid_infill_every_layers = 0
solid_infill_extruder = 1 solid_infill_extruder = 1
solid_infill_speed = 175 solid_infill_extrusion_width = 0.4
solid_infill_speed = 250
spiral_vase = 0 spiral_vase = 0
standby_temperature_delta = -5 standby_temperature_delta = -5
support_material_auto = 0
support_material = 0 support_material = 0
support_material_angle = 0 support_material_angle = 0
support_material_buildplate_only = 0 support_material_buildplate_only = 0
support_material_contact_distance = 0.15 support_material_contact_distance = 0.1
support_material_enforce_layers = 0 support_material_enforce_layers = 0
support_material_extruder = 0 support_material_extruder = 0
support_material_interface_contact_loops = 0 support_material_interface_contact_loops = 0
support_material_interface_extruder = 0 support_material_interface_extruder = 0
support_material_interface_layers = 2 support_material_interface_layers = 2
support_material_interface_spacing = 0.2 support_material_interface_spacing = 0.2
support_material_interface_speed = 100% support_material_interface_speed = 80%
support_material_pattern = rectilinear support_material_pattern = rectilinear
support_material_spacing = 2 support_material_spacing = 2
support_material_speed = 125 support_material_speed = 150
support_material_synchronize_layers = 0 support_material_synchronize_layers = 0
support_material_threshold = 40 support_material_threshold = 55
support_material_with_sheath = 0 support_material_with_sheath = 0
support_material_xy_spacing = 60% support_material_xy_spacing = 50%
thick_bridges = 0 thick_bridges = 0
thin_walls = 0 thin_walls = 0
top_solid_infill_speed = 150 top_solid_infill_speed = 150
travel_speed = 300 top_infill_extrusion_width = 0.4
travel_speed_z = 10 top_fill_pattern = rectilinear
bottom_fill_pattern = rectilinear
travel_speed = 250
travel_speed_z = 0
wipe_tower = 0 wipe_tower = 0
wipe_tower_bridging = 10 wipe_tower_bridging = 10
wipe_tower_rotation_angle = 0 wipe_tower_rotation_angle = 0
@ -131,86 +141,49 @@ wipe_tower_x = 170
wipe_tower_y = 140 wipe_tower_y = 140
xy_size_compensation = 0 xy_size_compensation = 0
[print:*0.08mm*]
inherits = *common*
layer_height = 0.08
first_layer_height = 0.12
bottom_solid_layers = 9
top_solid_layers = 11
bridge_flow_ratio = 0.70
[print:*0.10mm*] [print:*0.10mm*]
inherits = *common* inherits = *common*
layer_height = 0.10 layer_height = 0.10
first_layer_height = 0.14 first_layer_height = 0.10
bottom_solid_layers = 7 bottom_solid_layers = 7
top_solid_layers = 9 top_solid_layers = 9
bridge_flow_ratio = 0.70 bridge_flow_ratio = 1
[print:*0.12mm*]
inherits = *common*
layer_height = 0.12
first_layer_height = 0.16
bottom_solid_layers = 6
top_solid_layers = 7
bridge_flow_ratio = 0.70
[print:*0.16mm*]
inherits = *common*
layer_height = 0.16
first_layer_height = 0.20
bottom_solid_layers = 5
top_solid_layers = 7
bridge_flow_ratio = 0.85
[print:*0.20mm*] [print:*0.20mm*]
inherits = *common* inherits = *common*
layer_height = 0.20 layer_height = 0.20
first_layer_height = 0.24 first_layer_height = 0.14
bottom_solid_layers = 4 bottom_solid_layers = 4
top_solid_layers = 5 top_solid_layers = 5
[print:*0.24mm*] [print:*0.30mm*]
inherits = *common* inherits = *common*
layer_height = 0.24 layer_height = 0.30
first_layer_height = 0.28 first_layer_height = 0.21
bottom_solid_layers = 3 bottom_solid_layers = 3
top_solid_layers = 4 top_solid_layers = 4
[print:*0.28mm*]
inherits = *common*
layer_height = 0.28
first_layer_height = 0.28
bottom_solid_layers = 3
top_solid_layers = 4
[print:0.08 mm SUPERDETAIL (0.4 mm nozzle) @ANKER]
inherits = *0.08mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.10 mm HIGHDETAIL (0.4 mm nozzle) @ANKER] [print:0.10 mm HIGHDETAIL (0.4 mm nozzle) @ANKER]
inherits = *0.10mm* inherits = *0.10mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.12 mm DETAIL (0.4 mm nozzle) @ANKER]
inherits = *0.12mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.16 mm OPTIMAL (0.4 mm nozzle) @ANKER]
inherits = *0.16mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.20 mm NORMAL (0.4 mm nozzle) @ANKER] [print:0.20 mm NORMAL (0.4 mm nozzle) @ANKER]
inherits = *0.20mm* inherits = *0.20mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.24 mm DRAFT (0.4 mm nozzle) @ANKER]
inherits = *0.24mm* [print:0.30 mm SUPERDRAFT (0.4 mm nozzle) @ANKER]
inherits = *0.30mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.28 mm SUPERDRAFT (0.4 mm nozzle) @ANKER] # When submitting new filaments please print the following temperature tower at 0.1mm layer height:
inherits = *0.28mm* # https://www.thingiverse.com/thing:2615842
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 # Pay particular attention to bridging, overhangs and retractions.
# Also print the following bed adhesion test at 0.1 layer height as well:
# https://www.prusaprinters.org/prints/4634-bed-adhesion-warp-test
# At least for PLA, please keep bed temp at 60, as many Creality printers do not have any ABL
# So having some leeway to get good bed adhesion is not a luxury for many users
[filament:*common*] [filament:*common*]
cooling = 0 cooling = 0
@ -235,47 +208,47 @@ filament_type = PLA
filament_density = 1.24 filament_density = 1.24
filament_cost = 20 filament_cost = 20
first_layer_bed_temperature = 60 first_layer_bed_temperature = 60
first_layer_temperature = 210 first_layer_temperature = 230
fan_always_on = 1 fan_always_on = 1
max_fan_speed = 100 max_fan_speed = 100
min_fan_speed = 100 min_fan_speed = 100
bridge_fan_speed = 100 bridge_fan_speed = 100
disable_fan_first_layers = 2 disable_fan_first_layers = 1
temperature = 205 temperature = 200
[filament:*PLA+*] [filament:*PLA+*]
inherits = *common* inherits = *common*
bed_temperature = 60 bed_temperature = 60
fan_below_layer_time = 100 fan_below_layer_time = 100
filament_colour = #DDDDDD filament_colour = #DDDDDD
filament_type = PLA filament_type = PLA+
filament_density = 1.24 filament_density = 1.24
filament_cost = 20 filament_cost = 20
first_layer_bed_temperature = 60 first_layer_bed_temperature = 60
first_layer_temperature = 220 first_layer_temperature = 230
fan_always_on = 1 fan_always_on = 1
max_fan_speed = 100 max_fan_speed = 100
min_fan_speed = 100 min_fan_speed = 100
bridge_fan_speed = 100 bridge_fan_speed = 100
disable_fan_first_layers = 2 disable_fan_first_layers = 1
temperature = 210 temperature = 200
[filament:*PET*] [filament:*PET*]
inherits = *common* inherits = *common*
bed_temperature = 70 bed_temperature = 80
disable_fan_first_layers = 2 disable_fan_first_layers = 2
fan_below_layer_time = 20 fan_below_layer_time = 20
filament_colour = #DDDDDD filament_colour = #DDDDDD
filament_type = PETG filament_type = PETG
filament_density = 1.27 filament_density = 1.27
filament_cost = 30 filament_cost = 30
first_layer_bed_temperature = 70 first_layer_bed_temperature = 80
first_layer_temperature = 240 first_layer_temperature = 260
fan_always_on = 1 fan_always_on = 1
max_fan_speed = 50 max_fan_speed = 50
min_fan_speed = 50 min_fan_speed = 50
bridge_fan_speed = 100 bridge_fan_speed = 100
temperature = 240 temperature = 260
[filament:*ABS*] [filament:*ABS*]
inherits = *common* inherits = *common*
@ -286,14 +259,14 @@ filament_colour = #DDDDDD
filament_type = ABS filament_type = ABS
filament_density = 1.04 filament_density = 1.04
filament_cost = 20 filament_cost = 20
first_layer_bed_temperature = 100 first_layer_bed_temperature = 90
first_layer_temperature = 245 first_layer_temperature = 260
fan_always_on = 0 fan_always_on = 0
max_fan_speed = 0 max_fan_speed = 0
min_fan_speed = 0 min_fan_speed = 0
bridge_fan_speed = 30 bridge_fan_speed = 30
top_fan_speed = 0 top_fan_speed = 0
temperature = 245 temperature = 260
[filament:Generic PLA @ANKER] [filament:Generic PLA @ANKER]
inherits = *PLA* inherits = *PLA*
@ -324,8 +297,8 @@ deretract_speed = 60
extruder_colour = #FCE94F extruder_colour = #FCE94F
extruder_offset = 0x0 extruder_offset = 0x0
gcode_flavor = marlin gcode_flavor = marlin
silent_mode = 0 silent_mode = 1
remaining_times = 0 remaining_times = 1
machine_max_acceleration_e = 2500 machine_max_acceleration_e = 2500
machine_max_acceleration_extruding = 2500 machine_max_acceleration_extruding = 2500
machine_max_acceleration_retracting = 2500 machine_max_acceleration_retracting = 2500
@ -338,8 +311,8 @@ machine_max_feedrate_x = 300
machine_max_feedrate_y = 300 machine_max_feedrate_y = 300
machine_max_feedrate_z = 20 machine_max_feedrate_z = 20
machine_max_jerk_e = 3 machine_max_jerk_e = 3
machine_max_jerk_x = 30 machine_max_jerk_x = 15
machine_max_jerk_y = 30 machine_max_jerk_y = 15
machine_max_jerk_z = 0.3 machine_max_jerk_z = 0.3
machine_min_extruding_rate = 0 machine_min_extruding_rate = 0
machine_min_travel_rate = 0 machine_min_travel_rate = 0
@ -347,10 +320,10 @@ layer_gcode = ;AFTER_LAYER_CHANGE\n;{layer_z}
max_print_height = 250 max_print_height = 250
printer_notes = printer_notes =
printer_settings_id = printer_settings_id =
retract_before_travel = 2 retract_before_travel = 3
retract_before_wipe = 70% retract_before_wipe = 0
retract_layer_change = 1 retract_layer_change = 1
retract_length_toolchange = 1 retract_length_toolchange = 4
retract_lift = 0 retract_lift = 0
retract_lift_above = 0 retract_lift_above = 0
retract_lift_below = 0 retract_lift_below = 0
@ -365,10 +338,10 @@ use_firmware_retraction = 0
use_relative_e_distances = 0 use_relative_e_distances = 0
use_volumetric_e = 0 use_volumetric_e = 0
variable_layer_height = 1 variable_layer_height = 1
wipe = 1 wipe = 0
z_offset = 0 z_offset = 0
default_filament_profile = "Generic PLA+ @ANKER" default_filament_profile = Generic PLA+ @ANKER
start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for nozzle temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\nG1 E10 F3600; push out retracted filament(fix for over retraction after prime) start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\nM420 S1; restore saved Auto Bed Leveling data\nG1 E10 F3600; push out retracted filament(fix for over retraction after prime)
end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84 end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84
[printer:*M5*] [printer:*M5*]
@ -376,12 +349,12 @@ inherits = *common*
bed_shape = 0x0,235-0,235x235,0x235 bed_shape = 0x0,235-0,235x235,0x235
max_print_height = 250 max_print_height = 250
printer_model = M5 printer_model = M5
retract_length = 1.25 retract_length = 3
retract_speed = 60 retract_speed = 60
deretract_speed = 60 deretract_speed = 60
retract_before_travel = 1 retract_before_travel = 3
retract_before_wipe = 0% retract_before_wipe = 0%
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_ANKERMAKE\nPRINTER_MODEL_M5 printer_notes = Don 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_ANKERMAKE\nPRINTER_MODEL_M5
[printer:AnkerMake M5 (0.4 mm nozzle)] [printer:AnkerMake M5 (0.4 mm nozzle)]
inherits = *M5* inherits = *M5*
@ -389,5 +362,5 @@ nozzle_diameter = 0.4
printer_variant = 0.4 printer_variant = 0.4
min_layer_height = 0.08 min_layer_height = 0.08
max_layer_height = 0.32 max_layer_height = 0.32
retract_lift_above = 0.2 retract_lift_above = 0
default_print_profile = "0.16 mm OPTIMAL (0.4 mm nozzle) @ANKER" default_print_profile = 0.2 mm OPTIMAL (0.4 mm nozzle) @ANKER

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,4 +1,5 @@
min_slic3r_version = 2.6.0-alpha5 min_slic3r_version = 2.6.0-alpha5
1.7.0-alpha2 Updated compatibility condition in some filament profiles (Prusa XL).
1.7.0-alpha1 Added profiles for Original Prusa XL. Added filament profile for Prusament PETG Tungsten 75%. 1.7.0-alpha1 Added profiles for Original Prusa XL. Added filament profile for Prusament PETG Tungsten 75%.
min_slic3r_version = 2.6.0-alpha1 min_slic3r_version = 2.6.0-alpha1
1.7.0-alpha0 Added profiles for Print With Smile filaments. 1.7.0-alpha0 Added profiles for Print With Smile filaments.
@ -6,6 +7,7 @@ min_slic3r_version = 2.6.0-alpha1
1.6.0-alpha1 Updated FW version notification. Decreased min layer time for PLA. 1.6.0-alpha1 Updated FW version notification. Decreased min layer time for PLA.
1.6.0-alpha0 Default top fill set to monotonic lines. Updated infill/perimeter overlap values. Updated output filename format. Enabled dynamic overhang speeds. 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.1-rc0 min_slic3r_version = 2.5.1-rc0
1.6.2 Updated compatibility condition in some filament profiles (Prusa XL).
1.6.1 Added filament profile for Prusament PETG Tungsten 75%. Updated Prusa XL profiles. 1.6.1 Added filament profile for Prusament PETG Tungsten 75%. Updated Prusa XL profiles.
1.6.0 Added Original Prusa XL profiles. Updated acceleration settings for Prusa MINI. Updated infill/perimeter overlap values. 1.6.0 Added Original Prusa XL profiles. Updated acceleration settings for Prusa MINI. Updated infill/perimeter overlap values.
min_slic3r_version = 2.5.0-alpha0 min_slic3r_version = 2.5.0-alpha0

View File

@ -5,7 +5,7 @@
name = Prusa Research name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs. # Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.7.0-alpha1 config_version = 1.7.0-alpha2
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -5178,7 +5178,7 @@ compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model!="MINI
inherits = Filatech FilaCarbon; *ABSPG*; *04PLUSPG* inherits = Filatech FilaCarbon; *ABSPG*; *04PLUSPG*
first_layer_bed_temperature = 100 first_layer_bed_temperature = 100
[filament:Filatech FilaCarbonc 0.6] [filament:Filatech FilaCarbon @PG 0.6]
inherits = Filatech FilaCarbon @PG; *ABS06PG* inherits = Filatech FilaCarbon @PG; *ABS06PG*
[filament:Filatech FilaCarbon @PG 0.8] [filament:Filatech FilaCarbon @PG 0.8]
@ -6428,7 +6428,7 @@ extrusion_multiplier = 1.03
filament_cost = 54.99 filament_cost = 54.99
filament_density = 1.27 filament_density = 1.27
filament_colour = #BBBBBB filament_colour = #BBBBBB
compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and printer_model!="XL" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:Prusament PETG Carbon Fiber @PG] [filament:Prusament PETG Carbon Fiber @PG]
inherits = Prusament PETG; *PETPG*; *04PLUSPG* inherits = Prusament PETG; *PETPG*; *04PLUSPG*
@ -7969,7 +7969,7 @@ temperature = 285
first_layer_bed_temperature = 90 first_layer_bed_temperature = 90
bed_temperature = 90 bed_temperature = 90
fan_below_layer_time = 10 fan_below_layer_time = 10
compatible_printers_condition = printer_model!="MINI" and ! single_extruder_multi_material compatible_printers_condition = printer_model!="MINI" and printer_model!="XL" and ! single_extruder_multi_material
max_fan_speed = 15 max_fan_speed = 15
min_fan_speed = 15 min_fan_speed = 15
filament_type = PA filament_type = PA

View File

@ -957,7 +957,7 @@ namespace Slic3r {
try try
{ {
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t { res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque; CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) { if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) {
char error_buf[1024]; char error_buf[1024];
@ -991,7 +991,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading cut information data to buffer"); add_error("Error while reading cut information data to buffer");
return; return;
@ -1053,7 +1053,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading config data to buffer"); add_error("Error while reading config data to buffer");
return; return;
@ -1073,7 +1073,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading layer heights profile data to buffer"); add_error("Error while reading layer heights profile data to buffer");
return; return;
@ -1135,7 +1135,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading layer config ranges data to buffer"); add_error("Error while reading layer config ranges data to buffer");
return; return;
@ -1192,7 +1192,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading sla support points data to buffer"); add_error("Error while reading sla support points data to buffer");
return; return;
@ -1274,7 +1274,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer(size_t(stat.m_uncomp_size), 0); std::string buffer(size_t(stat.m_uncomp_size), 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading sla support points data to buffer"); add_error("Error while reading sla support points data to buffer");
return; return;
@ -1379,7 +1379,7 @@ namespace Slic3r {
return false; return false;
} }
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, parser_buffer, (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading config data to buffer"); add_error("Error while reading config data to buffer");
return false; return false;
@ -1399,7 +1399,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading custom Gcodes per height data to buffer"); add_error("Error while reading custom Gcodes per height data to buffer");
return; return;

View File

@ -965,7 +965,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
try try
{ {
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t { res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque; CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->ctx.error()) if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->ctx.error())
{ {

View File

@ -18,7 +18,7 @@ boost::property_tree::ptree read_ini(const mz_zip_archive_file_stat &entry,
{ {
std::string buf(size_t(entry.m_uncomp_size), '\0'); std::string buf(size_t(entry.m_uncomp_size), '\0');
if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename, if (!mz_zip_reader_extract_to_mem(&zip.arch, entry.m_file_index,
buf.data(), buf.size(), 0)) buf.data(), buf.size(), 0))
throw Slic3r::FileIOError(zip.get_errorstr()); throw Slic3r::FileIOError(zip.get_errorstr());
@ -35,7 +35,7 @@ EntryBuffer read_entry(const mz_zip_archive_file_stat &entry,
{ {
std::vector<uint8_t> buf(entry.m_uncomp_size); std::vector<uint8_t> buf(entry.m_uncomp_size);
if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename, if (!mz_zip_reader_extract_to_mem(&zip.arch, entry.m_file_index,
buf.data(), buf.size(), 0)) buf.data(), buf.size(), 0))
throw Slic3r::FileIOError(zip.get_errorstr()); throw Slic3r::FileIOError(zip.get_errorstr());

View File

@ -1,11 +1,14 @@
#include "Layer.hpp" #include "Layer.hpp"
#include "ClipperZUtils.hpp" #include "ClipperZUtils.hpp"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "Point.hpp"
#include "Polygon.hpp"
#include "Print.hpp" #include "Print.hpp"
#include "Fill/Fill.hpp" #include "Fill/Fill.hpp"
#include "ShortestPath.hpp" #include "ShortestPath.hpp"
#include "SVG.hpp" #include "SVG.hpp"
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
#include "clipper/clipper.hpp"
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
@ -180,6 +183,31 @@ static void connect_layer_slices(
break; break;
} }
} }
if (!found) {
// The check above might sometimes fail when the polygons overlap only on points, which causes the clipper to detect no intersection.
// The problem happens rarely, mostly on simple polygons (in terms of number of points), but regardless of size!
// example of failing link on two layers, each with single polygon without holes.
// layer A = Polygon{(-24931238,-11153865),(-22504249,-8726874),(-22504249,11477151),(-23261469,12235585),(-23752371,12727276),(-25002495,12727276),(-27502745,10227026),(-27502745,-12727274),(-26504645,-12727274)}
// layer B = Polygon{(-24877897,-11100524),(-22504249,-8726874),(-22504249,11477151),(-23244827,12218916),(-23752371,12727276),(-25002495,12727276),(-27502745,10227026),(-27502745,-12727274),(-26504645,-12727274)}
// note that first point is not identical, and the check above picks (-24877897,-11100524) as the first contour point (polynode.Contour.front()).
// that point is sadly slightly outisde of the layer A, so no link is detected, eventhough they are overlaping "completely"
Polygon contour_poly;
for (const auto& p : polynode.Contour) {
contour_poly.points.emplace_back(p.x(), p.y());
}
BoundingBox contour_aabb{contour_poly.points};
for (int l = int(m_above.lslices_ex.size()) - 1; l >= 0; --l) {
LayerSlice &lslice = m_above.lslices_ex[l];
// it is potentially slow, but should be executed rarely
if (contour_aabb.overlap(lslice.bbox) && !intersection(Polygons{contour_poly}, m_above.lslices[l]).empty()) {
found = true;
j = l;
assert(i >= 0 && i < m_below.lslices_ex.size());
assert(j >= 0 && j < m_above.lslices_ex.size());
break;
}
}
}
} else { } else {
// Index of an island above. Look-it up in the island below. // Index of an island above. Look-it up in the island below.
assert(j < m_offset_end); assert(j < m_offset_end);
@ -194,6 +222,23 @@ static void connect_layer_slices(
break; break;
} }
} }
if (!found) { // Explanation for aditional check is above.
Polygon contour_poly;
for (const auto &p : polynode.Contour) {
contour_poly.points.emplace_back(p.x(), p.y());
}
BoundingBox contour_aabb{contour_poly.points};
for (int l = int(m_below.lslices_ex.size()) - 1; l >= 0; --l) {
LayerSlice &lslice = m_below.lslices_ex[l];
if (contour_aabb.overlap(lslice.bbox) && !intersection(Polygons{contour_poly}, m_below.lslices[l]).empty()) {
found = true;
i = l;
assert(i >= 0 && i < m_below.lslices_ex.size());
assert(j >= 0 && j < m_above.lslices_ex.size());
break;
}
}
}
} }
} else { } else {
assert(assert_intersection_valid(i, j)); assert(assert_intersection_valid(i, j));

View File

@ -171,8 +171,13 @@ namespace client
struct OptWithPos { struct OptWithPos {
OptWithPos() {} OptWithPos() {}
OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range<Iterator> it_range) : opt(opt), it_range(it_range) {} OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range<Iterator> it_range) : opt(opt), it_range(it_range) {}
ConfigOptionConstPtr opt = nullptr; ConfigOptionConstPtr opt { nullptr };
bool writable { false };
// -1 means it is a scalar variable, or it is a vector variable and index was not assigned yet or the whole vector is considered.
int index { -1 };
boost::iterator_range<Iterator> it_range; boost::iterator_range<Iterator> it_range;
bool has_index() const { return index != -1; }
}; };
template<typename ITERATOR> template<typename ITERATOR>
@ -688,6 +693,7 @@ namespace client
const DynamicConfig *external_config = nullptr; const DynamicConfig *external_config = nullptr;
const DynamicConfig *config = nullptr; const DynamicConfig *config = nullptr;
const DynamicConfig *config_override = nullptr; const DynamicConfig *config_override = nullptr;
mutable DynamicConfig *config_outputs = nullptr;
size_t current_extruder_id = 0; size_t current_extruder_id = 0;
PlaceholderParser::ContextData *context_data = nullptr; PlaceholderParser::ContextData *context_data = nullptr;
// If false, the macro_processor will evaluate a full macro. // If false, the macro_processor will evaluate a full macro.
@ -713,6 +719,7 @@ namespace client
} }
const ConfigOption* resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); } const ConfigOption* resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); }
ConfigOption* resolve_output_symbol(const std::string &opt_key) const { return this->config_outputs ? this->config_outputs->optptr(opt_key, false) : nullptr; }
template <typename Iterator> template <typename Iterator>
static void legacy_variable_expansion( static void legacy_variable_expansion(
@ -788,20 +795,59 @@ namespace client
OptWithPos<Iterator> &output) OptWithPos<Iterator> &output)
{ {
const ConfigOption *opt = ctx->resolve_symbol(std::string(opt_key.begin(), opt_key.end())); const ConfigOption *opt = ctx->resolve_symbol(std::string(opt_key.begin(), opt_key.end()));
if (opt == nullptr) {
opt = ctx->resolve_output_symbol(std::string(opt_key.begin(), opt_key.end()));
if (opt == nullptr) if (opt == nullptr)
ctx->throw_exception("Not a variable name", opt_key); ctx->throw_exception("Not a variable name", opt_key);
output.writable = true;
}
output.opt = opt; output.opt = opt;
output.it_range = opt_key; output.it_range = opt_key;
} }
template <typename Iterator> template <typename Iterator>
static void scalar_variable_reference( static void store_variable_index(
const MyContext *ctx,
OptWithPos<Iterator> &opt,
int index,
Iterator it_end,
OptWithPos<Iterator> &output)
{
if (! opt.opt->is_vector())
ctx->throw_exception("Cannot index a scalar variable", opt.it_range);
if (index < 0)
ctx->throw_exception("Referencing a vector variable with a negative index", opt.it_range);
output = opt;
output.index = index;
output.it_range.end() = it_end;
}
template <typename Iterator>
static void variable_value(
const MyContext *ctx, const MyContext *ctx,
OptWithPos<Iterator> &opt, OptWithPos<Iterator> &opt,
expr<Iterator> &output) expr<Iterator> &output)
{ {
if (opt.opt->is_vector()) if (opt.opt->is_vector()) {
if (! opt.has_index())
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range); ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index);
switch (opt.opt->type()) {
case coFloats: output.set_d(static_cast<const ConfigOptionFloats *>(opt.opt)->values[idx]); break;
case coInts: output.set_i(static_cast<const ConfigOptionInts *>(opt.opt)->values[idx]); break;
case coStrings: output.set_s(static_cast<const ConfigOptionStrings *>(opt.opt)->values[idx]); break;
case coPercents: output.set_d(static_cast<const ConfigOptionPercents*>(opt.opt)->values[idx]); break;
case coPoints: output.set_s(to_string(static_cast<const ConfigOptionPoints *>(opt.opt)->values[idx])); break;
case coBools: output.set_b(static_cast<const ConfigOptionBools *>(opt.opt)->values[idx] != 0); break;
//case coEnums: output.set_s(opt.opt->vserialize()[idx]); break;
default:
ctx->throw_exception("Unknown vector variable type", opt.it_range);
}
} else {
assert(opt.opt->is_scalar());
switch (opt.opt->type()) { switch (opt.opt->type()) {
case coFloat: output.set_d(opt.opt->getFloat()); break; case coFloat: output.set_d(opt.opt->getFloat()); break;
case coInt: output.set_i(opt.opt->getInt()); break; case coInt: output.set_i(opt.opt->getInt()); break;
@ -851,67 +897,111 @@ namespace client
default: default:
ctx->throw_exception("Unknown scalar variable type", opt.it_range); ctx->throw_exception("Unknown scalar variable type", opt.it_range);
} }
output.it_range = opt.it_range;
} }
template <typename Iterator> output.it_range = opt.it_range;
static void vector_variable_reference(
const MyContext *ctx,
OptWithPos<Iterator> &opt,
int &index,
Iterator it_end,
expr<Iterator> &output)
{
if (opt.opt->is_scalar())
ctx->throw_exception("Referencing a scalar variable when vector is expected", opt.it_range);
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
size_t idx = (index < 0) ? 0 : (index >= int(vec->size())) ? 0 : size_t(index);
switch (opt.opt->type()) {
case coFloats: output.set_d(static_cast<const ConfigOptionFloats *>(opt.opt)->values[idx]); break;
case coInts: output.set_i(static_cast<const ConfigOptionInts *>(opt.opt)->values[idx]); break;
case coStrings: output.set_s(static_cast<const ConfigOptionStrings *>(opt.opt)->values[idx]); break;
case coPercents: output.set_d(static_cast<const ConfigOptionPercents*>(opt.opt)->values[idx]); break;
case coPoints: output.set_s(to_string(static_cast<const ConfigOptionPoints *>(opt.opt)->values[idx])); break;
case coBools: output.set_b(static_cast<const ConfigOptionBools *>(opt.opt)->values[idx] != 0); break;
//case coEnums: output.set_s(opt.opt->vserialize()[idx]); break;
default:
ctx->throw_exception("Unknown vector variable type", opt.it_range);
}
output.it_range = boost::iterator_range<Iterator>(opt.it_range.begin(), it_end);
} }
// Return a boolean value, true if the scalar variable referenced by "opt" is nullable and it has a nil value. // Return a boolean value, true if the scalar variable referenced by "opt" is nullable and it has a nil value.
template <typename Iterator>
static void is_nil_test_scalar(
const MyContext *ctx,
OptWithPos<Iterator> &opt,
expr<Iterator> &output)
{
if (opt.opt->is_vector())
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
output.set_b(opt.opt->is_nil());
output.it_range = opt.it_range;
}
// Return a boolean value, true if an element of a vector variable referenced by "opt[index]" is nullable and it has a nil value. // Return a boolean value, true if an element of a vector variable referenced by "opt[index]" is nullable and it has a nil value.
template <typename Iterator> template <typename Iterator>
static void is_nil_test_vector( static void is_nil_test(
const MyContext *ctx, const MyContext *ctx,
OptWithPos<Iterator> &opt, OptWithPos<Iterator> &opt,
int &index,
Iterator it_end,
expr<Iterator> &output) expr<Iterator> &output)
{ {
if (opt.opt->is_scalar()) if (opt.opt->is_vector()) {
ctx->throw_exception("Referencing a scalar variable when vector is expected", opt.it_range); if (! opt.has_index())
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt); const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vec->empty()) if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", opt.it_range); ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
size_t idx = (index < 0) ? 0 : (index >= int(vec->size())) ? 0 : size_t(index); output.set_b(static_cast<const ConfigOptionVectorBase*>(opt.opt)->is_nil(opt.index >= int(vec->size()) ? 0 : size_t(opt.index)));
output.set_b(static_cast<const ConfigOptionVectorBase*>(opt.opt)->is_nil(idx)); } else {
output.it_range = boost::iterator_range<Iterator>(opt.it_range.begin(), it_end); assert(opt.opt->is_scalar());
output.set_b(opt.opt->is_nil());
}
output.it_range = opt.it_range;
}
// Decoding a scalar variable symbol "opt", assigning it a value of "param".
template <typename Iterator>
static void variable_assign(
const MyContext *ctx,
OptWithPos<Iterator> &opt,
expr<Iterator> &param,
// Not used, just clear it.
std::string &out)
{
if (! opt.writable)
ctx->throw_exception("Cannot modify a read-only variable", opt.it_range);
if (opt.opt->is_vector()) {
if (! opt.has_index())
ctx->throw_exception("Referencing an output vector variable when scalar is expected", opt.it_range);
ConfigOptionVectorBase *vec = const_cast<ConfigOptionVectorBase*>(static_cast<const ConfigOptionVectorBase*>(opt.opt));
if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
if (opt.index >= int(vec->size()))
ctx->throw_exception("Index out of range", opt.it_range);
switch (opt.opt->type()) {
case coFloats:
if (param.type() != expr<Iterator>::TYPE_INT && param.type() != expr<Iterator>::TYPE_DOUBLE)
ctx->throw_exception("Right side is not a numeric expression", param.it_range);
static_cast<ConfigOptionFloats*>(vec)->values[opt.index] = param.as_d();
break;
case coInts:
if (param.type() != expr<Iterator>::TYPE_INT && param.type() != expr<Iterator>::TYPE_DOUBLE)
ctx->throw_exception("Right side is not a numeric expression", param.it_range);
static_cast<ConfigOptionInts*>(vec)->values[opt.index] = param.as_i();
break;
case coStrings:
static_cast<ConfigOptionStrings*>(vec)->values[opt.index] = param.to_string();
break;
case coPercents:
if (param.type() != expr<Iterator>::TYPE_INT && param.type() != expr<Iterator>::TYPE_DOUBLE)
ctx->throw_exception("Right side is not a numeric expression", param.it_range);
static_cast<ConfigOptionPercents*>(vec)->values[opt.index] = param.as_d();
break;
case coBools:
if (param.type() != expr<Iterator>::TYPE_BOOL)
ctx->throw_exception("Right side is not a boolean expression", param.it_range);
static_cast<ConfigOptionBools*>(vec)->values[opt.index] = param.b();
break;
default:
ctx->throw_exception("Unsupported output vector variable type", opt.it_range);
}
} else {
assert(opt.opt->is_scalar());
ConfigOption *wropt = const_cast<ConfigOption*>(opt.opt);
switch (wropt->type()) {
case coFloat:
if (param.type() != expr<Iterator>::TYPE_INT && param.type() != expr<Iterator>::TYPE_DOUBLE)
ctx->throw_exception("Right side is not a numeric expression", param.it_range);
static_cast<ConfigOptionFloat*>(wropt)->value = param.as_d();
break;
case coInt:
if (param.type() != expr<Iterator>::TYPE_INT && param.type() != expr<Iterator>::TYPE_DOUBLE)
ctx->throw_exception("Right side is not a numeric expression", param.it_range);
static_cast<ConfigOptionInt*>(wropt)->value = param.as_i();
break;
case coString:
static_cast<ConfigOptionString*>(wropt)->value = param.to_string();
break;
case coPercent:
if (param.type() != expr<Iterator>::TYPE_INT && param.type() != expr<Iterator>::TYPE_DOUBLE)
ctx->throw_exception("Right side is not a numeric expression", param.it_range);
static_cast<ConfigOptionPercent*>(wropt)->value = param.as_d();
break;
case coBool:
if (param.type() != expr<Iterator>::TYPE_BOOL)
ctx->throw_exception("Right side is not a boolean expression", param.it_range);
static_cast<ConfigOptionBool*>(wropt)->value = param.b();
break;
default:
ctx->throw_exception("Unsupported output scalar variable type", opt.it_range);
}
}
out.clear();
} }
// Verify that the expression returns an integer, which may be used // Verify that the expression returns an integer, which may be used
@ -1011,9 +1101,9 @@ namespace client
{ "multiplicative_expression", "Expecting an expression." }, { "multiplicative_expression", "Expecting an expression." },
{ "unary_expression", "Expecting an expression." }, { "unary_expression", "Expecting an expression." },
{ "optional_parameter", "Expecting a closing brace or an optional parameter." }, { "optional_parameter", "Expecting a closing brace or an optional parameter." },
{ "scalar_variable_reference", "Expecting a scalar variable reference."},
{ "is_nil_test", "Expecting a scalar variable reference."},
{ "variable_reference", "Expecting a variable reference."}, { "variable_reference", "Expecting a variable reference."},
{ "is_nil_test", "Expecting a scalar variable reference."},
{ "variable", "Expecting a variable name."},
{ "regular_expression", "Expecting a regular expression."} { "regular_expression", "Expecting a regular expression."}
}; };
@ -1165,7 +1255,9 @@ namespace client
macro = macro =
(kw["if"] > if_else_output(_r1) [_val = _1]) (kw["if"] > if_else_output(_r1) [_val = _1])
// | (kw["switch"] > switch_output(_r1) [_val = _1]) // | (kw["switch"] > switch_output(_r1) [_val = _1])
| additive_expression(_r1) [ px::bind(&expr<Iterator>::to_string2, _1, _val) ]; | (assignment_statement(_r1) [_val = _1])
| (additive_expression(_r1) [ px::bind(&expr<Iterator>::to_string2, _1, _val) ])
;
macro.name("macro"); macro.name("macro");
// An if expression enclosed in {} (the outmost {} are already parsed by the caller). // An if expression enclosed in {} (the outmost {} are already parsed by the caller).
@ -1257,6 +1349,10 @@ namespace client
); );
multiplicative_expression.name("multiplicative_expression"); multiplicative_expression.name("multiplicative_expression");
assignment_statement =
(variable_reference(_r1) >> '=' > additive_expression(_r1))
[px::bind(&MyContext::variable_assign<Iterator>, _r1, _1, _2, _val)];
struct FactorActions { struct FactorActions {
static void set_start_pos(Iterator &start_pos, expr<Iterator> &out) static void set_start_pos(Iterator &start_pos, expr<Iterator> &out)
{ out.it_range = boost::iterator_range<Iterator>(start_pos, start_pos); } { out.it_range = boost::iterator_range<Iterator>(start_pos, start_pos); }
@ -1282,7 +1378,7 @@ namespace client
static void noexpr(expr<Iterator> &out) { out.reset(); } static void noexpr(expr<Iterator> &out) { out.reset(); }
}; };
unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> (
scalar_variable_reference(_r1) [ _val = _1 ] variable_reference(_r1) [px::bind(&MyContext::variable_value<Iterator>, _r1, _1, _val)]
| (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] | (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ]
| (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] | (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ]
| (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] | (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ]
@ -1314,27 +1410,20 @@ namespace client
); );
optional_parameter.name("optional_parameter"); optional_parameter.name("optional_parameter");
scalar_variable_reference = is_nil_test = variable_reference(_r1)[px::bind(&MyContext::is_nil_test<Iterator>, _r1, _1, _val)];
variable_reference(_r1)[_a=_1] >> is_nil_test.name("is_nil test");
(
('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index<Iterator>, _1, _b)] > ']' >
iter_pos[px::bind(&MyContext::vector_variable_reference<Iterator>, _r1, _a, _b, _1, _val)])
| eps[px::bind(&MyContext::scalar_variable_reference<Iterator>, _r1, _a, _val)]
);
scalar_variable_reference.name("scalar variable reference");
variable_reference = identifier variable_reference =
[ px::bind(&MyContext::resolve_variable<Iterator>, _r1, _1, _val) ]; variable(_r1)[_a=_1] >>
(
('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index<Iterator>, _1, _b)] > ']' > iter_pos)
[px::bind(&MyContext::store_variable_index<Iterator>, _r1, _a, _b, _2, _val)]
| eps[_val=_a]
);
variable_reference.name("variable reference"); variable_reference.name("variable reference");
is_nil_test = variable = identifier[ px::bind(&MyContext::resolve_variable<Iterator>, _r1, _1, _val) ];
variable_reference(_r1)[_a=_1] >> variable.name("variable reference");
(
('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index<Iterator>, _1, _b)] > ']' >
iter_pos[px::bind(&MyContext::is_nil_test_vector<Iterator>, _r1, _a, _b, _1, _val)])
| eps[px::bind(&MyContext::is_nil_test_scalar<Iterator>, _r1, _a, _val)]
);
is_nil_test.name("is_nil test");
regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']]; regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']];
regular_expression.name("regular_expression"); regular_expression.name("regular_expression");
@ -1378,8 +1467,8 @@ namespace client
debug(multiplicative_expression); debug(multiplicative_expression);
debug(unary_expression); debug(unary_expression);
debug(optional_parameter); debug(optional_parameter);
debug(scalar_variable_reference);
debug(variable_reference); debug(variable_reference);
debug(variable);
debug(is_nil_test); debug(is_nil_test);
debug(regular_expression); debug(regular_expression);
} }
@ -1423,13 +1512,14 @@ namespace client
// Evaluate boolean expression into bool. // Evaluate boolean expression into bool.
qi::rule<Iterator, bool(const MyContext*), spirit_encoding::space_type> bool_expr_eval; qi::rule<Iterator, bool(const MyContext*), spirit_encoding::space_type> bool_expr_eval;
// Reference of a scalar variable, or reference to a field of a vector variable. // Reference of a scalar variable, or reference to a field of a vector variable.
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> scalar_variable_reference; qi::rule<Iterator, OptWithPos<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> variable_reference;
// Rule to translate an identifier to a ConfigOption, or to fail. // Rule to translate an identifier to a ConfigOption, or to fail.
qi::rule<Iterator, OptWithPos<Iterator>(const MyContext*), spirit_encoding::space_type> variable_reference; qi::rule<Iterator, OptWithPos<Iterator>(const MyContext*), spirit_encoding::space_type> variable;
// Evaluating whether a nullable variable is nil. // Evaluating whether a nullable variable is nil.
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> is_nil_test; qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit_encoding::space_type> is_nil_test;
qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool, bool>, spirit_encoding::space_type> if_else_output; qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool, bool>, spirit_encoding::space_type> if_else_output;
qi::rule<Iterator, std::string(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> assignment_statement;
// qi::rule<Iterator, std::string(const MyContext*), qi::locals<expr<Iterator>, bool, std::string>, spirit_encoding::space_type> switch_output; // qi::rule<Iterator, std::string(const MyContext*), qi::locals<expr<Iterator>, bool, std::string>, spirit_encoding::space_type> switch_output;
qi::symbols<char> keywords; qi::symbols<char> keywords;
@ -1461,12 +1551,13 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
return output; return output;
} }
std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override, ContextData *context_data) const std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override, DynamicConfig *config_outputs, ContextData *context_data) const
{ {
client::MyContext context; client::MyContext context;
context.external_config = this->external_config(); context.external_config = this->external_config();
context.config = &this->config(); context.config = &this->config();
context.config_override = config_override; context.config_override = config_override;
context.config_outputs = config_outputs;
context.current_extruder_id = current_extruder_id; context.current_extruder_id = current_extruder_id;
context.context_data = context_data; context.context_data = context_data;
return process_macro(templ, context); return process_macro(templ, context);

View File

@ -55,7 +55,9 @@ public:
// Fill in the template using a macro processing language. // Fill in the template using a macro processing language.
// Throws Slic3r::PlaceholderParserError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr, ContextData *context = nullptr) const; std::string process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override, DynamicConfig *config_outputs, ContextData *context) const;
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr, ContextData *context = nullptr) const
{ return this->process(templ, current_extruder_id, config_override, nullptr /* config_outputs */, context); }
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
// Throws Slic3r::PlaceholderParserError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.

View File

@ -1618,7 +1618,8 @@ void PrintObject::bridge_over_infill()
if (layer->lower_layer == nullptr) { if (layer->lower_layer == nullptr) {
continue; continue;
} }
auto spacing = layer->regions().front()->flow(frSolidInfill).scaled_spacing(); double spacing = layer->regions().front()->flow(frSolidInfill).scaled_spacing();
// unsupported area will serve as a filter for polygons worth bridging.
Polygons unsupported_area; Polygons unsupported_area;
Polygons lower_layer_solids; Polygons lower_layer_solids;
bool contains_only_lightning = true; bool contains_only_lightning = true;
@ -1627,7 +1628,8 @@ void PrintObject::bridge_over_infill()
contains_only_lightning = false; contains_only_lightning = false;
} }
Polygons fill_polys = to_polygons(region->fill_expolygons()); Polygons fill_polys = to_polygons(region->fill_expolygons());
unsupported_area = union_(unsupported_area, expand(fill_polys, spacing)); // initially consider the whole layer unsupported, but also gather solid layers to later cut off supported parts
unsupported_area.insert(unsupported_area.end(), fill_polys.begin(), fill_polys.end());
for (const Surface &surface : region->fill_surfaces()) { for (const Surface &surface : region->fill_surfaces()) {
if (surface.surface_type != stInternal || region->region().config().fill_density.value == 100) { if (surface.surface_type != stInternal || region->region().config().fill_density.value == 100) {
Polygons p = to_polygons(surface.expolygon); Polygons p = to_polygons(surface.expolygon);
@ -1635,30 +1637,43 @@ void PrintObject::bridge_over_infill()
} }
} }
} }
unsupported_area = closing(unsupported_area, SCALED_EPSILON);
lower_layer_solids = expand(lower_layer_solids, 4 * spacing); // By expanding the lower layer solids, we avoid making bridges from the tiny internal overhangs that are (very likely) supported by previous layer solids
unsupported_area = shrink(unsupported_area, 5 * spacing); // NOTE that we cannot filter out polygons worth bridging by their area, because sometimes there is a very small internal island that will grow into large hole
lower_layer_solids = expand(lower_layer_solids, 3 * spacing);
// By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
unsupported_area = shrink(unsupported_area, 3 * spacing);
unsupported_area = diff(unsupported_area, lower_layer_solids); unsupported_area = diff(unsupported_area, lower_layer_solids);
for (const LayerRegion *region : layer->regions()) { for (const LayerRegion *region : layer->regions()) {
SurfacesPtr region_internal_solids = region->fill_surfaces().filter_by_type(stInternalSolid); SurfacesPtr region_internal_solids = region->fill_surfaces().filter_by_type(stInternalSolid);
for (const Surface *s : region_internal_solids) { for (const Surface *s : region_internal_solids) {
Polygons unsupported = intersection(to_polygons(s->expolygon), unsupported_area); Polygons unsupported = intersection(to_polygons(s->expolygon), unsupported_area);
// The following flag marks those surfaces, which overlap with unuspported area, but at least part of them is supported.
// These regions can be filtered by area, because they for sure are touching solids on lower layers, and it does not make sense to bridge their tiny overhangs
bool partially_supported = area(unsupported) < area(to_polygons(s->expolygon)) - EPSILON; bool partially_supported = area(unsupported) < area(to_polygons(s->expolygon)) - EPSILON;
if (!unsupported.empty() && (!partially_supported || area(unsupported) > 5 * 5 * spacing * spacing)) { if (!unsupported.empty() && (!partially_supported || area(unsupported) > 3 * 3 * spacing * spacing)) {
Polygons worth_bridging = intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing)); Polygons worth_bridging = intersection(to_polygons(s->expolygon), expand(unsupported, 4 * spacing));
for (Polygon p : diff(to_polygons(s->expolygon), worth_bridging)) { // after we extracted the part worth briding, we go over the leftovers and merge the tiny ones back, to not brake the surface too much
if (p.area() < region->flow(frSolidInfill, true).scaled_spacing() * scale_(12.0)) { for (const Polygon& p : diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))) {
double area = p.area();
if (area < spacing * scale_(12.0) && area > spacing * spacing) {
worth_bridging.push_back(p); worth_bridging.push_back(p);
} }
} }
worth_bridging = intersection(closing(worth_bridging, 3 * region->flow(frSolidInfill, true).scaled_spacing()), s->expolygon); worth_bridging = intersection(closing(worth_bridging, SCALED_EPSILON), s->expolygon);
candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0, contains_only_lightning)); candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0, contains_only_lightning));
#ifdef DEBUG_BRIDGE_OVER_INFILL #ifdef DEBUG_BRIDGE_OVER_INFILL
debug_draw(std::to_string(lidx) + "_candidate_surface_" + std::to_string(area(s->expolygon)), debug_draw(std::to_string(lidx) + "_candidate_surface_" + std::to_string(area(s->expolygon)),
to_lines(region->layer()->lslices), to_lines(s->expolygon), to_lines(worth_bridging), to_lines(region->layer()->lslices), to_lines(s->expolygon), to_lines(worth_bridging),
to_lines(unsupported_area)); to_lines(unsupported_area));
#endif
#ifdef DEBUG_BRIDGE_OVER_INFILL
debug_draw(std::to_string(lidx) + "_candidate_processing_" + std::to_string(area(unsupported)),
to_lines(unsupported), to_lines(intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing))),
to_lines(diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))),
to_lines(unsupported_area));
#endif #endif
} }
} }
@ -1720,15 +1735,15 @@ void PrintObject::bridge_over_infill()
layer_area_covered_by_candidates[pair.first] = {}; layer_area_covered_by_candidates[pair.first] = {};
} }
// prepare inflated filter for each candidate on each layer. layers will be put into single thread cluster if they are close to each other (z-axis-wise)
// and if the inflated AABB polygons overlap somewhere
tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_with_candidates.size()), [&layers_with_candidates, &surfaces_by_layer, tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_with_candidates.size()), [&layers_with_candidates, &surfaces_by_layer,
&layer_area_covered_by_candidates]( &layer_area_covered_by_candidates](
tbb::blocked_range<size_t> r) { tbb::blocked_range<size_t> r) {
for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) { for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) {
size_t lidx = layers_with_candidates[job_idx]; size_t lidx = layers_with_candidates[job_idx];
for (const auto &candidate : surfaces_by_layer.at(lidx)) { for (const auto &candidate : surfaces_by_layer.at(lidx)) {
Polygon candiate_inflated_aabb = get_extents(candidate.new_polys) Polygon candiate_inflated_aabb = get_extents(candidate.new_polys).inflated(scale_(7)).polygon();
.inflated(candidate.region->flow(frSolidInfill, true).scaled_spacing() * 5)
.polygon();
layer_area_covered_by_candidates.at(lidx) = union_(layer_area_covered_by_candidates.at(lidx), layer_area_covered_by_candidates.at(lidx) = union_(layer_area_covered_by_candidates.at(lidx),
Polygons{candiate_inflated_aabb}); Polygons{candiate_inflated_aabb});
} }
@ -1765,9 +1780,9 @@ void PrintObject::bridge_over_infill()
// LAMBDA to gather areas with sparse infill deep enough that we can fit thick bridges there. // LAMBDA to gather areas with sparse infill deep enough that we can fit thick bridges there.
auto gather_areas_w_depth = [target_flow_height_factor](const PrintObject *po, int lidx, float target_flow_height) { auto gather_areas_w_depth = [target_flow_height_factor](const PrintObject *po, int lidx, float target_flow_height) {
// Gather lower layers sparse infill areas, to depth defined by used bridge flow // Gather layers sparse infill areas, to depth defined by used bridge flow
Polygons lower_layers_sparse_infill{}; ExPolygons layers_sparse_infill{};
Polygons not_sparse_infill{}; ExPolygons not_sparse_infill{};
double bottom_z = po->get_layer(lidx)->print_z - target_flow_height * target_flow_height_factor - EPSILON; double bottom_z = po->get_layer(lidx)->print_z - target_flow_height * target_flow_height_factor - EPSILON;
for (int i = int(lidx) - 1; i >= 0; --i) { for (int i = int(lidx) - 1; i >= 0; --i) {
// Stop iterating if layer is lower than bottom_z. // Stop iterating if layer is lower than bottom_z.
@ -1778,19 +1793,19 @@ void PrintObject::bridge_over_infill()
for (const LayerRegion *region : layer->regions()) { for (const LayerRegion *region : layer->regions()) {
bool has_low_density = region->region().config().fill_density.value < 100; bool has_low_density = region->region().config().fill_density.value < 100;
for (const Surface &surface : region->fill_surfaces()) { for (const Surface &surface : region->fill_surfaces()) {
if (surface.surface_type == stInternal && has_low_density) { if ((surface.surface_type == stInternal && has_low_density) || surface.surface_type == stInternalVoid ) {
Polygons p = to_polygons(surface.expolygon); layers_sparse_infill.push_back(surface.expolygon);
lower_layers_sparse_infill.insert(lower_layers_sparse_infill.end(), p.begin(), p.end());
} else { } else {
Polygons p = to_polygons(surface.expolygon); not_sparse_infill.push_back(surface.expolygon);
not_sparse_infill.insert(not_sparse_infill.end(), p.begin(), p.end());
} }
} }
} }
lower_layers_sparse_infill = union_(lower_layers_sparse_infill);
} }
lower_layers_sparse_infill = closing(lower_layers_sparse_infill, SCALED_EPSILON); layers_sparse_infill = union_ex(layers_sparse_infill);
return diff(lower_layers_sparse_infill, not_sparse_infill); layers_sparse_infill = closing_ex(layers_sparse_infill, SCALED_EPSILON);
not_sparse_infill = union_ex(not_sparse_infill);
not_sparse_infill = closing_ex(not_sparse_infill, SCALED_EPSILON);
return diff(layers_sparse_infill, not_sparse_infill);
}; };
// LAMBDA do determine optimal bridging angle // LAMBDA do determine optimal bridging angle
@ -1927,7 +1942,7 @@ void PrintObject::bridge_over_infill()
}); });
if (maybe_below_anchor != anchors_intersections.rend()) { if (maybe_below_anchor != anchors_intersections.rend()) {
section.a = maybe_below_anchor->first; section.a = maybe_below_anchor->first;
section.a.y() -= bridging_flow.scaled_width() * (0.5 + 1.0); section.a.y() -= bridging_flow.scaled_width() * (0.5 + 0.5);
} }
auto maybe_upper_anchor = std::upper_bound(anchors_intersections.begin(), anchors_intersections.end(), section.b, auto maybe_upper_anchor = std::upper_bound(anchors_intersections.begin(), anchors_intersections.end(), section.b,
@ -1936,7 +1951,7 @@ void PrintObject::bridge_over_infill()
}); });
if (maybe_upper_anchor != anchors_intersections.end()) { if (maybe_upper_anchor != anchors_intersections.end()) {
section.b = maybe_upper_anchor->first; section.b = maybe_upper_anchor->first;
section.b.y() += bridging_flow.scaled_width() * (0.5 + 1.0); section.b.y() += bridging_flow.scaled_width() * (0.5 + 0.5);
} }
} }
@ -2059,6 +2074,7 @@ void PrintObject::bridge_over_infill()
}); });
// Gather deep infill areas, where thick bridges fit // Gather deep infill areas, where thick bridges fit
coordf_t spacing = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).scaled_spacing();
coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).height() * target_flow_height_factor; coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).height() * target_flow_height_factor;
Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height); Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
@ -2079,11 +2095,13 @@ void PrintObject::bridge_over_infill()
} }
} }
deep_infill_area = expand(deep_infill_area, spacing * 1.5);
// Now gather expansion polygons - internal infill on current layer, from which we can cut off anchors // Now gather expansion polygons - internal infill on current layer, from which we can cut off anchors
Polygons expansion_area; Polygons expansion_area;
Polygons total_fill_area; Polygons total_fill_area;
for (const LayerRegion *region : layer->regions()) { for (const LayerRegion *region : layer->regions()) {
Polygons internal_polys = to_polygons(region->fill_surfaces().filter_by_type(stInternal)); Polygons internal_polys = to_polygons(region->fill_surfaces().filter_by_types({stInternal, stInternalSolid}));
expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end()); expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end());
Polygons fill_polys = to_polygons(region->fill_expolygons()); Polygons fill_polys = to_polygons(region->fill_expolygons());
total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end()); total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end());
@ -2093,25 +2111,37 @@ void PrintObject::bridge_over_infill()
expansion_area = intersection(expansion_area, deep_infill_area); expansion_area = intersection(expansion_area, deep_infill_area);
Polylines anchors = intersection_pl(infill_lines[lidx - 1], expansion_area); Polylines anchors = intersection_pl(infill_lines[lidx - 1], expansion_area);
#ifdef DEBUG_BRIDGE_OVER_INFILL
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
"_total_area",
to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
#endif
std::vector<CandidateSurface> expanded_surfaces; std::vector<CandidateSurface> expanded_surfaces;
expanded_surfaces.reserve(surfaces_by_layer[lidx].size()); expanded_surfaces.reserve(surfaces_by_layer[lidx].size());
for (const CandidateSurface &candidate : surfaces_by_layer[lidx]) { for (const CandidateSurface &candidate : surfaces_by_layer[lidx]) {
const Flow &flow = candidate.region->bridging_flow(frSolidInfill, true); const Flow &flow = candidate.region->bridging_flow(frSolidInfill, true);
Polygons area_to_be_bridge = intersection(candidate.new_polys, deep_infill_area); Polygons area_to_be_bridge = expand(candidate.new_polys, flow.scaled_spacing());
area_to_be_bridge = intersection(area_to_be_bridge, deep_infill_area);
Polygons limiting_area = union_(area_to_be_bridge, expansion_area);
if (area_to_be_bridge.empty()) if (area_to_be_bridge.empty())
continue; continue;
area_to_be_bridge = expand(area_to_be_bridge, flow.scaled_spacing());
Polylines boundary_plines = to_polylines(expand(total_fill_area, 1.3 * flow.scaled_spacing())); Polylines boundary_plines = to_polylines(expand(total_fill_area, 1.3 * flow.scaled_spacing()));
{ {
Polylines expansion_plines = to_polylines(expansion_area); Polylines limiting_plines = to_polylines(expand(limiting_area, 0.3*flow.spacing()));
boundary_plines.insert(boundary_plines.end(), expansion_plines.begin(), expansion_plines.end()); boundary_plines.insert(boundary_plines.end(), limiting_plines.begin(), limiting_plines.end());
Polylines expanded_expansion_plines = to_polylines(expand(expansion_area, 1.3 * flow.scaled_spacing()));
boundary_plines.insert(boundary_plines.end(), expanded_expansion_plines.begin(), expanded_expansion_plines.end());
} }
#ifdef DEBUG_BRIDGE_OVER_INFILL
int r = rand();
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
"_anchors_" + std::to_string(r),
to_lines(area_to_be_bridge), to_lines(boundary_plines), to_lines(anchors), to_lines(expansion_area));
#endif
double bridging_angle = 0; double bridging_angle = 0;
if (!anchors.empty()) { if (!anchors.empty()) {
bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(anchors), bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(anchors),
@ -2145,14 +2175,13 @@ void PrintObject::bridge_over_infill()
} }
bridging_area = opening(bridging_area, flow.scaled_spacing()); bridging_area = opening(bridging_area, flow.scaled_spacing());
bridging_area = intersection(bridging_area, limiting_area);
bridging_area = intersection(bridging_area, total_fill_area); bridging_area = intersection(bridging_area, total_fill_area);
expansion_area = diff(expansion_area, bridging_area); expansion_area = diff(expansion_area, bridging_area);
#ifdef DEBUG_BRIDGE_OVER_INFILL #ifdef DEBUG_BRIDGE_OVER_INFILL
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_expanded_bridging" + std::to_string(r),
"_expanded_bridging", to_lines(layer->lslices), to_lines(boundary_plines), to_lines(candidate.new_polys), to_lines(bridging_area));
to_lines(layer->lslices), to_lines(boundary_plines), to_lines(candidate.new_polys),
to_lines(bridging_area));
#endif #endif
expanded_surfaces.push_back(CandidateSurface(candidate.original_surface, candidate.layer_index, bridging_area, expanded_surfaces.push_back(CandidateSurface(candidate.original_surface, candidate.layer_index, bridging_area,

View File

@ -166,11 +166,11 @@ ArchiveViewCtrl::~ArchiveViewCtrl()
} }
} }
FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<boost::filesystem::path>& selected_paths) FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<std::pair<boost::filesystem::path, size_t>>& selected_paths_w_size)
: DPIDialog(parent_window, wxID_ANY, _(L("Archive preview")), wxDefaultPosition, : DPIDialog(parent_window, wxID_ANY, _(L("Archive preview")), wxDefaultPosition,
wxSize(45 * wxGetApp().em_unit(), 40 * wxGetApp().em_unit()), wxSize(45 * wxGetApp().em_unit(), 40 * wxGetApp().em_unit()),
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX) wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
, m_selected_paths (selected_paths) , m_selected_paths_w_size (selected_paths_w_size)
{ {
#ifdef _WIN32 #ifdef _WIN32
wxGetApp().UpdateDarkUI(this); wxGetApp().UpdateDarkUI(this);
@ -213,7 +213,7 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
const std::regex pattern_drop(".*[.](stl|obj|amf|3mf|prusa|step|stp)", std::regex::icase); const std::regex pattern_drop(".*[.](stl|obj|amf|3mf|prusa|step|stp)", std::regex::icase);
mz_uint num_entries = mz_zip_reader_get_num_files(archive); mz_uint num_entries = mz_zip_reader_get_num_files(archive);
mz_zip_archive_file_stat stat; mz_zip_archive_file_stat stat;
std::vector<boost::filesystem::path> filtered_entries; std::vector<std::pair<boost::filesystem::path, size_t>> filtered_entries; // second is unzipped size
for (mz_uint i = 0; i < num_entries; ++i) { for (mz_uint i = 0; i < num_entries; ++i) {
if (mz_zip_reader_file_stat(archive, i, &stat)) { if (mz_zip_reader_file_stat(archive, i, &stat)) {
std::string extra(1024, 0); std::string extra(1024, 0);
@ -232,22 +232,25 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
// filter out MACOS specific hidden files // filter out MACOS specific hidden files
if (boost::algorithm::starts_with(path.string(), "__MACOSX")) if (boost::algorithm::starts_with(path.string(), "__MACOSX"))
continue; continue;
filtered_entries.emplace_back(std::move(path)); filtered_entries.emplace_back(std::move(path), stat.m_uncomp_size);
} }
} }
// sorting files will help adjust_stack function to not create multiple same folders // sorting files will help adjust_stack function to not create multiple same folders
std::sort(filtered_entries.begin(), filtered_entries.end(), [](const boost::filesystem::path& p1, const boost::filesystem::path& p2){ return p1.string() > p2.string(); }); std::sort(filtered_entries.begin(), filtered_entries.end(), [](const std::pair<boost::filesystem::path, size_t>& p1, const std::pair<boost::filesystem::path, size_t>& p2){ return p1.first.string() < p2.first.string(); });
size_t entry_count = 0; size_t entry_count = 0;
size_t depth = 1; size_t depth = 1;
for (const boost::filesystem::path& path : filtered_entries) for (const auto& entry : filtered_entries)
{ {
const boost::filesystem::path& path = entry.first;
std::shared_ptr<ArchiveViewNode> parent(nullptr); std::shared_ptr<ArchiveViewNode> parent(nullptr);
depth = std::max(depth, adjust_stack(path, stack)); depth = std::max(depth, adjust_stack(path, stack));
if (!stack.empty()) if (!stack.empty())
parent = stack.back(); parent = stack.back();
if (std::regex_match(path.extension().string(), pattern_drop)) { // this leaves out non-compatible files if (std::regex_match(path.extension().string(), pattern_drop)) { // this leaves out non-compatible files
m_avc->get_model()->AddFile(parent, boost::nowide::widen(path.filename().string()), false)->set_fullpath(/*std::move(path)*/path); // filename string to wstring? std::shared_ptr<ArchiveViewNode> new_node = m_avc->get_model()->AddFile(parent, boost::nowide::widen(path.filename().string()), false);
new_node->set_fullpath(/*std::move(path)*/path); // filename string to wstring?
new_node->set_size(entry.second);
entry_count++; entry_count++;
} }
} }
@ -305,12 +308,12 @@ void FileArchiveDialog::on_open_button()
wxDataViewItemArray top_items; wxDataViewItemArray top_items;
m_avc->get_model()->GetChildren(wxDataViewItem(nullptr), top_items); m_avc->get_model()->GetChildren(wxDataViewItem(nullptr), top_items);
std::function<void(ArchiveViewNode*)> deep_fill = [&paths = m_selected_paths, &deep_fill](ArchiveViewNode* node){ std::function<void(ArchiveViewNode*)> deep_fill = [&paths = m_selected_paths_w_size, &deep_fill](ArchiveViewNode* node){
if (node == nullptr) if (node == nullptr)
return; return;
if (node->get_children().empty()) { if (node->get_children().empty()) {
if (node->get_toggle()) if (node->get_toggle())
paths.emplace_back(node->get_fullpath()); paths.emplace_back(node->get_fullpath(), node->get_size());
} else { } else {
for (std::shared_ptr<ArchiveViewNode> child : node->get_children()) for (std::shared_ptr<ArchiveViewNode> child : node->get_children())
deep_fill(child.get()); deep_fill(child.get());

View File

@ -33,6 +33,8 @@ public:
void set_is_folder(bool is_folder) { m_folder = is_folder; } void set_is_folder(bool is_folder) { m_folder = is_folder; }
void set_fullpath(boost::filesystem::path path) { m_fullpath = path; } void set_fullpath(boost::filesystem::path path) { m_fullpath = path; }
boost::filesystem::path get_fullpath() const { return m_fullpath; } boost::filesystem::path get_fullpath() const { return m_fullpath; }
void set_size(size_t size) { m_size = size; }
size_t get_size() const { return m_size; }
private: private:
wxString m_name; wxString m_name;
@ -43,6 +45,7 @@ private:
bool m_folder { false }; bool m_folder { false };
boost::filesystem::path m_fullpath; boost::filesystem::path m_fullpath;
bool m_container { false }; bool m_container { false };
size_t m_size { 0 };
}; };
class ArchiveViewModel : public wxDataViewModel class ArchiveViewModel : public wxDataViewModel
@ -100,7 +103,7 @@ protected:
class FileArchiveDialog : public DPIDialog class FileArchiveDialog : public DPIDialog
{ {
public: public:
FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<boost::filesystem::path>& selected_paths); FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<std::pair<boost::filesystem::path, size_t>>& selected_paths_w_size);
protected: protected:
void on_dpi_changed(const wxRect& suggested_rect) override; void on_dpi_changed(const wxRect& suggested_rect) override;
@ -109,7 +112,9 @@ protected:
void on_all_button(); void on_all_button();
void on_none_button(); void on_none_button();
std::vector<boost::filesystem::path>& m_selected_paths; // chosen files are written into this vector and returned to caller via reference.
// path in archive and decompressed size. The size can be used to distinguish between files with same path.
std::vector<std::pair<boost::filesystem::path,size_t>>& m_selected_paths_w_size;
ArchiveViewCtrl* m_avc; ArchiveViewCtrl* m_avc;
}; };

View File

@ -3160,6 +3160,8 @@ void Plater::priv::split_object()
// causing original positions not to be kept // causing original positions not to be kept
std::vector<size_t> idxs = load_model_objects(new_objects); std::vector<size_t> idxs = load_model_objects(new_objects);
// clear previosli selection
get_selection().clear();
// select newly added objects // select newly added objects
for (size_t idx : idxs) for (size_t idx : idxs)
{ {
@ -5558,23 +5560,25 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
std::string err_msg = GUI::format(_utf8("Loading of a zip archive on path %1% has failed."), archive_path.string()); std::string err_msg = GUI::format(_utf8("Loading of a zip archive on path %1% has failed."), archive_path.string());
throw Slic3r::FileIOError(err_msg); throw Slic3r::FileIOError(err_msg);
} }
mz_uint num_entries = mz_zip_reader_get_num_files(&archive); mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
mz_zip_archive_file_stat stat; mz_zip_archive_file_stat stat;
// selected_paths contains paths and its uncompressed size. The size is used to distinguish between files with same path.
std::vector<fs::path> selected_paths; std::vector<std::pair<fs::path, size_t>> selected_paths;
FileArchiveDialog dlg(static_cast<wxWindow*>(wxGetApp().mainframe), &archive, selected_paths); FileArchiveDialog dlg(static_cast<wxWindow*>(wxGetApp().mainframe), &archive, selected_paths);
if (dlg.ShowModal() == wxID_OK) if (dlg.ShowModal() == wxID_OK)
{ {
std::string archive_path_string = archive_path.string(); std::string archive_path_string = archive_path.string();
archive_path_string = archive_path_string.substr(0, archive_path_string.size() - 4); archive_path_string = archive_path_string.substr(0, archive_path_string.size() - 4);
fs::path archive_dir(wxStandardPaths::Get().GetTempDir().utf8_str().data()); fs::path archive_dir(wxStandardPaths::Get().GetTempDir().utf8_str().data());
for (auto& path_w_size : selected_paths) {
const fs::path& path = path_w_size.first;
size_t size = path_w_size.second;
// find path in zip archive
for (mz_uint i = 0; i < num_entries; ++i) { for (mz_uint i = 0; i < num_entries; ++i) {
if (mz_zip_reader_file_stat(&archive, i, &stat)) { if (mz_zip_reader_file_stat(&archive, i, &stat)) {
if (size != stat.m_uncomp_size) // size must fit
continue;
wxString wname = boost::nowide::widen(stat.m_filename); wxString wname = boost::nowide::widen(stat.m_filename);
std::string name = boost::nowide::narrow(wname); std::string name = boost::nowide::narrow(wname);
fs::path archive_path(name); fs::path archive_path(name);
@ -5588,8 +5592,9 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
if (archive_path.empty()) if (archive_path.empty())
continue; continue;
for (const auto& path : selected_paths) { if (path != archive_path)
if (path == archive_path) { continue;
// decompressing
try try
{ {
std::replace(name.begin(), name.end(), '\\', '/'); std::replace(name.begin(), name.end(), '\\', '/');
@ -5607,15 +5612,16 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
} }
filename = final_filename + extension; filename = final_filename + extension;
fs::path final_path = archive_dir / filename; fs::path final_path = archive_dir / filename;
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); // Decompress action. We already has correct file index in stat structure.
mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
wxString error_log = GUI::format_wxstr(_L("Failed to unzip file to %1%: %2% "), final_path.string(), mz_zip_get_error_string(mz_zip_get_last_error(&archive))); wxString error_log = GUI::format_wxstr(_L("Failed to unzip file to %1%: %2% "), final_path.string(), mz_zip_get_error_string(mz_zip_get_last_error(&archive)));
BOOST_LOG_TRIVIAL(error) << error_log; BOOST_LOG_TRIVIAL(error) << error_log;
show_error(nullptr, error_log); show_error(nullptr, error_log);
continue; break;
} }
// write buffer to file
fs::fstream file(final_path, std::ios::out | std::ios::binary | std::ios::trunc); fs::fstream file(final_path, std::ios::out | std::ios::binary | std::ios::trunc);
file.write(buffer.c_str(), buffer.size()); file.write(buffer.c_str(), buffer.size());
file.close(); file.close();
@ -5623,22 +5629,22 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
wxString error_log = GUI::format_wxstr(_L("Failed to find unzipped file at %1%. Unzipping of file has failed."), final_path.string()); wxString error_log = GUI::format_wxstr(_L("Failed to find unzipped file at %1%. Unzipping of file has failed."), final_path.string());
BOOST_LOG_TRIVIAL(error) << error_log; BOOST_LOG_TRIVIAL(error) << error_log;
show_error(nullptr, error_log); show_error(nullptr, error_log);
continue; break;
} }
BOOST_LOG_TRIVIAL(info) << "Unzipped " << final_path; BOOST_LOG_TRIVIAL(info) << "Unzipped " << final_path;
if (!boost::algorithm::iends_with(filename, ".3mf") && !boost::algorithm::iends_with(filename, ".amf")) { if (!boost::algorithm::iends_with(filename, ".3mf") && !boost::algorithm::iends_with(filename, ".amf")) {
non_project_paths.emplace_back(final_path); non_project_paths.emplace_back(final_path);
continue; break;
} }
// if 3mf - read archive headers to find project file // if 3mf - read archive headers to find project file
if ((boost::algorithm::iends_with(filename, ".3mf") && !is_project_3mf(final_path.string())) || if ((boost::algorithm::iends_with(filename, ".3mf") && !is_project_3mf(final_path.string())) ||
(boost::algorithm::iends_with(filename, ".amf") && !boost::algorithm::iends_with(filename, ".zip.amf"))) { (boost::algorithm::iends_with(filename, ".amf") && !boost::algorithm::iends_with(filename, ".zip.amf"))) {
non_project_paths.emplace_back(final_path); non_project_paths.emplace_back(final_path);
continue; break;
} }
project_paths.emplace_back(final_path); project_paths.emplace_back(final_path);
break;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -5646,8 +5652,6 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
close_zip_reader(&archive); close_zip_reader(&archive);
throw Slic3r::FileIOError(e.what()); throw Slic3r::FileIOError(e.what());
} }
break;
}
} }
} }
} }

View File

@ -399,7 +399,7 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors, const std::string
std::string name(stat.m_filename); std::string name(stat.m_filename);
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
BOOST_LOG_TRIVIAL(error) << "Failed to unzip " << stat.m_filename; BOOST_LOG_TRIVIAL(error) << "Failed to unzip " << stat.m_filename;
continue; continue;

View File

@ -117,4 +117,17 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
SECTION("complex expression2") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)")); } SECTION("complex expression2") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)")); }
SECTION("complex expression3") { REQUIRE(! boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)")); } SECTION("complex expression3") { REQUIRE(! boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)")); }
SECTION("enum expression") { REQUIRE(boolean_expression("gcode_flavor == \"marlin\"")); } SECTION("enum expression") { REQUIRE(boolean_expression("gcode_flavor == \"marlin\"")); }
SECTION("write to a scalar variable") {
DynamicConfig config_outputs;
config_outputs.set_key_value("writable_string", new ConfigOptionString());
parser.process("{writable_string = \"Written\"}", 0, nullptr, &config_outputs, nullptr);
REQUIRE(parser.process("{writable_string}", 0, nullptr, &config_outputs, nullptr) == "Written");
}
SECTION("write to a vector variable") {
DynamicConfig config_outputs;
config_outputs.set_key_value("writable_floats", new ConfigOptionFloats({ 0., 0., 0. }));
parser.process("{writable_floats[1] = 33}", 0, nullptr, &config_outputs, nullptr);
REQUIRE(config_outputs.opt_float("writable_floats", 1) == Approx(33.));
}
} }