mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 09:51:06 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1880bd29dd | ||
|
|
2df07b7ed8 | ||
|
|
295094a594 | ||
|
|
210bc927bc | ||
|
|
00cfb5b259 | ||
|
|
2bd105b0ce | ||
|
|
b81d761605 | ||
|
|
6922edfc20 | ||
|
|
7ec147603f | ||
|
|
8ee9e5915a | ||
|
|
cd5b786704 | ||
|
|
d715bb760c | ||
|
|
63918b44a8 | ||
|
|
64d09c9bca |
+674
-230
File diff suppressed because it is too large
Load Diff
+1006
-340
File diff suppressed because it is too large
Load Diff
+1003
-337
File diff suppressed because it is too large
Load Diff
+1002
-336
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1001
-335
File diff suppressed because it is too large
Load Diff
+1003
-337
File diff suppressed because it is too large
Load Diff
+1005
-339
File diff suppressed because it is too large
Load Diff
+1007
-341
File diff suppressed because it is too large
Load Diff
+1001
-332
File diff suppressed because it is too large
Load Diff
+1013
-347
File diff suppressed because it is too large
Load Diff
+1009
-343
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1012
-346
File diff suppressed because it is too large
Load Diff
+1000
-334
File diff suppressed because it is too large
Load Diff
+1006
-340
File diff suppressed because it is too large
Load Diff
+1006
-340
File diff suppressed because it is too large
Load Diff
+1009
-343
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Anker",
|
||||
"version": "02.04.00.05",
|
||||
"version": "02.04.00.06",
|
||||
"force_update": "0",
|
||||
"description": "Anker configurations",
|
||||
"machine_model_list": [
|
||||
@@ -304,6 +304,26 @@
|
||||
"name": "Generic PLA Silk @Anker 0.25 nozzle",
|
||||
"sub_path": "filament/Generic PLA Silk @Anker 0.25 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Basic @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Basic @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Glitter @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Glitter @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Matte @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Matte @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Metallic @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Metallic @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Silk @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Silk @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "Generic PLA+ @Anker",
|
||||
"sub_path": "filament/Generic PLA+ @Anker.json"
|
||||
@@ -327,6 +347,26 @@
|
||||
{
|
||||
"name": "Generic TPU @Anker",
|
||||
"sub_path": "filament/Generic TPU @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Basic @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Basic @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Glitter @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Glitter @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Matte @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Matte @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Metallic @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Metallic @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Silk @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Silk @Anker.json"
|
||||
}
|
||||
],
|
||||
"machine_list": [
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Basic @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFUuZlQL",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"200"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"8"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#FFFFFF"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"22"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Basic @Anker",
|
||||
"inherits": "AnkerMake PLA+ Basic @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "EfM5rmn4w6pMBajC",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 0.6 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.6 nozzle",
|
||||
"Anker M5C 0.4 nozzle",
|
||||
"Anker M5C 0.6 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Glitter @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFxCURdg",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"200"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"6"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#00AD66"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"22"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Glitter @Anker",
|
||||
"inherits": "AnkerMake PLA+ Glitter @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "blGHp0htgHEj7khE",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 0.6 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.6 nozzle",
|
||||
"Anker M5C 0.4 nozzle",
|
||||
"Anker M5C 0.6 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Matte @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFKDOyNK",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"210"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"6"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#FFFFFF"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"22"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Matte @Anker",
|
||||
"inherits": "AnkerMake PLA+ Matte @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "tPgwC1eEXyWPOn9S",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5C 0.4 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Metallic @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFBfbmtb",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"200"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"60"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"60"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"6"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"overhang_fan_speed": [
|
||||
"50"
|
||||
],
|
||||
"reduce_fan_stop_start_freq": [
|
||||
"0"
|
||||
],
|
||||
"filament_retraction_length": [
|
||||
"1"
|
||||
],
|
||||
"filament_retraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"filament_deretraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#ACAC8A"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"20"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Metallic @Anker",
|
||||
"inherits": "AnkerMake PLA+ Metallic @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "jlbAMNNaEacdUASZ",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5C 0.4 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Silk @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFkxTGQc",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"210"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"2"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"20"
|
||||
],
|
||||
"filament_retraction_length": [
|
||||
"0.5"
|
||||
],
|
||||
"filament_retraction_speed": [
|
||||
"20"
|
||||
],
|
||||
"filament_wipe": [
|
||||
"0"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#99ADA3"
|
||||
],
|
||||
"filament_deretraction_speed": [
|
||||
"20"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"13"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Silk @Anker",
|
||||
"inherits": "AnkerMake PLA+ Silk @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "eVM9Ckwjl5vEvEKN",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.6 nozzle",
|
||||
"Anker M5C 0.4 nozzle",
|
||||
"Anker M5C 0.6 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Anycubic",
|
||||
"version": "02.04.00.08",
|
||||
"version": "02.04.00.09",
|
||||
"force_update": "0",
|
||||
"description": "Anycubic configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
"default_filament_profile": [
|
||||
"Generic PLA @Anycubic"
|
||||
],
|
||||
"machine_start_gcode": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG0 Z0.2 F1800 ; move nozzle to print position\nG92 E0 ; specify current extruder position as zero\nG1 Y10 X180 E50 F1200 ; extrude a line in front of the printer\nG92 E0 ; specify current extruder position as zero\nG0 Z20 F6000 ; move head up\nG1 E-7 F2400 ; retract\nG04 S2 ; wait 2s\nG0 X0 F6000 ; wipe from oozed filament\nG1 E-1 F2400 ; undo some of the retraction to avoid oozing\nG1 F6000 ; set travel speed to move to start printing point\nM117",
|
||||
"machine_start_gcode": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG0 Z0.2 F1800 ; move nozzle to print position\nG92 E0 ; specify current extruder position as zero\nM109 S[nozzle_temperature_initial_layer] ; wait for nozzle temp to stabilize\nG1 Y10 X180 E50 F1200 ; extrude a line in front of the printer\nG92 E0 ; specify current extruder position as zero\nG0 Z20 F6000 ; move head up\nG1 E-7 F2400 ; retract\nG04 S2 ; wait 2s\nG0 X0 F6000 ; wipe from oozed filament\nG1 E-1 F2400 ; undo some of the retraction to avoid oozing\nG1 F6000 ; set travel speed to move to start printing point\nM117",
|
||||
"machine_end_gcode": "G4 ; wait\nG92 E0\nG1{if max_layer_z < printable_height} Z{z_offset+min(max_layer_z+30, printable_height)}{endif} ; move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]",
|
||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Bambulab",
|
||||
"url": "http://www.bambulab.com/Parameters/vendor/BBL.json",
|
||||
"version": "02.08.00.13",
|
||||
"version": "02.08.00.14",
|
||||
"force_update": "0",
|
||||
"description": "the initial version of BBL configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"0.4"
|
||||
],
|
||||
"printer_variant": "0.4",
|
||||
"use_3mf": "1",
|
||||
"bed_exclude_area": [
|
||||
"0x0",
|
||||
"28x0",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"0.4"
|
||||
],
|
||||
"printer_variant": "0.4",
|
||||
"use_3mf": "1",
|
||||
"best_object_pos": "0.3x0.5",
|
||||
"bed_exclude_area": [],
|
||||
"bed_temperature_formula": "by_highest_temp",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Prusa",
|
||||
"version": "02.04.00.16",
|
||||
"version": "02.04.00.17",
|
||||
"force_update": "0",
|
||||
"description": "Prusa configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"35"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"110"
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
"35"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"110"
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"0.8"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_wipe": [
|
||||
"1"
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"15"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One|CORE One L).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_z_hop": [
|
||||
"0.6"
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"7"
|
||||
],
|
||||
"filament_start_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=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[0]==0.4}0.03{elsif nozzle_diameter[0]==0.5}0.022{elsif nozzle_diameter[0]==0.6}0.018{elsif nozzle_diameter[0]==0.8}0.012{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.075{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"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=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[0]==0.4}0.03{elsif nozzle_diameter[0]==0.5}0.022{elsif nozzle_diameter[0]==0.6}0.018{elsif nozzle_diameter[0]==0.8}0.012{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.075{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_z_hop": [
|
||||
"0.6",
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"ASA"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PA11-CF"
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PC"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PC-CF"
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PETG"
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One|CORE One L).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PLA"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"1"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PVB"
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PLA"
|
||||
|
||||
@@ -405,6 +405,7 @@ set(lisbslic3r_sources
|
||||
Polyline.hpp
|
||||
PresetBundle.cpp
|
||||
PresetBundle.hpp
|
||||
PrinterBedAssets.hpp
|
||||
PresetCacheFormat.cpp
|
||||
PresetCacheFormat.hpp
|
||||
Preset.cpp
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
#include "JumpPointSearch.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "libslic3r/AStar.hpp"
|
||||
#include "libslic3r/KDTreeIndirect.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <oneapi/tbb/scalable_allocator.h>
|
||||
|
||||
//#define DEBUG_FILES
|
||||
#ifdef DEBUG_FILES
|
||||
#include "libslic3r/SVG.hpp"
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// execute fn for each pixel on the line. If fn returns false, terminate the iteration
|
||||
template<typename PointFn> void dda(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
|
||||
{
|
||||
coord_t dx = abs(x1 - x0);
|
||||
coord_t dy = abs(y1 - y0);
|
||||
coord_t x = x0;
|
||||
coord_t y = y0;
|
||||
coord_t n = 1 + dx + dy;
|
||||
coord_t x_inc = (x1 > x0) ? 1 : -1;
|
||||
coord_t y_inc = (y1 > y0) ? 1 : -1;
|
||||
coord_t error = dx - dy;
|
||||
dx *= 2;
|
||||
dy *= 2;
|
||||
|
||||
for (; n > 0; --n) {
|
||||
if (!fn(x, y)) return;
|
||||
|
||||
if (error > 0) {
|
||||
x += x_inc;
|
||||
error -= dy;
|
||||
} else {
|
||||
y += y_inc;
|
||||
error += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will draw the line twice, second time with and offset of 1 in the direction of normal
|
||||
// may call the fn on the same coordiantes multiple times!
|
||||
template<typename PointFn> void double_dda_with_offset(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
|
||||
{
|
||||
Vec2d normal = Point{y1 - y0, x1 - x0}.cast<double>().normalized();
|
||||
normal.x() = ceil(normal.x());
|
||||
normal.y() = ceil(normal.y());
|
||||
Point start_offset = Point(x0, y0) + (normal).cast<coord_t>();
|
||||
Point end_offset = Point(x1, y1) + (normal).cast<coord_t>();
|
||||
|
||||
dda(x0, y0, x1, y1, fn);
|
||||
dda(start_offset.x(), start_offset.y(), end_offset.x(), end_offset.y(), fn);
|
||||
}
|
||||
|
||||
template<typename CellPositionType, typename CellQueryFn> class JPSTracer
|
||||
{
|
||||
public:
|
||||
// Use incoming_dir [0,0] for starting points, so that all directions are checked from that point
|
||||
struct Node
|
||||
{
|
||||
CellPositionType position;
|
||||
CellPositionType incoming_dir;
|
||||
};
|
||||
|
||||
JPSTracer(CellPositionType target, CellQueryFn is_passable) : target(target), is_passable(is_passable) {}
|
||||
|
||||
private:
|
||||
CellPositionType target;
|
||||
CellQueryFn is_passable; // should return boolean whether the cell is passable or not
|
||||
|
||||
CellPositionType find_jump_point(CellPositionType start, CellPositionType forward_dir) const
|
||||
{
|
||||
CellPositionType next = start + forward_dir;
|
||||
while (next != target && is_passable(next) && !(is_jump_point(next, forward_dir))) { next = next + forward_dir; }
|
||||
|
||||
if (is_passable(next)) {
|
||||
return next;
|
||||
} else {
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_jump_point(CellPositionType pos, CellPositionType forward_dir) const
|
||||
{
|
||||
if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) {
|
||||
// diagonal
|
||||
CellPositionType horizontal_check_dir = CellPositionType{forward_dir.x(), 0};
|
||||
CellPositionType vertical_check_dir = CellPositionType{0, forward_dir.y()};
|
||||
|
||||
if (!is_passable(pos - horizontal_check_dir) && is_passable(pos + forward_dir - 2 * horizontal_check_dir)) { return true; }
|
||||
|
||||
if (!is_passable(pos - vertical_check_dir) && is_passable(pos + forward_dir - 2 * vertical_check_dir)) { return true; }
|
||||
|
||||
if (find_jump_point(pos, horizontal_check_dir) != pos) { return true; }
|
||||
|
||||
if (find_jump_point(pos, vertical_check_dir) != pos) { return true; }
|
||||
|
||||
return false;
|
||||
} else { // horizontal or vertical
|
||||
CellPositionType side_dir = CellPositionType(forward_dir.y(), forward_dir.x());
|
||||
|
||||
if (!is_passable(pos + side_dir) && is_passable(pos + forward_dir + side_dir)) { return true; }
|
||||
|
||||
if (!is_passable(pos - side_dir) && is_passable(pos + forward_dir - side_dir)) { return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<class Fn> void foreach_reachable(const Node &from, Fn &&fn) const
|
||||
{
|
||||
const CellPositionType & pos = from.position;
|
||||
const CellPositionType & forward_dir = from.incoming_dir;
|
||||
std::vector<CellPositionType> dirs_to_check{};
|
||||
|
||||
if (abs(forward_dir.x()) + abs(forward_dir.y()) == 0) { // special case for starting point
|
||||
dirs_to_check = all_directions;
|
||||
} else if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) {
|
||||
// diagonal
|
||||
CellPositionType horizontal_check_dir = CellPositionType{forward_dir.x(), 0};
|
||||
CellPositionType vertical_check_dir = CellPositionType{0, forward_dir.y()};
|
||||
|
||||
if (!is_passable(pos - horizontal_check_dir) && is_passable(pos + forward_dir - 2 * horizontal_check_dir)) {
|
||||
dirs_to_check.push_back(forward_dir - 2 * horizontal_check_dir);
|
||||
}
|
||||
|
||||
if (!is_passable(pos - vertical_check_dir) && is_passable(pos + forward_dir - 2 * vertical_check_dir)) {
|
||||
dirs_to_check.push_back(forward_dir - 2 * vertical_check_dir);
|
||||
}
|
||||
|
||||
dirs_to_check.push_back(horizontal_check_dir);
|
||||
dirs_to_check.push_back(vertical_check_dir);
|
||||
dirs_to_check.push_back(forward_dir);
|
||||
|
||||
} else { // horizontal or vertical
|
||||
CellPositionType side_dir = CellPositionType(forward_dir.y(), forward_dir.x());
|
||||
|
||||
if (!is_passable(pos + side_dir) && is_passable(pos + forward_dir + side_dir)) { dirs_to_check.push_back(forward_dir + side_dir); }
|
||||
|
||||
if (!is_passable(pos - side_dir) && is_passable(pos + forward_dir - side_dir)) { dirs_to_check.push_back(forward_dir - side_dir); }
|
||||
dirs_to_check.push_back(forward_dir);
|
||||
}
|
||||
|
||||
for (const CellPositionType &dir : dirs_to_check) {
|
||||
CellPositionType jp = find_jump_point(pos, dir);
|
||||
if (jp != pos) fn(Node{jp, dir});
|
||||
}
|
||||
}
|
||||
|
||||
float distance(Node a, Node b) const { return (a.position - b.position).template cast<double>().norm(); }
|
||||
|
||||
float goal_heuristic(Node n) const { return n.position == target ? -1.f : (target - n.position).template cast<double>().norm(); }
|
||||
|
||||
size_t unique_id(Node n) const { return (static_cast<size_t>(uint16_t(n.position.x())) << 16) + static_cast<size_t>(uint16_t(n.position.y())); }
|
||||
|
||||
const std::vector<CellPositionType> all_directions{{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};
|
||||
};
|
||||
|
||||
void JPSPathFinder::clear()
|
||||
{
|
||||
inpassable.clear();
|
||||
max_search_box.max = Pixel(std::numeric_limits<coord_t>::min(), std::numeric_limits<coord_t>::min());
|
||||
max_search_box.min = Pixel(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max());
|
||||
add_obstacles(bed_shape);
|
||||
}
|
||||
|
||||
void JPSPathFinder::add_obstacles(const Lines &obstacles)
|
||||
{
|
||||
auto store_obstacle = [&](coord_t x, coord_t y) {
|
||||
max_search_box.max.x() = std::max(max_search_box.max.x(), x);
|
||||
max_search_box.max.y() = std::max(max_search_box.max.y(), y);
|
||||
max_search_box.min.x() = std::min(max_search_box.min.x(), x);
|
||||
max_search_box.min.y() = std::min(max_search_box.min.y(), y);
|
||||
inpassable.insert(Pixel{x, y});
|
||||
return true;
|
||||
};
|
||||
|
||||
for (const Line &l : obstacles) {
|
||||
Pixel start = pixelize(l.a);
|
||||
Pixel end = pixelize(l.b);
|
||||
double_dda_with_offset(start.x(), start.y(), end.x(), end.y(), store_obstacle);
|
||||
}
|
||||
}
|
||||
|
||||
Polyline JPSPathFinder::find_path(const Point &p0, const Point &p1)
|
||||
{
|
||||
Pixel start = pixelize(p0);
|
||||
Pixel end = pixelize(p1);
|
||||
if (inpassable.empty() || (start - end).cast<float>().norm() < 3.0) { return Polyline{p0, p1}; }
|
||||
|
||||
if (inpassable.find(start) != inpassable.end()) {
|
||||
dda(start.x(), start.y(), end.x(), end.y(), [&](coord_t x, coord_t y) {
|
||||
if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
|
||||
start = Pixel(x, y);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (inpassable.find(end) != inpassable.end()) {
|
||||
dda(end.x(), end.y(), start.x(), start.y(), [&](coord_t x, coord_t y) {
|
||||
if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
|
||||
end = Pixel(x, y);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
BoundingBox search_box = max_search_box;
|
||||
search_box.max -= Pixel(1, 1);
|
||||
search_box.min += Pixel(1, 1);
|
||||
|
||||
BoundingBox bounding_square(Points{start, end});
|
||||
bounding_square.max += Pixel(5, 5);
|
||||
bounding_square.min -= Pixel(5, 5);
|
||||
coord_t bounding_square_size = 2 * std::max(bounding_square.size().x(), bounding_square.size().y());
|
||||
bounding_square.max.x() += (bounding_square_size - bounding_square.size().x()) / 2;
|
||||
bounding_square.min.x() -= (bounding_square_size - bounding_square.size().x()) / 2;
|
||||
bounding_square.max.y() += (bounding_square_size - bounding_square.size().y()) / 2;
|
||||
bounding_square.min.y() -= (bounding_square_size - bounding_square.size().y()) / 2;
|
||||
|
||||
// Intersection - limit the search box to a square area around the start and end, to fasten the path searching
|
||||
search_box.max = search_box.max.cwiseMin(bounding_square.max);
|
||||
search_box.min = search_box.min.cwiseMax(bounding_square.min);
|
||||
|
||||
auto cell_query = [&](Pixel pixel) { return search_box.contains(pixel) && (pixel == start || pixel == end || inpassable.find(pixel) == inpassable.end()); };
|
||||
|
||||
JPSTracer<Pixel, decltype(cell_query)> tracer(end, cell_query);
|
||||
using QNode = astar::QNode<JPSTracer<Pixel, decltype(cell_query)>>;
|
||||
|
||||
std::unordered_map<size_t, QNode> astar_cache{};
|
||||
std::vector<Pixel, PointsAllocator<Pixel>> out_path;
|
||||
std::vector<decltype(tracer)::Node> out_nodes;
|
||||
|
||||
if (!astar::search_route(tracer, {start, {0, 0}}, std::back_inserter(out_nodes), astar_cache)) {
|
||||
// path not found - just reconstruct the best path from astar cache.
|
||||
// Note that astar_cache is NOT empty - at least the starting point should always be there
|
||||
auto coordiante_func = [&astar_cache](size_t idx, size_t dim) { return float(astar_cache[idx].node.position[dim]); };
|
||||
std::vector<size_t> keys;
|
||||
keys.reserve(astar_cache.size());
|
||||
for (const auto &pair : astar_cache) { keys.push_back(pair.first); }
|
||||
KDTreeIndirect<2, float, decltype(coordiante_func)> kd_tree(coordiante_func, keys);
|
||||
size_t closest_qnode = find_closest_point(kd_tree, end.cast<float>());
|
||||
|
||||
out_path.push_back(end);
|
||||
while (closest_qnode != astar::Unassigned) {
|
||||
out_path.push_back(astar_cache[closest_qnode].node.position);
|
||||
closest_qnode = astar_cache[closest_qnode].parent;
|
||||
}
|
||||
} else {
|
||||
for (const auto &node : out_nodes) { out_path.push_back(node.position); }
|
||||
out_path.push_back(start);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
auto scaled_points = [](const Points &ps) {
|
||||
Points r;
|
||||
for (const Point &p : ps) { r.push_back(Point::new_scale(p.x(), p.y())); }
|
||||
return r;
|
||||
};
|
||||
auto scaled_point = [](const Point &p) { return Point::new_scale(p.x(), p.y()); };
|
||||
::Slic3r::SVG svg(debug_out_path(("path_jps" + std::to_string(print_z) + "_" + std::to_string(rand() % 1000)).c_str()).c_str(),
|
||||
BoundingBox(scaled_point(search_box.min), scaled_point(search_box.max)));
|
||||
for (const auto &p : inpassable) { svg.draw(scaled_point(p), "black", scale_(0.4)); }
|
||||
for (const auto &qn : astar_cache) { svg.draw(scaled_point(qn.second.node.position), "blue", scale_(0.3)); }
|
||||
svg.draw(Polyline(scaled_points(out_path)), "yellow", scale_(0.25));
|
||||
svg.draw(scaled_point(end), "purple", scale_(0.4));
|
||||
svg.draw(scaled_point(start), "green", scale_(0.4));
|
||||
#endif
|
||||
|
||||
std::vector<Pixel, PointsAllocator<Pixel>> tmp_path;
|
||||
tmp_path.reserve(out_path.size());
|
||||
// Some path found, reverse and remove points that do not change direction
|
||||
std::reverse(out_path.begin(), out_path.end());
|
||||
{
|
||||
tmp_path.push_back(out_path.front()); // first point
|
||||
for (size_t i = 1; i < out_path.size() - 1; i++) {
|
||||
if ((out_path[i] - out_path[i - 1]).cast<float>().normalized() != (out_path[i + 1] - out_path[i]).cast<float>().normalized()) { tmp_path.push_back(out_path[i]); }
|
||||
}
|
||||
tmp_path.push_back(out_path.back()); // last_point
|
||||
out_path = tmp_path;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
svg.draw(Polyline(scaled_points(out_path)), "orange", scale_(0.20));
|
||||
#endif
|
||||
|
||||
tmp_path.clear();
|
||||
// remove redundant jump points - there are points that change direction but are not needed - this inefficiency arises from the
|
||||
// usage of grid search The removal alg tries to find the longest Px Px+k path without obstacles. If Px Px+k+1 is blocked, it will
|
||||
// insert the Px+k point to result and continue search from Px+k
|
||||
{
|
||||
tmp_path.push_back(out_path.front()); // first point
|
||||
size_t index_of_last_stored_point = 0;
|
||||
for (size_t i = 1; i < out_path.size(); i++) {
|
||||
if (i - index_of_last_stored_point < 2) continue;
|
||||
bool passable = true;
|
||||
auto store_obstacle = [&](coord_t x, coord_t y) {
|
||||
if (Pixel(x, y) != start && Pixel(x, y) != end && inpassable.find(Pixel(x, y)) != inpassable.end()) {
|
||||
passable = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
dda(tmp_path.back().x(), tmp_path.back().y(), out_path[i].x(), out_path[i].y(), store_obstacle);
|
||||
if (!passable) {
|
||||
tmp_path.push_back(out_path[i - 1]);
|
||||
index_of_last_stored_point = i - 1;
|
||||
}
|
||||
}
|
||||
tmp_path.push_back(out_path.back()); // last_point
|
||||
out_path = tmp_path;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
svg.draw(Polyline(scaled_points(out_path)), "red", scale_(0.15));
|
||||
svg.Close();
|
||||
#endif
|
||||
|
||||
// before returing the path, transform it from pixels back to points.
|
||||
// Also replace the first and last pixel by input points so that result path patches input params exactly.
|
||||
for (Pixel &p : out_path) { p = unpixelize(p); }
|
||||
out_path.front() = p0;
|
||||
out_path.back() = p1;
|
||||
|
||||
return Polyline(out_path);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
#include "Line.hpp"
|
||||
#ifndef SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_
|
||||
#define SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_
|
||||
|
||||
#include "BoundingBox.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class JPSPathFinder
|
||||
{
|
||||
using Pixel = Point;
|
||||
std::unordered_set<Pixel, PointHash> inpassable;
|
||||
coordf_t print_z;
|
||||
BoundingBox max_search_box;
|
||||
Lines bed_shape;
|
||||
|
||||
const coord_t resolution = scaled(1.5);
|
||||
Pixel pixelize(const Point &p) { return p / resolution; }
|
||||
Point unpixelize(const Pixel &p) { return p * resolution; }
|
||||
|
||||
public:
|
||||
JPSPathFinder() = default;
|
||||
void init_bed_shape(const Points &bed_shape) { this->bed_shape = (to_lines(Polygon{bed_shape})); };
|
||||
void clear();
|
||||
void add_obstacles(const Lines &obstacles);
|
||||
Polyline find_path(const Point &start, const Point &end);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_ */
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <ios>
|
||||
#include <optional>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "PresetBundle.hpp"
|
||||
#include "PrinterBedAssets.hpp"
|
||||
|
||||
#include "Config.hpp"
|
||||
#include "Exception.hpp"
|
||||
@@ -64,6 +66,7 @@
|
||||
#include <boost/algorithm/clamp.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
@@ -1678,6 +1681,258 @@ bool PresetBundle::apply_vendor_config(
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// The two bed files a printer bundle can carry. Zip names are bed/<n>/<stem><ext>, never the source basename.
|
||||
struct BedAssetSlot {
|
||||
const char *option;
|
||||
const char *stem;
|
||||
};
|
||||
|
||||
constexpr BedAssetSlot k_bed_asset_slots[] = {
|
||||
{"bed_custom_texture", "texture"},
|
||||
{"bed_custom_model", "model"},
|
||||
};
|
||||
|
||||
std::string zip_slashes(std::string name)
|
||||
{
|
||||
for (char &c : name)
|
||||
if (c == '\\')
|
||||
c = '/';
|
||||
return name;
|
||||
}
|
||||
|
||||
// The bed dialog loads only png/svg textures and stl models. Anything else is not a bed asset.
|
||||
bool bed_extension_allowed(const char *option, const std::string &ext)
|
||||
{
|
||||
if (std::string(option) == "bed_custom_texture")
|
||||
return boost::iequals(ext, ".png") || boost::iequals(ext, ".svg");
|
||||
if (std::string(option) == "bed_custom_model")
|
||||
return boost::iequals(ext, ".stl");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extension including the dot, or empty when this option may not use it.
|
||||
std::string bed_asset_extension(const std::string &path, const char *option)
|
||||
{
|
||||
const auto slash = path.find_last_of("/\\");
|
||||
const auto base = slash == std::string::npos ? 0 : slash + 1;
|
||||
const auto dot = path.find_last_of('.');
|
||||
if (dot == std::string::npos || dot < base || dot + 1 >= path.size())
|
||||
return {};
|
||||
const std::string ext = path.substr(dot);
|
||||
if (!bed_extension_allowed(option, ext))
|
||||
return {};
|
||||
return ext;
|
||||
}
|
||||
|
||||
bool utf8_is_file(const std::string &path)
|
||||
{
|
||||
if (path.empty())
|
||||
return false;
|
||||
boost::system::error_code ec;
|
||||
#ifdef _WIN32
|
||||
// A narrow path is the ANSI code page unless nowide_filesystem() has run.
|
||||
const std::wstring wide = boost::nowide::widen(path);
|
||||
if (wide.empty())
|
||||
return false;
|
||||
return boost::filesystem::is_regular_file(boost::filesystem::path(wide), ec) && !ec;
|
||||
#else
|
||||
return boost::filesystem::is_regular_file(path, ec) && !ec;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string bed_asset_dest_utf8(const fs::path &dest)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return boost::nowide::narrow(dest.wstring());
|
||||
#else
|
||||
return dest.string();
|
||||
#endif
|
||||
}
|
||||
|
||||
// True only for bed/<digits>/<stem><ext> with an extension the bed dialog accepts for this field.
|
||||
bool accepted_bed_zip_name(const std::string &raw, const BedAssetSlot &slot, const fs::path &bundle_dir,
|
||||
std::string &zip_name, std::string &folder)
|
||||
{
|
||||
const std::string name = zip_slashes(raw);
|
||||
if (name.find("..") != std::string::npos)
|
||||
return false;
|
||||
if (name.size() < 8 || name.compare(0, 4, "bed/") != 0)
|
||||
return false;
|
||||
const auto slash = name.find('/', 4);
|
||||
if (slash == std::string::npos || slash == 4 || name.find('/', slash + 1) != std::string::npos)
|
||||
return false;
|
||||
const std::string digits = name.substr(4, slash - 4);
|
||||
for (unsigned char c : digits) {
|
||||
if (!std::isdigit(c))
|
||||
return false;
|
||||
}
|
||||
const std::string filename = name.substr(slash + 1);
|
||||
const std::string ext = bed_asset_extension(filename, slot.option);
|
||||
if (ext.empty() || filename != std::string(slot.stem) + ext)
|
||||
return false;
|
||||
if (!is_path_within_root(name, bundle_dir))
|
||||
return false;
|
||||
zip_name = name;
|
||||
folder = digits;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct PendingBedAsset {
|
||||
std::string option;
|
||||
std::string zip_name;
|
||||
std::string dest;
|
||||
std::string printer_key;
|
||||
fs::path final_path;
|
||||
fs::path staged;
|
||||
};
|
||||
|
||||
// Validated asset names only. A raw manifest value that fails the check is not skipped later,
|
||||
// so a value like printer/Name.json cannot hide that preset.
|
||||
// printer_asset is keyed by printer_config zip entry. A flat (unkeyed) object is not read.
|
||||
std::vector<PendingBedAsset> pending_bed_assets(const json &bundle_json, const fs::path &bundle_dir,
|
||||
std::unordered_set<std::string> &skip_names,
|
||||
const std::unordered_set<std::string> &zip_entries)
|
||||
{
|
||||
std::vector<PendingBedAsset> pending;
|
||||
if (!bundle_json.contains("printer_asset") || !bundle_json["printer_asset"].is_object())
|
||||
return pending;
|
||||
const json &assets = bundle_json["printer_asset"];
|
||||
for (auto it = assets.begin(); it != assets.end(); ++it) {
|
||||
const std::string printer_key = it.key();
|
||||
if (zip_entries.count(printer_key) == 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset entry is ignored, no matching printer in the zip: " << printer_key;
|
||||
continue;
|
||||
}
|
||||
if (!it.value().is_object())
|
||||
continue;
|
||||
const json &per_printer = it.value();
|
||||
for (const BedAssetSlot &slot : k_bed_asset_slots) {
|
||||
if (!per_printer.contains(slot.option) || !per_printer[slot.option].is_string())
|
||||
continue;
|
||||
const std::string raw = per_printer[slot.option].get<std::string>();
|
||||
std::string zip_name;
|
||||
std::string folder;
|
||||
if (!accepted_bed_zip_name(raw, slot, bundle_dir, zip_name, folder)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset path is rejected: " << raw;
|
||||
continue;
|
||||
}
|
||||
const std::string filename = zip_name.substr(zip_name.rfind('/') + 1);
|
||||
const fs::path final_path = fs::absolute(bundle_dir / "bed" / folder / filename);
|
||||
pending.push_back({slot.option, zip_name, bed_asset_dest_utf8(final_path), printer_key, final_path, {}});
|
||||
skip_names.insert(zip_name);
|
||||
}
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
|
||||
// Stage under temp_folder. The bundle bed/ directory is not touched until a printer preset keeps the path.
|
||||
bool stage_bed_asset(mz_zip_archive &zip, PendingBedAsset &asset, const fs::path &temp_folder)
|
||||
{
|
||||
size_t size = 0;
|
||||
void *buf = mz_zip_reader_extract_file_to_heap(&zip, asset.zip_name.c_str(), &size, MZ_ZIP_FLAG_CASE_SENSITIVE);
|
||||
if (buf == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset is missing, skipping " << asset.option << ": " << asset.zip_name;
|
||||
return false;
|
||||
}
|
||||
const std::string filename = asset.zip_name.substr(asset.zip_name.rfind('/') + 1);
|
||||
asset.staged = temp_folder / "bed" / asset.final_path.parent_path().filename() / filename;
|
||||
boost::system::error_code ec;
|
||||
fs::create_directories(asset.staged.parent_path(), ec);
|
||||
const std::string staged_utf8 = bed_asset_dest_utf8(asset.staged);
|
||||
bool wrote = false;
|
||||
if (!ec) {
|
||||
boost::nowide::ofstream out(staged_utf8, std::ios::binary | std::ios::trunc);
|
||||
wrote = static_cast<bool>(out);
|
||||
if (wrote && size > 0)
|
||||
wrote = static_cast<bool>(out.write(static_cast<const char *>(buf), static_cast<std::streamsize>(size)));
|
||||
}
|
||||
mz_free(buf);
|
||||
if (!wrote) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset could not be written, skipping " << asset.option << ": " << staged_utf8;
|
||||
fs::remove(asset.staged, ec);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool install_bed_asset(const PendingBedAsset &asset)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
fs::create_directories(asset.final_path.parent_path(), ec);
|
||||
if (!ec)
|
||||
fs::copy_file(asset.staged, asset.final_path, fs::copy_options::overwrite_existing, ec);
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset could not be installed: " << asset.dest;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_pending_bed_asset_entry(const std::string &entry, const std::unordered_set<std::string> &names)
|
||||
{
|
||||
return names.count(entry) != 0 || names.count(zip_slashes(entry)) != 0;
|
||||
}
|
||||
|
||||
bool printer_kept_bed_paths(const PresetCollection &printers, const std::map<std::string, std::string> &paths)
|
||||
{
|
||||
if (paths.empty())
|
||||
return false;
|
||||
for (const Preset &preset : printers.get_presets()) {
|
||||
for (const auto &entry : paths)
|
||||
if (preset.config.opt_string(entry.first) == entry.second)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool append_printer_bed_assets(mz_zip_archive &zip, const DynamicPrintConfig &config, json &bundle_structure,
|
||||
const std::string &printer_config_entry, int printer_index)
|
||||
{
|
||||
if (printer_config_entry.empty() || printer_index < 0)
|
||||
return true;
|
||||
json assets = json::object();
|
||||
for (const BedAssetSlot &slot : k_bed_asset_slots) {
|
||||
if (!config.has(slot.option))
|
||||
continue;
|
||||
const std::string stored = config.opt_string(slot.option);
|
||||
if (stored.empty())
|
||||
continue;
|
||||
if (!utf8_is_file(stored)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset file is missing, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
const std::string ext = bed_asset_extension(stored, slot.option);
|
||||
if (ext.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset extension is not packable, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
boost::nowide::ifstream in(stored, std::ios::binary);
|
||||
if (!in) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset file cannot be read, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
const std::string bytes((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
|
||||
if (in.bad()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset file cannot be read, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
const std::string zip_name = std::string("bed/") + std::to_string(printer_index) + "/" + slot.stem + ext;
|
||||
const void *data = bytes.empty() ? static_cast<const void *>("") : static_cast<const void *>(bytes.data());
|
||||
if (mz_zip_writer_add_mem(&zip, zip_name.c_str(), data, bytes.size(), MZ_DEFAULT_COMPRESSION) == MZ_FALSE) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to add bed asset to printer bundle: " << zip_name;
|
||||
return false;
|
||||
}
|
||||
assets[slot.option] = zip_name;
|
||||
}
|
||||
if (!assets.empty())
|
||||
bundle_structure["printer_asset"][printer_config_entry] = std::move(assets);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Import presets from UI control
|
||||
PresetsConfigSubstitutions PresetBundle::import_presets(std::vector<std::string> & files,
|
||||
std::function<int(std::string const &)> override_confirm,
|
||||
@@ -1773,14 +2028,44 @@ PresetsConfigSubstitutions PresetBundle::import_presets(std::vector<std::string>
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " No bundle_structure.json found, importing presets into the user preset directory";
|
||||
}
|
||||
|
||||
json bundle_json = json::object();
|
||||
std::unordered_set<std::string> bed_asset_entries;
|
||||
std::vector<PendingBedAsset> bed_assets;
|
||||
std::map<std::string, std::map<std::string, std::string>> bed_paths_by_printer;
|
||||
bool bed_paths_loaded = false;
|
||||
if (has_bundle_structure && !bundle_base_dir.empty()) {
|
||||
try {
|
||||
boost::nowide::ifstream manifest_in(metadata_path.string());
|
||||
manifest_in >> bundle_json;
|
||||
} catch (const std::exception &err) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " failed to read bundle manifest: " << err.what();
|
||||
bundle_json = json::object();
|
||||
}
|
||||
std::unordered_set<std::string> zip_entries;
|
||||
const int zip_file_count = mz_zip_reader_get_num_files(&zip_archive);
|
||||
for (int zi = 0; zi < zip_file_count; ++zi) {
|
||||
mz_zip_archive_file_stat st;
|
||||
if (mz_zip_reader_file_stat(&zip_archive, zi, &st))
|
||||
zip_entries.insert(zip_slashes(st.m_filename));
|
||||
}
|
||||
bed_assets = pending_bed_assets(bundle_json, bundle_base_dir, bed_asset_entries, zip_entries);
|
||||
for (PendingBedAsset &asset : bed_assets)
|
||||
if (stage_bed_asset(zip_archive, asset, temp_folder))
|
||||
bed_paths_by_printer[asset.printer_key].emplace(asset.option, asset.dest);
|
||||
}
|
||||
|
||||
// Extract Files
|
||||
int num_files = mz_zip_reader_get_num_files(&zip_archive);
|
||||
const std::map<std::string, std::string> no_bed_paths;
|
||||
for (int i = 0; i < num_files; i++) {
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
status = mz_zip_reader_file_stat(&zip_archive, i, &file_stat);
|
||||
if (status) {
|
||||
std::string file_name = file_stat.m_filename;
|
||||
const std::string zip_entry = zip_slashes(file_name);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " From zip file: " << file << ". Read file name: " << file_stat.m_filename;
|
||||
if (is_pending_bed_asset_entry(file_name, bed_asset_entries))
|
||||
continue;
|
||||
size_t index = file_name.find_last_of("/\\");
|
||||
if (std::string::npos != index) {
|
||||
file_name = file_name.substr(index + 1);
|
||||
@@ -1798,13 +2083,26 @@ PresetsConfigSubstitutions PresetBundle::import_presets(std::vector<std::string>
|
||||
if (MZ_FALSE == status) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to open target file: " << target_file_path;
|
||||
} else {
|
||||
const auto paths_it = bed_paths_by_printer.find(zip_entry);
|
||||
const std::map<std::string, std::string> &this_bed_paths =
|
||||
paths_it != bed_paths_by_printer.end() ? paths_it->second : no_bed_paths;
|
||||
bool is_success = import_json_presets(substitutions, target_file_path, override_confirm, rule, overwrite, result,
|
||||
has_bundle_structure ? bundle_base_dir.string() : std::string());
|
||||
has_bundle_structure ? bundle_base_dir.string() : std::string(),
|
||||
this_bed_paths, &bed_paths_loaded);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " import target file: " << target_file_path << " import result" << is_success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy into bed/ only after this import loads a printer that still holds the staged path.
|
||||
// A preset left from an earlier import must not count: declining this import leaves its files alone.
|
||||
if (bed_paths_loaded) {
|
||||
for (const PendingBedAsset &asset : bed_assets) {
|
||||
if (printer_kept_bed_paths(printers, {{asset.option, asset.dest}}))
|
||||
install_bed_asset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
// Set imported_time to current time if not already set
|
||||
if (metadata.imported_time == 0) {
|
||||
metadata.imported_time = std::time(nullptr);
|
||||
@@ -1846,7 +2144,9 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
|
||||
ForwardCompatibilitySubstitutionRule rule,
|
||||
int & overwrite,
|
||||
std::vector<std::string> & result,
|
||||
const std::string & bundle_dir)
|
||||
const std::string & bundle_dir,
|
||||
const std::map<std::string, std::string> & bed_asset_paths,
|
||||
bool * bed_paths_loaded)
|
||||
{
|
||||
try {
|
||||
DynamicPrintConfig config;
|
||||
@@ -1910,6 +2210,10 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
|
||||
if (inherit_preset)
|
||||
inherits_value = inherit_preset->name; // keep the base_id redo below in sync
|
||||
}
|
||||
if (collection == &printers) {
|
||||
for (const auto &entry : bed_asset_paths)
|
||||
config.option<ConfigOptionString>(entry.first, true)->value = entry.second;
|
||||
}
|
||||
if (inherit_preset) {
|
||||
new_config = inherit_preset->config;
|
||||
new_config.apply(std::move(config));
|
||||
@@ -1927,6 +2231,8 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
|
||||
new_config.apply(std::move(config));
|
||||
extend_default_config_length(new_config, true, default_preset.config);
|
||||
}
|
||||
if (bed_paths_loaded != nullptr && collection == &printers && !bed_asset_paths.empty())
|
||||
*bed_paths_loaded = true;
|
||||
|
||||
Preset &preset = collection->load_preset(collection->path_from_name(name, inherit_preset == nullptr), preset_name, std::move(new_config), false);
|
||||
preset.bundle_id = load_origin.bundle_id;
|
||||
|
||||
@@ -319,7 +319,9 @@ public:
|
||||
ForwardCompatibilitySubstitutionRule rule,
|
||||
int& overwrite,
|
||||
std::vector<std::string>& result,
|
||||
const std::string& bundle_dir = "");
|
||||
const std::string& bundle_dir = "",
|
||||
const std::map<std::string, std::string> &bed_asset_paths = {},
|
||||
bool *bed_paths_loaded = nullptr);
|
||||
|
||||
void save_user_presets(AppConfig& config, std::map<std::string, std::string>& need_to_delete_list);
|
||||
void check_and_fix_user_presets_syncinfo(const std::string& user_id);
|
||||
|
||||
@@ -1148,6 +1148,8 @@ void PrintConfigDef::init_common_params()
|
||||
|
||||
def = this->add("print_host", coString);
|
||||
def->label = L("Hostname, IP or URL");
|
||||
// The URL is an example of the format to type, not a link, so it stays in the text.
|
||||
// xgettext:no-url-check
|
||||
def->tooltip = L("Orca Slicer can upload G-code files to a printer host. This field should contain "
|
||||
"the hostname, IP address or URL of the printer host instance. "
|
||||
"Print host behind HAProxy with basic auth enabled can be accessed by putting the user name and password into the URL "
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "miniz_extension.hpp"
|
||||
|
||||
#include <miniz.h>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
|
||||
// Not on PresetBundle.hpp: miniz.h's zlib-compat macros rename GUI methods (GLTexture::Compressor::compress).
|
||||
// printer_config_entry is the zip name also pushed onto bundle_structure["printer_config"].
|
||||
// printer_index is that entry's 0-based index in the exported printer_config list.
|
||||
bool append_printer_bed_assets(mz_zip_archive &zip, const DynamicPrintConfig &config, nlohmann::json &bundle_structure,
|
||||
const std::string &printer_config_entry, int printer_index);
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -109,7 +109,6 @@ extern std::string format_memsize_MB(size_t n);
|
||||
extern std::string format_memsize(size_t bytes, unsigned int decimals = 1);
|
||||
// Return string to be added to the boost::log output to inform about the current process memory allocation.
|
||||
// The string is non-empty if the loglevel >= info (3) or ignore_loglevel==true.
|
||||
// Latter is used to get the memory info from SysInfoDialog.
|
||||
extern std::string log_memory_info(bool ignore_loglevel = false);
|
||||
extern void disable_multi_threading();
|
||||
// Returns the size of physical memory (RAM) in bytes.
|
||||
|
||||
@@ -1744,9 +1744,7 @@ std::string format_diameter_to_str(double diameter, int precision)
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// Returns platform-specific string to be used as log output or parsed in SysInfoDialog.
|
||||
// The latter parses the string with (semi)colons as separators, it should look about as
|
||||
// "desc1: value1; desc2: value2" or similar (spaces should not matter).
|
||||
// Returns platform-specific string to be used as log output.
|
||||
std::string log_memory_info(bool ignore_loglevel)
|
||||
{
|
||||
std::string out;
|
||||
|
||||
@@ -416,8 +416,6 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/MultiSendMachineModel.hpp
|
||||
GUI/MultiTaskManagerPage.cpp
|
||||
GUI/MultiTaskManagerPage.hpp
|
||||
GUI/MultiTaskModel.cpp
|
||||
GUI/MultiTaskModel.hpp
|
||||
GUI/NetworkTestDialog.cpp
|
||||
GUI/NetworkTestDialog.hpp
|
||||
GUI/Notebook.cpp
|
||||
@@ -804,7 +802,6 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/PrintHost.hpp
|
||||
Utils/Process.cpp
|
||||
Utils/Process.hpp
|
||||
Utils/Profile.hpp
|
||||
Utils/RaycastManager.cpp
|
||||
Utils/RaycastManager.hpp
|
||||
Utils/Repetier.cpp
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "libslic3r/Exception.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ConfigError : public Slic3r::RuntimeError {
|
||||
using Slic3r::RuntimeError::RuntimeError;
|
||||
};
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class ConfigGUITypeError : public ConfigError {
|
||||
using ConfigError::ConfigError;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
@@ -65,6 +65,7 @@
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <wx/valtext.h>
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/PrinterBedAssets.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
@@ -3674,9 +3675,20 @@ ExportConfigsDialog::~ExportConfigsDialog()
|
||||
}
|
||||
|
||||
void ExportConfigsDialog::on_dpi_changed(const wxRect &suggested_rect) {
|
||||
if (m_include_bed_assets)
|
||||
m_include_bed_assets->Rescale();
|
||||
Layout();
|
||||
}
|
||||
|
||||
void ExportConfigsDialog::update_include_bed_assets_enabled()
|
||||
{
|
||||
const bool on = get_curr_radio_type(m_export_type_btns) == m_exprot_type.preset_bundle;
|
||||
if (m_include_bed_assets)
|
||||
m_include_bed_assets->Enable(on);
|
||||
if (m_include_bed_assets_label)
|
||||
m_include_bed_assets_label->Enable(on);
|
||||
}
|
||||
|
||||
void ExportConfigsDialog::show_export_result(const ExportCase &export_case)
|
||||
{
|
||||
MessageDialog *msg_dlg = nullptr;
|
||||
@@ -3819,6 +3831,17 @@ wxBoxSizer *ExportConfigsDialog::create_export_config_item(wxWindow *parent)
|
||||
static_export_printer_preset_bundle_text->SetFont(Label::Body_12);
|
||||
static_export_printer_preset_bundle_text->SetForegroundColour(wxColour("#6B6B6B"));
|
||||
radioBoxSizer->Add(static_export_printer_preset_bundle_text, 0, wxEXPAND | wxLEFT, FromDIP(22));
|
||||
wxBoxSizer *include_bed_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_include_bed_assets = new ::CheckBox(parent);
|
||||
m_include_bed_assets->SetValue(true);
|
||||
include_bed_sizer->Add(m_include_bed_assets, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
m_include_bed_assets_label = new wxStaticText(parent, wxID_ANY, _L("Include custom bed texture and model"));
|
||||
m_include_bed_assets_label->SetFont(Label::Body_12);
|
||||
m_include_bed_assets_label->SetForegroundColour(wxColour("#6B6B6B"));
|
||||
include_bed_sizer->Add(m_include_bed_assets_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(5));
|
||||
radioBoxSizer->Add(0, 0, 0, wxTOP, FromDIP(6));
|
||||
radioBoxSizer->Add(include_bed_sizer, 0, wxEXPAND | wxLEFT, FromDIP(22));
|
||||
update_include_bed_assets_enabled();
|
||||
radioBoxSizer->Add(create_radio_item(m_exprot_type.filament_bundle, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10));
|
||||
wxStaticText *static_export_filament_preset_bundle_text = new wxStaticText(parent, wxID_ANY, _L("User's filament preset set.\nCan be shared with others."),
|
||||
wxDefaultPosition, wxDefaultSize);
|
||||
@@ -3988,9 +4011,10 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *,
|
||||
radiobox_list[i].first->SetValue(false);
|
||||
}
|
||||
}
|
||||
update_include_bed_assets_enabled();
|
||||
}
|
||||
|
||||
ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_preset_bundle_to_file(const wxString &path)
|
||||
ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_preset_bundle_to_file(const wxString &path, bool include_bed_assets)
|
||||
{
|
||||
std::string export_path = initial_file_path(path, "");
|
||||
if (export_path.empty() || "initial_failed" == export_path) return ExportCase::EXPORT_CANCEL;
|
||||
@@ -4092,6 +4116,12 @@ ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_preset_bundle_to_fi
|
||||
bundle_structure["filament_config"] = filament_configs;
|
||||
bundle_structure["process_config"] = process_configs;
|
||||
|
||||
if (include_bed_assets &&
|
||||
!append_printer_bed_assets(zip_archive, printer_preset->config, bundle_structure, printer_config_file_name, 0)) {
|
||||
mz_zip_writer_end(&zip_archive);
|
||||
return ExportCase::ADD_FILE_FAIL;
|
||||
}
|
||||
|
||||
std::string bundle_structure_str = bundle_structure.dump();
|
||||
status = mz_zip_writer_add_mem(&zip_archive, BUNDLE_STRUCTURE_JSON_NAME, bundle_structure_str.data(), bundle_structure_str.size(), MZ_DEFAULT_COMPRESSION);
|
||||
if (MZ_FALSE == status) {
|
||||
@@ -4339,7 +4369,7 @@ wxWindow *ExportConfigsDialog::create_dialog_buttons(wxWindow* parent)
|
||||
const wxString curr_radio_type = get_curr_radio_type(m_export_type_btns);
|
||||
|
||||
if (curr_radio_type == m_exprot_type.preset_bundle) {
|
||||
export_case = archive_preset_bundle_to_file(path);
|
||||
export_case = archive_preset_bundle_to_file(path, m_include_bed_assets->GetValue());
|
||||
} else if (curr_radio_type == m_exprot_type.filament_bundle) {
|
||||
export_case = archive_filament_bundle_to_file(path);
|
||||
} else if (curr_radio_type == m_exprot_type.printer_preset) {
|
||||
|
||||
@@ -271,6 +271,7 @@ protected:
|
||||
private:
|
||||
void data_init();
|
||||
void select_curr_radiobox(std::vector<std::pair<RadioBox *, wxString>> &radiobox_list, int btn_idx);
|
||||
void update_include_bed_assets_enabled();
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
void show_export_result(const ExportCase &export_case);
|
||||
bool has_check_box_selected();
|
||||
@@ -284,7 +285,7 @@ private:
|
||||
int initial_zip_archive(mz_zip_archive &zip_archive, const std::string &file_path);
|
||||
ExportCase save_zip_archive_to_file(mz_zip_archive &zip_archive);
|
||||
ExportCase save_presets_to_zip(const std::string &export_file, const std::vector<std::pair<std::string, std::string>> &config_paths);
|
||||
ExportCase archive_preset_bundle_to_file(const wxString &path);
|
||||
ExportCase archive_preset_bundle_to_file(const wxString &path, bool include_bed_assets);
|
||||
ExportCase archive_filament_bundle_to_file(const wxString &path);
|
||||
ExportCase archive_printer_preset_to_file(const wxString &path);
|
||||
ExportCase archive_filament_preset_to_file(const wxString &path);
|
||||
@@ -304,6 +305,8 @@ private:
|
||||
wxGridSizer * m_preset_sizer = nullptr;
|
||||
wxPanel * m_presets_window = nullptr;
|
||||
wxStaticText * m_serial_text = nullptr;
|
||||
::CheckBox * m_include_bed_assets = nullptr;
|
||||
wxStaticText * m_include_bed_assets_label = nullptr;
|
||||
};
|
||||
|
||||
class CreatePresetForPrinterDialog : public DPIDialog
|
||||
|
||||
@@ -2654,9 +2654,10 @@ void GUI_App::init_webview_runtime()
|
||||
BOOST_LOG_TRIVIAL(info) << "WebView2 runtime installed successfully.";
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebView2 runtime installation failed or still not detected.";
|
||||
wxMessageBox(_L("The Microsoft WebView2 Runtime could not be installed.\n"
|
||||
"Some features, including the setup wizard, may appear blank until it is installed.\n"
|
||||
"Please install it manually from https://developer.microsoft.com/microsoft-edge/webview2/ and restart Orca Slicer."),
|
||||
wxMessageBox(format_wxstr(_L("The Microsoft WebView2 Runtime could not be installed.\n"
|
||||
"Some features, including the setup wizard, may appear blank until it is installed.\n"
|
||||
"Please install it manually from %1% and restart Orca Slicer."),
|
||||
"https://developer.microsoft.com/microsoft-edge/webview2/"),
|
||||
_L("WebView2 Runtime"), wxOK | wxICON_WARNING);
|
||||
}
|
||||
}
|
||||
@@ -4854,12 +4855,6 @@ void GUI_App::recreate_GUI(const wxString &msg_name)
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "recreate_GUI exit";
|
||||
}
|
||||
|
||||
void GUI_App::system_info()
|
||||
{
|
||||
//SysInfoDialog dlg;
|
||||
//dlg.ShowModal();
|
||||
}
|
||||
|
||||
void GUI_App::keyboard_shortcuts(ShortcutContext page, wxWindow* parent)
|
||||
{
|
||||
KBShortcutsDialog dlg(parent != nullptr ? parent : mainframe, page);
|
||||
|
||||
@@ -519,7 +519,6 @@ public:
|
||||
void check_printer_presets();
|
||||
|
||||
void recreate_GUI(const wxString& message);
|
||||
void system_info();
|
||||
void keyboard_shortcuts(ShortcutContext page, wxWindow* parent = nullptr); // the main frame when null
|
||||
void troubleshoot();
|
||||
void load_project(wxWindow *parent, wxString& input_file) const;
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef slic3r_MultiTaskModel_hpp_
|
||||
#define slic3r_MultiTaskModel_hpp_
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
||||
@@ -12820,8 +12820,8 @@ void Plater::priv::on_select_bed_type(wxCommandEvent &evt)
|
||||
|
||||
// update plater with new config
|
||||
q->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||
if (auto *plate_tab = dynamic_cast<TabPrintPlate *>(wxGetApp().get_plate_tab()))
|
||||
plate_tab->update_model_config();
|
||||
// Rebuild the plate tab from the current selection; its cached plates may be gone after a reset.
|
||||
wxGetApp().obj_list()->update_and_show_object_settings_item();
|
||||
|
||||
// update app_config
|
||||
AppConfig* app_config = wxGetApp().app_config;
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
#include "SysInfoDialog.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "Plater.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/platinfo.h>
|
||||
#include "GUI_App.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "libslic3r/BlacklistedLibraryCheck.hpp"
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include "format.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
// The standard Windows includes.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <psapi.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
std::string get_main_info(bool format_as_html)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
std::string b_start = format_as_html ? "<b>" : "";
|
||||
std::string b_end = format_as_html ? "</b>" : "";
|
||||
std::string line_end = format_as_html ? "<br>" : "\n";
|
||||
|
||||
if (!format_as_html)
|
||||
out << b_start << (wxGetApp().is_editor() ? SLIC3R_APP_FULL_NAME : GCODEVIEWER_APP_NAME) << b_end << line_end;
|
||||
out << b_start << "Version: " << b_end << SLIC3R_VERSION << line_end;
|
||||
out << b_start << "Build: " << b_end << (wxGetApp().is_editor() ? SLIC3R_BUILD_ID : GCODEVIEWER_BUILD_ID) << line_end;
|
||||
out << line_end;
|
||||
out << b_start << "Operating System: " << b_end << wxPlatformInfo::Get().GetOperatingSystemFamilyName() << line_end;
|
||||
out << b_start << "System Architecture: " << b_end << wxPlatformInfo::Get().GetArchName() << line_end;
|
||||
out << b_start <<
|
||||
#if defined _WIN32
|
||||
"Windows Version: "
|
||||
#else
|
||||
// Hopefully some kind of unix / linux.
|
||||
"System Version: "
|
||||
#endif
|
||||
<< b_end << wxPlatformInfo::Get().GetOperatingSystemDescription() << line_end;
|
||||
out << b_start << "Total RAM size [MB]: " << b_end << Slic3r::format_memsize_MB(Slic3r::total_physical_memory());
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string get_mem_info(bool format_as_html)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
std::string b_start = format_as_html ? "<b>" : "";
|
||||
std::string b_end = format_as_html ? "</b>" : "";
|
||||
std::string line_end = format_as_html ? "<br>" : "\n";
|
||||
|
||||
std::string mem_info_str = log_memory_info(true);
|
||||
std::istringstream mem_info(mem_info_str);
|
||||
std::string value;
|
||||
while (std::getline(mem_info, value, ':')) {
|
||||
out << b_start << (value+": ") << b_end;
|
||||
std::getline(mem_info, value, ';');
|
||||
out << value << line_end;
|
||||
}
|
||||
|
||||
const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main();
|
||||
out << b_start << "RAM size reserved for the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end;
|
||||
out << b_start << "RAM size occupied by the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end;
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
SysInfoDialog::SysInfoDialog()
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, (wxGetApp().is_editor() ? wxString(SLIC3R_APP_FULL_NAME) : wxString(GCODEVIEWER_APP_NAME)) + " - " + _L("System Information"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
wxColour bgr_clr = wxGetApp().get_window_default_clr();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
SetBackgroundColour(bgr_clr);
|
||||
SetFont(wxGetApp().normal_font());
|
||||
|
||||
wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
hsizer->SetMinSize(wxSize(50 * wxGetApp().em_unit(), -1));
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10);
|
||||
|
||||
// logo
|
||||
m_logo_bmp = ScalableBitmap(this, wxGetApp().logo_name(), 192);
|
||||
m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bmp.bmp());
|
||||
hsizer->Add(m_logo, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
|
||||
hsizer->Add(vsizer, 1, wxEXPAND|wxLEFT, 20);
|
||||
|
||||
// title
|
||||
{
|
||||
wxStaticText* title = new wxStaticText(this, wxID_ANY, wxGetApp().is_editor() ? SLIC3R_APP_FULL_NAME : GCODEVIEWER_APP_NAME, wxDefaultPosition, wxDefaultSize);
|
||||
wxFont title_font = wxGetApp().bold_font();
|
||||
title_font.SetFamily(wxFONTFAMILY_ROMAN);
|
||||
title_font.SetPointSize(22);
|
||||
title->SetFont(title_font);
|
||||
vsizer->Add(title, 0, wxEXPAND | wxTOP, wxGetApp().em_unit()/*50*/);
|
||||
}
|
||||
|
||||
// main_info_text
|
||||
wxFont font = get_default_font(this);
|
||||
const auto text_clr = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
|
||||
auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
|
||||
|
||||
const int fs = font.GetPointSize() - 1;
|
||||
int size[] = { static_cast<int>(fs*1.5), static_cast<int>(fs*1.4), static_cast<int>(fs*1.3), fs, fs, fs, fs };
|
||||
|
||||
m_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER);
|
||||
{
|
||||
m_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
|
||||
m_html->SetBorders(2);
|
||||
const auto text = wxString::Format(
|
||||
"<html>"
|
||||
"<body bgcolor= %s link= %s>"
|
||||
"<font color=%s>"
|
||||
"%s"
|
||||
"</font>"
|
||||
"</body>"
|
||||
"</html>", bgr_clr_str, text_clr_str, text_clr_str,
|
||||
get_main_info(true));
|
||||
m_html->SetPage(text);
|
||||
vsizer->Add(m_html, 1, wxEXPAND | wxBOTTOM, wxGetApp().em_unit());
|
||||
}
|
||||
|
||||
// opengl_info
|
||||
m_opengl_info_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
|
||||
{
|
||||
m_opengl_info_html->SetMinSize(wxSize(-1, 16 * wxGetApp().em_unit()));
|
||||
m_opengl_info_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
|
||||
m_opengl_info_html->SetBorders(10);
|
||||
wxString blacklisted_libraries_message;
|
||||
#ifdef WIN32
|
||||
std::wstring blacklisted_libraries = BlacklistedLibraryCheck::get_instance().get_blacklisted_string().c_str();
|
||||
if (! blacklisted_libraries.empty())
|
||||
blacklisted_libraries_message = wxString("<br><b>") + _L("Blacklisted libraries loaded into OrcaSlicer process:") + "</b><br>" + blacklisted_libraries;
|
||||
#endif // WIN32
|
||||
const auto text = GUI::format_wxstr(
|
||||
"<html>"
|
||||
"<body bgcolor= %s link= %s>"
|
||||
"<font color=%s>"
|
||||
"%s<br>%s<br>%s<br>%s"
|
||||
"</font>"
|
||||
"</body>"
|
||||
"</html>", bgr_clr_str, text_clr_str, text_clr_str,
|
||||
blacklisted_libraries_message,
|
||||
get_mem_info(true), wxGetApp().get_gl_info(false),
|
||||
"<b>" + _L("SIMD is supported:") + "</b> " + Eigen::SimdInstructionSetsInUse());
|
||||
|
||||
m_opengl_info_html->SetPage(text);
|
||||
main_sizer->Add(m_opengl_info_html, 1, wxEXPAND | wxBOTTOM, 15);
|
||||
}
|
||||
|
||||
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK);
|
||||
m_btn_copy_to_clipboard = new wxButton(this, wxID_ANY, _L("Copy to Clipboard"), wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
buttons->Insert(0, m_btn_copy_to_clipboard, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5);
|
||||
m_btn_copy_to_clipboard->Bind(wxEVT_BUTTON, &SysInfoDialog::onCopyToClipboard, this);
|
||||
|
||||
this->SetEscapeId(wxID_OK);
|
||||
this->Bind(wxEVT_BUTTON, &SysInfoDialog::onCloseDialog, this, wxID_OK);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
|
||||
|
||||
wxGetApp().UpdateDlgDarkUI(this, true);
|
||||
|
||||
// this->Bind(wxEVT_LEFT_DOWN, &SysInfoDialog::onCloseDialog, this);
|
||||
// logo->Bind(wxEVT_LEFT_DOWN, &SysInfoDialog::onCloseDialog, this);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
}
|
||||
|
||||
void SysInfoDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||
{
|
||||
m_logo_bmp.msw_rescale();
|
||||
m_logo->SetBitmap(m_logo_bmp.bmp());
|
||||
|
||||
wxFont font = get_default_font(this);
|
||||
const int fs = font.GetPointSize() - 1;
|
||||
int font_size[] = { static_cast<int>(fs*1.5), static_cast<int>(fs*1.4), static_cast<int>(fs*1.3), fs, fs, fs, fs };
|
||||
|
||||
m_html->SetFonts(font.GetFaceName(), font.GetFaceName(), font_size);
|
||||
m_html->Refresh();
|
||||
|
||||
const int& em = em_unit();
|
||||
|
||||
msw_buttons_rescale(this, em, { wxID_OK, m_btn_copy_to_clipboard->GetId() });
|
||||
|
||||
m_opengl_info_html->SetMinSize(wxSize(-1, 16 * em));
|
||||
m_opengl_info_html->SetFonts(font.GetFaceName(), font.GetFaceName(), font_size);
|
||||
m_opengl_info_html->Refresh();
|
||||
|
||||
const wxSize& size = wxSize(65 * em, 55 * em);
|
||||
|
||||
SetMinSize(size);
|
||||
Fit();
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void SysInfoDialog::onCopyToClipboard(wxEvent &)
|
||||
{
|
||||
wxTheClipboard->Open();
|
||||
const auto text = get_main_info(false) + "\n" + wxGetApp().get_gl_info(true);
|
||||
wxTheClipboard->SetData(new wxTextDataObject(text));
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
|
||||
void SysInfoDialog::onCloseDialog(wxEvent &)
|
||||
{
|
||||
this->EndModal(wxID_CLOSE);
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef slic3r_GUI_SysInfoDialog_hpp_
|
||||
#define slic3r_GUI_SysInfoDialog_hpp_
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/wx.h>
|
||||
#include <wx/html/htmlwin.h>
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class SysInfoDialog : public DPIDialog
|
||||
{
|
||||
ScalableBitmap m_logo_bmp;
|
||||
wxStaticBitmap* m_logo;
|
||||
wxHtmlWindow* m_opengl_info_html;
|
||||
wxHtmlWindow* m_html;
|
||||
|
||||
wxButton* m_btn_copy_to_clipboard;
|
||||
|
||||
public:
|
||||
SysInfoDialog();
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
|
||||
private:
|
||||
void onCopyToClipboard(wxEvent &);
|
||||
void onCloseDialog(wxEvent &);
|
||||
};
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
||||
@@ -5957,7 +5957,7 @@ if (is_marlin_flavor)
|
||||
{
|
||||
// In the configuration group rather than a group of its own: a full-width widget line
|
||||
// records no mode, so a group holding only this line would show in every mode.
|
||||
auto line = Line{ L("Modes"), L("") };
|
||||
auto line = Line{ L("Modes"), "" };
|
||||
line.full_width = 1;
|
||||
line.widget = [this](wxWindow* parent) -> wxSizer* {
|
||||
int n_cols = 0, n_rows = 0, layout = 0;
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/webview.h>
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
WebDialog::WebDialog(wxWindow* parent,
|
||||
@@ -52,6 +56,17 @@ WebDialog::WebDialog(wxWindow* parent,
|
||||
Bind(wxEVT_CLOSE_WINDOW, &WebDialog::on_close_window, this);
|
||||
}
|
||||
|
||||
void WebDialog::use_normal_window_type()
|
||||
{
|
||||
#ifdef __WXGTK__
|
||||
// wxGTK types every wxDialog as a dialog, and Mutter offers no maximize for anything but a
|
||||
// normal window. Mutter also stops hiding a normal window from the taskbar, so keep it hidden
|
||||
// as a dialog with a parent is everywhere else.
|
||||
gtk_window_set_type_hint(GTK_WINDOW(m_widget), GDK_WINDOW_TYPE_HINT_NORMAL);
|
||||
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebDialog::add_user_scripts()
|
||||
{
|
||||
if (wxWebView* wv = browser()) {
|
||||
|
||||
@@ -62,6 +62,10 @@ public:
|
||||
|
||||
bool is_open() const { return m_open; }
|
||||
|
||||
// Lets a modeless window be maximized on X11; call before Show(). Modal ones stay dialogs so the
|
||||
// window manager keeps routing focus from the parent to them.
|
||||
void use_normal_window_type();
|
||||
|
||||
// The payload submitted via window.orca.submit() (modal use), if any.
|
||||
const std::optional<nlohmann::json>& result() const { return m_result; }
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
BEGIN_EVENT_TABLE(SideButton, wxWindow)
|
||||
EVT_LEFT_DOWN(SideButton::mouseDown)
|
||||
EVT_LEFT_UP(SideButton::mouseReleased)
|
||||
EVT_MOUSE_CAPTURE_LOST(SideButton::mouseCaptureLost)
|
||||
EVT_PAINT(SideButton::paintEvent)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
@@ -332,30 +331,20 @@ void SideButton::mouseDown(wxMouseEvent& event)
|
||||
event.Skip();
|
||||
pressedDown = true;
|
||||
SetFocus();
|
||||
// Capturing twice pushes this button onto the capture stack twice, and the
|
||||
// release would then hand the capture straight back to it.
|
||||
if (!HasCapture())
|
||||
CaptureMouse();
|
||||
CaptureMouse();
|
||||
}
|
||||
|
||||
void SideButton::mouseReleased(wxMouseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
// A press whose release went elsewhere still holds the capture.
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
if (pressedDown) {
|
||||
pressedDown = false;
|
||||
ReleaseMouse();
|
||||
if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition()))
|
||||
sendButtonEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void SideButton::mouseCaptureLost(wxMouseCaptureLostEvent&)
|
||||
{
|
||||
pressedDown = false;
|
||||
}
|
||||
|
||||
void SideButton::sendButtonEvent()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
|
||||
|
||||
@@ -94,7 +94,6 @@ private:
|
||||
|
||||
void mouseDown(wxMouseEvent& event);
|
||||
void mouseReleased(wxMouseEvent& event);
|
||||
void mouseCaptureLost(wxMouseCaptureLostEvent& event);
|
||||
|
||||
void sendButtonEvent();
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef slic3r_wxinit_hpp_
|
||||
#define slic3r_wxinit_hpp_
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/intl.h>
|
||||
#include <wx/html/htmlwin.h>
|
||||
|
||||
// Perl redefines a _ macro, so we undef this one
|
||||
#undef _
|
||||
|
||||
// We do want to use translation however, so define it as __ so we can do a find/replace
|
||||
// later when we no longer need to undef _
|
||||
#define __(s) wxGetTranslation((s))
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef slic3r_GUI_Profile_hpp_
|
||||
#define slic3r_GUI_Profile_hpp_
|
||||
|
||||
// Profiling support using the Shiny intrusive profiler
|
||||
//#define SLIC3R_PROFILE_GUI
|
||||
#if defined(SLIC3R_PROFILE) && defined(SLIC3R_PROFILE_GUI)
|
||||
#include <Shiny/Shiny.h>
|
||||
#define SLIC3R_GUI_PROFILE_FUNC() PROFILE_FUNC()
|
||||
#define SLIC3R_GUI_PROFILE_BLOCK(name) PROFILE_BLOCK(name)
|
||||
#define SLIC3R_GUI_PROFILE_UPDATE() PROFILE_UPDATE()
|
||||
#define SLIC3R_GUI_PROFILE_OUTPUT(x) PROFILE_OUTPUT(x)
|
||||
#else
|
||||
#define SLIC3R_GUI_PROFILE_FUNC()
|
||||
#define SLIC3R_GUI_PROFILE_BLOCK(name)
|
||||
#define SLIC3R_GUI_PROFILE_UPDATE()
|
||||
#define SLIC3R_GUI_PROFILE_OUTPUT(x)
|
||||
#endif
|
||||
|
||||
#endif // slic3r_GUI_Profile_hpp_
|
||||
@@ -197,6 +197,7 @@ bool CloudPluginService::download_cloud_plugin(PluginDescriptor& entry,
|
||||
Http http = Http::get(download_url);
|
||||
http.timeout_connect(30)
|
||||
.timeout_max(300)
|
||||
.tls_verify(true)
|
||||
.on_complete([&body, &http_status](std::string response_body, unsigned status) {
|
||||
body = std::move(response_body);
|
||||
http_status = status;
|
||||
|
||||
@@ -399,6 +399,7 @@ py::object ui_create_window(const std::string& html, const std::string& title, i
|
||||
if (UiRegistry::instance().is_open(new_id))
|
||||
dlg->Destroy();
|
||||
} else {
|
||||
dlg->use_normal_window_type();
|
||||
dlg->Show();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
|
||||
@@ -22,6 +24,7 @@
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
#include "libslic3r/PrinterBedAssets.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
@@ -5853,6 +5856,609 @@ TEST_CASE("Config import confines zip entries, preset names and bundle ids to th
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string kTextureBytes("\x89PNG\x00tex", 8);
|
||||
const std::string kModelBytes("stl\x00model", 9);
|
||||
const std::string kOtherBytes("\x89PNG\x00other", 10);
|
||||
|
||||
void write_bytes(const std::string &utf8_path, const std::string &bytes)
|
||||
{
|
||||
const auto slash = utf8_path.find_last_of("/\\");
|
||||
if (slash != std::string::npos) {
|
||||
#ifdef _WIN32
|
||||
fs::create_directories(fs::path(boost::nowide::widen(utf8_path.substr(0, slash))));
|
||||
#else
|
||||
fs::create_directories(utf8_path.substr(0, slash));
|
||||
#endif
|
||||
}
|
||||
boost::nowide::ofstream out(utf8_path, std::ios::binary | std::ios::trunc);
|
||||
REQUIRE(out);
|
||||
out.write(bytes.data(), static_cast<std::streamsize>(bytes.size()));
|
||||
REQUIRE(out);
|
||||
}
|
||||
|
||||
fs::path write_printer_json(const DynamicPrintConfig &defaults, const fs::path &file, const std::string &name,
|
||||
const std::string &texture, const std::string &model, const std::string &inherits = {})
|
||||
{
|
||||
DynamicPrintConfig config(defaults);
|
||||
config.option<ConfigOptionString>("printer_settings_id", true)->value = name;
|
||||
config.option<ConfigOptionString>("inherits", true)->value = inherits;
|
||||
if (texture.empty())
|
||||
config.erase("bed_custom_texture");
|
||||
else
|
||||
config.option<ConfigOptionString>("bed_custom_texture", true)->value = texture;
|
||||
if (model.empty())
|
||||
config.erase("bed_custom_model");
|
||||
else
|
||||
config.option<ConfigOptionString>("bed_custom_model", true)->value = model;
|
||||
fs::create_directories(file.parent_path());
|
||||
config.save_to_json(file.string(), name, "User", "1.0.0");
|
||||
return file;
|
||||
}
|
||||
|
||||
nlohmann::json bed_manifest(const std::string &bundle_id)
|
||||
{
|
||||
nlohmann::json structure = nlohmann::json::object();
|
||||
structure["id"] = bundle_id;
|
||||
structure["bundle_type"] = "printer config bundle";
|
||||
structure["printer_config"] = nlohmann::json::array({"printer/BedPrinter.json"});
|
||||
return structure;
|
||||
}
|
||||
|
||||
void set_printer_bed_asset(nlohmann::json &structure, const std::string &option, const std::string &zip_name,
|
||||
const std::string &printer_entry = "printer/BedPrinter.json")
|
||||
{
|
||||
structure["printer_asset"][printer_entry][option] = zip_name;
|
||||
}
|
||||
|
||||
nlohmann::json pack_bed_zip(const fs::path &zip_file, const fs::path &printer_json, const DynamicPrintConfig &defaults,
|
||||
const std::string &texture, const std::string &model, const std::string &bundle_id,
|
||||
bool include_bed_assets = true)
|
||||
{
|
||||
DynamicPrintConfig config(defaults);
|
||||
if (!texture.empty())
|
||||
config.option<ConfigOptionString>("bed_custom_texture", true)->value = texture;
|
||||
if (!model.empty())
|
||||
config.option<ConfigOptionString>("bed_custom_model", true)->value = model;
|
||||
nlohmann::json structure = bed_manifest(bundle_id);
|
||||
mz_zip_archive zip;
|
||||
mz_zip_zero_struct(&zip);
|
||||
const std::string printer_bytes = read_file(printer_json);
|
||||
REQUIRE(open_zip_writer(&zip, zip_file.string()));
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, "printer/BedPrinter.json", printer_bytes.data(), printer_bytes.size(),
|
||||
MZ_DEFAULT_COMPRESSION));
|
||||
if (include_bed_assets)
|
||||
REQUIRE(append_printer_bed_assets(zip, config, structure, "printer/BedPrinter.json", 0));
|
||||
const std::string manifest = structure.dump();
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, BUNDLE_STRUCTURE_JSON_NAME, manifest.data(), manifest.size(),
|
||||
MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(mz_zip_writer_finalize_archive(&zip));
|
||||
REQUIRE(close_zip_writer(&zip));
|
||||
return structure;
|
||||
}
|
||||
|
||||
std::vector<std::string> zip_entry_names(const fs::path &zip_file)
|
||||
{
|
||||
mz_zip_archive zip;
|
||||
mz_zip_zero_struct(&zip);
|
||||
REQUIRE(open_zip_reader(&zip, zip_file.string()));
|
||||
std::vector<std::string> names;
|
||||
const int n = static_cast<int>(mz_zip_reader_get_num_files(&zip));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
mz_zip_archive_file_stat st;
|
||||
REQUIRE(mz_zip_reader_file_stat(&zip, i, &st));
|
||||
names.emplace_back(st.m_filename);
|
||||
}
|
||||
REQUIRE(close_zip_reader(&zip));
|
||||
return names;
|
||||
}
|
||||
|
||||
const Preset *import_named_printer(PresetBundle &bundle, const fs::path &zip_file, const fs::path &data_root,
|
||||
const std::string &bare_name, int confirm = 1)
|
||||
{
|
||||
ScopedDataDir scoped(data_root);
|
||||
AppConfig config;
|
||||
std::vector<std::string> files{zip_file.string()};
|
||||
bundle.import_presets(files, [confirm](std::string const &) { return confirm; },
|
||||
ForwardCompatibilitySubstitutionRule::Disable, config);
|
||||
for (const Preset &preset : bundle.printers.get_presets())
|
||||
if (get_preset_bare_name(preset.name) == bare_name && !preset.file.empty())
|
||||
return &preset;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Preset *import_bed(PresetBundle &bundle, const fs::path &zip_file, const fs::path &data_root, int confirm = 1)
|
||||
{
|
||||
return import_named_printer(bundle, zip_file, data_root, "BedPrinter", confirm);
|
||||
}
|
||||
|
||||
struct BedRoots {
|
||||
ScopedTemporaryDir temp_dir;
|
||||
fs::path src;
|
||||
fs::path data_root;
|
||||
PresetBundle bundle;
|
||||
BedRoots()
|
||||
: src(temp_dir.path() / "src")
|
||||
, data_root(temp_dir.path() / "datadir")
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Printer bundle round trip packs bed texture and model and rewrites both keys", "[Preset][Bundle]")
|
||||
{
|
||||
// tex_rel "*" builds a non-ASCII source path under the temp directory.
|
||||
const auto pack_import = [](const std::string &bundle_id, const std::string &tex_rel, const std::string &mod_rel,
|
||||
const std::string &tex_bytes, const std::string &mod_bytes, bool tex_exists,
|
||||
bool mod_exists, int imports) {
|
||||
ScopedTemporaryDir temp_dir;
|
||||
const fs::path src = temp_dir.path() / "src";
|
||||
const fs::path data_root = temp_dir.path() / "datadir";
|
||||
std::string texture = tex_rel.empty() ? std::string() : (src / tex_rel).make_preferred().string();
|
||||
std::string model = mod_rel.empty() ? std::string() : (src / mod_rel).make_preferred().string();
|
||||
if (tex_rel == "*") {
|
||||
const fs::path dir = fs::path(src.wstring()) / fs::path(boost::nowide::widen("\xE5\xBA\x8A"));
|
||||
texture = boost::nowide::narrow((dir / fs::path(boost::nowide::widen("\xE7\xBA\xB9\xE7\x90\x86.png"))).wstring());
|
||||
}
|
||||
if (tex_exists)
|
||||
write_bytes(texture, tex_bytes);
|
||||
if (mod_exists)
|
||||
write_bytes(model, mod_bytes);
|
||||
PresetBundle bundle;
|
||||
const fs::path printer_json = write_printer_json(bundle.printers.default_preset().config, src / "BedPrinter.json",
|
||||
"BedPrinter", texture, model);
|
||||
const fs::path zip_file = src / "bundle.orca_printer";
|
||||
const nlohmann::json structure = pack_bed_zip(zip_file, printer_json, bundle.printers.default_preset().config,
|
||||
texture, model, bundle_id);
|
||||
const Preset *saved = nullptr;
|
||||
for (int i = 0; i < imports; ++i)
|
||||
saved = import_bed(bundle, zip_file, data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
const std::string got[] = {saved->config.opt_string("bed_custom_texture"), saved->config.opt_string("bed_custom_model")};
|
||||
const std::string rel[] = {tex_rel, mod_rel};
|
||||
const std::string bytes[] = {tex_bytes, mod_bytes};
|
||||
const std::string path[] = {texture, model};
|
||||
const bool exists[] = {tex_exists, mod_exists};
|
||||
const char *option[] = {"bed_custom_texture", "bed_custom_model"};
|
||||
const char *stem[] = {"texture", "model"};
|
||||
for (int slot = 0; slot < 2; ++slot) {
|
||||
if (exists[slot]) {
|
||||
const std::string ext = fs::path(rel[slot] == "*" ? "x.png" : rel[slot]).extension().string();
|
||||
const std::string zip_name = std::string("bed/0/") + stem[slot] + ext;
|
||||
REQUIRE(structure["printer_asset"]["printer/BedPrinter.json"][option[slot]] == zip_name);
|
||||
REQUIRE(fs::path(got[slot]).filename().string() == std::string(stem[slot]) + fs::path(zip_name).extension().string());
|
||||
REQUIRE(fs::path(got[slot]).parent_path().filename() == "0");
|
||||
REQUIRE(fs::path(got[slot]).parent_path().parent_path().filename() == "bed");
|
||||
REQUIRE(got[slot].find(bundle_id) != std::string::npos);
|
||||
REQUIRE(read_file(got[slot]) == bytes[slot]);
|
||||
REQUIRE(got[slot] != path[slot]);
|
||||
} else if (!rel[slot].empty() && rel[slot] != "*") {
|
||||
REQUIRE_FALSE(structure.value("printer_asset", nlohmann::json::object())
|
||||
.value("printer/BedPrinter.json", nlohmann::json::object())
|
||||
.contains(option[slot]));
|
||||
REQUIRE(got[slot] == path[slot]);
|
||||
} else if (rel[slot].empty()) {
|
||||
REQUIRE(got[slot].empty());
|
||||
}
|
||||
}
|
||||
if (imports > 1) {
|
||||
int copies = 0;
|
||||
for (fs::recursive_directory_iterator it(data_root), end; it != end; ++it)
|
||||
if (it->path().filename() == "texture.png" || it->path().filename() == "model.stl")
|
||||
++copies;
|
||||
REQUIRE(copies == (tex_exists ? 1 : 0) + (mod_exists ? 1 : 0));
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("both assets are packed from the preset config and rewritten on import") {
|
||||
pack_import("bed-roundtrip", "fixture/baseline_bed_texture.png", "fixture/baseline_bed_model.stl",
|
||||
kTextureBytes, kModelBytes, true, true, 1);
|
||||
}
|
||||
SECTION("texture only") {
|
||||
pack_import("texture-only", "only.png", "", kTextureBytes, "", true, false, 1);
|
||||
}
|
||||
SECTION("model only") {
|
||||
pack_import("model-only", "", "only.stl", "", kModelBytes, false, true, 1);
|
||||
}
|
||||
SECTION("texture and model share a source basename") {
|
||||
pack_import("shared-basename", "a/plate.png", "b/plate.stl", kTextureBytes, kOtherBytes, true, true, 1);
|
||||
}
|
||||
SECTION("importing the same bundle twice keeps one copy of the assets") {
|
||||
// First import installs kTextureBytes / kModelBytes. The second pack uses different bytes so
|
||||
// the Yes-overwrite path (copy_file overwrite_existing) is actually proven.
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "twice.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "twice.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config,
|
||||
bed.src / "BedPrinter.json", "BedPrinter", texture, model);
|
||||
const fs::path zip_file = bed.src / "bundle.orca_printer";
|
||||
pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config, texture, model, "reimport");
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
const std::string got_tex = saved->config.opt_string("bed_custom_texture");
|
||||
const std::string got_mod = saved->config.opt_string("bed_custom_model");
|
||||
REQUIRE(read_file(got_tex) == kTextureBytes);
|
||||
REQUIRE(read_file(got_mod) == kModelBytes);
|
||||
write_bytes(texture, kOtherBytes);
|
||||
write_bytes(model, std::string("stl\x00other", 9));
|
||||
pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config, texture, model, "reimport");
|
||||
saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == got_tex);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") == got_mod);
|
||||
REQUIRE(read_file(got_tex) == kOtherBytes);
|
||||
REQUIRE(read_file(got_mod) == std::string("stl\x00other", 9));
|
||||
}
|
||||
SECTION("a non-ASCII source path is packed") {
|
||||
pack_import("non-ascii", "*", "", kTextureBytes, "", true, false, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("An old printer bundle without printer_asset imports unchanged", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "old.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "old.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, model);
|
||||
nlohmann::json structure = bed_manifest("old-bundle");
|
||||
REQUIRE_FALSE(structure.contains("printer_asset"));
|
||||
const fs::path zip_file = bed.src / "old.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}});
|
||||
// A bed/ folder left by an earlier import into the same bundle folder must survive an asset-less import.
|
||||
const fs::path old_bed = bed.data_root / "user" / "default" / "_local" / "old-bundle" / "bed";
|
||||
write_bytes((old_bed / "texture.png").string(), kTextureBytes);
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") == model);
|
||||
CHECK(fs::exists(old_bed / "texture.png"));
|
||||
}
|
||||
|
||||
TEST_CASE("Printer bundle asset names that escape the bundle directory are rejected", "[Preset][Bundle]")
|
||||
{
|
||||
const char *bad_names[] = {"../../pwned.png", "bed/../../pwned.png", "..\\..\\pwned.png", "C:/Windows/pwned.png",
|
||||
"machine/texture.png", "/bed/texture.png"};
|
||||
const std::string marker = "PWNED-BED-ASSET-MARKER";
|
||||
for (const char *name : bad_names) {
|
||||
DYNAMIC_SECTION("rejects " << name) {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "kept.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config,
|
||||
bed.src / "BedPrinter.json", "BedPrinter", texture, model);
|
||||
nlohmann::json structure = bed_manifest("traverse");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", name);
|
||||
std::vector<std::pair<std::string, std::string>> entries = {
|
||||
{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}};
|
||||
if (name[0] != '/' && name[0] != '\\')
|
||||
entries.emplace_back(name, marker);
|
||||
const fs::path zip_file = bed.src / "bad.orca_printer";
|
||||
write_zip(zip_file, entries);
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") == model);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, fs::path(name).filename().string()));
|
||||
if (fs::exists(bed.data_root))
|
||||
for (fs::recursive_directory_iterator it(bed.data_root), end; it != end; ++it)
|
||||
if (fs::is_regular_file(*it))
|
||||
CHECK(read_file(*it).find(marker) == std::string::npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A printer bundle asset that is missing is skipped", "[Preset][Bundle]")
|
||||
{
|
||||
SECTION("a manifest entry with no zip bytes leaves the original path") {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "gone.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("missing-zip");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
const fs::path zip_file = bed.src / "missing.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
|
||||
SECTION("a missing file at export is omitted and the export still succeeds") {
|
||||
BedRoots bed;
|
||||
const std::string missing = (bed.src / "missing.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "present.stl").make_preferred().string();
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", missing, model);
|
||||
const fs::path zip_file = bed.src / "partial.orca_printer";
|
||||
const nlohmann::json structure = pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config,
|
||||
missing, model, "missing-export");
|
||||
REQUIRE_FALSE(structure["printer_asset"]["printer/BedPrinter.json"].contains("bed_custom_texture"));
|
||||
REQUIRE(structure["printer_asset"]["printer/BedPrinter.json"]["bed_custom_model"] == "bed/0/model.stl");
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == missing);
|
||||
REQUIRE(read_file(saved->config.opt_string("bed_custom_model")) == kModelBytes);
|
||||
REQUIRE(fs::path(saved->config.opt_string("bed_custom_model")).filename() == "model.stl");
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("An inherited printer bundle rewrites bed paths taken from the parent", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "parent.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "parent.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
DynamicPrintConfig parent(bed.bundle.printers.default_preset().config);
|
||||
parent.option<ConfigOptionString>("printer_settings_id", true)->value = "ParentPrinter";
|
||||
parent.option<ConfigOptionString>("inherits", true)->value.clear();
|
||||
parent.option<ConfigOptionString>("bed_custom_texture", true)->value = texture;
|
||||
parent.option<ConfigOptionString>("bed_custom_model", true)->value = model;
|
||||
bed.bundle.printers.load_preset((bed.src / "ParentPrinter.json").string(), "ParentPrinter", std::move(parent), false);
|
||||
const fs::path child_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {}, "ParentPrinter");
|
||||
const nlohmann::json written = nlohmann::json::parse(read_file(child_json));
|
||||
REQUIRE_FALSE(written.contains("bed_custom_texture"));
|
||||
REQUIRE_FALSE(written.contains("bed_custom_model"));
|
||||
nlohmann::json structure = bed_manifest("inherit-bed");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
set_printer_bed_asset(structure, "bed_custom_model", "bed/0/model.stl");
|
||||
const fs::path zip_file = bed.src / "inherit.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(child_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.png", kTextureBytes}, {"bed/0/model.stl", kModelBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") != texture);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") != model);
|
||||
REQUIRE(read_file(saved->config.opt_string("bed_custom_texture")) == kTextureBytes);
|
||||
REQUIRE(read_file(saved->config.opt_string("bed_custom_model")) == kModelBytes);
|
||||
REQUIRE(fs::path(saved->config.opt_string("bed_custom_texture")).filename() == "texture.png");
|
||||
REQUIRE(fs::path(saved->config.opt_string("bed_custom_model")).filename() == "model.stl");
|
||||
}
|
||||
|
||||
TEST_CASE("A printer bundle rejects bed assets whose extension the bed dialog does not allow", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("bad-ext");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.stl");
|
||||
set_printer_bed_asset(structure, "bed_custom_model", "bed/0/model.exe");
|
||||
const fs::path zip_file = bed.src / "bad-ext.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.stl", kTextureBytes}, {"bed/0/model.exe", std::string("MZ")}});
|
||||
REQUIRE(import_bed(bed.bundle, zip_file, bed.data_root) != nullptr);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "model.exe"));
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.stl"));
|
||||
}
|
||||
|
||||
TEST_CASE("A manifest asset name that points at a preset does not drop that preset", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("name-clash");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "printer/BedPrinter.json");
|
||||
const fs::path zip_file = bed.src / "clash.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}});
|
||||
REQUIRE(import_bed(bed.bundle, zip_file, bed.data_root) != nullptr);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
|
||||
TEST_CASE("A declined printer bundle import leaves existing bed files alone", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path kept = bed.data_root / "user" / "default" / "_local" / "keep-bed" / "bed" / "texture.png";
|
||||
const std::string original("kept-texture");
|
||||
write_bytes(kept.string(), original);
|
||||
DynamicPrintConfig existing(bed.bundle.printers.default_preset().config);
|
||||
existing.option<ConfigOptionString>("printer_settings_id", true)->value = "BedPrinter";
|
||||
existing.option<ConfigOptionString>("inherits", true)->value.clear();
|
||||
bed.bundle.printers.load_preset((bed.src / "existing.json").string(), "_local/keep-bed/BedPrinter", std::move(existing),
|
||||
false);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("keep-bed");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
set_printer_bed_asset(structure, "bed_custom_model", "bed/0/model.stl");
|
||||
const fs::path zip_file = bed.src / "keep.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.png", kTextureBytes}, {"bed/0/model.stl", kModelBytes}});
|
||||
import_bed(bed.bundle, zip_file, bed.data_root, 0);
|
||||
// This import wrote nothing: the existing texture is unchanged and model.stl was not added.
|
||||
REQUIRE(fs::exists(kept));
|
||||
REQUIRE(read_file(kept) == original);
|
||||
CHECK_FALSE(fs::exists(kept.parent_path() / "model.stl"));
|
||||
CHECK_FALSE(fs::exists(kept.parent_path() / "0" / "model.stl"));
|
||||
}
|
||||
|
||||
TEST_CASE("A declined re-import does not replace bed bytes an earlier import wrote", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("reimport-no");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
const std::string manifest = structure.dump();
|
||||
const std::string printer_bytes = read_file(printer_json);
|
||||
const fs::path first_zip = bed.src / "first.orca_printer";
|
||||
const fs::path second_zip = bed.src / "second.orca_printer";
|
||||
write_zip(first_zip, {{"printer/BedPrinter.json", printer_bytes}, {BUNDLE_STRUCTURE_JSON_NAME, manifest},
|
||||
{"bed/0/texture.png", kTextureBytes}});
|
||||
write_zip(second_zip, {{"printer/BedPrinter.json", printer_bytes}, {BUNDLE_STRUCTURE_JSON_NAME, manifest},
|
||||
{"bed/0/texture.png", kOtherBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, first_zip, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
const std::string installed = saved->config.opt_string("bed_custom_texture");
|
||||
REQUIRE(read_file(installed) == kTextureBytes);
|
||||
import_bed(bed.bundle, second_zip, bed.data_root, 0);
|
||||
REQUIRE(fs::exists(installed));
|
||||
REQUIRE(read_file(installed) == kTextureBytes);
|
||||
}
|
||||
|
||||
TEST_CASE("Export with bed assets disabled packs no bed files and writes no printer_asset", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "off.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "off.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, model);
|
||||
const fs::path zip_file = bed.src / "off.orca_printer";
|
||||
const nlohmann::json structure = pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config,
|
||||
texture, model, "bed-off", false);
|
||||
REQUIRE_FALSE(structure.contains("printer_asset"));
|
||||
for (const std::string &name : zip_entry_names(zip_file))
|
||||
REQUIRE(name.compare(0, 4, "bed/") != 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Two printers in one bundle keep separate bed folders", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string tex_a = (bed.src / "a.png").make_preferred().string();
|
||||
const std::string mod_a = (bed.src / "a.stl").make_preferred().string();
|
||||
const std::string tex_b = (bed.src / "b.png").make_preferred().string();
|
||||
const std::string mod_b = (bed.src / "b.stl").make_preferred().string();
|
||||
write_bytes(tex_a, kTextureBytes);
|
||||
write_bytes(mod_a, kModelBytes);
|
||||
write_bytes(tex_b, kOtherBytes);
|
||||
write_bytes(mod_b, std::string("stl\x00other", 9));
|
||||
const fs::path json_a = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "PrinterA.json",
|
||||
"PrinterA", tex_a, mod_a);
|
||||
const fs::path json_b = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "PrinterB.json",
|
||||
"PrinterB", tex_b, mod_b);
|
||||
nlohmann::json structure = nlohmann::json::object();
|
||||
structure["id"] = "two-printers";
|
||||
structure["bundle_type"] = "printer config bundle";
|
||||
structure["printer_config"] = nlohmann::json::array({"printer/PrinterA.json", "printer/PrinterB.json"});
|
||||
DynamicPrintConfig config_a(bed.bundle.printers.default_preset().config);
|
||||
config_a.option<ConfigOptionString>("bed_custom_texture", true)->value = tex_a;
|
||||
config_a.option<ConfigOptionString>("bed_custom_model", true)->value = mod_a;
|
||||
DynamicPrintConfig config_b(bed.bundle.printers.default_preset().config);
|
||||
config_b.option<ConfigOptionString>("bed_custom_texture", true)->value = tex_b;
|
||||
config_b.option<ConfigOptionString>("bed_custom_model", true)->value = mod_b;
|
||||
const fs::path zip_file = bed.src / "two.orca_printer";
|
||||
mz_zip_archive zip;
|
||||
mz_zip_zero_struct(&zip);
|
||||
const std::string bytes_a = read_file(json_a);
|
||||
const std::string bytes_b = read_file(json_b);
|
||||
REQUIRE(open_zip_writer(&zip, zip_file.string()));
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, "printer/PrinterA.json", bytes_a.data(), bytes_a.size(), MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, "printer/PrinterB.json", bytes_b.data(), bytes_b.size(), MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(append_printer_bed_assets(zip, config_a, structure, "printer/PrinterA.json", 0));
|
||||
REQUIRE(append_printer_bed_assets(zip, config_b, structure, "printer/PrinterB.json", 1));
|
||||
const std::string manifest = structure.dump();
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, BUNDLE_STRUCTURE_JSON_NAME, manifest.data(), manifest.size(),
|
||||
MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(mz_zip_writer_finalize_archive(&zip));
|
||||
REQUIRE(close_zip_writer(&zip));
|
||||
REQUIRE(structure["printer_asset"]["printer/PrinterA.json"]["bed_custom_texture"] == "bed/0/texture.png");
|
||||
REQUIRE(structure["printer_asset"]["printer/PrinterB.json"]["bed_custom_texture"] == "bed/1/texture.png");
|
||||
ScopedDataDir scoped(bed.data_root);
|
||||
AppConfig app_config;
|
||||
std::vector<std::string> files{zip_file.string()};
|
||||
bed.bundle.import_presets(files, [](std::string const &) { return 1; },
|
||||
ForwardCompatibilitySubstitutionRule::Disable, app_config);
|
||||
const Preset *saved_a = nullptr;
|
||||
const Preset *saved_b = nullptr;
|
||||
for (const Preset &preset : bed.bundle.printers.get_presets()) {
|
||||
if (preset.file.empty())
|
||||
continue;
|
||||
if (get_preset_bare_name(preset.name) == "PrinterA")
|
||||
saved_a = &preset;
|
||||
if (get_preset_bare_name(preset.name) == "PrinterB")
|
||||
saved_b = &preset;
|
||||
}
|
||||
REQUIRE(saved_a != nullptr);
|
||||
REQUIRE(saved_b != nullptr);
|
||||
const std::string got_tex_a = saved_a->config.opt_string("bed_custom_texture");
|
||||
const std::string got_tex_b = saved_b->config.opt_string("bed_custom_texture");
|
||||
REQUIRE(fs::path(got_tex_a).parent_path().filename() == "0");
|
||||
REQUIRE(fs::path(got_tex_b).parent_path().filename() == "1");
|
||||
REQUIRE(got_tex_a != got_tex_b);
|
||||
REQUIRE(read_file(got_tex_a) == kTextureBytes);
|
||||
REQUIRE(read_file(got_tex_b) == kOtherBytes);
|
||||
REQUIRE(read_file(saved_a->config.opt_string("bed_custom_model")) == kModelBytes);
|
||||
REQUIRE(read_file(saved_b->config.opt_string("bed_custom_model")) == std::string("stl\x00other", 9));
|
||||
}
|
||||
|
||||
TEST_CASE("A printer_asset entry keyed to a printer not in the zip is ignored", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("ghost-key");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png", "printer/Ghost.json");
|
||||
const fs::path zip_file = bed.src / "ghost.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.png", kOtherBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
|
||||
TEST_CASE("Keyed printer_asset rejects malformed bed paths", "[Preset][Bundle]")
|
||||
{
|
||||
const char *bad_names[] = {"bed/texture.png", "bed/x/texture.png", "bed/0/../texture.png", "bed/0/model.png"};
|
||||
const std::string marker = "PWNED-BED-ASSET-MARKER";
|
||||
for (const char *name : bad_names) {
|
||||
DYNAMIC_SECTION("rejects " << name) {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config,
|
||||
bed.src / "BedPrinter.json", "BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("bad-keyed");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", name);
|
||||
std::vector<std::pair<std::string, std::string>> entries = {
|
||||
{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{name, marker}};
|
||||
const fs::path zip_file = bed.src / "bad-keyed.orca_printer";
|
||||
write_zip(zip_file, entries);
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
if (fs::exists(bed.data_root))
|
||||
for (fs::recursive_directory_iterator it(bed.data_root), end; it != end; ++it)
|
||||
if (fs::is_regular_file(*it))
|
||||
CHECK(read_file(*it).find(marker) == std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("field name does not match file kind") {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("kind-mismatch");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/model.stl");
|
||||
const fs::path zip_file = bed.src / "kind.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/model.stl", kModelBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "model.stl"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A saved printer preset reloads the tool layout it was saved with", "[Preset][Bundle][IMEX]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
|
||||
Reference in New Issue
Block a user