diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index b68100ac8e..aa8f2b4a52 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,9 +1,12 @@ min_slic3r_version = 2.6.2-alpha0 +1.11.0-alpha5 Added new profiles (additional nozzle diameters) for Prusa MINI Input Shaper (Alpha). Arc fitting changed to I J. 1.11.0-alpha4 Updated compatible printer conditions for specific filament profiles. 1.11.0-alpha3 Added new print profiles for Prusa MINI Input Shaper (Alpha). Updated MK4 IS profiles. 1.11.0-alpha2 Added MK3.9 and Prusa MINI Input Shaper (alpha). Enabled binary g-code, arc fitting and QOI/PNG for MINI and MINI IS. 1.11.0-alpha1 Updated ramming parameters. Updated start-gcode for XL Multi-Tool. Updated output filename format. 1.11.0-alpha0 Binary g-code, arc fitting, QOI/PNG thumbnails, 90degree XL tower, XL specific filament variants. +min_slic3r_version = 2.6.1-rc2 +1.10.0 Added new profiles for Prusa MINI Input Shaper (Alpha). Enabled XL ramming feature. Prusa XL users may need to re-enable filament profiles in configuration wizard. min_slic3r_version = 2.6.0-beta2 1.9.10 Added new print profiles for Prusa MINI Input Shaper (Alpha). Updated MK4 IS profiles. 1.9.9 Added Original Prusa MK3.9 and Original Prusa MINI/MINI+ Input Shaper (Alpha). FW version notification (5.0.0 final with input shaper). Updated output filename format. Added additional thumbnail resolution. diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index b208e92ea5..fc67b72344 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -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.11.0-alpha4 +config_version = 1.11.0-alpha5 # 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% @@ -54,7 +54,7 @@ default_materials = Generic PLA; Generic ABS @MINI; Generic PETG @MINI; Prusamen [printer_model:MINIIS] name = Original Prusa MINI && MINI+ Input Shaper (Alpha) -variants = 0.4 +variants = 0.4; 0.25; 0.6; 0.8 technology = FFF family = MINI bed_model = mini_bed.stl @@ -362,7 +362,7 @@ wipe_tower_rotation_angle = 90 ooze_prevention = 1 standby_temperature_delta = -110 gcode_binary = 1 -arc_fitting = emit_radius +arc_fitting = emit_center [print:*MK4*] inherits = *common* @@ -388,7 +388,7 @@ raft_first_layer_density = 80% ## gcode_substitutions = "; stop printing object\\s(.*)\\s+id:(\\d+)\\s+.*";"$0\\nM486 S-1\\n";r;;"; printing object\\s(.*)\\s+id:(\\d+)\\s+.*";"$0\\nM486 S$2\\nM486 N$1\\n";r; output_filename_format = {input_filename_base}_0.4n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.bgcode gcode_binary = 1 -arc_fitting = emit_radius +arc_fitting = emit_center [print:*MK306*] inherits = *MK3* @@ -411,7 +411,7 @@ extruder_clearance_height = 20 extruder_clearance_radius = 35 output_filename_format = {input_filename_base}_0.4n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.bgcode gcode_binary = 1 -arc_fitting = emit_radius +arc_fitting = emit_center [print:*0.25nozzle*] elefant_foot_compensation = 0 @@ -3860,7 +3860,7 @@ top_solid_min_thickness = 0.7 bottom_solid_min_thickness = 0.5 compatible_printers_condition = printer_notes=~/.*MK4IS.*/ and nozzle_diameter[0]==0.4 gcode_binary = 1 -arc_fitting = emit_radius +arc_fitting = emit_center [print:*MK4IS_common025*] inherits = *MK4IS_common* @@ -4656,7 +4656,7 @@ external_perimeter_extrusion_width = 1 ## MINI IS -## 0.4mm nozzle MINI IS +## common [print:*MINIIS_common*] inherits = *MK4IS_common* @@ -4694,9 +4694,30 @@ top_solid_min_thickness = 0.7 bottom_solid_min_thickness = 0.5 compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]==0.4 gcode_binary = 1 -arc_fitting = emit_radius +arc_fitting = emit_center output_filename_format = {input_filename_base}_0.4n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.bgcode +[print:*MINIIS_common025*] +inherits = *MK4IS_common025* +infill_acceleration = 2500 +wipe_tower = 0 +output_filename_format = {input_filename_base}_0.25n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.bgcode +compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]==0.25 + +[print:*MINIIS_common06*] +inherits = *MK4IS_common06* +overhang_speed_3 = 45 +output_filename_format = {input_filename_base}_0.6n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.bgcode +compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]==0.6 + +[print:*MINIIS_common08*] +inherits = *MK4IS_common08* +infill_anchor = 3 +output_filename_format = {input_filename_base}_0.8n_{layer_height}mm_{printing_filament_types}_{printer_model}_{print_time}.bgcode +compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]==0.8 + +## 0.4mm nozzle MINI IS + [print:0.20mm SPEED @MINIIS 0.4] inherits = *MINIIS_common* renamed_from = "0.20mm SPEED @MINIIS" @@ -4761,6 +4782,257 @@ infill_extrusion_width = 0.4 solid_infill_extrusion_width = 0.4 top_infill_extrusion_width = 0.4 +# 0.25mm nozzle MINIIS + +[print:0.07mm DETAIL @MINIIS 0.25] +inherits = *MINIIS_common025* +layer_height = 0.07 +bottom_solid_layers = 9 +top_solid_layers = 11 +support_material_contact_distance = 0.1 +raft_contact_distance = 0.1 +perimeter_speed = 60 +small_perimeter_speed = 40 +external_perimeter_speed = 40 +top_solid_infill_speed = 60 +gap_fill_speed = 40 +support_material_speed = 60 +external_perimeter_acceleration = 1000 +perimeter_acceleration = 1200 +top_solid_infill_acceleration = 1000 +solid_infill_acceleration = 2000 +infill_acceleration = 2000 +bridge_acceleration = 1000 +default_acceleration = 1500 +perimeter_extrusion_width = 0.25 +external_perimeter_extrusion_width = 0.25 +infill_extrusion_width = 0.25 +solid_infill_extrusion_width = 0.25 +solid_infill_speed = 140 +bridge_speed = 30 + +[print:0.12mm SPEED @MINIIS 0.25] +inherits = *MINIIS_common025* +layer_height = 0.12 +perimeter_speed = 120 +external_perimeter_speed = 120 +small_perimeter_speed = 120 +external_perimeter_acceleration = 1500 +perimeter_acceleration = 2000 +support_material_contact_distance = 0.09 +raft_contact_distance = 0.08 + +[print:0.12mm STRUCTURAL @MINIIS 0.25] +inherits = 0.12mm SPEED @MINIIS 0.25 +perimeter_speed = 70 +external_perimeter_speed = 40 +small_perimeter_speed = 40 +external_perimeter_acceleration = 1500 +perimeter_acceleration = 2000 +infill_acceleration = 3000 +solid_infill_acceleration = 2500 + +[print:0.15mm SPEED @MINIIS 0.25] +inherits = 0.12mm SPEED @MINIIS 0.25 +layer_height = 0.15 +bottom_solid_layers = 7 +top_solid_layers = 6 + +[print:0.15mm STRUCTURAL @MINIIS 0.25] +inherits = 0.15mm SPEED @MINIIS 0.25 +perimeter_speed = 70 +external_perimeter_speed = 40 +small_perimeter_speed = 40 +external_perimeter_acceleration = 2000 +perimeter_acceleration = 2000 + +# 0.6mm nozzle MINIIS + +[print:0.15mm STRUCTURAL @MINIIS 0.6] +inherits = *MINIIS_common06* +layer_height = 0.15 +bottom_solid_layers = 6 +top_solid_layers = 7 +perimeter_speed = 70 +external_perimeter_speed = 45 +small_perimeter_speed = 45 +solid_infill_speed = 140 +infill_speed = 140 +top_solid_infill_speed = 70 +bridge_speed = 40 +gap_fill_speed = 80 +external_perimeter_acceleration = 1500 +perimeter_acceleration = 2500 +top_solid_infill_acceleration = 1500 +solid_infill_acceleration = 2500 +infill_acceleration = 4000 +bridge_acceleration = 1500 +default_acceleration = 2000 +support_material_contact_distance = 0.22 +extrusion_width = 0.68 +perimeter_extrusion_width = 0.6 +external_perimeter_extrusion_width = 0.6 +infill_extrusion_width = 0.6 +solid_infill_extrusion_width = 0.6 +top_infill_extrusion_width = 0.5 + +[print:0.20mm SPEED @MINIIS 0.6] +inherits = *MINIIS_common06* +layer_height = 0.2 +bottom_solid_layers = 4 +top_solid_layers = 5 +perimeter_speed = 115 +external_perimeter_speed = 115 +small_perimeter_speed = 115 +solid_infill_speed = 100 +infill_speed = 120 +top_solid_infill_speed = 70 +bridge_speed = 40 +gap_fill_speed = 80 +external_perimeter_acceleration = 2500 +perimeter_acceleration = 3000 +top_solid_infill_acceleration = 1500 +solid_infill_acceleration = 3000 +infill_acceleration = 4000 +bridge_acceleration = 1500 +default_acceleration = 2000 +support_material_contact_distance = 0.22 +extrusion_width = 0.68 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +top_infill_extrusion_width = 0.5 + +[print:0.25mm SPEED @MINIIS 0.6] +inherits = *MINIIS_common06* +layer_height = 0.25 +perimeter_speed = 80 +external_perimeter_speed = 70 +small_perimeter_speed = 70 +infill_speed = 90 +solid_infill_speed = 80 +top_solid_infill_speed = 60 +support_material_speed = 80 +bridge_speed = 30 +gap_fill_speed = 60 +external_perimeter_acceleration = 2000 +perimeter_acceleration = 3000 +top_solid_infill_acceleration = 1500 +solid_infill_acceleration = 3000 +infill_acceleration = 4000 +bridge_acceleration = 1500 +default_acceleration = 2000 +support_material_contact_distance = 0.25 + +[print:0.25mm STRUCTURAL @MINIIS 0.6] +inherits = 0.25mm SPEED @MINIIS 0.6 +perimeter_speed = 80 +external_perimeter_speed = 45 +small_perimeter_speed = 45 +top_solid_infill_speed = 60 +bridge_speed = 30 +external_perimeter_acceleration = 2000 +perimeter_acceleration = 2000 +top_solid_infill_acceleration = 1500 +solid_infill_acceleration = 3000 + +[print:0.35mm STRUCTURAL @MINIIS 0.6] +inherits = *MINIIS_common06* +layer_height = 0.35 +bottom_solid_layers = 3 +top_solid_layers = 4 +perimeter_speed = 60 +external_perimeter_speed = 45 +small_perimeter_speed = 45 +infill_speed = 70 +solid_infill_speed = 60 +top_solid_infill_speed = 55 +bridge_speed = 30 +gap_fill_speed = 45 +support_material_speed = 60 +external_perimeter_acceleration = 2000 +perimeter_acceleration = 2000 +top_solid_infill_acceleration = 1500 +solid_infill_acceleration = 3000 +infill_acceleration = 4000 +bridge_acceleration = 1500 +default_acceleration = 2000 +support_material_contact_distance = 0.28 + +# 0.8mm nozzle MINIIS + +[print:0.30mm DETAIL @MINIIS 0.8] +inherits = *MINIIS_common08* +layer_height = 0.30 +bottom_solid_layers = 3 +top_solid_layers = 4 +perimeter_speed = 60 +external_perimeter_speed = 45 +small_perimeter_speed = 45 +infill_speed = 70 +solid_infill_speed = 50 +top_solid_infill_speed = 35 +support_material_speed = 55 +bridge_speed = 22 +gap_fill_speed = 40 +external_perimeter_acceleration = 1500 +perimeter_acceleration = 2000 +top_solid_infill_acceleration = 1000 +solid_infill_acceleration = 3000 +infill_acceleration = 4000 +bridge_acceleration = 1000 +default_acceleration = 2000 +top_infill_extrusion_width = 0.7 + +[print:0.40mm QUALITY @MINIIS 0.8] +inherits = *MINIIS_common08* +layer_height = 0.4 +bottom_solid_layers = 3 +top_solid_layers = 4 +perimeter_speed = 40 +external_perimeter_speed = 40 +small_perimeter_speed = 40 +infill_speed = 50 +solid_infill_speed = 40 +top_solid_infill_speed = 35 +support_material_speed = 40 +bridge_speed = 22 +gap_fill_speed = 35 +external_perimeter_acceleration = 1500 +perimeter_acceleration = 2000 +top_solid_infill_acceleration = 1000 +solid_infill_acceleration = 3000 +infill_acceleration = 4000 +bridge_acceleration = 1000 +default_acceleration = 2000 +top_infill_extrusion_width = 0.75 + +[print:0.5mm DRAFT @MINIIS 0.8] +inherits = *MINIIS_common08* +layer_height = 0.5 +bottom_solid_layers = 3 +top_solid_layers = 4 +perimeter_speed = 35 +external_perimeter_speed = 30 +small_perimeter_speed = 30 +infill_speed = 45 +solid_infill_speed = 35 +top_solid_infill_speed = 30 +support_material_speed = 35 +bridge_speed = 22 +gap_fill_speed = 30 +external_perimeter_acceleration = 1500 +perimeter_acceleration = 2000 +top_solid_infill_acceleration = 1000 +solid_infill_acceleration = 3000 +infill_acceleration = 4000 +bridge_acceleration = 1000 +default_acceleration = 2000 +top_infill_extrusion_width = 0.75 +perimeter_extrusion_width = 1 +external_perimeter_extrusion_width = 1 + # XXXXXXxxXXXXXXXXXXXXXX # XXX--- filament ---XXX # XXXXXXXXxxXXXXXXXXXXXX @@ -4769,7 +5041,7 @@ top_infill_extrusion_width = 0.4 cooling = 1 compatible_printers = # For now, all but selected filaments are disabled for the MMU 2.0 -compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) and printer_notes!~/.*PG.*/ and printer_notes!~/.*MINIIS.*/ +compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) and printer_notes!~/.*PG.*/ end_filament_gcode = "; Filament-specific end gcode" extrusion_multiplier = 1 filament_loading_speed = 28 @@ -4811,8 +5083,8 @@ max_fan_speed = 100 min_fan_speed = 100 temperature = 210 slowdown_below_layer_time = 10 -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.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0" -compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) and printer_notes!~/.*PG.*/ and printer_notes!~/.*MINIIS.*/ +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.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.17{elsif nozzle_diameter[0]==0.8}0.12{elsif nozzle_diameter[0]==0.4}0.3{elsif nozzle_diameter[0]==0.25}0.85{else}0{endif}\n{endif}" +compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) and printer_notes!~/.*PG.*/ [filament:*PLAPG*] start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_MK4IS.*/}\nM572 S{if nozzle_diameter[0]==0.4}0.038{elsif nozzle_diameter[0]==0.5}0.025{elsif nozzle_diameter[0]==0.6}0.02{elsif nozzle_diameter[0]==0.8}0.014{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp" @@ -4882,7 +5154,7 @@ first_layer_bed_temperature = 85 first_layer_temperature = 230 max_fan_speed = 50 min_fan_speed = 30 -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.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" temperature = 240 filament_retract_length = 1 filament_retract_lift = 0.2 @@ -4945,7 +5217,7 @@ inherits = *PETXL* compatible_printers_condition = printer_notes=~/.*XL.*/ and nozzle_diameter[0]==0.8 [filament:*04PLUS*] -compatible_printers_condition = nozzle_diameter[0]>=0.4 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) and printer_notes!~/.*PG.*/ and printer_notes!~/.*MINIIS.*/ +compatible_printers_condition = nozzle_diameter[0]>=0.4 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) and printer_notes!~/.*PG.*/ [filament:*04PLUSPG*] compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.6 and nozzle_diameter[0]!=0.8 and printer_notes=~/.*MK4.*/ @@ -4966,16 +5238,16 @@ filament_retract_speed = 45 filament_deretract_speed = 25 filament_retract_lift = nil filament_retract_before_travel = 1 -filament_max_volumetric_speed = 7 -compatible_printers_condition = printer_model=="MINI" -start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.6}0.12{elsif nozzle_diameter[0]==0.8}0.06{else}0.2{endif} ; Filament gcode" +filament_max_volumetric_speed = 8 +compatible_printers_condition = printer_notes=~/.*PRINTER_MODEL_MINI.*/ +start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.6}0.12{elsif nozzle_diameter[0]==0.8}0.06{else}0.2{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" [filament:*PETMINIIS*] inherits = *PETMINI* -filament_max_volumetric_speed = 11 +filament_max_volumetric_speed = 10 slowdown_below_layer_time = 10 -compatible_printers_condition = printer_notes=~/.*MINIIS.*/ -start_filament_gcode = "M572 S{if nozzle_diameter[0]==0.6}0.2{elsif nozzle_diameter[0]==0.4}0.4{else}0{endif}" +compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]!=0.8 +start_filament_gcode = "M572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}" [filament:*PETMINI06*] full_fan_speed_layer = 0 @@ -4984,9 +5256,9 @@ filament_retract_speed = 45 filament_deretract_speed = 25 filament_retract_lift = nil filament_retract_before_travel = 1 -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]==0.6 -start_filament_gcode = "M900 K0.12 ; Filament gcode" -filament_max_volumetric_speed = 13 +compatible_printers_condition = printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6 +start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.6}0.12{elsif nozzle_diameter[0]==0.8}0.06{else}0.2{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" +filament_max_volumetric_speed = 15 [filament:*ABSMINI*] bed_temperature = 100 @@ -4999,8 +5271,8 @@ filament_retract_before_travel = 3 filament_wipe = 0 filament_max_volumetric_speed = 10 slowdown_below_layer_time = 20 -compatible_printers_condition = printer_model=="MINI" -start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.6}0.12{elsif nozzle_diameter[0]==0.8}0.06{else}0.2{endif} ; Filament gcode" +compatible_printers_condition = printer_notes=~/.*PRINTER_MODEL_MINI.*/ +start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.6}0.12{elsif nozzle_diameter[0]==0.8}0.06{else}0.2{endif} ; Filament gcode\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" [filament:*FLEXMINI*] inherits = *FLEX* @@ -5018,7 +5290,7 @@ cooling = 0 max_fan_speed = 50 min_fan_speed = 50 filament_max_volumetric_speed = 1.35 -compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_notes=~/.*PRINTER_MODEL_MINI.*/ disable_fan_first_layers = 4 full_fan_speed_layer = 6 extrusion_multiplier = 1.15 @@ -5043,7 +5315,7 @@ first_layer_temperature = 255 max_fan_speed = 30 min_fan_speed = 20 temperature = 255 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" compatible_printers_condition = printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:*ABSC*] @@ -5065,7 +5337,7 @@ max_fan_speed = 15 min_fan_speed = 15 min_print_speed = 15 temperature = 255 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" compatible_printers_condition = printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:*ABSPG*] @@ -5426,7 +5698,7 @@ filament_spool_weight = 236 filament_colour = #dfc287 filament_max_volumetric_speed = 9 first_layer_temperature = 200 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 200 filament_retract_lift = 0.2 @@ -5462,7 +5734,7 @@ filament_spool_weight = 236 filament_colour = #634d33 filament_max_volumetric_speed = 6 first_layer_temperature = 220 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 220 filament_retract_lift = 0.2 @@ -5527,7 +5799,7 @@ filament_colour = #804040 filament_max_volumetric_speed = 2 first_layer_bed_temperature = 90 first_layer_temperature = 260 -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.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.06{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.06{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.17{elsif nozzle_diameter[0]==0.8}0.12{elsif nozzle_diameter[0]==0.4}0.3{elsif nozzle_diameter[0]==0.25}0.85{else}0{endif}\n{endif}" temperature = 260 filament_retract_length = nil filament_retract_lift = 0.4 @@ -5654,7 +5926,7 @@ first_layer_temperature = 240 temperature = 240 filament_retract_length = nil filament_retract_lift = 0.3 -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.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.06{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.06{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.17{elsif nozzle_diameter[0]==0.8}0.12{elsif nozzle_diameter[0]==0.4}0.3{elsif nozzle_diameter[0]==0.25}0.85{else}0{endif}\n{endif}" compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model!="MK2SMM" and printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! single_extruder_multi_material [filament:Kimya PETG Carbon @PG] @@ -5935,7 +6207,7 @@ slowdown_below_layer_time = 15 disable_fan_first_layers = 4 filament_type = ASA filament_colour = #FFF2EC -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:Prusament ASA @XL] @@ -5993,7 +6265,7 @@ filament_colour = #DEE0E6 filament_max_volumetric_speed = 8 filament_retract_lift = 0.2 compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and nozzle_diameter[0]!=0.8 and printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) -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.04{else}0.07{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.2{elsif nozzle_diameter[0]==0.8}0.09{elsif nozzle_diameter[0]==0.4}0.37{elsif nozzle_diameter[0]==0.25}0.98{else}0{endif}\n{endif}" [filament:Prusament PC Blend @XL] inherits = Prusament PC Blend; *PCPG*; *PCXL* @@ -6082,7 +6354,7 @@ first_layer_bed_temperature = 105 bed_temperature = 110 disable_fan_first_layers = 6 compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and printer_notes=~/.*PRINTER_MODEL_MK(2|2.5).*/ and ! (printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and single_extruder_multi_material) -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.04{else}0.07{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.2{elsif nozzle_diameter[0]==0.8}0.09{elsif nozzle_diameter[0]==0.4}0.37{elsif nozzle_diameter[0]==0.25}0.98{else}0{endif}\n{endif}" [filament:Prusament PA11 Carbon Fiber] inherits = Prusament PC Blend Carbon Fiber @@ -6129,7 +6401,7 @@ first_layer_bed_temperature = 90 bed_temperature = 110 disable_fan_first_layers = 6 compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and printer_notes=~/.*PRINTER_MODEL_MK(2|2.5).*/ and ! (printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and single_extruder_multi_material) -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.04{else}0.07{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.2{elsif nozzle_diameter[0]==0.8}0.09{elsif nozzle_diameter[0]==0.4}0.37{elsif nozzle_diameter[0]==0.25}0.98{else}0{endif}\n{endif}" [filament:Fillamentum CPE] inherits = *PET* @@ -6145,7 +6417,7 @@ max_fan_speed = 50 disable_fan_first_layers = 3 full_fan_speed_layer = 5 temperature = 275 -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.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" [filament:Fillamentum CPE @PG] inherits = Fillamentum CPE; *PETPG* @@ -6175,7 +6447,7 @@ filament_spool_weight = 230 filament_colour = #804040 filament_max_volumetric_speed = 10 first_layer_temperature = 190 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 190 filament_retract_lift = 0.2 @@ -6211,7 +6483,7 @@ filament_density = 1.58 filament_colour = #804040 filament_max_volumetric_speed = 9 first_layer_temperature = 220 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 220 filament_retract_lift = 0.2 @@ -6365,7 +6637,7 @@ filament_vendor = Verbatim filament_cost = 25.87 filament_density = 1.05 filament_spool_weight = 235 -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.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" [filament:Verbatim ABS @XL] inherits = Verbatim ABS; *ABSPG*; *ABSXL* @@ -6424,7 +6696,7 @@ inherits = Generic PETG @PG 0.8; *PET08XL* [filament:Generic PETG @PGIS] inherits = Generic PETG @PG renamed_from = "Generic PETG @MK4IS" -filament_max_volumetric_speed = 11 +filament_max_volumetric_speed = 10 min_fan_speed = 35 max_fan_speed = 60 first_layer_temperature = 240 @@ -6555,7 +6827,7 @@ inherits = Extrudr XPETG CF @PG 0.8; *PET08XL* [filament:Extrudr XPETG CF @MINI] inherits = Extrudr XPETG CF; *PETMINI* -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:Extrudr XPETG Matt] inherits = Extrudr PETG @@ -6599,7 +6871,7 @@ temperature = 220 max_fan_speed = 45 min_fan_speed = 25 slowdown_below_layer_time = 20 -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.04{else}0.07{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K43{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K43{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.2{elsif nozzle_diameter[0]==0.8}0.09{elsif nozzle_diameter[0]==0.4}0.37{elsif nozzle_diameter[0]==0.25}0.98{else}0{endif}\n{endif}" filament_spool_weight = 230 [filament:Extrudr BioFusion @PG] @@ -7025,7 +7297,7 @@ full_fan_speed_layer = 0 filament_retract_length = 1.4 filament_retract_lift = 0.4 filament_max_volumetric_speed = 4 -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.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" filament_spool_weight = 0 compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and nozzle_diameter[0]>=0.4 and printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) @@ -7066,7 +7338,7 @@ filament_retract_speed = 40 filament_deretract_speed = 25 bed_temperature = 60 first_layer_bed_temperature = 60 -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:addnorth Adura X @MMU1] inherits = addnorth Adura X @@ -7165,7 +7437,7 @@ filament_retract_length = nil filament_retract_speed = 40 filament_deretract_speed = 25 filament_max_volumetric_speed = 2 -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:addnorth ESD-PETG @MMU1] inherits = addnorth ESD-PETG @@ -7280,7 +7552,7 @@ filament_retract_lift = nil filament_retract_speed = 40 filament_deretract_speed = 25 filament_max_volumetric_speed = 7 -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:addnorth PETG @MMU1] inherits = addnorth PETG @@ -7341,7 +7613,7 @@ filament_retract_length = nil filament_retract_lift = nil filament_retract_speed = 40 filament_deretract_speed = 25 -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:addnorth Rigid X @MMU1] inherits = addnorth Rigid X @@ -7390,7 +7662,7 @@ inherits = addnorth Textura @PG 0.8; *PLA08XL* [filament:addnorth Textura @MINI] inherits = addnorth Textura filament_retract_length = nil -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:addnorth Textura @MMU1] inherits = addnorth Textura @@ -7441,7 +7713,7 @@ inherits = Filamentworld ABS first_layer_bed_temperature = 100 min_fan_speed = 15 fan_below_layer_time = 60 -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:Filamentworld PETG] inherits = *PET* @@ -7493,7 +7765,7 @@ filament_retract_lift = nil filament_retract_speed = 40 filament_deretract_speed = 25 filament_max_volumetric_speed = 7 -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:Filamentworld PLA] inherits = *PLA* @@ -7609,9 +7881,9 @@ compatible_printers_condition = printer_notes=~/.*PG.*/ and printer_notes=~/.*MK inherits = Generic PLA first_layer_temperature = 230 temperature = 220 -filament_max_volumetric_speed = 12 -start_filament_gcode = "M572 S0.3" -compatible_printers_condition = nozzle_diameter[0]==0.4 and printer_notes=~/.*MINIIS.*/ +filament_max_volumetric_speed = 14 +start_filament_gcode = "M572 S{if nozzle_diameter[0]==0.6}0.17{elsif nozzle_diameter[0]==0.8}0.12{elsif nozzle_diameter[0]==0.4}0.3{elsif nozzle_diameter[0]==0.25}0.85{else}0{endif}" +compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_notes=~/.*MINIIS.*/ [filament:Generic PLA Silk @PGIS] inherits = Generic PLA @PG @@ -8156,7 +8428,7 @@ inherits = Spectrum ASA Kevlar; *ABSMINI* temperature = 250 bed_temperature = 100 extrusion_multiplier = 1.03 -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:Spectrum Tough PLA] inherits = *PLA* @@ -8804,7 +9076,7 @@ inherits = Filatech FilaCarbon @PG 0.8; *ABS08XL* [filament:Filatech FilaCarbon @MINI] inherits = Filatech FilaCarbon; *ABSMINI* first_layer_bed_temperature = 100 -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:Filatech FilaPLA] inherits = *PLA* @@ -9022,7 +9294,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_MODEL_MK(2|2.5).*/ and inherits = Filatech PA first_layer_bed_temperature = 100 bed_temperature = 100 -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:Filatech PC] inherits = Filatech PA @@ -9240,7 +9512,7 @@ filament_retract_length = nil filament_retract_speed = nil filament_retract_before_travel = nil filament_retract_layer_change = nil -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:Ultrafuse ABS] inherits = *ABSC* @@ -9440,7 +9712,7 @@ filament_retract_layer_change = 0 filament_cost = 0 filament_spool_weight = 0 compatible_printers_condition = printer_notes!~/.*MINI.*/ and printer_model!="MK2SMM" and printer_notes!~/.*PG.*/ and ! single_extruder_multi_material -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" filament_notes = "Material Description\nThe key features of Ultrafuse PA are the high strength and high modulus. Furthermore, Ultrafuse PA shows a good thermal distortion stability.\n\nPrinting Recommendations:\nApply PVA glue, Kapton tape or PA adhesive to a clean buildplate to improve adhesion." [filament:Ultrafuse PA @PG] @@ -9540,7 +9812,7 @@ bridge_fan_speed = 30 disable_fan_first_layers = 4 compatible_printers_condition = printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) filament_notes = "Material Description\nUltrafuse® PC/ABS FR Black is a V-0 flame retardant blend of Polycarbonate and ABS – two of the most used thermoplastics for engineering & electrical applications. The combination of these two materials results in a premium material with a mix of the excellent mechanical properties of PC and the comparably low printing temperature of ABS. Combined with a halogen free flame retardant, parts printed with Ultrafuse® PC/ABS FR Black feature great tensile and impact strength, higher thermal resistance than ABS and can fulfill the requirements of the UL94 V-0 standard.\n\nPrinting Recommendations:\nApply Magigoo PC to a clean build plate to improve adhesion." -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.04{else}0.07{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.2{elsif nozzle_diameter[0]==0.8}0.09{elsif nozzle_diameter[0]==0.4}0.37{elsif nozzle_diameter[0]==0.25}0.98{else}0{endif}\n{endif}" [filament:Ultrafuse PC-ABS-FR @XL] inherits = Ultrafuse PC-ABS-FR; *ABSPG*; *ABSXL* @@ -9592,7 +9864,7 @@ filament_retract_speed = 40 filament_deretract_speed = 30 filament_retract_lift = nil filament_wipe = 0 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.17{elsif nozzle_diameter[0]==0.8}0.12{elsif nozzle_diameter[0]==0.4}0.3{elsif nozzle_diameter[0]==0.25}0.85{else}0{endif}\n{endif}" filament_notes = "Material Description\nPET CF15 is a Carbon Fiber reinforced PET which has precisely tuned material properties, for a wide range of technical applications. The filament is very strong and stiff and has high heat resistance. With its high dimensional stability and low abrasiveness, the filament offers an easy to print experience which allows direct printing on glass or a PEI sheet. It is compatible with HiPS for breakaway support and water soluble support and has an excellent surface finish.\n\nPrinting Recommendations:\nThis material contains fibers that have an abrasive effect on printer components. Use a hardened nozzle with a diameter of 0.6 or larger for optimal performance and avoid damage to the nozzle.\n\nUltrafuse PET-CF15 can be printed directly onto a clean build plate. For challenging prints, use 3dLac to improve adhesion." compatible_printers_condition = nozzle_diameter[0]>=0.6 and printer_notes!~/.*MINI.*/ and printer_model!="MK2SMM" and printer_notes!~/.*PG.*/ and ! single_extruder_multi_material @@ -10008,7 +10280,7 @@ filament_ramming_parameters = "120 100 8.3871 8.6129 8.93548 9.22581 9.48387 9.7 filament_soluble = 1 filament_type = PVA first_layer_temperature = 195 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 195 [filament:PrimaSelect PVA+ @PG] @@ -10214,7 +10486,7 @@ filament_type = HIPS filament_soluble = 1 filament_colour = #FFFFD7 filament_ramming_parameters = "130 120 2.74194 2.96774 3.25806 3.77419 4.83871 6.3871 8.09677 9.64516 10.7419 11.2903| 0.05 2.66451 0.45 3.05805 0.95 4.05807 1.45 7.13871 1.95 10.2806 2.45 11.4194 2.95 11.342 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.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" [filament:Prusament ASA @MMU] inherits = *ABS MMU2* @@ -10240,7 +10512,7 @@ filament_cooling_initial_speed = 3 filament_cooling_moves = 1 filament_type = ASA filament_colour = #FFF2EC -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" [filament:Prusament PC Blend @MMU] inherits = *ABS MMU2* @@ -10270,7 +10542,7 @@ filament_retract_lift = 0.2 filament_ramming_parameters = "130 120 2.70968 2.93548 3.32258 3.83871 4.58065 5.54839 6.51613 7.35484 7.93548 8.16129| 0.05 2.66451 0.45 3.05805 0.95 4.05807 1.45 5.97742 1.95 7.69999 2.45 8.1936 2.95 11.342 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6" filament_type = PC filament_colour = #DEE0E6 -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.04{else}0.07{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 K22{elsif nozzle_diameter[0]==0.8};{else}M900 K40{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{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 K22{elsif nozzle_diameter[0]==0.8};{else}M900 K40{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.2{elsif nozzle_diameter[0]==0.8}0.09{elsif nozzle_diameter[0]==0.4}0.37{elsif nozzle_diameter[0]==0.25}0.98{else}0{endif}\n{endif}" [filament:Prusament PC Blend Carbon Fiber @MMU] inherits = Prusament PC Blend @MMU @@ -10319,7 +10591,7 @@ filament_type = HIPS first_layer_temperature = 220 max_fan_speed = 20 min_fan_speed = 20 -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.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 220 compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) @@ -10339,7 +10611,7 @@ filament_type = HIPS first_layer_temperature = 230 max_fan_speed = 20 min_fan_speed = 20 -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.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.03{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 230 compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) @@ -10399,7 +10671,7 @@ inherits = Prusa PETG @PG 0.8; *PET08XL* [filament:Prusa PETG @PGIS] inherits = Generic PETG @PG renamed_from = "Prusa PETG @MK4IS" -filament_max_volumetric_speed = 15 +filament_max_volumetric_speed = 10 min_fan_speed = 35 max_fan_speed = 60 first_layer_temperature = 240 @@ -11858,7 +12130,7 @@ bridge_fan_speed = 30 fan_always_on = 0 filament_retract_lift = 0.2 filament_max_volumetric_speed = 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.04{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 K26{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{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 K26{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" [filament:Fiberlogy Nylon PA12 @XL] inherits = Fiberlogy Nylon PA12; *ABSPG*; *ABSXL* @@ -12328,7 +12600,7 @@ filament_soluble = 1 filament_colour = #FFFF6F compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) and printer_notes!~/.*MINIIS.*/ slowdown_below_layer_time = 20 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.05{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.05{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" [filament:Prusament PVB @PG] inherits = Prusament PVB; *PLAPG* @@ -12412,7 +12684,7 @@ 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" +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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" [filament:Fillamentum PLA @MMU] inherits = *PLA MMU2* @@ -12531,7 +12803,7 @@ first_layer_temperature = 260 temperature = 260 max_fan_speed = 0 min_fan_speed = 0 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" compatible_printers_condition = printer_notes!~/.*MINI.*/ and printer_notes!~/.*PG.*/ and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:Taulman Bridge @XL] @@ -12572,7 +12844,7 @@ bed_temperature = 90 first_layer_bed_temperature = 60 first_layer_temperature = 240 temperature = 250 -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:Fillamentum Nylon FX256] inherits = *common* @@ -12596,7 +12868,7 @@ first_layer_bed_temperature = 90 first_layer_temperature = 250 max_fan_speed = 0 min_fan_speed = 0 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.05{else}0.1{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 K28{elsif nozzle_diameter[0]==0.8};{else}M900 K48{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.05{else}0.1{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 K28{elsif nozzle_diameter[0]==0.8};{else}M900 K48{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" temperature = 250 [filament:Fillamentum Nylon FX256 @PG] @@ -12642,7 +12914,7 @@ filament_soluble = 0 filament_type = PA max_fan_speed = 20 min_fan_speed = 20 -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.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.17{elsif nozzle_diameter[0]==0.8}0.12{elsif nozzle_diameter[0]==0.4}0.3{elsif nozzle_diameter[0]==0.25}0.85{else}0{endif}\n{endif}" filament_retract_length = 2 filament_retract_speed = 40 filament_retract_lift = nil @@ -12699,7 +12971,7 @@ filament_soluble = 0 filament_type = PA max_fan_speed = 0 min_fan_speed = 0 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{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 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.17{elsif nozzle_diameter[0]==0.8}0.12{elsif nozzle_diameter[0]==0.4}0.3{elsif nozzle_diameter[0]==0.25}0.85{else}0{endif}\n{endif}" filament_retract_length = 2 filament_retract_speed = 40 filament_retract_lift = nil @@ -12826,7 +13098,7 @@ first_layer_bed_temperature = 90 first_layer_temperature = 240 max_fan_speed = 5 min_fan_speed = 0 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{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\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" [filament:Taulman T-Glase @PG] inherits = Taulman T-Glase; *PAPG* @@ -12894,7 +13166,7 @@ first_layer_bed_temperature = 60 first_layer_temperature = 215 max_fan_speed = 100 min_fan_speed = 100 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 210 [filament:Verbatim BVOH @PG] @@ -12979,7 +13251,7 @@ max_fan_speed = 100 min_fan_speed = 100 min_print_speed = 15 slowdown_below_layer_time = 20 -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.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.02{else}0.04{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 K12{elsif nozzle_diameter[0]==0.8};{else}M900 K20{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}\n{endif}" temperature = 195 [filament:Verbatim PP] @@ -13046,7 +13318,7 @@ bed_temperature = 85 first_layer_temperature = 235 max_fan_speed = 70 min_fan_speed = 70 -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.1{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 K28{elsif nozzle_diameter[0]==0.8};{else}M900 K48{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.05{else}0.1{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 K28{elsif nozzle_diameter[0]==0.8};{else}M900 K48{endif} ; Filament gcode LA 1.0\n\n{if printer_notes=~/.*PRINTER_MODEL_MINIIS.*/}\nM572 S{if nozzle_diameter[0]==0.6}0.22{elsif nozzle_diameter[0]==0.8}0.15{elsif nozzle_diameter[0]==0.4}0.4{elsif nozzle_diameter[0]==0.25}1.02{else}0{endif}\n{endif}" temperature = 235 filament_wipe = 0 filament_retract_lift = 0 @@ -13083,7 +13355,7 @@ filament_retract_speed = 45 filament_deretract_speed = 20 filament_retract_lift = 0 filament_retract_before_travel = 4 -compatible_printers_condition = nozzle_diameter[0]>=0.35 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.35 and printer_notes=~/.*MINI.*/ ## Filaments MMU1 @@ -13215,21 +13487,21 @@ max_fan_speed = 55 [filament:Devil Design PETG @MINI] inherits = Devil Design PETG; *PETMINI* -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.6 [filament:Filament PM PETG @MINI] inherits = Filament PM PETG; *PETMINI* renamed_from = "Plasty Mladec PETG @MINI" -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.6 [filament:Verbatim PETG @MINI] inherits = Verbatim PETG; *PETMINI* -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.6 [filament:Fiberlogy Easy PET-G @MINI] inherits = Fiberlogy Easy PET-G; *PETMINI* renamed_from = Fiberlogy PETG @MINI -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.6 [filament:Generic ABS @MINI] inherits = Generic ABS; *ABSMINI* @@ -13237,8 +13509,8 @@ compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0. [filament:Generic ABS @MINIIS] inherits = Generic ABS @MINI -start_filament_gcode = "M572 S0.19" -compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]==0.4 +start_filament_gcode = "M572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}" +compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]!=0.8 [filament:Fiberthree F3 PA Pure Pro @MINI] inherits = Fiberthree F3 PA Pure Pro @@ -13252,7 +13524,7 @@ filament_retract_speed = nil filament_retract_lift = nil filament_retract_before_travel = nil filament_wipe = nil -compatible_printers_condition = printer_model=="MINI" +compatible_printers_condition = printer_notes=~/.*MINI.*/ [filament:Fiberthree F3 PA-CF Pro @MINI] inherits = Fiberthree F3 PA-CF Pro @@ -13266,7 +13538,7 @@ filament_retract_speed = nil filament_retract_lift = nil filament_retract_before_travel = nil filament_wipe = nil -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:Fiberthree F3 PA-GF Pro @MINI] inherits = Fiberthree F3 PA-CF Pro @MINI @@ -13282,7 +13554,7 @@ inherits = Fiberthree F3 PA-GF30 Pro filament_vendor = Fiberthree first_layer_temperature = 275 temperature = 280 -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ filament_retract_length = nil filament_retract_speed = nil filament_retract_lift = nil @@ -13293,7 +13565,7 @@ filament_type = PA [filament:Kimya ABS Carbon @MINI] inherits = Kimya ABS Carbon; *ABSMINI* filament_max_volumetric_speed = 6 -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:Kimya ABS Kevlar @MINI] inherits = Kimya ABS Carbon @MINI @@ -13327,21 +13599,21 @@ temperature = 265 extrusion_multiplier = 1.03 filament_cost = 54.99 filament_colour = #BBBBBB -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 ## [filament:Prusament PETG Tungsten 75% @MINI] ## inherits = Prusament PETG Tungsten 75%; *PETMINI* ## full_fan_speed_layer = 5 ## start_filament_gcode = "M900 K0" ## filament_colour = #BBBBBB -## compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +## compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:Kimya PETG Carbon @MINI] inherits = Kimya PETG Carbon; *PETMINI* filament_max_volumetric_speed = 6 filament_retract_length = nil filament_retract_lift = 0.3 -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ [filament:Prusament PETG @0.6 nozzle MINI] inherits = Prusament PETG; *PETMINI06* @@ -13380,10 +13652,10 @@ compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0. [filament:Prusament ASA @MINIIS] inherits = Prusament ASA @MINI -start_filament_gcode = "M572 S0.19" +start_filament_gcode = "M572 S{if nozzle_diameter[0]==0.6}0.1{elsif nozzle_diameter[0]==0.8}0.07{elsif nozzle_diameter[0]==0.4}0.19{elsif nozzle_diameter[0]==0.25}0.55{else}0{endif}" filament_retract_length = nil filament_retract_before_travel = 2 -compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]==0.4 +compatible_printers_condition = printer_notes=~/.*MINIIS.*/ and nozzle_diameter[0]!=0.8 [filament:Fillamentum Flexfill 98A @MINI] inherits = SemiFlex; *FLEXMINI* @@ -13405,7 +13677,7 @@ first_layer_temperature = 240 temperature = 240 filament_retract_length = 3 filament_max_volumetric_speed = 1.35 -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.8 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.8 [filament:AmazonBasics TPU @MINI] @@ -13480,7 +13752,7 @@ cooling = 0 max_fan_speed = 60 min_fan_speed = 60 filament_max_volumetric_speed = 1.2 -compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_notes=~/.*MINI.*/ disable_fan_first_layers = 4 extrusion_multiplier = 1.15 start_filament_gcode = "M900 K0 ; Filament gcode" @@ -13534,7 +13806,7 @@ filament_deretract_speed = nil filament_retract_lift = nil filament_retract_before_travel = nil filament_wipe = nil -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.8 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.8 [filament:Prusament PC Blend Carbon Fiber @MINI] inherits = Prusament PC Blend @MINI @@ -13547,11 +13819,11 @@ disable_fan_first_layers = 4 fan_below_layer_time = 10 filament_max_volumetric_speed = 6.5 filament_colour = #BBBBBB -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 [filament:Prusa ABS @MINI] inherits = Prusa ABS; *ABSMINI* -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.8 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.8 [filament:Generic HIPS @MINI] inherits = Generic HIPS; *ABSMINI* @@ -13568,7 +13840,7 @@ first_layer_bed_temperature = 90 [filament:ColorFabb XT-CF20 @MINI] inherits = ColorFabb XT-CF20; *PETMINI* -compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_notes=~/.*MINI.*/ first_layer_bed_temperature = 90 first_layer_temperature = 260 temperature = 260 @@ -13582,7 +13854,7 @@ inherits = E3D Edge; *PETMINI* [filament:Prusa PETG @MINI] inherits = Prusa PETG; *PETMINI* renamed_from = "Prusa PET MINI"; "Prusa PETG MINI" -compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 +compatible_printers_condition = printer_notes=~/.*MINI.*/ and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 [filament:Prusa PETG @0.6 nozzle MINI] inherits = Prusa PETG; *PETMINI06* @@ -13808,7 +14080,7 @@ filament_retract_speed = nil filament_deretract_speed = nil filament_retract_lift = nil filament_retract_before_travel = 2 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Generic PETG @0.8 nozzle MINI] inherits = Generic PETG @MINI @@ -13816,7 +14088,7 @@ first_layer_temperature = 240 temperature = 250 filament_max_volumetric_speed = 15 slowdown_below_layer_time = 20 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Prusa PETG @0.8 nozzle MINI] inherits = Prusa PETG @MINI @@ -13824,7 +14096,7 @@ first_layer_temperature = 240 temperature = 250 filament_max_volumetric_speed = 15 slowdown_below_layer_time = 20 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Prusa ABS @0.8 nozzle MINI] inherits = Prusa ABS @MINI @@ -13838,12 +14110,12 @@ filament_retract_speed = nil filament_deretract_speed = nil filament_retract_lift = nil filament_retract_before_travel = 2 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Generic FLEX @0.8 nozzle MINI] inherits = Generic FLEX @MINI filament_max_volumetric_speed = 4.3 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Prusament PETG @0.8 nozzle MINI] inherits = Prusament PETG @MINI @@ -13852,7 +14124,7 @@ temperature = 255 filament_max_volumetric_speed = 15 filament_retract_lift = 0.25 slowdown_below_layer_time = 20 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Prusament PETG Carbon Fiber @0.8 nozzle MINI] inherits = Prusament PETG @0.8 nozzle MINI @@ -13874,21 +14146,21 @@ filament_retract_speed = nil filament_deretract_speed = nil filament_retract_lift = nil filament_retract_before_travel = 2 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Prusament PC Blend @0.8 nozzle MINI] inherits = Prusament PC Blend @MINI filament_max_volumetric_speed = 11 filament_retract_lift = 0.25 slowdown_below_layer_time = 20 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [filament:Prusament PC Blend Carbon Fiber @0.8 nozzle MINI] inherits = Prusament PC Blend Carbon Fiber @MINI filament_max_volumetric_speed = 10 filament_retract_lift = 0.25 slowdown_below_layer_time = 20 -compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI" +compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*MINI.*/ [sla_print:*common*] compatible_printers_condition = printer_model=="SL1" @@ -18848,6 +19120,40 @@ end_gcode = G1 E-1 F2100 ; retract\n{if max_layer_z < max_print_height}G1 Z{z_of 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_MINIIS\nNO_TEMPLATES\n before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\nM201 X{interpolate_table(extruded_weight_total, (0,4000), (1000,1700), (10000,1700))} Y{interpolate_table(extruded_weight_total, (0,4000), (1000,1700), (10000,1700))}\n{if ! spiral_vase}M74 W[extruded_weight_total]{endif}\n +[printer:Original Prusa MINI & MINI+ Input Shaper (Alpha) 0.25 nozzle] +inherits = Original Prusa MINI & MINI+ Input Shaper (Alpha) +printer_variant = 0.25 +nozzle_diameter = 0.25 +max_layer_height = 0.15 +min_layer_height = 0.05 +default_print_profile = 0.12mm SPEED @MINIIS 0.25 +retract_length = 2.5 +retract_lift = 0.15 +retract_before_travel = 1 + +[printer:Original Prusa MINI & MINI+ Input Shaper (Alpha) 0.6 nozzle] +inherits = Original Prusa MINI & MINI+ Input Shaper (Alpha) +printer_variant = 0.6 +nozzle_diameter = 0.6 +max_layer_height = 0.40 +min_layer_height = 0.15 +default_print_profile = 0.30mm QUALITY @MINIIS 0.6 +retract_length = 2.8 +retract_before_travel = 1.5 + +[printer:Original Prusa MINI & MINI+ Input Shaper (Alpha) 0.8 nozzle] +inherits = Original Prusa MINI & MINI+ Input Shaper (Alpha) +printer_variant = 0.8 +nozzle_diameter = 0.8 +max_layer_height = 0.55 +min_layer_height = 0.2 +default_print_profile = 0.40mm QUALITY @MINIIS 0.8 +default_filament_profile = Prusament PLA @0.8 nozzle +retract_length = 2.8 +retract_before_travel = 1.5 +retract_speed = 45 +deretract_speed = 20 + [printer:*commonXL*] inherits = *common* bed_shape = 0x0,360x0,360x360,0x360 diff --git a/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp b/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp index c8a5488b36..3bb1cad0ea 100644 --- a/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp +++ b/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp @@ -17,7 +17,9 @@ struct GravityKernel { std::optional item_sink; Vec2d active_sink; - GravityKernel(Vec2crd gravity_center) : sink{gravity_center} {} + GravityKernel(Vec2crd gravity_center) : + sink{gravity_center}, active_sink{unscaled(gravity_center)} {} + GravityKernel() = default; template diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 0f3c3b5da7..085cae66cb 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -502,6 +502,7 @@ set(SLIC3R_SOURCES Arachne/SkeletalTrapezoidationJoint.hpp Arachne/WallToolPaths.hpp Arachne/WallToolPaths.cpp + StaticMap.hpp ) add_library(libslic3r STATIC ${SLIC3R_SOURCES}) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index dd62029769..3a8b8842fa 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2641,6 +2641,8 @@ static inline bool validate_smooth_path(const GCode::SmoothPath &smooth_path, bo } #endif //NDEBUG +static constexpr const double min_gcode_segment_length = 0.002; + std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed) { // Extrude all loops CCW. @@ -2659,7 +2661,7 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC // if polyline was shorter than the clipping distance we'd get a null polyline, so // we discard it in that case. if (m_enable_loop_clipping) - clip_end(smooth_path, scale_(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER); + clip_end(smooth_path, scaled(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, scaled(min_gcode_segment_length)); if (smooth_path.empty()) return {}; @@ -2704,7 +2706,7 @@ std::string GCodeGenerator::extrude_skirt( // if polyline was shorter than the clipping distance we'd get a null polyline, so // we discard it in that case. if (m_enable_loop_clipping) - clip_end(smooth_path, scale_(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER); + clip_end(smooth_path, scale_(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, scaled(min_gcode_segment_length)); if (smooth_path.empty()) return {}; @@ -3065,12 +3067,14 @@ std::string GCodeGenerator::_extrude( comment = description; comment += description_bridge; } - Vec2d prev = this->point_to_gcode_quantized(path.front().point); + Vec2d prev_exact = this->point_to_gcode(path.front().point); + Vec2d prev = GCodeFormatter::quantize(prev_exact); auto it = path.begin(); auto end = path.end(); const bool emit_radius = m_config.arc_fitting == ArcFittingType::EmitRadius; for (++ it; it != end; ++ it) { - Vec2d p = this->point_to_gcode_quantized(it->point); + Vec2d p_exact = this->point_to_gcode(it->point); + Vec2d p = GCodeFormatter::quantize(p_exact); assert(p != prev); if (p != prev) { // Center of the radius to be emitted into the G-code: Either by radius or by center offset. @@ -3083,11 +3087,12 @@ std::string GCodeGenerator::_extrude( radius = unscaled(it->radius); if (emit_radius) { // Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values. + //FIXME rather re-fit the arc to improve accuracy! radius = GCodeFormatter::quantize_xyzf(radius); } else { // Calculate quantized IJ circle center offset. ij = GCodeFormatter::quantize(Vec2d( - Geometry::ArcWelder::arc_center(prev.cast(), p.cast(), double(radius), it->ccw()) + Geometry::ArcWelder::arc_center(prev_exact.cast(), p_exact.cast(), double(radius), it->ccw()) - prev)); if (ij == Vec2d::Zero()) // Don't extrude a degenerated circle. @@ -3112,6 +3117,7 @@ std::string GCodeGenerator::_extrude( m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment); } prev = p; + prev_exact = p_exact; } } diff --git a/src/libslic3r/GCode/LabelObjects.hpp b/src/libslic3r/GCode/LabelObjects.hpp index 78add73009..e6cf9b36b7 100644 --- a/src/libslic3r/GCode/LabelObjects.hpp +++ b/src/libslic3r/GCode/LabelObjects.hpp @@ -1,6 +1,9 @@ #ifndef slic3r_GCode_LabelObjects_hpp_ #define slic3r_GCode_LabelObjects_hpp_ +#include +#include + namespace Slic3r { enum GCodeFlavor : unsigned char; diff --git a/src/libslic3r/GCode/SmoothPath.cpp b/src/libslic3r/GCode/SmoothPath.cpp index ba793b465e..f27f1f2318 100644 --- a/src/libslic3r/GCode/SmoothPath.cpp +++ b/src/libslic3r/GCode/SmoothPath.cpp @@ -102,7 +102,10 @@ std::optional sample_path_point_at_distance_from_end(const SmoothPath &pa return {}; } -double clip_end(SmoothPath &path, double distance) +// Clip length of a smooth path, for seam hiding. +// When clipping the end of a path, don't create segments shorter than min_point_distance_threshold, +// rather discard such a degenerate segment. +double clip_end(SmoothPath &path, double distance, double min_point_distance_threshold) { while (! path.empty() && distance > 0) { Geometry::ArcWelder::Path &p = path.back().path; @@ -111,9 +114,18 @@ double clip_end(SmoothPath &path, double distance) path.pop_back(); } else { // Trailing path was trimmed and it is valid. - assert(path.back().path.size() > 1); + Geometry::ArcWelder::Path &last_path = path.back().path; + assert(last_path.size() > 1); assert(distance == 0); // Distance to go is zero. + // Remove the last segment if its length is shorter than min_point_distance_threshold. + const Geometry::ArcWelder::Segment &prev_segment = last_path[last_path.size() - 2]; + const Geometry::ArcWelder::Segment &last_segment = last_path.back(); + if (Geometry::ArcWelder::segment_length(prev_segment, last_segment) < min_point_distance_threshold) { + last_path.pop_back(); + if (last_path.size() < 2) + path.pop_back(); + } return 0; } } diff --git a/src/libslic3r/GCode/SmoothPath.hpp b/src/libslic3r/GCode/SmoothPath.hpp index b2eb335a32..83afd60983 100644 --- a/src/libslic3r/GCode/SmoothPath.hpp +++ b/src/libslic3r/GCode/SmoothPath.hpp @@ -29,7 +29,9 @@ std::optional sample_path_point_at_distance_from_start(const SmoothPath & std::optional sample_path_point_at_distance_from_end(const SmoothPath &path, double distance); // Clip end of a smooth path, for seam hiding. -double clip_end(SmoothPath &path, double distance); +// When clipping the end of a path, don't create segments shorter than min_point_distance_threshold, +// rather discard such a degenerate segment. +double clip_end(SmoothPath &path, double distance, double min_point_distance_threshold); class SmoothPathCache { diff --git a/src/libslic3r/Geometry/ArcWelder.cpp b/src/libslic3r/Geometry/ArcWelder.cpp index 1bb9fea77d..e30f6b07a9 100644 --- a/src/libslic3r/Geometry/ArcWelder.cpp +++ b/src/libslic3r/Geometry/ArcWelder.cpp @@ -148,36 +148,205 @@ static inline bool get_deviation_sum_squared(const Circle &circle, const Points: return true; } +double arc_fit_variance(const Point &start_pos, const Point &end_pos, const float radius, bool is_ccw, + const Points::const_iterator begin, const Points::const_iterator end) +{ + const Vec2d center = arc_center(start_pos.cast(), end_pos.cast(), double(radius), is_ccw); + const double r = std::abs(radius); + + // The circle was calculated from the 1st and last point of the point sequence, thus the fitting of those points does not need to be evaluated. + assert(std::abs((begin->cast() - center).norm() - r) < SCALED_EPSILON); + assert(std::abs((std::prev(end)->cast() - center).norm() - r) < SCALED_EPSILON); + assert(end - begin >= 3); + + double total_deviation = 0; + size_t cnt = 0; + for (auto it = begin; std::next(it) != end; ++ it) { + if (it != begin) { + total_deviation += sqr((it->cast() - center).norm() - r); + ++ cnt; + } + Point closest_point; + if (foot_pt_on_segment(*it, *std::next(it), center.cast(), closest_point)) { + total_deviation += sqr((closest_point.cast() - center).cast().norm() - r); + ++ cnt; + } + } + + return total_deviation / double(cnt); +} + +double arc_fit_max_deviation(const Point &start_pos, const Point &end_pos, const float radius, bool is_ccw, + const Points::const_iterator begin, const Points::const_iterator end) +{ + const Vec2d center = arc_center(start_pos.cast(), end_pos.cast(), double(radius), is_ccw); + const double r = std::abs(radius); + + // The circle was calculated from the 1st and last point of the point sequence, thus the fitting of those points does not need to be evaluated. + assert(std::abs((begin->cast() - center).norm() - r) < SCALED_EPSILON); + assert(std::abs((std::prev(end)->cast() - center).norm() - r) < SCALED_EPSILON); + assert(end - begin >= 3); + + double max_deviation = 0; + double max_signed_deviation = 0; + for (auto it = begin; std::next(it) != end; ++ it) { + if (it != begin) { + double signed_deviation = (it->cast() - center).norm() - r; + double deviation = std::abs(signed_deviation); + if (deviation > max_deviation) { + max_deviation = deviation; + max_signed_deviation = signed_deviation; + } + } + Point closest_point; + if (foot_pt_on_segment(*it, *std::next(it), center.cast(), closest_point)) { + double signed_deviation = (closest_point.cast() - center).cast().norm() - r; + double deviation = std::abs(signed_deviation); + if (deviation > max_deviation) { + max_deviation = deviation; + max_signed_deviation = signed_deviation; + } + } + } + return max_signed_deviation; +} + +static inline int sign(const int64_t i) +{ + return i > 0 ? 1 : i < 0 ? -1 : 0; +} + static std::optional try_create_circle(const Points::const_iterator begin, const Points::const_iterator end, const double max_radius, const double tolerance) { std::optional out; size_t size = end - begin; if (size == 3) { + // Fit the circle throuh the three input points. out = try_create_circle(*begin, *std::next(begin), *std::prev(end), max_radius); - if (out && ! circle_approximation_sufficient(*out, begin, end, tolerance)) - out.reset(); - } else { -#if 0 - size_t ipivot = size / 2; - // Take a center difference of points at the center of the path. - //FIXME does it really help? For short arches, the linear interpolation may be - Point pivot = (size % 2 == 0) ? (*(begin + ipivot) + *(begin + ipivot - 1)) / 2 : - (*(begin + ipivot - 1) + *(begin + ipivot + 1)) / 2; - if (std::optional circle = try_create_circle(*begin, pivot, *std::prev(end), max_radius); - circle && circle_approximation_sufficient(*circle, begin, end, tolerance)) - return circle; -#endif - // Find the circle with the least deviation, if one exists. - double least_deviation = std::numeric_limits::max(); - double current_deviation; - for (auto it = std::next(begin); std::next(it) != end; ++ it) - if (std::optional circle = try_create_circle(*begin, *it, *std::prev(end), max_radius); - circle && get_deviation_sum_squared(*circle, begin, end, tolerance, current_deviation)) { - if (current_deviation < least_deviation) { + if (out) { + // Fit the center point and the two center points of the two edges with non-linear least squares. + std::array fpts; + Vec2d center_point = out->center.cast(); + Vec2d first_point = begin->cast(); + Vec2d mid_point = std::next(begin)->cast(); + Vec2d last_point = std::prev(end)->cast(); + fpts[0] = 0.5 * (first_point + mid_point); + fpts[1] = mid_point; + fpts[2] = 0.5 * (mid_point + last_point); + const double radius = (first_point - center_point).norm(); + if (std::abs((fpts[0] - center_point).norm() - radius) < 2. * tolerance && + std::abs((fpts[2] - center_point).norm() - radius) < 2. * tolerance) { + if (std::optional opt_center = ArcWelder::arc_fit_center_gauss_newton_ls(first_point, last_point, + center_point, fpts.begin(), fpts.end(), 3); + opt_center) { + out->center = opt_center->cast(); + out->radius = (out->radius > 0 ? 1.f : -1.f) * (*opt_center - first_point).norm(); + } + if (! circle_approximation_sufficient(*out, begin, end, tolerance)) + out.reset(); + } else + out.reset(); + } + } else { + std::optional circle; + { + // Try to fit a circle to first, middle and last point. + auto mid = begin + (end - begin) / 2; + circle = try_create_circle(*begin, *mid, *std::prev(end), max_radius); + if (// Use twice the tolerance for fitting the initial circle. + // Early exit if such approximation is grossly inaccurate, thus the tolerance could not be achieved. + circle && ! circle_approximation_sufficient(*circle, begin, end, tolerance * 2)) + circle.reset(); + } + if (! circle) { + // Find an intersection point of the polyline to be fitted with the bisector of the arc chord. + // At such a point the distance of a polyline to an arc wrt. the circle center (or circle radius) will have a largest gradient + // of all points on the polyline to be fitted. + Vec2i64 first_point = begin->cast(); + Vec2i64 last_point = std::prev(end)->cast(); + Vec2i64 c = (first_point.cast() + last_point.cast()) / 2; + Vec2i64 v = last_point - first_point; + Vec2i64 prev_point = first_point; + int prev_side = sign(v.dot(prev_point - c)); + assert(prev_side != 0); + Point point_on_bisector; +#ifndef NDEBUG + point_on_bisector = { std::numeric_limits::max(), std::numeric_limits::max() }; +#endif // NDEBUG + for (auto it = std::next(begin); it != end; ++ it) { + Vec2i64 this_point = it->cast(); + int64_t d = v.dot(this_point - c); + int this_side = sign(d); + int sideness = this_side * prev_side; + if (sideness < 0) { + // Calculate the intersection point. + Vec2d vd = v.cast(); + Vec2d p = c.cast() + vd * double(d) / vd.squaredNorm(); + point_on_bisector = p.cast(); + break; + } + if (sideness == 0) { + // this_point is on the bisector. + assert(prev_side != 0); + assert(this_side == 0); + point_on_bisector = this_point.cast(); + break; + } + prev_point = this_point; + prev_side = this_side; + } + // point_on_bisector must be set + assert(point_on_bisector.x() != std::numeric_limits::max() && point_on_bisector.y() != std::numeric_limits::max()); + circle = try_create_circle(*begin, point_on_bisector, *std::prev(end), max_radius); + if (// Use twice the tolerance for fitting the initial circle. + // Early exit if such approximation is grossly inaccurate, thus the tolerance could not be achieved. + circle && ! circle_approximation_sufficient(*circle, begin, end, tolerance * 2)) + circle.reset(); + } + if (circle) { + // Fit the arc between the end points by least squares. + // Optimize over all points along the path and the centers of the segments. + std::vector fpts; + Vec2d first_point = begin->cast(); + Vec2d last_point = std::prev(end)->cast(); + Vec2d prev_point = first_point; + for (auto it = std::next(begin); it != std::prev(end); ++ it) { + Vec2d this_point = it->cast(); + fpts.emplace_back(0.5 * (prev_point + this_point)); + fpts.emplace_back(this_point); + prev_point = this_point; + } + fpts.emplace_back(0.5 * (prev_point + last_point)); + std::optional opt_center = ArcWelder::arc_fit_center_gauss_newton_ls(first_point, last_point, + circle->center.cast(), fpts.begin(), fpts.end(), 5); + if (opt_center) { + circle->center = opt_center->cast(); + circle->radius = (circle->radius > 0 ? 1.f : -1.f) * (*opt_center - first_point).norm(); + if (circle_approximation_sufficient(*circle, begin, end, tolerance)) { out = circle; - least_deviation = current_deviation; + } else { + //FIXME One may consider adjusting the arc to fit the worst offender as a last effort, + // however Vojtech is not sure whether it is worth it. } } + } +/* + // From the original arc welder. + // Such a loop makes the time complexity of the arc fitting an ugly O(n^3). + else { + // Find the circle with the least deviation, if one exists. + double least_deviation = std::numeric_limits::max(); + double current_deviation; + for (auto it = std::next(begin); std::next(it) != end; ++ it) + if (std::optional circle = try_create_circle(*begin, *it, *std::prev(end), max_radius); + circle && get_deviation_sum_squared(*circle, begin, end, tolerance, current_deviation)) { + if (current_deviation < least_deviation) { + out = circle; + least_deviation = current_deviation; + } + } + } +*/ } return out; } @@ -192,11 +361,6 @@ public: Orientation direction { Orientation::Unknown }; }; -static inline int sign(const int64_t i) -{ - return i > 0 ? 1 : i < 0 ? -1 : 0; -} - // Return orientation of a polyline with regard to the center. // Successive points are expected to take less than a PI angle step. Orientation arc_orientation( @@ -317,21 +481,25 @@ static inline Segments::iterator douglas_peucker_in_place(Segments::iterator beg return douglas_peucker(begin, end, begin, tolerance, [](const Segment &s) { return s.point; }); } -Path fit_path(const Points &src, double tolerance, double fit_circle_percent_tolerance) +Path fit_path(const Points &src_in, double tolerance, double fit_circle_percent_tolerance) { assert(tolerance >= 0); assert(fit_circle_percent_tolerance >= 0); + double tolerance2 = Slic3r::sqr(tolerance); Path out; - out.reserve(src.size()); - if (tolerance <= 0 || src.size() <= 2) { + out.reserve(src_in.size()); + if (tolerance <= 0 || src_in.size() <= 2) { // No simplification, just convert. - std::transform(src.begin(), src.end(), std::back_inserter(out), [](const Point &p) -> Segment { return { p }; }); - } else if (fit_circle_percent_tolerance <= 0) { + std::transform(src_in.begin(), src_in.end(), std::back_inserter(out), [](const Point &p) -> Segment { return { p }; }); + } else if (double tolerance_fine = std::max(0.03 * tolerance, scaled(0.000060)); + fit_circle_percent_tolerance <= 0 || tolerance_fine > 0.5 * tolerance) { // Convert and simplify to a polyline. - std::transform(src.begin(), src.end(), std::back_inserter(out), [](const Point &p) -> Segment { return { p }; }); + std::transform(src_in.begin(), src_in.end(), std::back_inserter(out), [](const Point &p) -> Segment { return { p }; }); out.erase(douglas_peucker_in_place(out.begin(), out.end(), tolerance), out.end()); } else { + // Simplify the polyline first using a fine threshold. + Points src = douglas_peucker(src_in, tolerance_fine); // Perform simplification & fitting. // Index of the start of a last polyline, which has not yet been decimated. int begin_pl_idx = 0; @@ -349,13 +517,89 @@ Path fit_path(const Points &src, double tolerance, double fit_circle_percent_tol ArcWelder::default_scaled_max_radius, tolerance, fit_circle_percent_tolerance); this_arc) { + // Could extend the arc by one point. assert(this_arc->direction != Orientation::Unknown); arc = this_arc; end = next_end; - } else + if (end == src.end()) + // No way to extend the arc. + goto fit_end; + // Now try to expand the arc by adding points one by one. That should be cheaper than a full arc fit test. + while (std::next(end) != src.end()) { + assert(end == next_end); + { + Vec2i64 v1 = arc->start_point.cast() - arc->center.cast(); + Vec2i64 v2 = arc->end_point.cast() - arc->center.cast(); + do { + if (std::abs((arc->center.cast() - next_end->cast()).norm() - arc->radius) >= tolerance || + inside_arc_wedge_vectors(v1, v2, + arc->radius > 0, arc->direction == Orientation::CCW, + next_end->cast() - arc->center.cast())) + // Cannot extend the current arc with this new point. + break; + } while (++ next_end != src.end()); + } + if (next_end == end) + // No additional point could be added to a current arc. + break; + // Try to fit a new arc to the extended set of points. + // last_tested_failed set to invalid value, no test failed yet. + auto last_tested_failed = src.begin(); + for (;;) { + this_arc = try_create_arc( + begin, next_end, + ArcWelder::default_scaled_max_radius, + tolerance, fit_circle_percent_tolerance); + if (this_arc) { + arc = this_arc; + end = next_end; + if (last_tested_failed == src.begin()) { + // First run of the loop, the arc was extended fully. + if (end == src.end()) + goto fit_end; + // Otherwise try to extend the arc with another sample. + break; + } + } else + last_tested_failed = next_end; + // Take half of the interval up to the failed point. + next_end = end + (last_tested_failed - end) / 2; + if (next_end == end) + // Backed to the last successfull sample. + goto fit_end; + // Otherwise try to extend the arc up to next_end in another iteration. + } + } + } else { + // The last arc was the best we could get. break; + } } + fit_end: +#if 1 if (arc) { + // Check whether the arc end points are not too close with the risk of quantizing the arc ends to the same point on G-code export. + if ((arc->end_point - arc->start_point).cast().squaredNorm() < 2. * sqr(scaled(0.0011))) { + // Arc is too short. Skip it, decimate a polyline instead. + arc.reset(); + } else { + // Test whether the arc is so flat, that it could be replaced with a straight segment. + Line line(arc->start_point, arc->end_point); + bool arc_valid = false; + for (auto it2 = std::next(begin); it2 != std::prev(end); ++ it2) + if (line_alg::distance_to_squared(line, *it2) > tolerance2) { + // Polyline could not be fitted by a line segment, thus the arc is considered valid. + arc_valid = true; + break; + } + if (! arc_valid) + // Arc should be fitted by a line segment. Skip it, decimate a polyline instead. + arc.reset(); + } + } +#endif + if (arc) { + // printf("Arc radius: %lf, length: %lf\n", unscaled(arc->radius), arc_length(arc->start_point.cast(), arc->end_point.cast(), arc->radius)); // If there is a trailing polyline, decimate it first before saving a new arc. if (out.size() - begin_pl_idx > 2) { // Decimating linear segmens only. @@ -363,6 +607,14 @@ Path fit_path(const Points &src, double tolerance, double fit_circle_percent_tol out.erase(douglas_peucker_in_place(out.begin() + begin_pl_idx, out.end(), tolerance), out.end()); assert(out.back().linear()); } +#ifndef NDEBUG + // Check for a very short linear segment, that connects two arches. Such segment should not be created. + if (out.size() - begin_pl_idx > 1) { + const Point& p1 = out[begin_pl_idx].point; + const Point& p2 = out.back().point; + assert((p2 - p1).cast().squaredNorm() > sqr(scaled(0.0011))); + } +#endif // Save the index of an end of the new circle segment, which may become the first point of a possible future polyline. begin_pl_idx = int(out.size()); // This will be the next point to try to add. @@ -413,7 +665,7 @@ Path fit_path(const Points &src, double tolerance, double fit_circle_percent_tol #if 0 // Verify that all the source points are at tolerance distance from the interpolated path. - for (auto it = std::next(src.begin()); it != src.end(); ++ it) { + for (auto it = std::next(src_in.begin()); it != src_in.end(); ++ it) { Point start = *std::prev(it); Point end = *it; Vec2d v = (end - start).cast(); diff --git a/src/libslic3r/Geometry/ArcWelder.hpp b/src/libslic3r/Geometry/ArcWelder.hpp index dfc6d886e6..660d0ccf2c 100644 --- a/src/libslic3r/Geometry/ArcWelder.hpp +++ b/src/libslic3r/Geometry/ArcWelder.hpp @@ -7,7 +7,7 @@ namespace Slic3r { namespace Geometry { namespace ArcWelder { -// Calculate center point of an arc given two points and a radius. +// Calculate center point (center of a circle) of an arc given two points and a radius. // positive radius: take shorter arc // negative radius: take longer arc // radius must NOT be zero! @@ -36,6 +36,37 @@ inline Eigen::Matrix arc_center( return (radius > Float(0)) == is_ccw ? (mid + vp).eval() : (mid - vp).eval(); } +// Calculate middle sample point (point on an arc) of an arc given two points and a radius. +// positive radius: take shorter arc +// negative radius: take longer arc +// radius must NOT be zero! +// Taking a sample at the middle of a convex arc (less than PI) is likely much more +// useful than taking a sample at the middle of a concave arc (more than PI). +template +inline Eigen::Matrix arc_middle_point( + const Eigen::MatrixBase &start_pos, + const Eigen::MatrixBase &end_pos, + const Float radius, + const bool is_ccw) +{ + static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "arc_center(): first parameter is not a 2D vector"); + static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_center(): second parameter is not a 2D vector"); + static_assert(std::is_same::value, "arc_center(): Both vectors must be of the same type."); + static_assert(std::is_same::value, "arc_center(): Radius must be of the same type as the vectors."); + assert(radius != 0); + using Vector = Eigen::Matrix; + auto v = end_pos - start_pos; + Float q2 = v.squaredNorm(); + assert(q2 > 0); + Float t2 = sqr(radius) / q2 - Float(.25f); + // If the start_pos and end_pos are nearly antipodal, t2 may become slightly negative. + // In that case return a centroid of start_point & end_point. + Float t = (t2 > 0 ? sqrt(t2) : Float(0)) - radius / sqrt(q2); + auto mid = Float(0.5) * (start_pos + end_pos); + Vector vp{ -v.y() * t, v.x() * t }; + return (radius > Float(0)) == is_ccw ? (mid + vp).eval() : (mid - vp).eval(); +} + // Calculate angle of an arc given two points and a radius. // Returned angle is in the range <0, 2 PI) // positive radius: take shorter arc @@ -87,7 +118,7 @@ inline typename Derived::Scalar arc_length( { static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "arc_length(): first parameter is not a 2D vector"); static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_length(): second parameter is not a 2D vector"); - static_assert(Derived3::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_length(): third parameter is not a 2D vector"); + static_assert(Derived3::IsVectorAtCompileTime && int(Derived3::SizeAtCompileTime) == 2, "arc_length(): third parameter is not a 2D vector"); static_assert(std::is_same::value && std::is_same::value, "arc_length(): All third points must be of the same type."); using Float = typename Derived::Scalar; @@ -103,6 +134,145 @@ inline typename Derived::Scalar arc_length( return angle * radius; } +// Be careful! This version has a strong bias towards small circles with small radii +// for small angle (nearly straight) arches! +// One should rather use arc_fit_center_gauss_newton_ls(), which solves a non-linear least squares problem. +// +// Calculate center point (center of a circle) of an arc given two fixed points to interpolate +// and an additional list of points to fit by least squares. +// The circle fitting problem is non-linear, it was linearized by taking difference of squares of radii as a residual. +// Therefore the center point is required as a point to linearize at. +// Start & end point must be different and the interpolated points must not be collinear with input points. +template +inline typename Eigen::Matrix arc_fit_center_algebraic_ls( + const Eigen::MatrixBase &start_pos, + const Eigen::MatrixBase &end_pos, + const Eigen::MatrixBase ¢er_pos, + const Iterator it_begin, + const Iterator it_end) +{ + static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "arc_fit_center_algebraic_ls(): start_pos is not a 2D vector"); + static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_fit_center_algebraic_ls(): end_pos is not a 2D vector"); + static_assert(Derived3::IsVectorAtCompileTime && int(Derived3::SizeAtCompileTime) == 2, "arc_fit_center_algebraic_ls(): third parameter is not a 2D vector"); + static_assert(std::is_same::value && + std::is_same::value, "arc_fit_center_algebraic_ls(): All third points must be of the same type."); + using Float = typename Derived::Scalar; + using Vector = Eigen::Matrix; + // Prepare a vector space to transform the fitting into: + // center_pos, dir_x, dir_y + Vector v = end_pos - start_pos; + Vector c = Float(.5) * (start_pos + end_pos); + Float lv = v.norm(); + assert(lv > 0); + Vector dir_y = v / lv; + Vector dir_x = perp(dir_y); + // Center of the new system: + // Center X at the projection of center_pos + Float offset_x = dir_x.dot(center_pos); + // Center is supposed to lie on bisector of the arc end points. + // Center Y at the mid point of v. + Float offset_y = dir_y.dot(c); + assert(std::abs(dir_y.dot(center_pos) - offset_y) < SCALED_EPSILON); + assert((dir_x * offset_x + dir_y * offset_y - center_pos).norm() < SCALED_EPSILON); + // Solve the least squares fitting in a transformed space. + Float a = Float(0.5) * lv; + Float b = c.dot(dir_x) - offset_x; + Float ab2 = sqr(a) + sqr(b); + Float num = Float(0); + Float denom = Float(0); + const Float w = it_end - it_begin; + for (Iterator it = it_begin; it != it_end; ++ it) { + Vector p = *it; + Float x_i = dir_x.dot(p) - offset_x; + Float y_i = dir_y.dot(p) - offset_y; + Float x_i2 = sqr(x_i); + Float y_i2 = sqr(y_i); + num += (x_i - b) * (x_i2 + y_i2 - ab2); + denom += b * (b - Float(2) * x_i) + sqr(x_i) + Float(0.25) * w; + } + assert(denom != 0); + Float c_x = Float(0.5) * num / denom; + // Transform the center back. + Vector out = dir_x * (c_x + offset_x) + dir_y * offset_y; + return out; +} + +// Calculate center point (center of a circle) of an arc given two fixed points to interpolate +// and an additional list of points to fit by non-linear least squares. +// The non-linear least squares problem is solved by a Gauss-Newton iterative method. +// Start & end point must be different and the interpolated points must not be collinear with input points. +// Center position is used to calculate the initial solution of the Gauss-Newton method. +// +// In case the input points are collinear or close to collinear (such as a small angle arc), +// the solution may not converge and an error is indicated. +template +inline std::optional> arc_fit_center_gauss_newton_ls( + const Eigen::MatrixBase &start_pos, + const Eigen::MatrixBase &end_pos, + const Eigen::MatrixBase ¢er_pos, + const Iterator it_begin, + const Iterator it_end, + const size_t num_iterations) +{ + static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "arc_fit_center_gauss_newton_ls(): start_pos is not a 2D vector"); + static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "arc_fit_center_gauss_newton_ls(): end_pos is not a 2D vector"); + static_assert(Derived3::IsVectorAtCompileTime && int(Derived3::SizeAtCompileTime) == 2, "arc_fit_center_gauss_newton_ls(): third parameter is not a 2D vector"); + static_assert(std::is_same::value && + std::is_same::value, "arc_fit_center_gauss_newton_ls(): All third points must be of the same type."); + using Float = typename Derived::Scalar; + using Vector = Eigen::Matrix; + // Prepare a vector space to transform the fitting into: + // center_pos, dir_x, dir_y + Vector v = end_pos - start_pos; + Vector c = Float(.5) * (start_pos + end_pos); + Float lv = v.norm(); + assert(lv > 0); + Vector dir_y = v / lv; + Vector dir_x = perp(dir_y); + // Center is supposed to lie on bisector of the arc end points. + // Center Y at the mid point of v. + Float offset_y = dir_y.dot(c); + // Initial value of the parameter to be optimized iteratively. + Float c_x = dir_x.dot(center_pos); + // Solve the least squares fitting in a transformed space. + Float a = Float(0.5) * lv; + Float a2 = sqr(a); + Float b = c.dot(dir_x); + for (size_t iter = 0; iter < num_iterations; ++ iter) { + Float num = Float(0); + Float denom = Float(0); + Float u = b - c_x; + // Current estimate of the circle radius. + Float r = sqrt(a2 + sqr(u)); + assert(r > 0); + for (Iterator it = it_begin; it != it_end; ++ it) { + Vector p = *it; + Float x_i = dir_x.dot(p); + Float y_i = dir_y.dot(p) - offset_y; + Float v = x_i - c_x; + Float y_i2 = sqr(y_i); + // Distance of i'th sample from the current circle center. + Float r_i = sqrt(sqr(v) + y_i2); + if (r_i >= EPSILON) { + // Square of residual is differentiable at the current c_x and current sample. + // Jacobian: diff(residual, c_x) + Float j_i = u / r - v / r_i; + num += j_i * (r_i - r); + denom += sqr(j_i); + } else { + // Sample point is on current center of the circle, + // therefore the gradient is not defined. + } + } + if (denom == 0) + // Fitting diverged, the input points are likely nearly collinear with the arch end points. + return std::optional(); + c_x -= num / denom; + } + // Transform the center back. + return std::optional(dir_x * c_x + dir_y * offset_y); +} + // Test whether a point is inside a wedge of an arc. template inline bool inside_arc_wedge_vectors( @@ -194,6 +364,16 @@ size_t arc_discretization_steps(const FloatType radius, const FloatType angle, c // Returned polygon starts with p1, ends with p2 and it is discretized to guarantee the maximum deviation. Points arc_discretize(const Point &p1, const Point &p2, const double radius, const bool ccw, const double deviation); +// Variance of the arc fit of points (600.); // 0.05mm diff --git a/src/libslic3r/Geometry/Circle.cpp b/src/libslic3r/Geometry/Circle.cpp index 24d408c6a2..cb8af30cec 100644 --- a/src/libslic3r/Geometry/Circle.cpp +++ b/src/libslic3r/Geometry/Circle.cpp @@ -147,7 +147,7 @@ Circled circle_ransac(const Vec2ds& input, size_t iterations, double* min_error) } template -Circled circle_least_squares_by_solver(const Vec2ds &input, Solver solver) +Circled circle_linear_least_squares_by_solver(const Vec2ds &input, Solver solver) { Circled out; if (input.size() < 3) { @@ -172,21 +172,21 @@ Circled circle_least_squares_by_solver(const Vec2ds &input, Solver solver) return out; } -Circled circle_least_squares_svd(const Vec2ds &input) +Circled circle_linear_least_squares_svd(const Vec2ds &input) { - return circle_least_squares_by_solver(input, + return circle_linear_least_squares_by_solver(input, [](const Eigen::Matrix &A, const Eigen::VectorXd &b) { return A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b).eval(); }); } -Circled circle_least_squares_qr(const Vec2ds &input) +Circled circle_linear_least_squares_qr(const Vec2ds &input) { - return circle_least_squares_by_solver(input, + return circle_linear_least_squares_by_solver(input, [](const Eigen::Matrix &A, const Eigen::VectorXd &b) { return A.colPivHouseholderQr().solve(b).eval(); }); } -Circled circle_least_squares_normal(const Vec2ds &input) +Circled circle_linear_least_squares_normal(const Vec2ds &input) { Circled out; if (input.size() < 3) { diff --git a/src/libslic3r/Geometry/Circle.hpp b/src/libslic3r/Geometry/Circle.hpp index ca32d32b50..487ee84e8f 100644 --- a/src/libslic3r/Geometry/Circle.hpp +++ b/src/libslic3r/Geometry/Circle.hpp @@ -141,12 +141,17 @@ Circled circle_taubin_newton(const Vec2ds& input, size_t cycles = 20); // Find circle using RANSAC randomized algorithm. Circled circle_ransac(const Vec2ds& input, size_t iterations = 20, double* min_error = nullptr); -// Least squares fitting with SVD. Most accurate, but slowest. -Circled circle_least_squares_svd(const Vec2ds &input); -// Least squares fitting with QR decomposition. Medium accuracy, medium speed. -Circled circle_least_squares_qr(const Vec2ds &input); -// Least squares fitting solving normal equations. Low accuracy, high speed. -Circled circle_least_squares_normal(const Vec2ds &input); +// Linear Least squares fitting. +// Be careful! The linear least squares fitting is strongly biased towards small circles, +// thus the method is only recommended for circles or arches with large arc angle. +// Also it is strongly recommended to center the input at an expected circle (or arc) center +// to minimize the small circle bias! + // Linear Least squares fitting with SVD. Most accurate, but slowest. + Circled circle_linear_least_squares_svd(const Vec2ds &input); + // Linear Least squares fitting with QR decomposition. Medium accuracy, medium speed. + Circled circle_linear_least_squares_qr(const Vec2ds &input); + // Linear Least squares fitting solving normal equations. Low accuracy, high speed. + Circled circle_linear_least_squares_normal(const Vec2ds &input); // Randomized algorithm by Emo Welzl, working with squared radii for efficiency. The returned circle radius is inflated by epsilon. template diff --git a/src/libslic3r/StaticMap.hpp b/src/libslic3r/StaticMap.hpp new file mode 100644 index 0000000000..84054dda32 --- /dev/null +++ b/src/libslic3r/StaticMap.hpp @@ -0,0 +1,328 @@ +#ifndef PRUSASLICER_STATICMAP_HPP +#define PRUSASLICER_STATICMAP_HPP + +#include +#include +#include + +namespace Slic3r { + +// This module provides std::map and std::set like structures with fixed number +// of elements and usable at compile or in time constexpr contexts without +// any memory allocations. + +// C++20 emulation utilities to get the missing constexpr functionality in C++17 +namespace static_set_detail { + +// Simple bubble sort but constexpr +template> +constexpr void sort_array(std::array &arr, Cmp cmp = {}) +{ + // A bubble sort will do the job, C++20 will have constexpr std::sort + for (size_t i = 0; i < N - 1; ++i) + { + for (size_t j = 0; j < N - i - 1; ++j) + { + if (!cmp(arr[j], arr[j + 1])) { + T temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } +} + +// Simple emulation of lower_bound with constexpr +template> +constexpr auto array_lower_bound(It from, It to, const V &val, Cmp cmp) +{ + auto N = std::distance(from, to); + std::size_t middle = N / 2; + + if (N == 0) { + return from; // Key not found, return the beginning of the array + } else if (cmp(val, *(from + middle))) { + return array_lower_bound(from, from + middle, val, cmp); + } else if (cmp(*(from + middle), val)) { + return array_lower_bound(from + middle + 1, to, val, cmp); + } else { + return from + middle; // Key found, return an iterator to it + } + + return to; +} + +template> +constexpr auto array_lower_bound(const std::array &arr, + const T &val, + Cmp cmp = {}) +{ + return array_lower_bound(arr.begin(), arr.end(), val, cmp); +} + +template +constexpr std::array, N> +to_array_impl(T (&a)[N], std::index_sequence) +{ + return {{a[I]...}}; +} + +template +constexpr std::array, N> to_array(T (&a)[N]) +{ + return to_array_impl(a, std::make_index_sequence{}); +} + +// Emulating constexpr std::pair +template +struct StaticMapElement { + using KeyType = K; + + constexpr StaticMapElement(const K &k, const V &v): first{k}, second{v} {} + + K first; + V second; +}; + +} // namespace static_set_detail +} // namespace Slic3r + +namespace Slic3r { + +// std::set like set structure +template> +class StaticSet { + std::array m_vals; // building on top of std::array + Cmp m_cmp; + +public: + using value_type = T; + + constexpr StaticSet(const std::array &arr, Cmp cmp = {}) + : m_vals{arr}, m_cmp{cmp} + { + // TODO: C++20 can use std::sort(vals.begin(), vals.end()) + static_set_detail::sort_array(m_vals, m_cmp); + } + + template + constexpr StaticSet(Ts &&...args): m_vals{std::forward(args)...} + { + static_set_detail::sort_array(m_vals, m_cmp); + } + + template + constexpr StaticSet(Cmp cmp, Ts &&...args) + : m_vals{std::forward(args)...}, m_cmp{cmp} + { + static_set_detail::sort_array(m_vals, m_cmp); + } + + constexpr auto find(const T &val) const + { + // TODO: C++20 can use std::lower_bound + auto it = static_set_detail::array_lower_bound(m_vals, val, m_cmp); + if (it != m_vals.end() && ! m_cmp(*it, val) && !m_cmp(val, *it) ) + return it; + + return m_vals.cend(); + } + + constexpr bool empty() const { return m_vals.empty(); } + constexpr size_t size() const { return m_vals.size(); } + + // Can be iterated over + constexpr auto begin() const { return m_vals.begin(); } + constexpr auto end() const { return m_vals.end(); } +}; + +// These are "deduction guides", a C++17 feature. +// Reason is to be able to deduce template arguments from constructor arguments +// e.g.: StaticSet{1, 2, 3} is deduced as StaticSet>, no +// need to state the template types explicitly. +template +StaticSet(T, Vals...) -> + StaticSet && ...), T>, + 1 + sizeof...(Vals)>; + +// Same as above, only with the first argument being a comparison functor +template +StaticSet(Cmp, T, Vals...) -> + StaticSet && ...), T>, + 1 + sizeof...(Vals), + std::enable_if_t, Cmp>>; + +// Specialization for the empty set case. +template +class StaticSet { +public: + constexpr StaticSet() = default; + constexpr auto find(const T &val) const { return nullptr; } + constexpr bool empty() const { return true; } + constexpr size_t size() const { return 0; } + constexpr auto begin() const { return nullptr; } + constexpr auto end() const { return nullptr; } +}; + +// Constructor with no arguments need to be deduced as the specialization for +// empty sets (see above) +StaticSet() -> StaticSet; + + + +// StaticMap definition: + +template +using SMapEl = static_set_detail::StaticMapElement; + +template +struct DefaultCmp { + constexpr bool operator() (const SMapEl &el1, const SMapEl &el2) const + { + return std::less{}(el1.first, el2.first); + } +}; + +// Overriding the default comparison for C style strings, as std::less +// doesn't do the lexicographic comparisons, only the pointer values would be +// compared. Fortunately we can wrap the C style strings with string_views and +// do the comparison with those. +template +struct DefaultCmp { + constexpr bool operator() (const SMapEl &el1, + const SMapEl &el2) const + { + return std::string_view{el1.first} < std::string_view{el2.first}; + } +}; + +template> +class StaticMap { + std::array, N> m_vals; + Cmp m_cmp; + +public: + using value_type = SMapEl; + + constexpr StaticMap(const std::array, N> &arr, Cmp cmp = {}) + : m_vals{arr}, m_cmp{cmp} + { + static_set_detail::sort_array(m_vals, cmp); + } + + constexpr auto find(const K &key) const + { + auto ret = m_vals.end(); + + SMapEl vkey{key, V{}}; + + auto it = static_set_detail::array_lower_bound( + std::begin(m_vals), std::end(m_vals), vkey, m_cmp + ); + + if (it != std::end(m_vals) && ! m_cmp(*it, vkey) && !m_cmp(vkey, *it)) + ret = it; + + return ret; + } + + constexpr const V& at(const K& key) const + { + if (auto it = find(key); it != end()) + return it->second; + + throw std::out_of_range{"No such element"}; + } + + constexpr bool empty() const { return m_vals.empty(); } + constexpr size_t size() const { return m_vals.size(); } + + constexpr auto begin() const { return m_vals.begin(); } + constexpr auto end() const { return m_vals.end(); } +}; + +template +class StaticMap { +public: + constexpr StaticMap() = default; + constexpr auto find(const K &key) const { return nullptr; } + constexpr bool empty() const { return true; } + constexpr size_t size() const { return 0; } + [[noreturn]] constexpr const V& at(const K &) const { throw std::out_of_range{"Map is empty"}; } + constexpr auto begin() const { return nullptr; } + constexpr auto end() const { return nullptr; } +}; + +// Deducing template arguments from the StaticMap constructors is not easy, +// so there is a helper "make" function to be used instead: +// e.g.: auto map = make_staticmap({ {"one", 1}, {"two", 2}}) +// will work, and only the key and value type needs to be specified. No need +// to state the number of elements, that is deduced automatically. +template +constexpr auto make_staticmap(const SMapEl (&arr) [N]) +{ + return StaticMap{static_set_detail ::to_array(arr), DefaultCmp{}}; +} + +template +constexpr auto make_staticmap(const SMapEl (&arr) [N], Cmp cmp) +{ + return StaticMap{static_set_detail ::to_array(arr), cmp}; +} + +// Override for empty maps +template> +constexpr auto make_staticmap() +{ + return StaticMap{}; +} + +// Override which uses a c++ array as the initializer +template> +constexpr auto make_staticmap(const std::array, N> &arr, Cmp cmp = {}) +{ + return StaticMap{arr, cmp}; +} + +// Helper function to get a specific element from a set, returning a std::optional +// which is more convinient than working with iterators +template +constexpr std::enable_if_t, std::optional> +query(const StaticSet &sset, const T &val) +{ + std::optional ret; + if (auto it = sset.find(val); it != sset.end()) + ret = *it; + + return ret; +} + +template +constexpr std::enable_if_t, std::optional> +query(const StaticMap &sset, const KeyT &val) +{ + std::optional ret; + + if (auto it = sset.find(val); it != sset.end()) + ret = it->second; + + return ret; +} + +template +constexpr std::enable_if_t, bool> +contains(const StaticSet &sset, const T &val) +{ + return sset.find(val) != sset.end(); +} + +template +constexpr std::enable_if_t, bool> +contains(const StaticMap &smap, const KeyT &key) +{ + return smap.find(key) != smap.end(); +} + +} // namespace Slic3r + +#endif // STATICMAP_HPP diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 4d531900b4..679ef0215f 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -53,8 +53,12 @@ #ifdef DEBUG_FILES #include #include "libslic3r/Color.hpp" +constexpr bool debug_files = true; +#else +constexpr bool debug_files = false; #endif + namespace Slic3r::SupportSpotsGenerator { ExtrusionLine::ExtrusionLine() : a(Vec2f::Zero()), b(Vec2f::Zero()), len(0.0), origin_entity(nullptr) {} @@ -72,10 +76,6 @@ bool ExtrusionLine::is_external_perimeter() const return origin_entity->role().is_external_perimeter(); } -auto get_a(ExtrusionLine &&l) { return l.a; } -auto get_b(ExtrusionLine &&l) { return l.b; } - - using LD = AABBTreeLines::LinesDistancer; struct SupportGridFilter @@ -761,6 +761,284 @@ public: } }; +// Function that is used when new support point is generated. It will update the ObjectPart stability, weakest conneciton info, +// and the support presence grid and add the point to the issues. +void reckon_new_support_point(ObjectPart &part, + SliceConnection &weakest_conn, + SupportPoints &supp_points, + SupportGridFilter &supports_presence_grid, + const SupportPoint& support_point, + bool is_global = false) +{ + // if position is taken and point is for global stability (force > 0) or we are too close to the bed, do not add + // This allows local support points (e.g. bridging) to be generated densely + if ((supports_presence_grid.position_taken(support_point.position) && is_global)) { + return; + } + + float area = support_point.spot_radius * support_point.spot_radius * float(PI); + // add the stability effect of the point only if the spot is not taken, so that the densely created local support points do + // not add unrealistic amount of stability to the object (due to overlaping of local support points) + if (!(supports_presence_grid.position_taken(support_point.position))) { + part.add_support_point(support_point.position, area); + } + + supp_points.push_back(support_point); + supports_presence_grid.take_position(support_point.position); + + // The support point also increases the stability of the weakest connection of the object, which should be reflected + if (weakest_conn.area > EPSILON) { // Do not add it to the weakest connection if it is not valid - does not exist + weakest_conn.area += area; + weakest_conn.centroid_accumulator += support_point.position * area; + weakest_conn.second_moment_of_area_accumulator += area * + support_point.position.head<2>().cwiseProduct(support_point.position.head<2>()); + weakest_conn.second_moment_of_area_covariance_accumulator += area * support_point.position.x() * support_point.position.y(); + } +} + +struct LocalSupports { + std::vector> unstable_lines_per_slice; + std::vector> ext_perim_lines_per_slice; +}; + +struct EnitityToCheck +{ + const ExtrusionEntity *e; + const LayerRegion *region; + size_t slice_idx; +}; + +// TODO DRY: Very similar to gather extrusions. +std::vector gather_entities_to_check(const Layer* layer) { + auto get_flat_entities = [](const ExtrusionEntity *e) { + std::vector entities; + std::vector queue{e}; + while (!queue.empty()) { + const ExtrusionEntity *next = queue.back(); + queue.pop_back(); + if (next->is_collection()) { + for (const ExtrusionEntity *e : static_cast(next)->entities) { + queue.push_back(e); + } + } else { + entities.push_back(next); + } + } + return entities; + }; + + std::vector entities_to_check; + for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) { + const LayerSlice &slice = layer->lslices_ex.at(slice_idx); + for (const auto &island : slice.islands) { + for (const LayerExtrusionRange &fill_range : island.fills) { + const LayerRegion *fill_region = layer->get_region(fill_range.region()); + for (size_t fill_idx : fill_range) { + for (const ExtrusionEntity *e : get_flat_entities(fill_region->fills().entities[fill_idx])) { + if (e->role() == ExtrusionRole::BridgeInfill) { + entities_to_check.push_back({e, fill_region, slice_idx}); + } + } + } + } + + const LayerRegion *perimeter_region = layer->get_region(island.perimeters.region()); + for (size_t perimeter_idx : island.perimeters) { + for (const ExtrusionEntity *e : get_flat_entities(perimeter_region->perimeters().entities[perimeter_idx])) { + entities_to_check.push_back({e, perimeter_region, slice_idx}); + } + } + } + } + return entities_to_check; +} + +LocalSupports compute_local_supports( + const std::vector& entities_to_check, + const std::optional& previous_layer_boundary, + const LD& prev_layer_ext_perim_lines, + size_t slices_count, + const Params& params +) { + std::vector> unstable_lines_per_slice(slices_count); + std::vector> ext_perim_lines_per_slice(slices_count); + + AABBTreeLines::LinesDistancer prev_layer_boundary_distancer = + (previous_layer_boundary ? AABBTreeLines::LinesDistancer{*previous_layer_boundary} : AABBTreeLines::LinesDistancer{}); + + if constexpr (debug_files) { + for (const auto &e_to_check : entities_to_check) { + for (const auto &line : check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines, + prev_layer_boundary_distancer, params)) { + if (line.support_point_generated.has_value()) { + unstable_lines_per_slice[e_to_check.slice_idx].push_back(line); + } + if (line.is_external_perimeter()) { + ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line); + } + } + } + } else { + tbb::parallel_for(tbb::blocked_range(0, entities_to_check.size()), + [&entities_to_check, &prev_layer_ext_perim_lines, &prev_layer_boundary_distancer, &unstable_lines_per_slice, + &ext_perim_lines_per_slice, ¶ms](tbb::blocked_range r) { + for (size_t entity_idx = r.begin(); entity_idx < r.end(); ++entity_idx) { + const auto &e_to_check = entities_to_check[entity_idx]; + for (const auto &line : + check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines, + prev_layer_boundary_distancer, params)) { + if (line.support_point_generated.has_value()) { + unstable_lines_per_slice[e_to_check.slice_idx].push_back(line); + } + if (line.is_external_perimeter()) { + ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line); + } + } + } + }); + } + return {unstable_lines_per_slice, ext_perim_lines_per_slice}; +} + +struct SliceMappings +{ + std::unordered_map index_to_object_part_mapping; + std::unordered_map index_to_weakest_connection; +}; + +std::optional to_partial_object(const ObjectPart& part) { + if (part.volume > EPSILON) { + return PartialObject{part.volume_centroid_accumulator / part.volume, part.volume, + part.connected_to_bed}; + } + return {}; +} + +SliceMappings update_active_object_parts(const Layer *layer, + const Params ¶ms, + const std::vector &precomputed_slice_connections, + const SliceMappings &previous_slice_mappings, + ActiveObjectParts &active_object_parts, + PartialObjects &partial_objects) +{ + SliceMappings new_slice_mappings; + + for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) { + const LayerSlice &slice = layer->lslices_ex.at(slice_idx); + const std::vector extrusion_collections{gather_extrusions(slice, layer)}; + const bool connected_to_bed = int(layer->id()) == params.raft_layers_count; + + const std::optional brim{ + has_brim(layer, params) ? + std::optional{get_brim(layer->lslices[slice_idx], params.brim_type, params.brim_width)} : + std::nullopt + }; + ObjectPart new_part{ + extrusion_collections, + connected_to_bed, + layer->print_z, + layer->height, + brim + }; + + const SliceConnection &connection_to_below = precomputed_slice_connections[slice_idx]; + +#ifdef DETAILED_DEBUG_LOGS + std::cout << "SLICE IDX: " << slice_idx << std::endl; + for (const auto &link : slice.overlaps_below) { + std::cout << "connected to slice below: " << link.slice_idx << " by area : " << link.area << std::endl; + } + connection_to_below.print_info("CONNECTION TO BELOW"); +#endif + + if (connection_to_below.area < EPSILON) { // new object part emerging + size_t part_id = active_object_parts.insert(new_part); + new_slice_mappings.index_to_object_part_mapping.emplace(slice_idx, part_id); + new_slice_mappings.index_to_weakest_connection.emplace(slice_idx, connection_to_below); + } else { + size_t final_part_id{}; + SliceConnection transfered_weakest_connection{}; + // MERGE parts + { + std::unordered_set parts_ids; + for (const auto &link : slice.overlaps_below) { + size_t part_id = active_object_parts.get_flat_id(previous_slice_mappings.index_to_object_part_mapping.at(link.slice_idx)); + parts_ids.insert(part_id); + transfered_weakest_connection.add(previous_slice_mappings.index_to_weakest_connection.at(link.slice_idx)); + } + + final_part_id = *parts_ids.begin(); + for (size_t part_id : parts_ids) { + if (final_part_id != part_id) { + auto object_part = active_object_parts.access(part_id); + if (auto object = to_partial_object(object_part)) { + partial_objects.push_back(std::move(*object)); + } + active_object_parts.merge(part_id, final_part_id); + } + } + } + const float bottom_z = layer->bottom_z(); + auto estimate_conn_strength = [bottom_z](const SliceConnection &conn) { + if (conn.area < EPSILON) { // connection is empty, does not exists. Return max strength so that it is not picked as the + // weakest connection. + return INFINITY; + } + Vec3f centroid = conn.centroid_accumulator / conn.area; + Vec2f variance = (conn.second_moment_of_area_accumulator / conn.area - + centroid.head<2>().cwiseProduct(centroid.head<2>())); + float xy_variance = variance.x() + variance.y(); + float arm_len_estimate = std::max(1.0f, bottom_z - (conn.centroid_accumulator.z() / conn.area)); + return conn.area * sqrt(xy_variance) / arm_len_estimate; + }; + +#ifdef DETAILED_DEBUG_LOGS + connection_to_below.print_info("new_weakest_connection"); + transfered_weakest_connection.print_info("transfered_weakest_connection"); +#endif + + if (estimate_conn_strength(transfered_weakest_connection) > estimate_conn_strength(connection_to_below)) { + transfered_weakest_connection = connection_to_below; + } + new_slice_mappings.index_to_weakest_connection.emplace(slice_idx, transfered_weakest_connection); + new_slice_mappings.index_to_object_part_mapping.emplace(slice_idx, final_part_id); + ObjectPart &part = active_object_parts.access(final_part_id); + part.add(new_part); + } + } + return new_slice_mappings; +} + +void reckon_global_supports(const tbb::concurrent_vector &external_perimeter_lines, + const coordf_t layer_bottom_z, + const Params ¶ms, + ObjectPart &part, + SliceConnection &weakest_connection, + SupportPoints &supp_points, + SupportGridFilter &supports_presence_grid) +{ + LD current_slice_lines_distancer({external_perimeter_lines.begin(), external_perimeter_lines.end()}); + float unchecked_dist = params.min_distance_between_support_points + 1.0f; + + for (const ExtrusionLine &line : external_perimeter_lines) { + if ((unchecked_dist + line.len < params.min_distance_between_support_points && + line.curled_up_height < params.curling_tolerance_limit) || + line.len < EPSILON) { + unchecked_dist += line.len; + } else { + unchecked_dist = line.len; + Vec2f pivot_site_search_point = Vec2f(line.b + (line.b - line.a).normalized() * 300.0f); + auto [dist, nidx, nearest_point] = current_slice_lines_distancer.distance_from_lines_extra(pivot_site_search_point); + Vec3f position = to_3d(nearest_point, layer_bottom_z); + auto [force, cause] = part.is_stable_while_extruding(weakest_connection, line, position, layer_bottom_z, params); + if (force > 0) { + SupportPoint support_point{cause, position, params.support_points_interface_radius}; + reckon_new_support_point(part, weakest_connection, supp_points, supports_presence_grid, support_point, true); + } + } + } +} + std::tuple check_stability(const PrintObject *po, const PrecomputedSliceConnections &precomputed_slices_connections, const PrintTryCancel &cancel_func, @@ -772,257 +1050,55 @@ std::tuple check_stability(const PrintObject PartialObjects partial_objects{}; LD prev_layer_ext_perim_lines; - std::unordered_map prev_slice_idx_to_object_part_mapping; - std::unordered_map next_slice_idx_to_object_part_mapping; - std::unordered_map prev_slice_idx_to_weakest_connection; - std::unordered_map next_slice_idx_to_weakest_connection; + SliceMappings slice_mappings; - auto remember_partial_object = [&active_object_parts, &partial_objects](size_t object_part_id) { - auto object_part = active_object_parts.access(object_part_id); - if (object_part.volume > EPSILON) { - partial_objects.emplace_back(object_part.volume_centroid_accumulator / object_part.volume, object_part.volume, - object_part.connected_to_bed); - } - }; for (size_t layer_idx = 0; layer_idx < po->layer_count(); ++layer_idx) { cancel_func(); const Layer *layer = po->get_layer(layer_idx); float bottom_z = layer->bottom_z(); - auto create_support_point_position = [bottom_z](const Vec2f &layer_pos) { return Vec3f{layer_pos.x(), layer_pos.y(), bottom_z}; }; - for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) { - const LayerSlice &slice = layer->lslices_ex.at(slice_idx); - const std::vector extrusion_collections{gather_extrusions(slice, layer)}; - const bool connected_to_bed = int(layer->id()) == params.raft_layers_count; + slice_mappings = update_active_object_parts(layer, params, precomputed_slices_connections[layer_idx], slice_mappings, active_object_parts, partial_objects); - const std::optional brim{ - has_brim(layer, params) ? - std::optional{get_brim(layer->lslices[slice_idx], params.brim_type, params.brim_width)} : - std::nullopt - }; - ObjectPart new_part{ - extrusion_collections, - connected_to_bed, - layer->print_z, - layer->height, - brim - }; + std::optional prev_layer_boundary = layer->lower_layer != nullptr ? + std::optional{to_unscaled_linesf(layer->lower_layer->lslices)} : + std::nullopt; - const SliceConnection &connection_to_below = precomputed_slices_connections[layer_idx][slice_idx]; - -#ifdef DETAILED_DEBUG_LOGS - std::cout << "SLICE IDX: " << slice_idx << std::endl; - for (const auto &link : slice.overlaps_below) { - std::cout << "connected to slice below: " << link.slice_idx << " by area : " << link.area << std::endl; - } - connection_to_below.print_info("CONNECTION TO BELOW"); -#endif - - if (connection_to_below.area < EPSILON) { // new object part emerging - size_t part_id = active_object_parts.insert(new_part); - next_slice_idx_to_object_part_mapping.emplace(slice_idx, part_id); - next_slice_idx_to_weakest_connection.emplace(slice_idx, connection_to_below); - } else { - size_t final_part_id{}; - SliceConnection transfered_weakest_connection{}; - // MERGE parts - { - std::unordered_set parts_ids; - for (const auto &link : slice.overlaps_below) { - size_t part_id = active_object_parts.get_flat_id(prev_slice_idx_to_object_part_mapping.at(link.slice_idx)); - parts_ids.insert(part_id); - transfered_weakest_connection.add(prev_slice_idx_to_weakest_connection.at(link.slice_idx)); - } - - final_part_id = *parts_ids.begin(); - for (size_t part_id : parts_ids) { - if (final_part_id != part_id) { - remember_partial_object(part_id); - active_object_parts.merge(part_id, final_part_id); - } - } - } - auto estimate_conn_strength = [bottom_z](const SliceConnection &conn) { - if (conn.area < EPSILON) { // connection is empty, does not exists. Return max strength so that it is not picked as the - // weakest connection. - return INFINITY; - } - Vec3f centroid = conn.centroid_accumulator / conn.area; - Vec2f variance = (conn.second_moment_of_area_accumulator / conn.area - - centroid.head<2>().cwiseProduct(centroid.head<2>())); - float xy_variance = variance.x() + variance.y(); - float arm_len_estimate = std::max(1.0f, bottom_z - (conn.centroid_accumulator.z() / conn.area)); - return conn.area * sqrt(xy_variance) / arm_len_estimate; - }; - -#ifdef DETAILED_DEBUG_LOGS - connection_to_below.print_info("new_weakest_connection"); - transfered_weakest_connection.print_info("transfered_weakest_connection"); -#endif - - if (estimate_conn_strength(transfered_weakest_connection) > estimate_conn_strength(connection_to_below)) { - transfered_weakest_connection = connection_to_below; - } - next_slice_idx_to_weakest_connection.emplace(slice_idx, transfered_weakest_connection); - next_slice_idx_to_object_part_mapping.emplace(slice_idx, final_part_id); - ObjectPart &part = active_object_parts.access(final_part_id); - part.add(new_part); - } - } - - prev_slice_idx_to_object_part_mapping = next_slice_idx_to_object_part_mapping; - next_slice_idx_to_object_part_mapping.clear(); - prev_slice_idx_to_weakest_connection = next_slice_idx_to_weakest_connection; - next_slice_idx_to_weakest_connection.clear(); - - auto get_flat_entities = [](const ExtrusionEntity *e) { - std::vector entities; - std::vector queue{e}; - while (!queue.empty()) { - const ExtrusionEntity *next = queue.back(); - queue.pop_back(); - if (next->is_collection()) { - for (const ExtrusionEntity *e : static_cast(next)->entities) { - queue.push_back(e); - } - } else { - entities.push_back(next); - } - } - return entities; - }; - - struct EnitityToCheck - { - const ExtrusionEntity *e; - const LayerRegion *region; - size_t slice_idx; - }; - std::vector entities_to_check; - for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) { - const LayerSlice &slice = layer->lslices_ex.at(slice_idx); - for (const auto &island : slice.islands) { - for (const LayerExtrusionRange &fill_range : island.fills) { - const LayerRegion *fill_region = layer->get_region(fill_range.region()); - for (size_t fill_idx : fill_range) { - for (const ExtrusionEntity *e : get_flat_entities(fill_region->fills().entities[fill_idx])) { - if (e->role() == ExtrusionRole::BridgeInfill) { - entities_to_check.push_back({e, fill_region, slice_idx}); - } - } - } - } - - const LayerRegion *perimeter_region = layer->get_region(island.perimeters.region()); - for (size_t perimeter_idx : island.perimeters) { - for (const ExtrusionEntity *e : get_flat_entities(perimeter_region->perimeters().entities[perimeter_idx])) { - entities_to_check.push_back({e, perimeter_region, slice_idx}); - } - } - } - } - - AABBTreeLines::LinesDistancer prev_layer_boundary = layer->lower_layer != nullptr ? - AABBTreeLines::LinesDistancer{ - to_unscaled_linesf(layer->lower_layer->lslices)} : - AABBTreeLines::LinesDistancer{}; - - std::vector> unstable_lines_per_slice(layer->lslices_ex.size()); - std::vector> ext_perim_lines_per_slice(layer->lslices_ex.size()); - - tbb::parallel_for(tbb::blocked_range(0, entities_to_check.size()), - [&entities_to_check, &prev_layer_ext_perim_lines, &prev_layer_boundary, &unstable_lines_per_slice, - &ext_perim_lines_per_slice, ¶ms](tbb::blocked_range r) { - for (size_t entity_idx = r.begin(); entity_idx < r.end(); ++entity_idx) { - const auto &e_to_check = entities_to_check[entity_idx]; - for (const auto &line : - check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines, - prev_layer_boundary, params)) { - if (line.support_point_generated.has_value()) { - unstable_lines_per_slice[e_to_check.slice_idx].push_back(line); - } - if (line.is_external_perimeter()) { - ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line); - } - } - } - }); + LocalSupports local_supports{ + compute_local_supports(gather_entities_to_check(layer), prev_layer_boundary, prev_layer_ext_perim_lines, layer->lslices_ex.size(), params)}; std::vector current_layer_ext_perims_lines{}; current_layer_ext_perims_lines.reserve(prev_layer_ext_perim_lines.get_lines().size()); // All object parts updated, and for each slice we have coresponding weakest connection. // We can now check each slice and its corresponding weakest connection and object part for stability. for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) { - ObjectPart &part = active_object_parts.access(prev_slice_idx_to_object_part_mapping[slice_idx]); - SliceConnection &weakest_conn = prev_slice_idx_to_weakest_connection[slice_idx]; + ObjectPart &part = active_object_parts.access(slice_mappings.index_to_object_part_mapping[slice_idx]); + SliceConnection &weakest_conn = slice_mappings.index_to_weakest_connection[slice_idx]; -#ifdef DETAILED_DEBUG_LOGS - weakest_conn.print_info("weakest connection info: "); -#endif - // Function that is used when new support point is generated. It will update the ObjectPart stability, weakest conneciton info, - // and the support presence grid and add the point to the issues. - auto reckon_new_support_point = [&part, &weakest_conn, &supp_points, &supports_presence_grid, ¶ms, - &layer_idx](SupportPointCause cause, const Vec3f &support_point, float force, - const Vec2f &dir) { - // if position is taken and point is for global stability (force > 0) or we are too close to the bed, do not add - // This allows local support points (e.g. bridging) to be generated densely - if ((supports_presence_grid.position_taken(support_point) && force > 0) || layer_idx <= 1) { - return; - } - - float area = params.support_points_interface_radius * params.support_points_interface_radius * float(PI); - // add the stability effect of the point only if the spot is not taken, so that the densely created local support points do - // not add unrealistic amount of stability to the object (due to overlaping of local support points) - if (!(supports_presence_grid.position_taken(support_point))) { - part.add_support_point(support_point, area); - } - - float radius = params.support_points_interface_radius; - supp_points.emplace_back(cause, support_point, force, radius, dir); - supports_presence_grid.take_position(support_point); - - // The support point also increases the stability of the weakest connection of the object, which should be reflected - if (weakest_conn.area > EPSILON) { // Do not add it to the weakest connection if it is not valid - does not exist - weakest_conn.area += area; - weakest_conn.centroid_accumulator += support_point * area; - weakest_conn.second_moment_of_area_accumulator += area * support_point.head<2>().cwiseProduct(support_point.head<2>()); - weakest_conn.second_moment_of_area_covariance_accumulator += area * support_point.x() * support_point.y(); - } - }; - - for (const auto &l : unstable_lines_per_slice[slice_idx]) { - assert(l.support_point_generated.has_value()); - reckon_new_support_point(*l.support_point_generated, create_support_point_position(l.b), float(-EPSILON), Vec2f::Zero()); - } - - LD current_slice_lines_distancer({ext_perim_lines_per_slice[slice_idx].begin(), ext_perim_lines_per_slice[slice_idx].end()}); - float unchecked_dist = params.min_distance_between_support_points + 1.0f; - - for (const ExtrusionLine &line : current_slice_lines_distancer.get_lines()) { - if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < params.curling_tolerance_limit) || - line.len < EPSILON) { - unchecked_dist += line.len; - } else { - unchecked_dist = line.len; - Vec2f pivot_site_search_point = Vec2f(line.b + (line.b - line.a).normalized() * 300.0f); - auto [dist, nidx, - nearest_point] = current_slice_lines_distancer.distance_from_lines_extra(pivot_site_search_point); - Vec3f support_point = create_support_point_position(nearest_point); - auto [force, cause] = part.is_stable_while_extruding(weakest_conn, line, support_point, bottom_z, params); - if (force > 0) { - reckon_new_support_point(cause, support_point, force, (line.b - line.a).normalized()); - } + if (layer_idx > 1) { + for (const auto &l : local_supports.unstable_lines_per_slice[slice_idx]) { + assert(l.support_point_generated.has_value()); + SupportPoint support_point{*l.support_point_generated, to_3d(l.b, bottom_z), + params.support_points_interface_radius}; + reckon_new_support_point(part, weakest_conn, supp_points, supports_presence_grid, support_point); } } - current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), current_slice_lines_distancer.get_lines().begin(), - current_slice_lines_distancer.get_lines().end()); + + const tbb::concurrent_vector &external_perimeter_lines = local_supports.ext_perim_lines_per_slice[slice_idx]; + if (layer_idx > 1) { + reckon_global_supports(external_perimeter_lines, bottom_z, params, part, weakest_conn, supp_points, supports_presence_grid); + } + + current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), external_perimeter_lines.begin(), external_perimeter_lines.end()); } // slice iterations prev_layer_ext_perim_lines = LD(current_layer_ext_perims_lines); } // layer iterations - for (const auto& active_obj_pair : prev_slice_idx_to_object_part_mapping) { - remember_partial_object(active_obj_pair.second); + for (const auto& active_obj_pair : slice_mappings.index_to_object_part_mapping) { + auto object_part = active_object_parts.access(active_obj_pair.second); + if (auto object = to_partial_object(object_part)) { + partial_objects.push_back(std::move(*object)); + } } return {supp_points, partial_objects}; diff --git a/src/libslic3r/SupportSpotsGenerator.hpp b/src/libslic3r/SupportSpotsGenerator.hpp index 62f4e960d4..f13d0c9bb4 100644 --- a/src/libslic3r/SupportSpotsGenerator.hpp +++ b/src/libslic3r/SupportSpotsGenerator.hpp @@ -104,8 +104,8 @@ enum class SupportPointCause { // Note that the force is only the difference - the amount needed to stabilize the object again. struct SupportPoint { - SupportPoint(SupportPointCause cause, const Vec3f &position, float force, float spot_radius, const Vec2f &direction) - : cause(cause), position(position), force(force), spot_radius(spot_radius), direction(direction) + SupportPoint(SupportPointCause cause, const Vec3f &position, float spot_radius) + : cause(cause), position(position), spot_radius(spot_radius) {} bool is_local_extrusion_support() const @@ -117,17 +117,9 @@ struct SupportPoint SupportPointCause cause; // reason why this support point was generated. Used for the user alerts // position is in unscaled coords. The z coordinate is aligned with the layers bottom_z coordiantes Vec3f position; - // force that destabilizes the object to the point of falling/breaking. g*mm/s^2 units - // It is valid only for global_object_support. For local extrusion support points, the force is -EPSILON - // values gathered from large XL model: Min : 0 | Max : 18713800 | Average : 1361186 | Median : 329103 - // For reference 18713800 is weight of 1.8 Kg object, 329103 is weight of 0.03 Kg - // The final sliced object weight was approx 0.5 Kg - float force; // Expected spot size. The support point strength is calculated from the area defined by this value. // Currently equal to the support_points_interface_radius parameter above float spot_radius; - // direction of the fall of the object (z part is neglected) - Vec2f direction; }; using SupportPoints = std::vector; diff --git a/tests/arrange/test_arrange.cpp b/tests/arrange/test_arrange.cpp index dec1fc1398..a2eda8c480 100644 --- a/tests/arrange/test_arrange.cpp +++ b/tests/arrange/test_arrange.cpp @@ -202,10 +202,10 @@ static void check_nfp(const std::string & outfile_prefix, ExPolygons bed_negative = diff_ex(bedrect, bedpoly); ExPolygons orb_ex_r = to_expolygons(orbiter); ExPolygons orb_ex_r_ch = {ExPolygon(Geometry::convex_hull(orb_ex_r))}; - auto orb_ex_offs_pos_r = offset_ex(orb_ex_r, SCALED_EPSILON); - auto orb_ex_offs_neg_r = offset_ex(orb_ex_r, -SCALED_EPSILON); - auto orb_ex_offs_pos_r_ch = offset_ex(orb_ex_r_ch, SCALED_EPSILON); - auto orb_ex_offs_neg_r_ch = offset_ex(orb_ex_r_ch, -SCALED_EPSILON); + auto orb_ex_offs_pos_r = offset_ex(orb_ex_r, scaled(EPSILON)); + auto orb_ex_offs_neg_r = offset_ex(orb_ex_r, -scaled(EPSILON)); + auto orb_ex_offs_pos_r_ch = offset_ex(orb_ex_r_ch, scaled(EPSILON)); + auto orb_ex_offs_neg_r_ch = offset_ex(orb_ex_r_ch, -scaled(EPSILON)); auto bedpoly_offs = offset_ex(bedpoly, SCALED_EPSILON); diff --git a/tests/arrange/test_arrange_integration.cpp b/tests/arrange/test_arrange_integration.cpp index 6d8fda6bff..34b77ab33b 100644 --- a/tests/arrange/test_arrange_integration.cpp +++ b/tests/arrange/test_arrange_integration.cpp @@ -738,8 +738,8 @@ bool is_collision_free(const Slic3r::Range &item_range) bool collision_free = true; foreach_combo(item_range, [&collision_free](auto &itm1, auto &itm2) { - auto outline1 = offset(arr2::fixed_outline(itm1), -SCALED_EPSILON); - auto outline2 = offset(arr2::fixed_outline(itm2), -SCALED_EPSILON); + auto outline1 = offset(arr2::fixed_outline(itm1), -scaled(EPSILON)); + auto outline2 = offset(arr2::fixed_outline(itm2), -scaled(EPSILON)); auto inters = intersection(outline1, outline2); collision_free = collision_free && inters.empty(); diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index 7b0d200c7d..d10494461a 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -42,6 +42,7 @@ add_executable(${_TEST_NAME}_tests test_support_spots_generator.cpp ../data/prusaparts.cpp ../data/prusaparts.hpp + test_static_map.cpp ) if (TARGET OpenVDB::openvdb) diff --git a/tests/libslic3r/test_arc_welder.cpp b/tests/libslic3r/test_arc_welder.cpp index 2686216954..44b88655ea 100644 --- a/tests/libslic3r/test_arc_welder.cpp +++ b/tests/libslic3r/test_arc_welder.cpp @@ -1,7 +1,11 @@ #include #include +#include + #include +#include +#include #include using namespace Slic3r; @@ -13,25 +17,34 @@ TEST_CASE("arc basics", "[ArcWelder]") { Vec2f p1{ 2000.f, 1000.f }; Vec2f p2{ 1000.f, 2000.f }; float r{ 1000.f }; + const double s = 1000.f / sqrt(2.); THEN("90 degrees arc, CCW") { Vec2f c = ArcWelder::arc_center(p1, p2, r, true); + Vec2f m = ArcWelder::arc_middle_point(p1, p2, r, true); REQUIRE(is_approx(c, Vec2f{ 1000.f, 1000.f })); REQUIRE(ArcWelder::arc_angle(p1, p2, r) == Approx(0.5 * M_PI)); REQUIRE(ArcWelder::arc_length(p1, p2, r) == Approx(r * 0.5 * M_PI).epsilon(0.001)); + REQUIRE(is_approx(m, Vec2f{ 1000.f + s, 1000.f + s }, 0.001f)); } THEN("90 degrees arc, CW") { Vec2f c = ArcWelder::arc_center(p1, p2, r, false); + Vec2f m = ArcWelder::arc_middle_point(p1, p2, r, false); REQUIRE(is_approx(c, Vec2f{ 2000.f, 2000.f })); + REQUIRE(is_approx(m, Vec2f{ 2000.f - s, 2000.f - s }, 0.001f)); } THEN("270 degrees arc, CCW") { Vec2f c = ArcWelder::arc_center(p1, p2, - r, true); + Vec2f m = ArcWelder::arc_middle_point(p1, p2, - r, true); REQUIRE(is_approx(c, Vec2f{ 2000.f, 2000.f })); REQUIRE(ArcWelder::arc_angle(p1, p2, - r) == Approx(1.5 * M_PI)); REQUIRE(ArcWelder::arc_length(p1, p2, - r) == Approx(r * 1.5 * M_PI).epsilon(0.001)); + REQUIRE(is_approx(m, Vec2f{ 2000.f + s, 2000.f + s }, 0.001f)); } THEN("270 degrees arc, CW") { Vec2f c = ArcWelder::arc_center(p1, p2, - r, false); + Vec2f m = ArcWelder::arc_middle_point(p1, p2, - r, false); REQUIRE(is_approx(c, Vec2f{ 1000.f, 1000.f })); + REQUIRE(is_approx(m, Vec2f{ 1000.f - s, 1000.f - s }, 0.001f)); } } WHEN("arc from { 1707.11f, 1707.11f } to { 1000.f, 2000.f }") { @@ -126,6 +139,28 @@ TEST_CASE("arc discretization", "[ArcWelder]") { } } +void test_arc_fit_variance(const Point &p1, const Point &p2, const float r, const float r_fit, const bool ccw, const Points::const_iterator begin, const Points::const_iterator end) +{ + using namespace Slic3r::Geometry; + double variance = ArcWelder::arc_fit_variance(p1, p2, r, ccw, begin, end); + double variance_fit = ArcWelder::arc_fit_variance(p1, p2, r_fit, ccw, begin, end); + REQUIRE(variance_fit < variance); +}; + +void test_arc_fit_max_deviation(const Point &p1, const Point &p2, const float r, const float r_fit, const bool ccw, const Points::const_iterator begin, const Points::const_iterator end) +{ + using namespace Slic3r::Geometry; + double max_deviation = ArcWelder::arc_fit_max_deviation(p1, p2, r, ccw, begin, end); + double max_deviation_fit = ArcWelder::arc_fit_max_deviation(p1, p2, r_fit, ccw, begin, end); + REQUIRE(std::abs(max_deviation_fit) < std::abs(max_deviation)); +}; + +void test_arc_fit(const Point &p1, const Point &p2, const float r, const float r_fit, const bool ccw, const Points::const_iterator begin, const Points::const_iterator end) +{ + test_arc_fit_variance(p1, p2, r, r_fit, ccw, begin, end); + test_arc_fit_max_deviation(p1, p2, r, r_fit, ccw, begin, end); +}; + TEST_CASE("arc fitting", "[ArcWelder]") { using namespace Slic3r::Geometry; @@ -142,8 +177,8 @@ TEST_CASE("arc fitting", "[ArcWelder]") { REQUIRE(path.front().point == p1); REQUIRE(path.front().radius == 0.f); REQUIRE(path.back().point == p2); - REQUIRE(path.back().radius == Approx(r)); REQUIRE(path.back().ccw() == ccw); + test_arc_fit(p1, p2, r, path.back().radius, true, pts.begin(), pts.end()); }; THEN("90 degrees arc, CCW is fitted") { test(p1, p2, radius, true); @@ -169,6 +204,7 @@ TEST_CASE("arc fitting", "[ArcWelder]") { const float resolution = scaled(0.002); auto test = [center1, center2, resolution](const Point &p1, const Point &p2, const Point &p3, const float r, const bool ccw) { Points pts = ArcWelder::arc_discretize(p1, p2, r, ccw, resolution); + size_t num_pts1 = pts.size(); { Points pts2 = ArcWelder::arc_discretize(p2, p3, - r, ! ccw, resolution); REQUIRE(pts.back() == pts2.front()); @@ -179,11 +215,11 @@ TEST_CASE("arc fitting", "[ArcWelder]") { REQUIRE(path.front().point == p1); REQUIRE(path.front().radius == 0.f); REQUIRE(path[1].point == p2); - REQUIRE(path[1].radius == Approx(r)); REQUIRE(path[1].ccw() == ccw); REQUIRE(path.back().point == p3); - REQUIRE(path.back().radius == Approx(- r)); REQUIRE(path.back().ccw() == ! ccw); + test_arc_fit(p1, p2, r, path[1].radius, ccw, pts.begin(), pts.begin() + num_pts1); + test_arc_fit(p2, p3, - r, path.back().radius, ! ccw, pts.begin() + num_pts1 - 1, pts.end()); }; THEN("90 degrees arches, CCW are fitted") { test(p1, p2, p3, radius, true); @@ -200,6 +236,106 @@ TEST_CASE("arc fitting", "[ArcWelder]") { } } +TEST_CASE("least squares arc fitting, interpolating end points", "[ArcWelder]") { + using namespace Slic3r::Geometry; + + // Generate bunch of random arches. + const coord_t max_coordinate = scaled(sqrt(250. - 1.)); + static constexpr const double min_radius = scaled(0.01); + static constexpr const double max_radius = scaled(250.); +// static constexpr const double deviation = scaled(0.5); + static constexpr const double deviation = scaled(0.1); + // Seeded with a fixed seed, to be repeatable. + std::mt19937 rng(867092346); + std::uniform_int_distribution coord_sampler(0, int32_t(max_coordinate)); + std::uniform_real_distribution angle_sampler(0.001, 2. * M_PI - 0.001); + std::uniform_real_distribution radius_sampler(min_radius, max_radius); + std::uniform_int_distribution num_samples_sampler(1, 100); + auto test_arc_fitting = [&rng, &coord_sampler, &num_samples_sampler, &angle_sampler, &radius_sampler]() { + auto sample_point = [&rng, &coord_sampler]() { + return Vec2d(coord_sampler(rng), coord_sampler(rng)); + }; + // Start and end point of the arc: + Vec2d center_pos = sample_point(); + double angle0 = angle_sampler(rng); + double angle = angle_sampler(rng); + double radius = radius_sampler(rng); + Vec2d v1 = Eigen::Rotation2D(angle0) * Vec2d(1., 0.); + Vec2d v2 = Eigen::Rotation2D(angle0 + angle) * Vec2d(1., 0.); + Vec2d start_pos = center_pos + radius * v1; + Vec2d end_pos = center_pos + radius * v2; + std::vector samples; + size_t num_samples = num_samples_sampler(rng); + for (size_t i = 0; i < num_samples; ++ i) { + double sample_r = sqrt(std::uniform_real_distribution(sqr(std::max(0., radius - deviation)), sqr(radius + deviation))(rng)); + double sample_a = std::uniform_real_distribution(0., angle)(rng); + Vec2d pt = center_pos + Eigen::Rotation2D(angle0 + sample_a) * Vec2d(sample_r, 0.); + samples.emplace_back(pt); + assert((pt - center_pos).norm() > radius - deviation - SCALED_EPSILON); + assert((pt - center_pos).norm() < radius + deviation + SCALED_EPSILON); + } +// Vec2d new_center = ArcWelder::arc_fit_center_algebraic_ls(start_pos, end_pos, center_pos, samples.begin(), samples.end()); + THEN("Center is fitted correctly") { + std::optional new_center_opt = ArcWelder::arc_fit_center_gauss_newton_ls(start_pos, end_pos, center_pos, samples.begin(), samples.end(), 10); + REQUIRE(new_center_opt); + if (new_center_opt) { + Vec2d new_center = *new_center_opt; + double new_radius = (new_center - start_pos).norm(); + double total_deviation = 0; + double new_total_deviation = 0; + for (const Vec2d &s : samples) { + total_deviation += sqr((s - center_pos).norm() - radius); + new_total_deviation += sqr((s - new_center).norm() - radius); + } + total_deviation /= double(num_samples); + new_total_deviation /= double(num_samples); + REQUIRE(new_total_deviation <= total_deviation); + +#if 0 + double dist = (center_pos - new_center).norm(); + printf("Radius: %lf, Angle: %lf deg, Samples: %d, Dist: %lf\n", unscaled(radius), 180. * angle / M_PI, int(num_samples), unscaled(dist)); + // REQUIRE(is_approx(center_pos, new_center, deviation)); + if (dist > scaled(1.)) { + static int irun = 0; + char path[2048]; + sprintf(path, "d:\\temp\\debug\\circle-fit-%d.svg", irun++); + Eigen::AlignedBox bbox(start_pos, end_pos); + for (const Vec2d& sample : samples) + bbox.extend(sample); + bbox.extend(center_pos); + Slic3r::SVG svg(path, BoundingBox(bbox.min().cast(), bbox.max().cast()).inflated(bbox.sizes().maxCoeff() * 0.05)); + Points arc_src; + for (size_t i = 0; i <= 1000; ++i) + arc_src.emplace_back((center_pos + Eigen::Rotation2D(angle0 + double(i) * angle / 1000.) * Vec2d(radius, 0.)).cast()); + svg.draw(Polyline(arc_src)); + Points arc_new; + double new_arc_angle = ArcWelder::arc_angle(start_pos, end_pos, (new_center - start_pos).norm()); + for (size_t i = 0; i <= 1000; ++i) + arc_new.emplace_back((new_center + Eigen::Rotation2D(double(i) * new_arc_angle / 1000.) * (start_pos - new_center)).cast()); + svg.draw(Polyline(arc_new), "magenta"); + svg.draw(Point(start_pos.cast()), "blue"); + svg.draw(Point(end_pos.cast()), "blue"); + svg.draw(Point(center_pos.cast()), "blue"); + for (const Vec2d &sample : samples) + svg.draw(Point(sample.cast()), "red"); + svg.draw(Point(new_center.cast()), "magenta"); + } + if (!is_approx(center_pos, new_center, scaled(5.))) { + printf("Failed\n"); + } +#endif + } else { + printf("Fitting failed\n"); + } + } + }; + + WHEN("Generating a random arc and randomized arc samples") { + for (size_t i = 0; i < 1000; ++ i) + test_arc_fitting(); + } +} + TEST_CASE("arc wedge test", "[ArcWelder]") { using namespace Slic3r::Geometry; @@ -262,3 +398,114 @@ TEST_CASE("arc wedge test", "[ArcWelder]") { } } } + +#if 0 +// For quantization +//#include + +TEST_CASE("arc quantization", "[ArcWelder]") { + using namespace Slic3r::Geometry; + + WHEN("generating a bunch of random arches") { + static constexpr const size_t len = 100000; + static constexpr const coord_t max_coordinate = scaled(250.); + static constexpr const float max_radius = scaled(250.); + ArcWelder::Segments path; + path.reserve(len + 1); + // Seeded with a fixed seed, to be repeatable. + std::mt19937 rng(987432690); + // Generate bunch of random arches. + std::uniform_int_distribution coord_sampler(0, int32_t(max_coordinate)); + std::uniform_real_distribution radius_sampler(- max_radius, max_radius); + std::uniform_int_distribution orientation_sampler(0, 1); + path.push_back({ Point{coord_sampler(rng), coord_sampler(rng)}, 0, ArcWelder::Orientation::CCW }); + for (size_t i = 0; i < len; ++ i) { + ArcWelder::Segment seg { Point{coord_sampler(rng), coord_sampler(rng)}, radius_sampler(rng), orientation_sampler(rng) ? ArcWelder::Orientation::CCW : ArcWelder::Orientation::CW }; + while ((seg.point.cast() - path.back().point.cast()).norm() > 2. * std::abs(seg.radius)) + seg = { Point{coord_sampler(rng), coord_sampler(rng)}, radius_sampler(rng), orientation_sampler(rng) ? ArcWelder::Orientation::CCW : ArcWelder::Orientation::CW }; + path.push_back(seg); + } + // Run the test, quantize coordinates and radius, find the maximum error of quantization comparing the two arches. + struct ArcEval { + double error; + double radius; + double angle; + }; + std::vector center_errors_R; + center_errors_R.reserve(len); + std::vector center_errors_R_exact; + center_errors_R_exact.reserve(len); + std::vector center_errors_IJ; + center_errors_IJ.reserve(len); + for (size_t i = 0; i < len; ++ i) { + // Source arc: + const Vec2d start_point = unscaled(path[i].point); + const Vec2d end_point = unscaled(path[i + 1].point); + const double radius = unscaled(path[i + 1].radius); + const bool ccw = path[i + 1].ccw(); + const Vec2d center = ArcWelder::arc_center(start_point, end_point, radius, ccw); + { + const double d1 = (start_point - center).norm(); + const double d2 = (end_point - center).norm(); + const double dx = (end_point - start_point).norm(); + assert(std::abs(d1 - std::abs(radius)) < EPSILON); + assert(std::abs(d2 - std::abs(radius)) < EPSILON); + } + // Quantized arc: + const Vec2d start_point_quantized { GCodeFormatter::quantize_xyzf(start_point.x()), GCodeFormatter::quantize_xyzf(start_point.y()) }; + const Vec2d end_point_quantized { GCodeFormatter::quantize_xyzf(end_point .x()), GCodeFormatter::quantize_xyzf(end_point .y()) }; + const double radius_quantized { GCodeFormatter::quantize_xyzf(radius) }; + const Vec2d center_quantized { GCodeFormatter::quantize_xyzf(center .x()), GCodeFormatter::quantize_xyzf(center .y()) }; + // Evaulate maximum error for the quantized arc given by the end points and radius. + const Vec2d center_from_quantized = ArcWelder::arc_center(start_point_quantized, end_point_quantized, radius, ccw); + const Vec2d center_reconstructed = ArcWelder::arc_center(start_point_quantized, end_point_quantized, radius_quantized, ccw); +#if 0 + center_errors_R.push_back({ + std::abs((center_reconstructed - center).norm()), + radius, + ArcWelder::arc_angle(start_point, end_point, radius) * 180. / M_PI + }); + if (center_errors_R.back().error > 0.15) + printf("Fuj\n"); +#endif + center_errors_R_exact.emplace_back(std::abs((center_from_quantized - center).norm())); + if (center_errors_R_exact.back() > 0.15) + printf("Fuj\n"); + center_errors_IJ.emplace_back(std::abs((center_quantized - center).norm())); + if (center_errors_IJ.back() > 0.15) + printf("Fuj\n"); + + // Adjust center of the arc to the quantized end points. + Vec2d third_point = ArcWelder::arc_middle_point(start_point, end_point, radius, ccw); + double third_point_radius = (third_point - center).norm(); + assert(std::abs(third_point_radius - std::abs(radius)) < EPSILON); + std::optional center_adjusted = try_circle_center(start_point_quantized, end_point_quantized, third_point, EPSILON); + //assert(center_adjusted); + if (center_adjusted) { + const double radius_adjusted = (center_adjusted.value() - start_point_quantized).norm() * (radius > 0 ? 1. : -1.); + const double radius_adjusted_quantized = GCodeFormatter::quantize_xyzf(radius_adjusted); + // Evaulate maximum error for the quantized arc given by the end points and radius. + const Vec2f center_reconstructed = ArcWelder::arc_center(start_point_quantized.cast(), end_point_quantized.cast(), float(radius_adjusted_quantized), ccw); + double rtest = std::abs(radius_adjusted_quantized); + double d1 = std::abs((center_reconstructed - start_point.cast()).norm() - rtest); + double d2 = std::abs((center_reconstructed - end_point.cast()).norm() - rtest); + double d3 = std::abs((center_reconstructed - third_point.cast()).norm() - rtest); + double d = std::max(d1, std::max(d2, d3)); + center_errors_R.push_back({ + d, + radius, + ArcWelder::arc_angle(start_point, end_point, radius) * 180. / M_PI + }); + } else { + printf("Adjusted circle is collinear.\n"); + } + } + std::sort(center_errors_R.begin(), center_errors_R.end(), [](auto l, auto r) { return l.error > r.error; }); + std::sort(center_errors_R_exact.begin(), center_errors_R_exact.end(), [](auto l, auto r) { return l > r; }); + std::sort(center_errors_IJ.begin(), center_errors_IJ.end(), [](auto l, auto r) { return l > r; }); + printf("Maximum error R: %lf\n", center_errors_R.back().error); + printf("Maximum error R exact: %lf\n", center_errors_R_exact.back()); + printf("Maximum error IJ: %lf\n", center_errors_IJ.back()); + } +} +#endif diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp index 867ff25c62..ba61e1bd4b 100644 --- a/tests/libslic3r/test_geometry.cpp +++ b/tests/libslic3r/test_geometry.cpp @@ -323,6 +323,54 @@ SCENARIO("Circle Fit, TaubinFit with Newton's method", "[Geometry]") { } } +SCENARIO("Circle Fit, least squares by decomposition or by solving normal equation", "[Geometry]") { + auto test_circle_fit = [](const Geometry::Circled &circle, const Vec2d ¢er, const double radius) { + THEN("A center point matches.") { + REQUIRE(is_approx(circle.center, center)); + } + THEN("Radius matches") { + REQUIRE(is_approx(circle.radius, radius)); + } + }; + + GIVEN("A vector of Vec2ds arranged in a half-circle with approximately the same distance R from some point") { + const Vec2d expected_center(-6., 0.); + const double expected_radius = 6.; + Vec2ds sample{Vec2d(6.0, 0), Vec2d(5.1961524, 3), Vec2d(3 ,5.1961524), Vec2d(0, 6.0), Vec2d(3, 5.1961524), Vec2d(-5.1961524, 3), Vec2d(-6.0, 0)}; + std::transform(sample.begin(), sample.end(), sample.begin(), [expected_center] (const Vec2d &a) { return a + expected_center; }); + + WHEN("Circle fit is called on the entire array, least squares SVD") { + test_circle_fit(Geometry::circle_linear_least_squares_svd(sample), expected_center, expected_radius); + } + WHEN("Circle fit is called on the first four points, least squares SVD") { + test_circle_fit(Geometry::circle_linear_least_squares_svd(Vec2ds(sample.cbegin(), sample.cbegin() + 4)), expected_center, expected_radius); + } + WHEN("Circle fit is called on the middle four points, least squares SVD") { + test_circle_fit(Geometry::circle_linear_least_squares_svd(Vec2ds(sample.cbegin() + 2, sample.cbegin() + 6)), expected_center, expected_radius); + } + + WHEN("Circle fit is called on the entire array, least squares QR decomposition") { + test_circle_fit(Geometry::circle_linear_least_squares_qr(sample), expected_center, expected_radius); + } + WHEN("Circle fit is called on the first four points, least squares QR decomposition") { + test_circle_fit(Geometry::circle_linear_least_squares_qr(Vec2ds(sample.cbegin(), sample.cbegin() + 4)), expected_center, expected_radius); + } + WHEN("Circle fit is called on the middle four points, least squares QR decomposition") { + test_circle_fit(Geometry::circle_linear_least_squares_qr(Vec2ds(sample.cbegin() + 2, sample.cbegin() + 6)), expected_center, expected_radius); + } + + WHEN("Circle fit is called on the entire array, least squares by normal equations") { + test_circle_fit(Geometry::circle_linear_least_squares_normal(sample), expected_center, expected_radius); + } + WHEN("Circle fit is called on the first four points, least squares by normal equations") { + test_circle_fit(Geometry::circle_linear_least_squares_normal(Vec2ds(sample.cbegin(), sample.cbegin() + 4)), expected_center, expected_radius); + } + WHEN("Circle fit is called on the middle four points, least squares by normal equations") { + test_circle_fit(Geometry::circle_linear_least_squares_normal(Vec2ds(sample.cbegin() + 2, sample.cbegin() + 6)), expected_center, expected_radius); + } + } +} + TEST_CASE("smallest_enclosing_circle_welzl", "[Geometry]") { // Some random points in plane. Points pts { diff --git a/tests/libslic3r/test_static_map.cpp b/tests/libslic3r/test_static_map.cpp new file mode 100644 index 0000000000..6722a30bfe --- /dev/null +++ b/tests/libslic3r/test_static_map.cpp @@ -0,0 +1,98 @@ +#include +#include + +#include "libslic3r/StaticMap.hpp" + +TEST_CASE("Empty static map should be possible to create and should be empty", "[StaticMap]") +{ + using namespace Slic3r; + + static const constexpr StaticSet EmptySet; + + static const constexpr auto EmptyMap = make_staticmap(); + + constexpr bool is_map_empty = EmptyMap.empty(); + constexpr bool is_set_empty = EmptySet.empty(); + + REQUIRE(is_map_empty); + REQUIRE(is_set_empty); +} + +TEST_CASE("StaticSet should derive it's type from the initializer", "[StaticMap]") { + using namespace Slic3r; + static const constexpr StaticSet iOneSet = { 1 }; + static constexpr size_t iOneSetSize = iOneSet.size(); + + REQUIRE(iOneSetSize == 1); + + static const constexpr StaticSet iManySet = { 1, 3, 5, 80, 40 }; + static constexpr size_t iManySetSize = iManySet.size(); + + REQUIRE(iManySetSize == 5); +} + +TEST_CASE("StaticMap should derive it's type using make_staticmap", "[StaticMap]") { + using namespace Slic3r; + static const constexpr auto ciOneMap = make_staticmap({ + {'a', 1}, + }); + + static constexpr size_t ciOneMapSize = ciOneMap.size(); + static constexpr bool ciOneMapValid = query(ciOneMap, 'a').value_or(0) == 1; + + REQUIRE(ciOneMapSize == 1); + REQUIRE(ciOneMapValid); + + static const constexpr auto ciManyMap = make_staticmap({ + {'a', 1}, {'b', 2}, {'A', 10} + }); + + static constexpr size_t ciManyMapSize = ciManyMap.size(); + static constexpr bool ciManyMapValid = + query(ciManyMap, 'a').value_or(0) == 1 && + query(ciManyMap, 'b').value_or(0) == 2 && + query(ciManyMap, 'A').value_or(0) == 10 && + !contains(ciManyMap, 'B') && + !query(ciManyMap, 'c').has_value(); + + REQUIRE(ciManyMapSize == 3); + REQUIRE(ciManyMapValid); + + for (auto &[k, v] : ciManyMap) { + auto val = query(ciManyMap, k); + REQUIRE(val.has_value()); + REQUIRE(*val == v); + } +} + +TEST_CASE("StaticSet should be able to find contained values", "[StaticMap]") +{ + using namespace Slic3r; + using namespace std::string_view_literals; + + auto cmp = [](const char *a, const char *b) constexpr { + return std::string_view{a} < std::string_view{b}; + }; + + static constexpr StaticSet CStrSet = {cmp, "One", "Two", "Three"}; + static constexpr StaticSet StringSet = {"One"sv, "Two"sv, "Three"sv}; + + static constexpr bool CStrSetValid = query(CStrSet, "One").has_value() && + contains(CStrSet, "Two") && + contains(CStrSet, "Three") && + !contains(CStrSet, "one") && + !contains(CStrSet, "two") && + !contains(CStrSet, "three"); + + static constexpr bool StringSetValid = contains(StringSet, "One"sv) && + contains(StringSet, "Two"sv) && + contains(StringSet, "Three"sv) && + !contains(StringSet, "one"sv) && + !contains(StringSet, "two"sv) && + !contains(StringSet, "three"sv); + + REQUIRE(CStrSetValid); + REQUIRE(StringSetValid); + REQUIRE(CStrSet.size() == 3); + REQUIRE(StringSet.size() == 3); +}