diff --git a/resources/icons/sla_view_original.svg b/resources/icons/sla_view_original.svg
new file mode 100644
index 0000000000..4691721c87
--- /dev/null
+++ b/resources/icons/sla_view_original.svg
@@ -0,0 +1,72 @@
+
+
+
+
diff --git a/resources/icons/sla_view_processed.svg b/resources/icons/sla_view_processed.svg
new file mode 100644
index 0000000000..a26a0db2f1
--- /dev/null
+++ b/resources/icons/sla_view_processed.svg
@@ -0,0 +1,56 @@
+
+
+
+
diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx
index 3a3e2b333e..10ecdcbc42 100644
--- a/resources/profiles/PrusaResearch.idx
+++ b/resources/profiles/PrusaResearch.idx
@@ -1,3 +1,6 @@
+min_slic3r_version = 2.6.0-beta0
+1.9.0-beta1 Updated cooling settings for some ASA filaments to increase interlayer adhesion (XL/MK4).
+1.9.0-beta0 Updated start g-code script for MK4/XL.
min_slic3r_version = 2.6.0-alpha5
1.9.0-alpha4 Updated XL and MK4 profiles. Updated PC Blend Carbon Fiber density.
1.9.0-alpha3 Updated compatibility condition for MMU1 filaments.
@@ -12,11 +15,15 @@ min_slic3r_version = 2.6.0-alpha1
1.6.0-alpha1 Updated FW version notification. Decreased min layer time for PLA.
1.6.0-alpha0 Default top fill set to monotonic lines. Updated infill/perimeter overlap values. Updated output filename format. Enabled dynamic overhang speeds.
min_slic3r_version = 2.5.2-rc0
+1.7.5 Updated cooling settings for some ASA filaments to increase interlayer adhesion (XL/MK4). Updated LA values (XL/MK4).
+1.7.4 Updated start g-code script for MK4/XL (fixed pre-print temperature for PA filaments).
1.7.3 Updated XL and MK4 profiles. Updated PC Blend Carbon Fiber density.
1.7.2 Updated compatibility condition for MMU1 filaments.
1.7.1 Added SLA materials. Updated MK4 and XL profiles.
1.7.0 Added profiles for Original Prusa MK4.
min_slic3r_version = 2.5.1-rc0
+1.6.6 Updated cooling settings for some ASA filaments to increase interlayer adhesion (XL/MK4).
+1.6.5 Updated start g-code script for MK4/XL (fixed pre-print temperature for PA filaments).
1.6.4 Fixed compatibility condition for MMU1 filaments.
1.6.3 Added SLA materials.
1.6.2 Updated compatibility condition in some filament profiles (Prusa XL).
diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini
index d2528a70a5..268171a1a8 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.9.0-alpha4
+config_version = 1.9.0-beta1
# 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%
@@ -3618,7 +3618,7 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and no
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.06{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.08{elsif nozzle_diameter[0]==0.35}0.07{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
+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\nM142 S36 ; set heatbreak target temp"
compatible_printers_condition = printer_notes=~/.*PG.*/ and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6
slowdown_below_layer_time = 8
filament_cooling_final_speed = 2
@@ -3675,7 +3675,7 @@ filament_max_volumetric_speed = 15
[filament:*PETPG*]
compatible_printers_condition = printer_notes=~/.*PG.*/ and nozzle_diameter[0]!=0.6 and nozzle_diameter[0]!=0.8
filament_max_volumetric_speed = 10
-start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.4}0.08{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.1{elsif nozzle_diameter[0]==0.35}0.09{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\nM142 S40 ; set heatbreak target temp"
+start_filament_gcode = "M900 K{if nozzle_diameter[0]==0.4}0.07{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.09{elsif nozzle_diameter[0]==0.35}0.08{elsif nozzle_diameter[0]==0.6}0.04{elsif nozzle_diameter[0]==0.5}0.05{elsif nozzle_diameter[0]==0.8}0.02{else}0{endif} ; Filament gcode\n\nM142 S40 ; set heatbreak target temp"
filament_cooling_final_speed = 1
filament_cooling_initial_speed = 2
filament_cooling_moves = 1
@@ -4498,6 +4498,8 @@ filament_type = ASA
[filament:Fillamentum ASA @PG]
inherits = Fillamentum ASA; *ABSPG*
bed_temperature = 105
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Fillamentum ASA @PG 0.6]
inherits = Fillamentum ASA @PG; *ABS06PG*
@@ -4507,6 +4509,8 @@ inherits = Fillamentum ASA @PG; *ABS08PG*
[filament:Fillamentum ASA @MK4]
inherits = Fillamentum ASA; *ABSMK4*
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Fillamentum ASA @MK4 0.6]
inherits = Fillamentum ASA @MK4; *ABS06MK4*
@@ -4541,6 +4545,8 @@ compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_model!="MINI
inherits = Prusament ASA; *ABSPG*
first_layer_bed_temperature = 100
bed_temperature = 105
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Prusament ASA @PG 0.6]
inherits = Prusament ASA @PG; *ABS06PG*
@@ -4552,6 +4558,8 @@ temperature = 265
[filament:Prusament ASA @MK4]
inherits = Prusament ASA; *ABSMK4*
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Prusament ASA @MK4 0.6]
inherits = Prusament ASA @MK4; *ABS06MK4*
@@ -4590,6 +4598,8 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and no
[filament:Prusament PC Blend @PG]
inherits = Prusament PC Blend; *PCPG*
filament_max_volumetric_speed = 9
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Prusament PC Blend @PG 0.6]
inherits = Prusament PC Blend @PG; *PC06PG*
@@ -4602,6 +4612,8 @@ filament_max_volumetric_speed = 18
[filament:Prusament PC Blend @MK4]
inherits = Prusament PC Blend; *PCMK4*
filament_max_volumetric_speed = 9
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Prusament PC Blend @MK4 0.6]
inherits = Prusament PC Blend @MK4; *PC06MK4*
@@ -4634,24 +4646,28 @@ compatible_printers_condition = printer_notes!~/.*PRINTER_MODEL_MK(2|2.5).*/ and
[filament:Prusament PC Blend Carbon Fiber @PG]
inherits = Prusament PC Blend Carbon Fiber; *PCPG*
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Prusament PC Blend Carbon Fiber @PG 0.6]
-inherits = Prusament PC Blend Carbon Fiber; *PC06PG*
+inherits = Prusament PC Blend Carbon Fiber @PG; *PC06PG*
filament_max_volumetric_speed = 13
[filament:Prusament PC Blend Carbon Fiber @PG 0.8]
-inherits = Prusament PC Blend Carbon Fiber; *PC08PG*
+inherits = Prusament PC Blend Carbon Fiber @PG; *PC08PG*
filament_max_volumetric_speed = 18
[filament:Prusament PC Blend Carbon Fiber @MK4]
inherits = Prusament PC Blend Carbon Fiber; *PCMK4*
+min_fan_speed = 10
+max_fan_speed = 10
[filament:Prusament PC Blend Carbon Fiber @MK4 0.6]
-inherits = Prusament PC Blend Carbon Fiber; *PC06MK4*
+inherits = Prusament PC Blend Carbon Fiber @MK4; *PC06MK4*
filament_max_volumetric_speed = 13
[filament:Prusament PC Blend Carbon Fiber @MK4 0.8]
-inherits = Prusament PC Blend Carbon Fiber; *PC08MK4*
+inherits = Prusament PC Blend Carbon Fiber @MK4; *PC08MK4*
filament_max_volumetric_speed = 18
[filament:Prusament PC Blend Carbon Fiber @MK2]
@@ -7290,6 +7306,8 @@ inherits = Ultrafuse ASA; *ABSPG*
first_layer_bed_temperature = 105
bed_temperature = 105
filament_max_volumetric_speed = 5
+min_fan_speed = 15
+max_fan_speed = 40
[filament:Ultrafuse ASA @PG 0.6]
inherits = Ultrafuse ASA @PG; *ABS06PG*
@@ -7302,6 +7320,8 @@ filament_max_volumetric_speed = 12
[filament:Ultrafuse ASA @MK4]
inherits = Ultrafuse ASA; *ABSMK4*
filament_max_volumetric_speed = 5
+min_fan_speed = 15
+max_fan_speed = 40
[filament:Ultrafuse ASA @MK4 0.6]
inherits = Ultrafuse ASA @MK4; *ABS06MK4*
@@ -15778,7 +15798,7 @@ retract_before_travel = 1.5
retract_before_wipe = 80%
retract_layer_change = 1
retract_length = 0.8
-start_gcode = M17 ; enable steppers\nM862.3 P "[printer_model]" ; printer model check\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_type[0] == "PC" or filament_type[0] == "NYLON") ? (first_layer_temperature[0] - 25) : (filament_type[0] == "FLEX" ? 210 : 170))} ; set extruder temp for bed leveling\nM109 T0 R{((filament_type[0] == "PC" or filament_type[0] == "NYLON") ? (first_layer_temperature[0] - 25) : (filament_type[0] == "FLEX" ? 210 : 170))} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == "FLEX" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == "FLEX" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position\n
+start_gcode = M17 ; enable steppers\nM862.3 P "[printer_model]" ; printer model check\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; set print area\nM555 X{first_layer_print_min[0]} Y{first_layer_print_min[1]} W{(first_layer_print_max[0]) - (first_layer_print_min[0])} H{(first_layer_print_max[1]) - (first_layer_print_min[1])}\n; inform about nozzle diameter\nM862.1 P[nozzle_diameter]\n; set & wait for bed and extruder temp for MBL\nM140 S[first_layer_bed_temperature] ; set bed temp\nM104 T0 S{((filament_type[0] == "PC" or filament_type[0] == "PA") ? (first_layer_temperature[0] - 25) : (filament_type[0] == "FLEX" ? 210 : 170))} ; set extruder temp for bed leveling\nM109 T0 R{((filament_type[0] == "PC" or filament_type[0] == "PA") ? (first_layer_temperature[0] - 25) : (filament_type[0] == "FLEX" ? 210 : 170))} ; wait for temp\n; home carriage, pick tool, home all\nG28 XY\nM84 E ; turn off E motor\nG28 Z\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG29 G ; absorb heat\n; move to the nozzle cleanup area\nG1 X{(min(((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))), first_layer_print_min[0])) + 32} Y{(min((first_layer_print_min[1] - 7), first_layer_print_min[1]))} Z{5} F4800\nM302 S160 ; lower cold extrusion limit to 160C\nG1 E{-(filament_type[0] == "FLEX" ? 4 : 2)} F2400 ; retraction for nozzle cleanup\n; nozzle cleanup\nM84 E ; turn off E motor\nG29 P9 X{((((first_layer_print_min[0] + first_layer_print_max[0]) / 2) < ((print_bed_min[0] + print_bed_max[0]) / 2)) ? (((first_layer_print_min[1] - 7) < -2) ? 70 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)) : (((first_layer_print_min[1] - 7) < -2) ? 260 : (min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)))} Y{(first_layer_print_min[1] - 7)} W{32} H{7}\nG0 Z10 F480 ; move away in Z\n{if first_layer_bed_temperature[0] > 60}\nG0 Z70 F480 ; move away (a bit more) in Z\nG0 X30 Y{print_bed_min[1]} F6000 ; move away in X/Y for higher bed temperatures\n{endif}\nM106 S100 ; cool off the nozzle\nM107 ; stop cooling off the nozzle - turn off the fan\n; MBL\nM84 E ; turn off E motor\nG29 P1 ; invalidate mbl & probe print area\nG29 P1 X30 Y0 W50 H20 C ; probe near purge place\nG29 P3.2 ; interpolate mbl probes\nG29 P3.13 ; extrapolate mbl outside probe area\nG29 A ; activate mbl\nM104 S[first_layer_temperature] ; set extruder temp\nG1 Z10 F720 ; move away in Z\nG0 X30 Y-8 F6000 ; move next to the sheet\n; wait for extruder temp\nM109 T0 S{first_layer_temperature[0]}\n;\n; purge\n;\nG92 E0 ; reset extruder position\nG0 X{(0 == 0 ? 30 : (0 == 1 ? 150 : (0 == 2 ? 210 : 330)))} Y{(0 < 4 ? -8 : -5.5)} ; move close to the sheet's edge\nG1 E{(filament_type[0] == "FLEX" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E10 X40 Z0.2 F500 ; purge\nG0 X70 E9 F800 ; purge\nG0 X{70 + 3} Z{0.05} F{8000} ; wipe, move close to the bed\nG0 X{70 + 3 * 2} Z0.2 F{8000} ; wipe, move quickly away from the bed\nG92 E0 ; reset extruder position\n
default_print_profile = 0.20mm QUALITY @XL 0.4
default_filament_profile = "Prusament PLA @PG"
thumbnails = 16x16,313x173,440x240
@@ -15884,7 +15904,7 @@ retract_before_travel = 1.5
retract_before_wipe = 80%
retract_layer_change = 1
retract_length = 0.8
-start_gcode = M17 ; enable steppers\nM862.3 P "[printer_model]" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM555 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4)} W{((min(print_bed_max[0], max(first_layer_print_min[0] + 32, first_layer_print_max[0])))) - ((min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))} H{((first_layer_print_max[1])) - ((max(0, first_layer_print_min[1]) - 4))}\n\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n\nM140 S[first_layer_bed_temperature] ; set bed temp\n{if filament_type[initial_tool]=="PC" or filament_type[initial_tool]=="NYLON"}\nM104 S{first_layer_temperature[initial_tool]-25} ; set extruder temp for bed leveling\nM109 R{first_layer_temperature[initial_tool]-25} ; wait for temp\n{elsif filament_type[initial_tool]=="FLEX"}\nM104 S210 ; set extruder temp for bed leveling\nM109 R210 ; wait for temp\n{else}\nM104 S170 ; set extruder temp for bed leveling\nM109 R170 ; wait for temp\n{endif}\n\nM84 E ; turn off E motor\n\nG28 ; home all without mesh bed level\n\n; probe to clean the nozzle\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)+32} Y{((first_layer_print_min[1]) - 4)} Z{5} F4800\n\nM302 S160 ; lower cold extrusion limit to 160C\n\n{if filament_type[initial_tool]=="FLEX"}\nG1 E-4 F2400 ; retraction\n{else}\nG1 E-2 F2400 ; retraction\n{endif}\n\nM84 E ; turn off E motor\n\nG29 P9 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4)} W{32} H{4}\n\n{if first_layer_bed_temperature[initial_tool]<=60}M106 S100{endif}\n\nG0 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4)} Z{40} F10000\n\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nM107\n\n;\n; MBL\n;\nM84 E ; turn off E motor\nG29 ; mesh bed leveling\nM104 S[first_layer_temperature] ; set extruder temp\nG0 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4) + 4 - 4.5} Z{30} F4800\n\nM109 S[first_layer_temperature] ; wait for extruder temp\nG1 Z0.2 F720\nG92 E0\n\nM569 S0 E ; set spreadcycle mode for extruder\n\n;\n; Extrude purge line\n;\n{if filament_type[initial_tool]=="FLEX"}\nG1 E4 F2400 ; deretraction\n{else}\nG1 E2 F2400 ; deretraction\n{endif}\n\n; move right\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32) + 32} E{32 * 0.15} F1000\n; move down\nG1 Y{(max(0, first_layer_print_min[1]) - 4) + 4 - 4.5 - 1.5} E{1.5 * 0.15} F1000\n; move left\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} E{32 * 0.30} F800\n\nG92 E0\nM221 S100 ; set flow to 100%
+start_gcode = M17 ; enable steppers\nM862.3 P "[printer_model]" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM555 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4)} W{((min(print_bed_max[0], max(first_layer_print_min[0] + 32, first_layer_print_max[0])))) - ((min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))} H{((first_layer_print_max[1])) - ((max(0, first_layer_print_min[1]) - 4))}\n\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n\nM140 S[first_layer_bed_temperature] ; set bed temp\n{if filament_type[initial_tool]=="PC" or filament_type[initial_tool]=="PA"}\nM104 S{first_layer_temperature[initial_tool]-25} ; set extruder temp for bed leveling\nM109 R{first_layer_temperature[initial_tool]-25} ; wait for temp\n{elsif filament_type[initial_tool]=="FLEX"}\nM104 S210 ; set extruder temp for bed leveling\nM109 R210 ; wait for temp\n{else}\nM104 S170 ; set extruder temp for bed leveling\nM109 R170 ; wait for temp\n{endif}\n\nM84 E ; turn off E motor\n\nG28 ; home all without mesh bed level\n\n; probe to clean the nozzle\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)+32} Y{((first_layer_print_min[1]) - 4)} Z{5} F4800\n\nM302 S160 ; lower cold extrusion limit to 160C\n\n{if filament_type[initial_tool]=="FLEX"}\nG1 E-4 F2400 ; retraction\n{else}\nG1 E-2 F2400 ; retraction\n{endif}\n\nM84 E ; turn off E motor\n\nG29 P9 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4)} W{32} H{4}\n\n{if first_layer_bed_temperature[initial_tool]<=60}M106 S100{endif}\n\nG0 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4)} Z{40} F10000\n\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nM107\n\n;\n; MBL\n;\nM84 E ; turn off E motor\nG29 ; mesh bed leveling\nM104 S[first_layer_temperature] ; set extruder temp\nG0 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4) + 4 - 4.5} Z{30} F4800\n\nM109 S[first_layer_temperature] ; wait for extruder temp\nG1 Z0.2 F720\nG92 E0\n\nM569 S0 E ; set spreadcycle mode for extruder\n\n;\n; Extrude purge line\n;\n{if filament_type[initial_tool]=="FLEX"}\nG1 E4 F2400 ; deretraction\n{else}\nG1 E2 F2400 ; deretraction\n{endif}\n\n; move right\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32) + 32} E{32 * 0.15} F1000\n; move down\nG1 Y{(max(0, first_layer_print_min[1]) - 4) + 4 - 4.5 - 1.5} E{1.5 * 0.15} F1000\n; move left\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} E{32 * 0.30} F800\n\nG92 E0\nM221 S100 ; set flow to 100%
default_print_profile = 0.20mm QUALITY @MK4 0.4
default_filament_profile = "Prusament PLA @PG"
thumbnails = 16x16,313x173,440x240
diff --git a/resources/profiles/Templates.idx b/resources/profiles/Templates.idx
index 297aeb1fee..728a7da353 100644
--- a/resources/profiles/Templates.idx
+++ b/resources/profiles/Templates.idx
@@ -1,3 +1,4 @@
min_slic3r_version = 2.6.0-alpha0
+1.0.2 Updated compatible printer conditions.
1.0.1 Added Prusament PETG Carbon Fiber, Fiberthree F3 PA-GF30 Pro.
1.0.0 Initial
diff --git a/resources/profiles/Templates.ini b/resources/profiles/Templates.ini
index cf7b8ebe8f..d038d572db 100644
--- a/resources/profiles/Templates.ini
+++ b/resources/profiles/Templates.ini
@@ -2,7 +2,7 @@
[vendor]
name = Templates
-config_version = 1.0.1
+config_version = 1.0.2
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Templates/
templates_profile = 1
@@ -11,12 +11,12 @@ templates_profile = 1
[filament:*common*]
cooling = 1
compatible_printers =
-compatible_printers_condition =
+compatible_printers_condition = printer_notes!~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes!~/.*PRINTER_MODEL_MK4IS.*/
end_filament_gcode = "; Filament-specific end gcode"
extrusion_multiplier = 1
filament_loading_speed = 14
filament_loading_speed_start = 19
-filament_unloading_speed = 90
+filament_unloading_speed = 20
filament_unloading_speed_start = 100
filament_toolchange_delay = 0
filament_cooling_moves = 1
@@ -1460,7 +1460,6 @@ cooling = 0
fan_always_on = 0
filament_max_volumetric_speed = 4
filament_type = METAL
-compatible_printers_condition = nozzle_diameter[0]>=0.4
filament_colour = #FFFFFF
[filament:Polymaker PC-Max]
@@ -1519,7 +1518,6 @@ first_layer_temperature = 230
max_fan_speed = 20
min_fan_speed = 20
temperature = 230
-compatible_printers_condition = nozzle_diameter[0]!=0.8 and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:Prusa PETG]
inherits = *PET*
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index dff8aea9f7..5aed978426 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -166,6 +166,8 @@ namespace ImGui
const wchar_t PauseHoverButton = 0x261B;
const wchar_t OpenButton = 0x261C;
const wchar_t OpenHoverButton = 0x261D;
+ const wchar_t SlaViewOriginal = 0x261E;
+ const wchar_t SlaViewProcessed = 0x261F;
const wchar_t LegendTravel = 0x2701;
const wchar_t LegendWipe = 0x2702;
diff --git a/src/libslic3r/Algorithm/PathSorting.hpp b/src/libslic3r/Algorithm/PathSorting.hpp
new file mode 100644
index 0000000000..ab44627281
--- /dev/null
+++ b/src/libslic3r/Algorithm/PathSorting.hpp
@@ -0,0 +1,128 @@
+#ifndef SRC_LIBSLIC3R_PATH_SORTING_HPP_
+#define SRC_LIBSLIC3R_PATH_SORTING_HPP_
+
+#include "AABBTreeLines.hpp"
+#include "BoundingBox.hpp"
+#include "Line.hpp"
+#include "ankerl/unordered_dense.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Slic3r {
+namespace Algorithm {
+
+//Sorts the paths such that all paths between begin and last_seed are printed first, in some order. The rest of the paths is sorted
+// such that the paths that are touching some of the already printed are printed first, sorted secondary by the distance to the last point of the last
+// printed path.
+// begin, end, and last_seed are random access iterators. touch_limit_distance is used to check if the paths are touching - if any part of the path gets this close
+// to the second, then they touch.
+// convert_to_lines is a lambda that should accept the path as argument and return it as Lines vector, in correct order.
+template
+void sort_paths(RandomAccessIterator begin, RandomAccessIterator end, Point start, double touch_limit_distance, ToLines convert_to_lines)
+{
+ size_t paths_count = std::distance(begin, end);
+ if (paths_count <= 1)
+ return;
+
+ auto paths_touch = [touch_limit_distance](const AABBTreeLines::LinesDistancer &left,
+ const AABBTreeLines::LinesDistancer &right) {
+ for (const Line &l : left.get_lines()) {
+ if (right.distance_from_lines(l.a) < touch_limit_distance) {
+ return true;
+ }
+ }
+ if (right.distance_from_lines(left.get_lines().back().b) < touch_limit_distance) {
+ return true;
+ }
+
+ for (const Line &l : right.get_lines()) {
+ if (left.distance_from_lines(l.a) < touch_limit_distance) {
+ return true;
+ }
+ }
+ if (left.distance_from_lines(right.get_lines().back().b) < touch_limit_distance) {
+ return true;
+ }
+ return false;
+ };
+
+ std::vector> distancers(paths_count);
+ for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
+ distancers[path_idx] = AABBTreeLines::LinesDistancer{convert_to_lines(*std::next(begin, path_idx))};
+ }
+
+ std::vector> dependencies(paths_count);
+ for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
+ for (size_t next_path_idx = path_idx + 1; next_path_idx < paths_count; next_path_idx++) {
+ if (paths_touch(distancers[path_idx], distancers[next_path_idx])) {
+ dependencies[next_path_idx].insert(path_idx);
+ }
+ }
+ }
+
+ Point current_point = start;
+
+ std::vector> correct_order_and_direction(paths_count);
+ size_t unsorted_idx = 0;
+ size_t null_idx = size_t(-1);
+ size_t next_idx = null_idx;
+ bool reverse = false;
+ while (unsorted_idx < paths_count) {
+ next_idx = null_idx;
+ double lines_dist = std::numeric_limits::max();
+ for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
+ if (!dependencies[path_idx].empty())
+ continue;
+
+ double ldist = distancers[path_idx].distance_from_lines(current_point);
+ if (ldist < lines_dist) {
+ const auto &lines = distancers[path_idx].get_lines();
+ double dist_a = (lines.front().a - current_point).cast().squaredNorm();
+ double dist_b = (lines.back().b - current_point).cast().squaredNorm();
+ next_idx = path_idx;
+ reverse = dist_b < dist_a;
+ lines_dist = ldist;
+ }
+ }
+
+ // we have valid next_idx, sort it, update dependencies, update current point
+ correct_order_and_direction[next_idx] = {unsorted_idx, reverse};
+ unsorted_idx++;
+ current_point = reverse ? distancers[next_idx].get_lines().front().a : distancers[next_idx].get_lines().back().b;
+
+ dependencies[next_idx].insert(null_idx); // prevent it from being selected again
+ for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
+ dependencies[path_idx].erase(next_idx);
+ }
+ }
+
+ for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
+ if (correct_order_and_direction[path_idx].second) {
+ std::next(begin, path_idx)->reverse();
+ }
+ }
+
+ for (size_t i = 0; i < correct_order_and_direction.size() - 1; i++) {
+ bool swapped = false;
+ for (size_t j = 0; j < correct_order_and_direction.size() - i - 1; j++) {
+ if (correct_order_and_direction[j].first > correct_order_and_direction[j + 1].first) {
+ std::swap(correct_order_and_direction[j], correct_order_and_direction[j + 1]);
+ std::iter_swap(std::next(begin, j), std::next(begin, j + 1));
+ swapped = true;
+ }
+ }
+ if (swapped == false) {
+ break;
+ }
+ }
+}
+
+}} // namespace Slic3r::Algorithm
+
+#endif /*SRC_LIBSLIC3R_PATH_SORTING_HPP_*/
\ No newline at end of file
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index d44bfcde09..b94f94d9b7 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -22,8 +22,9 @@ set(SLIC3R_SOURCES
AABBTreeLines.hpp
AABBMesh.hpp
AABBMesh.cpp
- Algorithm/RegionExpansion.cpp
+ Algorithm/PathSorting.hpp
Algorithm/RegionExpansion.hpp
+ Algorithm/RegionExpansion.cpp
AnyPtr.hpp
BoundingBox.cpp
BoundingBox.hpp
@@ -131,6 +132,8 @@ set(SLIC3R_SOURCES
Format/AnycubicSLA.cpp
Format/STEP.hpp
Format/STEP.cpp
+ Format/SLAArchiveFormatRegistry.hpp
+ Format/SLAArchiveFormatRegistry.cpp
GCode/ThumbnailData.cpp
GCode/ThumbnailData.hpp
GCode/Thumbnails.cpp
diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp
index a6e5e1fb4a..abf4b1a2b3 100644
--- a/src/libslic3r/Fill/Fill.cpp
+++ b/src/libslic3r/Fill/Fill.cpp
@@ -306,47 +306,15 @@ std::vector group_fills(const Layer &layer)
}
}
- // Detect narrow internal solid infill area and use ipEnsuring pattern instead.
- {
- std::vector narrow_expolygons;
- static constexpr const auto narrow_pattern = ipEnsuring;
- for (size_t surface_fill_id = 0, num_old_fills = surface_fills.size(); surface_fill_id < num_old_fills; ++ surface_fill_id)
- if (SurfaceFill &fill = surface_fills[surface_fill_id]; fill.surface.surface_type == stInternalSolid) {
- size_t num_expolygons = fill.expolygons.size();
- narrow_expolygons.clear();
- narrow_expolygons.reserve(num_expolygons);
- // Detect narrow expolygons.
- int num_narrow = 0;
- for (const ExPolygon &ex : fill.expolygons) {
- bool narrow = offset_ex(ex, -scaled(NarrowInfillAreaThresholdMM)).empty();
- num_narrow += int(narrow);
- narrow_expolygons.emplace_back(narrow);
- }
- if (num_narrow == num_expolygons) {
- // All expolygons are narrow, change the fill pattern.
- fill.params.pattern = narrow_pattern;
- } else if (num_narrow > 0) {
- // Some expolygons are narrow, split the fills.
- params = fill.params;
- params.pattern = narrow_pattern;
- surface_fills.emplace_back(params);
- SurfaceFill &old_fill = surface_fills[surface_fill_id];
- SurfaceFill &new_fill = surface_fills.back();
- new_fill.region_id = old_fill.region_id;
- new_fill.surface.surface_type = stInternalSolid;
- new_fill.surface.thickness = old_fill.surface.thickness;
- new_fill.expolygons.reserve(num_narrow);
- for (size_t i = 0; i < narrow_expolygons.size(); ++ i)
- if (narrow_expolygons[i])
- new_fill.expolygons.emplace_back(std::move(old_fill.expolygons[i]));
- old_fill.expolygons.erase(std::remove_if(old_fill.expolygons.begin(), old_fill.expolygons.end(),
- [&narrow_expolygons, ex_first = old_fill.expolygons.data()](const ExPolygon& ex) { return narrow_expolygons[&ex - ex_first]; }),
- old_fill.expolygons.end());
- }
- }
- }
+ // Use ipEnsuring pattern for all internal Solids.
+ {
+ for (size_t surface_fill_id = 0; surface_fill_id < surface_fills.size(); ++surface_fill_id)
+ if (SurfaceFill &fill = surface_fills[surface_fill_id]; fill.surface.surface_type == stInternalSolid) {
+ fill.params.pattern = ipEnsuring;
+ }
+ }
- return surface_fills;
+ return surface_fills;
}
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp
index cf37667587..4130cc3313 100644
--- a/src/libslic3r/Fill/FillBase.hpp
+++ b/src/libslic3r/Fill/FillBase.hpp
@@ -147,9 +147,9 @@ protected:
virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; }
- virtual std::pair _infill_direction(const Surface *surface) const;
public:
+ virtual std::pair _infill_direction(const Surface *surface) const;
static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
static void connect_infill(Polylines &&infill_ordered, const std::vector &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams ¶ms);
diff --git a/src/libslic3r/Fill/FillEnsuring.cpp b/src/libslic3r/Fill/FillEnsuring.cpp
index 2522aee938..4838ad8d26 100644
--- a/src/libslic3r/Fill/FillEnsuring.cpp
+++ b/src/libslic3r/Fill/FillEnsuring.cpp
@@ -2,81 +2,472 @@
#include "../ShortestPath.hpp"
#include "../Arachne/WallToolPaths.hpp"
+#include "AABBTreeLines.hpp"
+#include "Algorithm/PathSorting.hpp"
+#include "BoundingBox.hpp"
+#include "ExPolygon.hpp"
#include "FillEnsuring.hpp"
+#include "KDTreeIndirect.hpp"
+#include "Line.hpp"
+#include "Point.hpp"
+#include "Polygon.hpp"
+#include "Polyline.hpp"
+#include "SVG.hpp"
+#include "libslic3r.h"
+#include
#include
+#include
+#include
+#include
+#include
+#include
namespace Slic3r {
-ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const FillParams ¶ms)
+ThickPolylines make_fill_polylines(
+ const Fill *fill, const Surface *surface, const FillParams ¶ms, bool stop_vibrations, bool fill_gaps, bool connect_extrusions)
{
- assert(params.use_arachne);
- assert(this->print_config != nullptr && this->print_object_config != nullptr && this->print_region_config != nullptr);
+ assert(fill->print_config != nullptr && fill->print_object_config != nullptr);
- const coord_t scaled_spacing = scaled(this->spacing);
-
- // Perform offset.
- Slic3r::ExPolygons expp = this->overlap != 0. ? offset_ex(surface->expolygon, scaled(this->overlap)) : ExPolygons{surface->expolygon};
- // Create the infills for each of the regions.
- ThickPolylines thick_polylines_out;
- for (ExPolygon &ex_poly : expp) {
- Point bbox_size = ex_poly.contour.bounding_box().size();
- coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / scaled_spacing + 1;
- Polygons polygons = to_polygons(ex_poly);
- Arachne::WallToolPaths wall_tool_paths(polygons, scaled_spacing, scaled_spacing, loops_count, 0, params.layer_height, *this->print_object_config, *this->print_config);
- if (std::vector loops = wall_tool_paths.getToolPaths(); !loops.empty()) {
- std::vector all_extrusions;
- for (Arachne::VariableWidthLines &loop : loops) {
- if (loop.empty())
- continue;
- for (const Arachne::ExtrusionLine &wall : loop)
- all_extrusions.emplace_back(&wall);
+ auto rotate_thick_polylines = [](ThickPolylines &tpolylines, double cos_angle, double sin_angle) {
+ for (ThickPolyline &tp : tpolylines) {
+ for (auto &p : tp.points) {
+ double px = double(p.x());
+ double py = double(p.y());
+ p.x() = coord_t(round(cos_angle * px - sin_angle * py));
+ p.y() = coord_t(round(cos_angle * py + sin_angle * px));
}
+ }
+ };
- // Split paths using a nearest neighbor search.
- size_t firts_poly_idx = thick_polylines_out.size();
- Point last_pos(0, 0);
- for (const Arachne::ExtrusionLine *extrusion : all_extrusions) {
- if (extrusion->empty())
- continue;
+ auto segments_overlap = [](coord_t alow, coord_t ahigh, coord_t blow, coord_t bhigh) {
+ return (alow >= blow && alow <= bhigh) || (ahigh >= blow && ahigh <= bhigh) || (blow >= alow && blow <= ahigh) ||
+ (bhigh >= alow && bhigh <= ahigh);
+ };
- ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion);
- if (thick_polyline.length() == 0.)
- //FIXME this should not happen.
- continue;
- assert(thick_polyline.size() > 1);
- assert(thick_polyline.length() > 0.);
- //assert(thick_polyline.points.size() == thick_polyline.width.size());
- if (extrusion->is_closed)
- thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, last_pos));
+ const coord_t scaled_spacing = scaled(fill->spacing);
+ double distance_limit_reconnection = 2.0 * double(scaled_spacing);
+ double squared_distance_limit_reconnection = distance_limit_reconnection * distance_limit_reconnection;
+ Polygons filled_area = to_polygons(surface->expolygon);
+ std::pair rotate_vector = fill->_infill_direction(surface);
+ double aligning_angle = -rotate_vector.first + PI;
+ polygons_rotate(filled_area, aligning_angle);
+ BoundingBox bb = get_extents(filled_area);
- assert(thick_polyline.size() > 1);
- //assert(thick_polyline.points.size() == thick_polyline.width.size());
- thick_polylines_out.emplace_back(std::move(thick_polyline));
- last_pos = thick_polylines_out.back().last_point();
- }
+ Polygons inner_area = stop_vibrations ? intersection(filled_area, opening(filled_area, 2 * scaled_spacing, 3 * scaled_spacing)) :
+ filled_area;
+
+ inner_area = shrink(inner_area, scaled_spacing * 0.5 - scaled(fill->overlap));
+
+ AABBTreeLines::LinesDistancer area_walls{to_lines(inner_area)};
- // clip the paths to prevent the extruder from getting exactly on the first point of the loop
- // Keep valid paths only.
- size_t j = firts_poly_idx;
- for (size_t i = firts_poly_idx; i < thick_polylines_out.size(); ++i) {
- assert(thick_polylines_out[i].size() > 1);
- assert(thick_polylines_out[i].length() > 0.);
- //assert(thick_polylines_out[i].points.size() == thick_polylines_out[i].width.size());
- thick_polylines_out[i].clip_end(this->loop_clipping);
- assert(thick_polylines_out[i].size() > 1);
- if (thick_polylines_out[i].is_valid()) {
- if (j < i)
- thick_polylines_out[j] = std::move(thick_polylines_out[i]);
- ++j;
+ const size_t n_vlines = (bb.max.x() - bb.min.x() + scaled_spacing - 1) / scaled_spacing;
+ std::vector vertical_lines(n_vlines);
+ coord_t y_min = bb.min.y();
+ coord_t y_max = bb.max.y();
+ for (size_t i = 0; i < n_vlines; i++) {
+ coord_t x = bb.min.x() + i * double(scaled_spacing);
+ vertical_lines[i].a = Point{x, y_min};
+ vertical_lines[i].b = Point{x, y_max};
+ }
+ if (vertical_lines.size() > 0) {
+ vertical_lines.push_back(vertical_lines.back());
+ vertical_lines.back().a = Point{coord_t(bb.min.x() + n_vlines * double(scaled_spacing) + scaled_spacing * 0.5), y_min};
+ vertical_lines.back().b = Point{vertical_lines.back().a.x(), y_max};
+ }
+
+ std::vector> polygon_sections(n_vlines);
+
+ for (size_t i = 0; i < n_vlines; i++) {
+ const auto intersections = area_walls.intersections_with_line(vertical_lines[i]);
+
+ for (int intersection_idx = 0; intersection_idx < int(intersections.size()) - 1; intersection_idx++) {
+ const auto &a = intersections[intersection_idx];
+ const auto &b = intersections[intersection_idx + 1];
+ if (area_walls.outside((a.first + b.first) / 2) < 0) {
+ if (std::abs(a.first.y() - b.first.y()) > scaled_spacing) {
+ polygon_sections[i].emplace_back(a.first, b.first);
}
}
- if (j < thick_polylines_out.size())
- thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end());
}
}
- return thick_polylines_out;
+ if (stop_vibrations) {
+ struct Node
+ {
+ int section_idx;
+ int line_idx;
+ int skips_taken = 0;
+ bool neighbours_explored = false;
+ std::vector> neighbours{};
+ };
+
+ coord_t length_filter = scale_(4);
+ size_t skips_allowed = 2;
+ size_t min_removal_conut = 5;
+ for (int section_idx = 0; section_idx < polygon_sections.size(); section_idx++) {
+ for (int line_idx = 0; line_idx < polygon_sections[section_idx].size(); line_idx++) {
+ if (const Line &line = polygon_sections[section_idx][line_idx]; line.a != line.b && line.length() < length_filter) {
+ std::set> to_remove{{section_idx, line_idx}};
+ std::vector to_visit{{section_idx, line_idx}};
+
+ bool initial_touches_long_lines = false;
+ if (section_idx > 0) {
+ for (int prev_line_idx = 0; prev_line_idx < polygon_sections[section_idx - 1].size(); prev_line_idx++) {
+ if (const Line &nl = polygon_sections[section_idx - 1][prev_line_idx];
+ nl.a != nl.b && segments_overlap(line.a.y(), line.b.y(), nl.a.y(), nl.b.y())) {
+ initial_touches_long_lines = true;
+ }
+ }
+ }
+
+ while (!to_visit.empty()) {
+ Node curr = to_visit.back();
+ const Line &curr_l = polygon_sections[curr.section_idx][curr.line_idx];
+ if (curr.neighbours_explored) {
+ bool is_valid_for_removal = (curr_l.length() < length_filter) &&
+ ((int(to_remove.size()) - curr.skips_taken > min_removal_conut) ||
+ (curr.neighbours.empty() && !initial_touches_long_lines));
+ if (!is_valid_for_removal) {
+ for (const auto &n : curr.neighbours) {
+ if (to_remove.find(n) != to_remove.end()) {
+ is_valid_for_removal = true;
+ break;
+ }
+ }
+ }
+ if (!is_valid_for_removal) {
+ to_remove.erase({curr.section_idx, curr.line_idx});
+ }
+ to_visit.pop_back();
+ } else {
+ to_visit.back().neighbours_explored = true;
+ int curr_index = to_visit.size() - 1;
+ bool can_use_skip = curr_l.length() <= length_filter && curr.skips_taken < skips_allowed;
+ if (curr.section_idx + 1 < polygon_sections.size()) {
+ for (int lidx = 0; lidx < polygon_sections[curr.section_idx + 1].size(); lidx++) {
+ if (const Line &nl = polygon_sections[curr.section_idx + 1][lidx];
+ nl.a != nl.b && segments_overlap(curr_l.a.y(), curr_l.b.y(), nl.a.y(), nl.b.y()) &&
+ (nl.length() < length_filter || can_use_skip)) {
+ to_visit[curr_index].neighbours.push_back({curr.section_idx + 1, lidx});
+ to_remove.insert({curr.section_idx + 1, lidx});
+ Node next_node{curr.section_idx + 1, lidx, curr.skips_taken + (nl.length() >= length_filter)};
+ to_visit.push_back(next_node);
+ }
+ }
+ }
+ }
+ }
+
+ for (const auto &pair : to_remove) {
+ Line &l = polygon_sections[pair.first][pair.second];
+ l.a = l.b;
+ }
+ }
+ }
+ }
+ }
+
+ for (size_t section_idx = 0; section_idx < polygon_sections.size(); section_idx++) {
+ polygon_sections[section_idx].erase(std::remove_if(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(),
+ [](const Line &s) { return s.a == s.b; }),
+ polygon_sections[section_idx].end());
+ std::sort(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(),
+ [](const Line &a, const Line &b) { return a.a.y() < b.b.y(); });
+ }
+
+ ThickPolylines thick_polylines;
+ {
+ for (const auto &polygon_slice : polygon_sections) {
+ for (const Line &segment : polygon_slice) {
+ ThickPolyline &new_path = thick_polylines.emplace_back();
+ new_path.points.push_back(segment.a);
+ new_path.width.push_back(scaled_spacing);
+ new_path.points.push_back(segment.b);
+ new_path.width.push_back(scaled_spacing);
+ new_path.endpoints = {true, true};
+ }
+ }
+ }
+
+ if (fill_gaps) {
+ Polygons reconstructed_area{};
+ // reconstruct polygon from polygon sections
+ {
+ struct TracedPoly
+ {
+ Points lows;
+ Points highs;
+ };
+
+ std::vector> polygon_sections_w_width = polygon_sections;
+ for (auto &slice : polygon_sections_w_width) {
+ for (Line &l : slice) {
+ l.a -= Point{0.0, 0.5 * scaled_spacing};
+ l.b += Point{0.0, 0.5 * scaled_spacing};
+ }
+ }
+
+ std::vector current_traced_polys;
+ for (const auto &polygon_slice : polygon_sections_w_width) {
+ std::unordered_set used_segments;
+ for (TracedPoly &traced_poly : current_traced_polys) {
+ auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
+ [](const Point &low, const Line &seg) { return seg.b.y() > low.y(); });
+ auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(),
+ [](const Point &high, const Line &seg) { return seg.a.y() > high.y(); });
+
+ bool segment_added = false;
+ for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) {
+ if (used_segments.find(&(*candidate)) != used_segments.end()) {
+ continue;
+ }
+ if (connect_extrusions && (traced_poly.lows.back() - candidates_begin->a).cast().squaredNorm() <
+ squared_distance_limit_reconnection) {
+ traced_poly.lows.push_back(candidates_begin->a);
+ } else {
+ traced_poly.lows.push_back(traced_poly.lows.back() + Point{scaled_spacing / 2, 0});
+ traced_poly.lows.push_back(candidates_begin->a - Point{scaled_spacing / 2, 0});
+ traced_poly.lows.push_back(candidates_begin->a);
+ }
+
+ if (connect_extrusions && (traced_poly.highs.back() - candidates_begin->b).cast().squaredNorm() <
+ squared_distance_limit_reconnection) {
+ traced_poly.highs.push_back(candidates_begin->b);
+ } else {
+ traced_poly.highs.push_back(traced_poly.highs.back() + Point{scaled_spacing / 2, 0});
+ traced_poly.highs.push_back(candidates_begin->b - Point{scaled_spacing / 2, 0});
+ traced_poly.highs.push_back(candidates_begin->b);
+ }
+ segment_added = true;
+ used_segments.insert(&(*candidates_begin));
+ }
+
+ if (!segment_added) {
+ // Zero or multiple overlapping segments. Resolving this is nontrivial,
+ // so we just close this polygon and maybe open several new. This will hopefully happen much less often
+ traced_poly.lows.push_back(traced_poly.lows.back() + Point{scaled_spacing / 2, 0});
+ traced_poly.highs.push_back(traced_poly.highs.back() + Point{scaled_spacing / 2, 0});
+ Polygon &new_poly = reconstructed_area.emplace_back(std::move(traced_poly.lows));
+ new_poly.points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
+ traced_poly.lows.clear();
+ traced_poly.highs.clear();
+ }
+ }
+
+ current_traced_polys.erase(std::remove_if(current_traced_polys.begin(), current_traced_polys.end(),
+ [](const TracedPoly &tp) { return tp.lows.empty(); }),
+ current_traced_polys.end());
+
+ for (const auto &segment : polygon_slice) {
+ if (used_segments.find(&segment) == used_segments.end()) {
+ TracedPoly &new_tp = current_traced_polys.emplace_back();
+ new_tp.lows.push_back(segment.a - Point{scaled_spacing / 2, 0});
+ new_tp.lows.push_back(segment.a);
+ new_tp.highs.push_back(segment.b - Point{scaled_spacing / 2, 0});
+ new_tp.highs.push_back(segment.b);
+ }
+ }
+ }
+
+ // add not closed polys
+ for (TracedPoly &traced_poly : current_traced_polys) {
+ Polygon &new_poly = reconstructed_area.emplace_back(std::move(traced_poly.lows));
+ new_poly.points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
+ }
+ }
+
+ reconstructed_area = union_safety_offset(reconstructed_area);
+ ExPolygons gaps_for_additional_filling = diff_ex(filled_area, reconstructed_area);
+ if (fill->overlap != 0) {
+ gaps_for_additional_filling = offset_ex(gaps_for_additional_filling, scaled(fill->overlap));
+ }
+
+ // BoundingBox bbox = get_extents(filled_area);
+ // bbox.offset(scale_(1.));
+ // ::Slic3r::SVG svg(debug_out_path(("surface" + std::to_string(surface->area())).c_str()).c_str(), bbox);
+ // svg.draw(to_lines(filled_area), "red", scale_(0.4));
+ // svg.draw(to_lines(reconstructed_area), "blue", scale_(0.3));
+ // svg.draw(to_lines(gaps_for_additional_filling), "green", scale_(0.2));
+ // svg.draw(vertical_lines, "black", scale_(0.1));
+ // svg.Close();
+
+ for (ExPolygon &ex_poly : gaps_for_additional_filling) {
+ BoundingBox ex_bb = ex_poly.contour.bounding_box();
+ coord_t loops_count = (std::max(ex_bb.size().x(), ex_bb.size().y()) + scaled_spacing - 1) / scaled_spacing;
+ Polygons polygons = to_polygons(ex_poly);
+ Arachne::WallToolPaths wall_tool_paths(polygons, scaled_spacing, scaled_spacing, loops_count, 0, params.layer_height,
+ *fill->print_object_config, *fill->print_config);
+ if (std::vector loops = wall_tool_paths.getToolPaths(); !loops.empty()) {
+ std::vector all_extrusions;
+ for (Arachne::VariableWidthLines &loop : loops) {
+ if (loop.empty())
+ continue;
+ for (const Arachne::ExtrusionLine &wall : loop)
+ all_extrusions.emplace_back(&wall);
+ }
+
+ for (const Arachne::ExtrusionLine *extrusion : all_extrusions) {
+ if (extrusion->junctions.size() < 2) {
+ continue;
+ }
+ ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion);
+ if (extrusion->is_closed) {
+ thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, ex_bb.min));
+ thick_polyline.clip_end(scaled_spacing * 0.5);
+ }
+ if (thick_polyline.is_valid() && thick_polyline.length() > 0 && thick_polyline.points.size() > 1) {
+ thick_polylines.push_back(thick_polyline);
+ }
+ }
+ }
+ }
+
+ std::sort(thick_polylines.begin(), thick_polylines.end(), [](const ThickPolyline &left, const ThickPolyline &right) {
+ BoundingBox lbb(left.points);
+ BoundingBox rbb(right.points);
+ if (lbb.min.x() == rbb.min.x())
+ return lbb.min.y() < rbb.min.y();
+ else
+ return lbb.min.x() < rbb.min.x();
+ });
+
+ // connect tiny gap fills to close colinear line
+ struct EndPoint
+ {
+ Vec2d position;
+ size_t polyline_idx;
+ size_t other_end_point_idx;
+ bool is_first;
+ bool used = false;
+ };
+ std::vector connection_endpoints;
+ connection_endpoints.reserve(thick_polylines.size() * 2);
+ for (size_t pl_idx = 0; pl_idx < thick_polylines.size(); pl_idx++) {
+ size_t current_idx = connection_endpoints.size();
+ connection_endpoints.push_back({thick_polylines[pl_idx].first_point().cast(), pl_idx, current_idx + 1, true});
+ connection_endpoints.push_back({thick_polylines[pl_idx].last_point().cast(), pl_idx, current_idx, false});
+ }
+
+ std::vector linear_segment_flags(thick_polylines.size());
+ for (size_t i = 0;i < thick_polylines.size(); i++) {
+ const ThickPolyline& tp = thick_polylines[i];
+ linear_segment_flags[i] = tp.points.size() == 2 && tp.points.front().x() == tp.points.back().x() &&
+ tp.width.front() == scaled_spacing && tp.width.back() == scaled_spacing;
+ }
+
+ auto coord_fn = [&connection_endpoints](size_t idx, size_t dim) { return connection_endpoints[idx].position[dim]; };
+ KDTreeIndirect<2, double, decltype(coord_fn)> endpoints_tree{coord_fn, connection_endpoints.size()};
+ for (size_t ep_idx = 0; ep_idx < connection_endpoints.size(); ep_idx++) {
+ EndPoint &ep1 = connection_endpoints[ep_idx];
+ if (!ep1.used) {
+ std::vector close_endpoints = find_nearby_points(endpoints_tree, ep1.position, double(scaled_spacing));
+ for (size_t close_endpoint_idx : close_endpoints) {
+ EndPoint &ep2 = connection_endpoints[close_endpoint_idx];
+ if (ep2.used || ep2.polyline_idx == ep1.polyline_idx ||
+ (linear_segment_flags[ep1.polyline_idx] && linear_segment_flags[ep2.polyline_idx])) {
+ continue;
+ }
+
+ EndPoint &target_ep = ep1.polyline_idx > ep2.polyline_idx ? ep1 : ep2;
+ EndPoint &source_ep = ep1.polyline_idx > ep2.polyline_idx ? ep2 : ep1;
+
+ ThickPolyline &target_tp = thick_polylines[target_ep.polyline_idx];
+ ThickPolyline &source_tp = thick_polylines[source_ep.polyline_idx];
+ linear_segment_flags[target_ep.polyline_idx] = linear_segment_flags[ep1.polyline_idx] ||
+ linear_segment_flags[ep2.polyline_idx];
+
+ Vec2d v1 = target_ep.is_first ?
+ (target_tp.points[0] - target_tp.points[1]).cast() :
+ (target_tp.points.back() - target_tp.points[target_tp.points.size() - 1]).cast();
+ Vec2d v2 = source_ep.is_first ?
+ (source_tp.points[1] - source_tp.points[0]).cast() :
+ (source_tp.points[source_tp.points.size() - 1] - source_tp.points.back()).cast();
+
+ if (std::abs(Slic3r::angle(v1, v2)) > PI / 6.0) {
+ continue;
+ }
+
+ // connect target_ep and source_ep, result is stored in target_tp, source_tp will be cleared
+ if (target_ep.is_first) {
+ target_tp.reverse();
+ target_ep.is_first = false;
+ connection_endpoints[target_ep.other_end_point_idx].is_first = true;
+ }
+
+ size_t new_start_idx = target_ep.other_end_point_idx;
+
+ if (!source_ep.is_first) {
+ source_tp.reverse();
+ source_ep.is_first = true;
+ connection_endpoints[source_ep.other_end_point_idx].is_first = false;
+ }
+
+ size_t new_end_idx = source_ep.other_end_point_idx;
+
+ target_tp.points.insert(target_tp.points.end(), source_tp.points.begin(), source_tp.points.end());
+ target_tp.width.push_back(target_tp.width.back());
+ target_tp.width.push_back(source_tp.width.front());
+ target_tp.width.insert(target_tp.width.end(), source_tp.width.begin(), source_tp.width.end());
+ target_ep.used = true;
+ source_ep.used = true;
+
+ connection_endpoints[new_start_idx].polyline_idx = target_ep.polyline_idx;
+ connection_endpoints[new_end_idx].polyline_idx = target_ep.polyline_idx;
+ connection_endpoints[new_start_idx].other_end_point_idx = new_end_idx;
+ connection_endpoints[new_end_idx].other_end_point_idx = new_start_idx;
+ source_tp.clear();
+ break;
+ }
+ }
+ }
+
+ thick_polylines.erase(std::remove_if(thick_polylines.begin(), thick_polylines.end(),
+ [scaled_spacing](const ThickPolyline &tp) {
+ return tp.length() < scaled_spacing &&
+ std::all_of(tp.width.begin(), tp.width.end(),
+ [scaled_spacing](double w) { return w < scaled_spacing; });
+ }),
+ thick_polylines.end());
+ }
+
+ Algorithm::sort_paths(thick_polylines.begin(), thick_polylines.end(), bb.min, double(scaled_spacing) * 1.2, [](const ThickPolyline &tp) {
+ Lines ls;
+ Point prev = tp.first_point();
+ for (size_t i = 1; i < tp.points.size(); i++) {
+ ls.emplace_back(prev, tp.points[i]);
+ prev = ls.back().b;
+ }
+ return ls;
+ });
+
+ if (connect_extrusions) {
+ ThickPolylines connected_thick_polylines;
+ if (!thick_polylines.empty()) {
+ connected_thick_polylines.push_back(thick_polylines.front());
+ for (size_t tp_idx = 1; tp_idx < thick_polylines.size(); tp_idx++) {
+ ThickPolyline &tp = thick_polylines[tp_idx];
+ ThickPolyline &tail = connected_thick_polylines.back();
+ Point last = tail.last_point();
+ if ((last - tp.last_point()).cast().squaredNorm() < (last - tp.first_point()).cast().squaredNorm()) {
+ tp.reverse();
+ }
+ if ((last - tp.first_point()).cast().squaredNorm() < squared_distance_limit_reconnection) {
+ tail.points.insert(tail.points.end(), tp.points.begin(), tp.points.end());
+ tail.width.push_back(scaled_spacing);
+ tail.width.push_back(scaled_spacing);
+ tail.width.insert(tail.width.end(), tp.width.begin(), tp.width.end());
+ } else {
+ connected_thick_polylines.push_back(tp);
+ }
+ }
+ }
+ thick_polylines = connected_thick_polylines;
+ }
+
+ rotate_thick_polylines(thick_polylines, cos(-aligning_angle), sin(-aligning_angle));
+ return thick_polylines;
}
} // namespace Slic3r
diff --git a/src/libslic3r/Fill/FillEnsuring.hpp b/src/libslic3r/Fill/FillEnsuring.hpp
index faa0801535..c20c93aff8 100644
--- a/src/libslic3r/Fill/FillEnsuring.hpp
+++ b/src/libslic3r/Fill/FillEnsuring.hpp
@@ -6,13 +6,19 @@
namespace Slic3r {
-class FillEnsuring : public FillRectilinear
+ThickPolylines make_fill_polylines(
+ const Fill *fill, const Surface *surface, const FillParams ¶ms, bool stop_vibrations, bool fill_gaps, bool connect_extrusions);
+
+class FillEnsuring : public Fill
{
public:
Fill *clone() const override { return new FillEnsuring(*this); }
~FillEnsuring() override = default;
Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override { return {}; };
- ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms) override;
+ ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms) override
+ {
+ return make_fill_polylines(this, surface, params, true, true, true);
+ };
protected:
void fill_surface_single_arachne(const Surface &surface, const FillParams ¶ms, ThickPolylines &thick_polylines_out);
diff --git a/src/libslic3r/Format/AnycubicSLA.hpp b/src/libslic3r/Format/AnycubicSLA.hpp
index 46eb68d00b..d1f8adf8ae 100644
--- a/src/libslic3r/Format/AnycubicSLA.hpp
+++ b/src/libslic3r/Format/AnycubicSLA.hpp
@@ -4,44 +4,14 @@
#include
#include "SLAArchiveWriter.hpp"
+#include "SLAArchiveFormatRegistry.hpp"
#include "libslic3r/PrintConfig.hpp"
-#define ANYCUBIC_SLA_FORMAT_VERSION_1 1
-#define ANYCUBIC_SLA_FORMAT_VERSION_515 515
-#define ANYCUBIC_SLA_FORMAT_VERSION_516 516
-#define ANYCUBIC_SLA_FORMAT_VERSION_517 517
-
-#define ANYCUBIC_SLA_FORMAT_VERSIONED(FILEFORMAT, NAME, VERSION) \
- { FILEFORMAT, { FILEFORMAT, [] (const auto &cfg) { return std::make_unique(cfg, VERSION); } } }
-
-#define ANYCUBIC_SLA_FORMAT(FILEFORMAT, NAME) \
- ANYCUBIC_SLA_FORMAT_VERSIONED(FILEFORMAT, NAME, ANYCUBIC_SLA_FORMAT_VERSION_1)
-
-/**
- // Supports only ANYCUBIC_SLA_VERSION_1
- ANYCUBIC_SLA_FORMAT_VERSIONED("pws", "Photon / Photon S", ANYCUBIC_SLA_VERSION_1),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pw0", "Photon Zero", ANYCUBIC_SLA_VERSION_1),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pwx", "Photon X", ANYCUBIC_SLA_VERSION_1),
-
- // Supports ANYCUBIC_SLA_VERSION_1 and ANYCUBIC_SLA_VERSION_515
- ANYCUBIC_SLA_FORMAT_VERSIONED("pwmo", "Photon Mono", ANYCUBIC_SLA_VERSION_1),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pwms", "Photon Mono SE", ANYCUBIC_SLA_VERSION_1),
- ANYCUBIC_SLA_FORMAT_VERSIONED("dlp", "Photon Ultra", ANYCUBIC_SLA_VERSION_1),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pwmx", "Photon Mono X", ANYCUBIC_SLA_VERSION_1),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pmsq", "Photon Mono SQ", ANYCUBIC_SLA_VERSION_1),
-
- // Supports ANYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516
- ANYCUBIC_SLA_FORMAT_VERSIONED("pwma", "Photon Mono 4K", ANYCUBIC_SLA_VERSION_515),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pm3", "Photon M3", ANYCUBIC_SLA_VERSION_515),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pm3m", "Photon M3 Max", ANYCUBIC_SLA_VERSION_515),
-
- // Supports NYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516 and ANYCUBIC_SLA_VERSION_517
- ANYCUBIC_SLA_FORMAT_VERSIONED("pwmb", "Photon Mono X 6K / Photon M3 Plus", ANYCUBIC_SLA_VERSION_515),
- ANYCUBIC_SLA_FORMAT_VERSIONED("dl2p", "Photon Photon D2", ANYCUBIC_SLA_VERSION_515),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pmx2", "Photon Mono X2", ANYCUBIC_SLA_VERSION_515),
- ANYCUBIC_SLA_FORMAT_VERSIONED("pm3r", "Photon M3 Premium", ANYCUBIC_SLA_VERSION_515),
-*/
+constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_1 = 1;
+constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_515 = 515;
+constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_516 = 516;
+constexpr uint16_t ANYCUBIC_SLA_FORMAT_VERSION_517 = 517;
namespace Slic3r {
@@ -75,6 +45,21 @@ public:
const std::string &projectname = "") override;
};
+inline Slic3r::ArchiveEntry anycubic_sla_format_versioned(const char *fileformat, const char *desc, uint16_t version)
+{
+ Slic3r::ArchiveEntry entry(fileformat);
+
+ entry.desc = desc;
+ entry.ext = fileformat;
+ entry.wrfactoryfn = [version] (const auto &cfg) { return std::make_unique(cfg, version); };
+
+ return entry;
+}
+
+inline Slic3r::ArchiveEntry anycubic_sla_format(const char *fileformat, const char *desc)
+{
+ return anycubic_sla_format_versioned(fileformat, desc, ANYCUBIC_SLA_FORMAT_VERSION_1);
+}
} // namespace Slic3r::sla
diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp
index 4a5a25b08c..6b7f57b7f6 100644
--- a/src/libslic3r/Format/SL1.cpp
+++ b/src/libslic3r/Format/SL1.cpp
@@ -17,6 +17,7 @@
#include "libslic3r/GCode/ThumbnailData.hpp"
#include "SLAArchiveReader.hpp"
+#include "SLAArchiveFormatRegistry.hpp"
#include "ZipperArchiveImport.hpp"
#include "libslic3r/MarchingSquares.hpp"
@@ -26,6 +27,7 @@
#include "libslic3r/SLA/RasterBase.hpp"
+
#include
#include
#include
@@ -436,7 +438,7 @@ ConfigSubstitutions SL1Reader::read(std::vector &slices,
ConfigSubstitutions SL1Reader::read(DynamicPrintConfig &out)
{
- ZipperArchive arch = read_zipper_archive(m_fname, {}, {"png"});
+ ZipperArchive arch = read_zipper_archive(m_fname, {"ini"}, {"png", "thumbnail"});
return out.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
}
diff --git a/src/libslic3r/Format/SLAArchiveFormatRegistry.cpp b/src/libslic3r/Format/SLAArchiveFormatRegistry.cpp
new file mode 100644
index 0000000000..17d3fa9a0b
--- /dev/null
+++ b/src/libslic3r/Format/SLAArchiveFormatRegistry.cpp
@@ -0,0 +1,148 @@
+#include
+#include
+#include
+
+#include "SL1.hpp"
+#include "SL1_SVG.hpp"
+#include "AnycubicSLA.hpp"
+#include "I18N.hpp"
+
+#include "SLAArchiveFormatRegistry.hpp"
+
+namespace Slic3r {
+
+static std::mutex arch_mtx;
+
+class Registry {
+ static std::unique_ptr registry;
+
+ std::set entries;
+public:
+
+ Registry ()
+ {
+ entries = {
+ {
+ "SL1", // id
+ L("SL1 archive format"), // description
+ "sl1", // main extension
+ {"sl1s", "zip"}, // extension aliases
+
+ // Writer factory
+ [] (const auto &cfg) { return std::make_unique(cfg); },
+
+ // Reader factory
+ [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) {
+ return std::make_unique(fname, quality, progr);
+ }
+ },
+ {
+ "SL1SVG",
+ L("SL1SVG archive files"),
+ "sl1_svg",
+ {},
+ [] (const auto &cfg) { return std::make_unique(cfg); },
+ [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) {
+ return std::make_unique(fname, quality, progr);
+ }
+ },
+ {
+ "SL2",
+ "",
+ "sl1_svg",
+ {},
+ [] (const auto &cfg) { return std::make_unique(cfg); },
+ nullptr
+ },
+ anycubic_sla_format("pwmo", "Photon Mono"),
+ anycubic_sla_format("pwmx", "Photon Mono X"),
+ anycubic_sla_format("pwms", "Photon Mono SE"),
+
+ /**
+ // Supports only ANYCUBIC_SLA_VERSION_1
+ anycubic_sla_format_versioned("pws", "Photon / Photon S", ANYCUBIC_SLA_VERSION_1),
+ anycubic_sla_format_versioned("pw0", "Photon Zero", ANYCUBIC_SLA_VERSION_1),
+ anycubic_sla_format_versioned("pwx", "Photon X", ANYCUBIC_SLA_VERSION_1),
+
+ // Supports ANYCUBIC_SLA_VERSION_1 and ANYCUBIC_SLA_VERSION_515
+ anycubic_sla_format_versioned("pwmo", "Photon Mono", ANYCUBIC_SLA_VERSION_1),
+ anycubic_sla_format_versioned("pwms", "Photon Mono SE", ANYCUBIC_SLA_VERSION_1),
+ anycubic_sla_format_versioned("dlp", "Photon Ultra", ANYCUBIC_SLA_VERSION_1),
+ anycubic_sla_format_versioned("pwmx", "Photon Mono X", ANYCUBIC_SLA_VERSION_1),
+ anycubic_sla_format_versioned("pmsq", "Photon Mono SQ", ANYCUBIC_SLA_VERSION_1),
+
+ // Supports ANYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516
+ anycubic_sla_format_versioned("pwma", "Photon Mono 4K", ANYCUBIC_SLA_VERSION_515),
+ anycubic_sla_format_versioned("pm3", "Photon M3", ANYCUBIC_SLA_VERSION_515),
+ anycubic_sla_format_versioned("pm3m", "Photon M3 Max", ANYCUBIC_SLA_VERSION_515),
+
+ // Supports NYCUBIC_SLA_VERSION_515 and ANYCUBIC_SLA_VERSION_516 and ANYCUBIC_SLA_VERSION_517
+ anycubic_sla_format_versioned("pwmb", "Photon Mono X 6K / Photon M3 Plus", ANYCUBIC_SLA_VERSION_515),
+ anycubic_sla_format_versioned("dl2p", "Photon Photon D2", ANYCUBIC_SLA_VERSION_515),
+ anycubic_sla_format_versioned("pmx2", "Photon Mono X2", ANYCUBIC_SLA_VERSION_515),
+ anycubic_sla_format_versioned("pm3r", "Photon M3 Premium", ANYCUBIC_SLA_VERSION_515),
+ */
+ };
+ }
+
+ static Registry& get_instance()
+ {
+ if (!registry)
+ registry = std::make_unique();
+
+ return *registry;
+ }
+
+ static std::set& get()
+ {
+ return get_instance().entries;
+ }
+
+ std::set& get_entries() { return entries; }
+};
+
+std::unique_ptr Registry::registry = nullptr;
+
+std::set registered_sla_archives()
+{
+ std::lock_guard lk{arch_mtx};
+
+ return Registry::get();
+}
+
+std::vector get_extensions(const ArchiveEntry &entry)
+{
+ auto ret = reserve_vector(entry.ext_aliases.size() + 1);
+
+ ret.emplace_back(entry.ext);
+ for (const char *alias : entry.ext_aliases)
+ ret.emplace_back(alias);
+
+ return ret;
+}
+
+ArchiveWriterFactory get_writer_factory(const char *formatid)
+{
+ std::lock_guard lk{arch_mtx};
+
+ ArchiveWriterFactory ret;
+ auto entry = Registry::get().find(ArchiveEntry{formatid});
+ if (entry != Registry::get().end())
+ ret = entry->wrfactoryfn;
+
+ return ret;
+}
+
+ArchiveReaderFactory get_reader_factory(const char *formatid)
+{
+ std::lock_guard lk{arch_mtx};
+
+ ArchiveReaderFactory ret;
+ auto entry = Registry::get().find(ArchiveEntry{formatid});
+ if (entry != Registry::get().end())
+ ret = entry->rdfactoryfn;
+
+ return ret;
+}
+
+} // namespace Slic3r::sla
diff --git a/src/libslic3r/Format/SLAArchiveFormatRegistry.hpp b/src/libslic3r/Format/SLAArchiveFormatRegistry.hpp
new file mode 100644
index 0000000000..fb1a18ca52
--- /dev/null
+++ b/src/libslic3r/Format/SLAArchiveFormatRegistry.hpp
@@ -0,0 +1,71 @@
+#ifndef SLA_ARCHIVE_FORMAT_REGISTRY_HPP
+#define SLA_ARCHIVE_FORMAT_REGISTRY_HPP
+
+#include "SLAArchiveWriter.hpp"
+#include "SLAArchiveReader.hpp"
+#include
+
+namespace Slic3r {
+
+// Factory function that returns an implementation of SLAArchiveWriter given
+// a printer configuration.
+using ArchiveWriterFactory = std::function<
+ std::unique_ptr(const SLAPrinterConfig &)
+>;
+
+// Factory function that returns an implementation of SLAArchiveReader
+using ArchiveReaderFactory = std::function<
+ std::unique_ptr(const std::string &fname,
+ SLAImportQuality quality,
+ const ProgrFn & progr)
+>;
+
+struct ArchiveEntry {
+ // Main ID for the format, for internal unique identification
+ const char *id;
+
+ // Generic description (usable in GUI) about an archive format. Should only
+ // be marked for localization (macro L).
+ const char *desc = "";
+
+ // Main extension of the format.
+ const char *ext = "zip";
+
+ ArchiveWriterFactory wrfactoryfn;
+ ArchiveReaderFactory rdfactoryfn;
+
+ // Secondary, alias extensions
+ std::vector ext_aliases;
+
+ explicit ArchiveEntry(const char *formatid) : id{formatid} {}
+
+ ArchiveEntry(const char *formatid,
+ const char *description,
+ const char *extension,
+ std::initializer_list extaliases,
+ const ArchiveWriterFactory &wrfn,
+ const ArchiveReaderFactory &rdfn)
+ : id{formatid}
+ , desc{description}
+ , ext{extension}
+ , ext_aliases{extaliases}
+ , wrfactoryfn{wrfn}
+ , rdfactoryfn{rdfn}
+ {}
+
+ bool operator <(const ArchiveEntry &other) const
+ {
+ return std::strcmp(id, other.id) < 0;
+ }
+};
+
+std::vector get_extensions(const ArchiveEntry &entry);
+
+std::set registered_sla_archives();
+
+ArchiveWriterFactory get_writer_factory(const char *formatid);
+ArchiveReaderFactory get_reader_factory(const char *formatid);
+
+} // namespace Slic3r
+
+#endif // ARCHIVEREGISTRY_HPP
diff --git a/src/libslic3r/Format/SLAArchiveReader.cpp b/src/libslic3r/Format/SLAArchiveReader.cpp
index b931ea0e4d..c8a15bc5ac 100644
--- a/src/libslic3r/Format/SLAArchiveReader.cpp
+++ b/src/libslic3r/Format/SLAArchiveReader.cpp
@@ -8,44 +8,13 @@
#include
#include
+#include "SLAArchiveFormatRegistry.hpp"
#include
#include