mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 21:26:01 +08:00
Merge branch 'master' into fs_emboss
This commit is contained in:
commit
08b8bc447a
@ -1,7 +1,9 @@
|
||||
min_slic3r_version = 2.6.0-alpha1
|
||||
1.6.0-alpha2 Added profile for Prusament PETG Carbon Fiber and Fiberthree F3 PA-GF30 Pro. Updated acceleration settings for Prusa MINI.
|
||||
1.6.0-alpha1 Updated FW version notification. Decreased min layer time for PLA.
|
||||
1.6.0-alpha0 Default top fill set to monotonic lines. Updated infill/perimeter overlap values. Updated output filename format. Enabled dynamic overhang speeds.
|
||||
min_slic3r_version = 2.5.0-alpha0
|
||||
1.5.7 Added filament profile for Prusament PETG Carbon Fiber and Fiberthree F3 PA-GF30 Pro.
|
||||
1.5.6 Updated FW version notification (MK2.5/MK3 family). Added filament profile for Kimya PEBA-S.
|
||||
1.5.5 Added new Prusament Resin material profiles. Enabled g-code thumbnails for MK2.5 family printers.
|
||||
1.5.4 Added material profiles for Prusament Resin BioBased60.
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = Prusa Research
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.6.0-alpha1
|
||||
config_version = 1.6.0-alpha2
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
|
||||
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
||||
@ -145,7 +145,6 @@ bridge_flow_ratio = 1
|
||||
bridge_speed = 25
|
||||
brim_width = 0
|
||||
brim_separation = 0.1
|
||||
clip_multipart_objects = 1
|
||||
compatible_printers =
|
||||
complete_objects = 0
|
||||
default_acceleration = 1000
|
||||
@ -268,8 +267,10 @@ fill_pattern = grid
|
||||
travel_speed = 150
|
||||
wipe_tower = 0
|
||||
default_acceleration = 1000
|
||||
first_layer_acceleration = 800
|
||||
infill_acceleration = 1000
|
||||
first_layer_acceleration = 600
|
||||
infill_acceleration = 1500
|
||||
solid_infill_acceleration = 1500
|
||||
top_solid_infill_acceleration = 800
|
||||
bridge_acceleration = 1000
|
||||
support_material_speed = 40
|
||||
max_print_speed = 150
|
||||
@ -373,7 +374,9 @@ fill_pattern = gyroid
|
||||
fill_density = 15%
|
||||
travel_speed = 150
|
||||
perimeter_acceleration = 800
|
||||
infill_acceleration = 1000
|
||||
infill_acceleration = 1500
|
||||
solid_infill_acceleration = 1500
|
||||
top_solid_infill_acceleration = 800
|
||||
bridge_acceleration = 1000
|
||||
first_layer_acceleration = 800
|
||||
default_acceleration = 1250
|
||||
@ -1283,6 +1286,10 @@ support_material_extrusion_width = 0.35
|
||||
bridge_acceleration = 300
|
||||
support_material_contact_distance = 0.1
|
||||
raft_contact_distance = 0.1
|
||||
infill_acceleration = 1000
|
||||
solid_infill_acceleration = 1000
|
||||
top_solid_infill_acceleration = 800
|
||||
external_perimeter_acceleration = 300
|
||||
|
||||
[print:0.07mm ULTRADETAIL @MINI]
|
||||
inherits = *0.07mm*; *MINI*
|
||||
@ -1298,6 +1305,10 @@ support_material_extrusion_width = 0.35
|
||||
bridge_acceleration = 300
|
||||
support_material_contact_distance = 0.1
|
||||
raft_contact_distance = 0.1
|
||||
infill_acceleration = 1000
|
||||
solid_infill_acceleration = 1000
|
||||
top_solid_infill_acceleration = 800
|
||||
external_perimeter_acceleration = 300
|
||||
|
||||
[print:0.10mm DETAIL @MINI]
|
||||
inherits = *0.10mm*; *MINI*
|
||||
@ -1314,6 +1325,11 @@ fill_pattern = gyroid
|
||||
fill_density = 15%
|
||||
perimeters = 3
|
||||
support_material_xy_spacing = 60%
|
||||
infill_acceleration = 1200
|
||||
solid_infill_acceleration = 1000
|
||||
top_solid_infill_acceleration = 800
|
||||
perimeter_acceleration = 700
|
||||
external_perimeter_acceleration = 600
|
||||
|
||||
[print:0.15mm QUALITY @MINI]
|
||||
inherits = *0.15mm*; *MINI*
|
||||
@ -1326,6 +1342,8 @@ top_solid_infill_speed = 40
|
||||
fill_pattern = gyroid
|
||||
fill_density = 15%
|
||||
support_material_xy_spacing = 60%
|
||||
perimeter_acceleration = 900
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.15mm SPEED @MINI]
|
||||
inherits = *0.15mm*; *MINI*
|
||||
@ -1336,6 +1354,8 @@ infill_speed = 140
|
||||
solid_infill_speed = 140
|
||||
top_solid_infill_speed = 40
|
||||
support_material_xy_spacing = 60%
|
||||
perimeter_acceleration = 1000
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.20mm QUALITY @MINI]
|
||||
inherits = *0.20mm*; *MINI*
|
||||
@ -1348,6 +1368,8 @@ top_solid_infill_speed = 40
|
||||
fill_pattern = gyroid
|
||||
fill_density = 15%
|
||||
support_material_xy_spacing = 60%
|
||||
perimeter_acceleration = 900
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.20mm SPEED @MINI]
|
||||
inherits = *0.20mm*; *MINI*
|
||||
@ -1359,6 +1381,8 @@ max_print_speed = 150
|
||||
solid_infill_speed = 140
|
||||
top_solid_infill_speed = 40
|
||||
support_material_xy_spacing = 60%
|
||||
perimeter_acceleration = 1000
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.25mm DRAFT @MINI]
|
||||
inherits = *0.25mm*; *MINI*
|
||||
@ -1378,6 +1402,8 @@ top_infill_extrusion_width = 0.4
|
||||
support_material_xy_spacing = 60%
|
||||
support_material_contact_distance = 0.2
|
||||
raft_contact_distance = 0.2
|
||||
perimeter_acceleration = 1000
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
# MINI - 0.25mm nozzle
|
||||
|
||||
@ -1389,6 +1415,10 @@ fill_density = 20%
|
||||
support_material_speed = 30
|
||||
support_material_contact_distance = 0.07
|
||||
raft_contact_distance = 0.07
|
||||
infill_acceleration = 1000
|
||||
solid_infill_acceleration = 1000
|
||||
top_solid_infill_acceleration = 800
|
||||
external_perimeter_acceleration = 300
|
||||
|
||||
[print:0.07mm ULTRADETAIL @0.25 nozzle MINI]
|
||||
inherits = *0.07mm*; *0.25nozzle*; *MINI*
|
||||
@ -1401,6 +1431,10 @@ fill_pattern = grid
|
||||
fill_density = 20%
|
||||
support_material_contact_distance = 0.07
|
||||
raft_contact_distance = 0.07
|
||||
infill_acceleration = 1000
|
||||
solid_infill_acceleration = 1000
|
||||
top_solid_infill_acceleration = 800
|
||||
external_perimeter_acceleration = 300
|
||||
|
||||
[print:0.10mm DETAIL @0.25 nozzle MINI]
|
||||
inherits = *0.10mm*; *0.25nozzleMINI*; *MINI*
|
||||
@ -1409,6 +1443,10 @@ fill_pattern = grid
|
||||
fill_density = 20%
|
||||
support_material_contact_distance = 0.07
|
||||
raft_contact_distance = 0.07
|
||||
infill_acceleration = 1200
|
||||
solid_infill_acceleration = 1000
|
||||
top_solid_infill_acceleration = 800
|
||||
external_perimeter_acceleration = 500
|
||||
|
||||
[print:0.15mm QUALITY @0.25 nozzle MINI]
|
||||
inherits = *0.15mm*; *0.25nozzleMINI*; *MINI*
|
||||
@ -1421,6 +1459,10 @@ perimeter_extrusion_width = 0.27
|
||||
external_perimeter_extrusion_width = 0.27
|
||||
infill_extrusion_width = 0.27
|
||||
solid_infill_extrusion_width = 0.27
|
||||
infill_acceleration = 1500
|
||||
solid_infill_acceleration = 1000
|
||||
top_solid_infill_acceleration = 800
|
||||
external_perimeter_acceleration = 500
|
||||
|
||||
# MINI - 0.6mm nozzle
|
||||
|
||||
@ -1433,11 +1475,17 @@ max_print_speed = 100
|
||||
perimeter_speed = 45
|
||||
solid_infill_speed = 70
|
||||
top_solid_infill_speed = 45
|
||||
infill_extrusion_width = 0.65
|
||||
solid_infill_extrusion_width = 0.65
|
||||
perimeter_extrusion_width = 0.6
|
||||
external_perimeter_extrusion_width = 0.6
|
||||
infill_extrusion_width = 0.6
|
||||
solid_infill_extrusion_width = 0.6
|
||||
top_infill_extrusion_width = 0.5
|
||||
support_material_contact_distance = 0.22
|
||||
raft_contact_distance = 0.22
|
||||
bridge_flow_ratio = 1
|
||||
top_solid_infill_acceleration = 800
|
||||
perimeter_acceleration = 900
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.20mm DETAIL @0.6 nozzle MINI]
|
||||
inherits = *0.20mm*; *0.6nozzleMINI*
|
||||
@ -1448,11 +1496,16 @@ max_print_speed = 100
|
||||
perimeter_speed = 45
|
||||
solid_infill_speed = 70
|
||||
top_solid_infill_speed = 45
|
||||
infill_extrusion_width = 0.65
|
||||
solid_infill_extrusion_width = 0.65
|
||||
perimeter_extrusion_width = 0.6
|
||||
external_perimeter_extrusion_width = 0.6
|
||||
infill_extrusion_width = 0.6
|
||||
solid_infill_extrusion_width = 0.6
|
||||
top_infill_extrusion_width = 0.5
|
||||
support_material_contact_distance = 0.22
|
||||
raft_contact_distance = 0.22
|
||||
bridge_flow_ratio = 1
|
||||
perimeter_acceleration = 900
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.30mm QUALITY @0.6 nozzle MINI]
|
||||
inherits = *0.30mm*; *0.6nozzleMINI*
|
||||
@ -1465,9 +1518,12 @@ solid_infill_speed = 65
|
||||
top_solid_infill_speed = 45
|
||||
external_perimeter_extrusion_width = 0.68
|
||||
perimeter_extrusion_width = 0.68
|
||||
top_infill_extrusion_width = 0.55
|
||||
support_material_contact_distance = 0.25
|
||||
raft_contact_distance = 0.25
|
||||
bridge_flow_ratio = 1
|
||||
perimeter_acceleration = 900
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.35mm SPEED @0.6 nozzle MINI]
|
||||
inherits = *0.35mm*; *0.6nozzleMINI*
|
||||
@ -1483,6 +1539,8 @@ perimeter_extrusion_width = 0.68
|
||||
support_material_contact_distance = 0.25
|
||||
raft_contact_distance = 0.25
|
||||
bridge_flow_ratio = 0.95
|
||||
perimeter_acceleration = 1000
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.40mm DRAFT @0.6 nozzle MINI]
|
||||
inherits = *0.40mm*; *0.6nozzleMINI*
|
||||
@ -1500,6 +1558,8 @@ solid_infill_extrusion_width = 0.68
|
||||
support_material_contact_distance = 0.25
|
||||
raft_contact_distance = 0.25
|
||||
bridge_flow_ratio = 0.95
|
||||
perimeter_acceleration = 1000
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
# MINI - 0.8mm nozzle
|
||||
|
||||
@ -1508,13 +1568,17 @@ inherits = 0.30mm DETAIL @0.8 nozzle
|
||||
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]==0.8
|
||||
perimeter_speed = 35
|
||||
external_perimeter_speed = 25
|
||||
infill_acceleration = 1000
|
||||
infill_speed = 50
|
||||
max_print_speed = 80
|
||||
solid_infill_speed = 45
|
||||
top_solid_infill_speed = 35
|
||||
support_material_speed = 40
|
||||
travel_speed = 150
|
||||
infill_acceleration = 1500
|
||||
solid_infill_acceleration = 1500
|
||||
top_solid_infill_acceleration = 800
|
||||
perimeter_acceleration = 900
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.40mm QUALITY @0.8 nozzle MINI]
|
||||
inherits = 0.40mm QUALITY @0.8 nozzle
|
||||
@ -1525,11 +1589,15 @@ solid_infill_speed = 40
|
||||
top_solid_infill_speed = 30
|
||||
support_material_speed = 40
|
||||
travel_speed = 150
|
||||
infill_acceleration = 1500
|
||||
solid_infill_acceleration = 1500
|
||||
top_solid_infill_acceleration = 800
|
||||
perimeter_acceleration = 1000
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
[print:0.55mm DRAFT @0.8 nozzle MINI]
|
||||
inherits = 0.55mm DRAFT @0.8 nozzle
|
||||
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]==0.8
|
||||
infill_acceleration = 1000
|
||||
infill_speed = 40
|
||||
solid_infill_speed = 40
|
||||
support_material_speed = 35
|
||||
@ -1539,6 +1607,11 @@ top_solid_infill_speed = 28
|
||||
external_perimeter_extrusion_width = 1
|
||||
perimeter_extrusion_width = 1
|
||||
travel_speed = 150
|
||||
infill_acceleration = 1500
|
||||
solid_infill_acceleration = 1500
|
||||
top_solid_infill_acceleration = 800
|
||||
perimeter_acceleration = 1000
|
||||
external_perimeter_acceleration = 800
|
||||
|
||||
# XXXXXXxxXXXXXXXXXXXXXX
|
||||
# XXX--- filament ---XXX
|
||||
@ -3865,6 +3938,17 @@ filament_spool_weight = 201
|
||||
filament_type = PETG
|
||||
compatible_printers_condition = nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber]
|
||||
inherits = Prusament PETG
|
||||
filament_vendor = Prusa Polymers
|
||||
first_layer_temperature = 260
|
||||
temperature = 265
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_density = 1.27
|
||||
filament_colour = #BBBBBB
|
||||
compatible_printers_condition = nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
|
||||
|
||||
[filament:Prusa PETG @0.6 nozzle]
|
||||
inherits = *PET06*
|
||||
renamed_from = "Prusa PET 0.6 nozzle"; "Prusa PETG 0.6 nozzle"
|
||||
@ -3883,6 +3967,14 @@ filament_density = 1.27
|
||||
filament_spool_weight = 201
|
||||
filament_type = PETG
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @0.6 nozzle]
|
||||
inherits = Prusament PETG @0.6 nozzle
|
||||
first_layer_temperature = 260
|
||||
temperature = 265
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Filament PM PETG @0.6 nozzle]
|
||||
inherits = *PET06*
|
||||
renamed_from = "Plasty Mladec PETG @0.6 nozzle"
|
||||
@ -3976,6 +4068,14 @@ filament_cost = 36.29
|
||||
filament_density = 1.27
|
||||
filament_spool_weight = 201
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @MMU2]
|
||||
inherits = Prusament PETG @MMU2
|
||||
first_layer_temperature = 260
|
||||
temperature = 260
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Generic PETG @MMU2 0.6 nozzle]
|
||||
inherits = *PET MMU2 06*
|
||||
renamed_from = "Generic PET MMU2 0.6 nozzle"; "Generic PETG MMU2 0.6 nozzle"
|
||||
@ -3995,6 +4095,14 @@ filament_cost = 36.29
|
||||
filament_density = 1.27
|
||||
filament_spool_weight = 201
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @MMU2 0.6 nozzle]
|
||||
inherits = Prusament PETG @MMU2 0.6 nozzle
|
||||
first_layer_temperature = 260
|
||||
temperature = 260
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Filament PM PETG @MMU2 0.6 nozzle]
|
||||
inherits = *PET MMU2 06*
|
||||
renamed_from = "Plasty Mladec PETG @MMU2 0.6 nozzle"
|
||||
@ -4079,6 +4187,87 @@ bed_temperature = 30
|
||||
filament_retract_length = 0
|
||||
extrusion_multiplier = 1.16
|
||||
|
||||
[filament:Print With Smile PLA]
|
||||
inherits = *PLA*
|
||||
filament_vendor = Print With Smile
|
||||
filament_cost = 535
|
||||
filament_density = 1.24
|
||||
filament_spool_weight = 0
|
||||
filament_colour = #FFFF6F
|
||||
filament_max_volumetric_speed = 15
|
||||
first_layer_temperature = 205
|
||||
temperature = 205
|
||||
|
||||
[filament:Print With Smile PETG]
|
||||
inherits = *PET*
|
||||
filament_vendor = Print With Smile
|
||||
filament_cost = 590
|
||||
filament_density = 1.27
|
||||
filament_spool_weight = 0
|
||||
filament_colour = #4D9398
|
||||
filament_max_volumetric_speed = 8
|
||||
temperature = 245
|
||||
first_layer_bed_temperature = 85
|
||||
first_layer_temperature = 240
|
||||
bed_temperature = 90
|
||||
|
||||
[filament:Print With Smile PETG @MINI]
|
||||
inherits = Print With Smile PETG; *PETMINI*
|
||||
|
||||
[filament:Print With Smile ASA]
|
||||
inherits = Ultrafuse ASA
|
||||
filament_vendor = Print With Smile
|
||||
filament_cost = 625
|
||||
first_layer_temperature = 250
|
||||
temperature = 250
|
||||
first_layer_bed_temperature = 105
|
||||
bed_temperature = 110
|
||||
filament_type = ASA
|
||||
max_fan_speed = 40
|
||||
bridge_fan_speed = 70
|
||||
filament_max_volumetric_speed = 11
|
||||
|
||||
[filament:Print With Smile ABS]
|
||||
inherits = *ABSC*
|
||||
filament_vendor = Print With Smile
|
||||
filament_cost = 535
|
||||
filament_density = 1.08
|
||||
first_layer_temperature = 240
|
||||
temperature = 240
|
||||
|
||||
[filament:Print With Smile PETG CF]
|
||||
inherits = Extrudr XPETG CF
|
||||
filament_vendor = Print With Smile
|
||||
filament_cost = 899
|
||||
filament_density = 1.29
|
||||
filament_notes =
|
||||
first_layer_temperature = 260
|
||||
temperature = 260
|
||||
first_layer_bed_temperature = 85
|
||||
bed_temperature = 85
|
||||
max_fan_speed = 55
|
||||
bridge_fan_speed = 60
|
||||
filament_max_volumetric_speed = 5
|
||||
|
||||
[filament:Print With Smile PETG CF @MINI]
|
||||
inherits = Print With Smile PETG CF; *PETMINI*
|
||||
|
||||
[filament:Print With Smile TPU96A]
|
||||
inherits = *FLEX*
|
||||
filament_vendor = Print With Smile
|
||||
filament_cost = 1200
|
||||
filament_density = 1.31
|
||||
extrusion_multiplier = 1.1
|
||||
filament_max_volumetric_speed = 1.35
|
||||
fan_always_on = 1
|
||||
cooling = 0
|
||||
max_fan_speed = 60
|
||||
min_fan_speed = 60
|
||||
disable_fan_first_layers = 4
|
||||
full_fan_speed_layer = 6
|
||||
filament_retract_length = 1.2
|
||||
filament_deretract_speed = 20
|
||||
|
||||
[filament:Fiberlogy Easy PLA]
|
||||
inherits = *PLA*
|
||||
renamed_from = Fiberlogy PLA
|
||||
@ -4680,6 +4869,23 @@ fan_always_on = 1
|
||||
max_fan_speed = 15
|
||||
min_fan_speed = 15
|
||||
|
||||
[filament:Fiberthree F3 PA-GF30 Pro]
|
||||
inherits = Prusament PC Blend Carbon Fiber
|
||||
filament_vendor = Fiberthree
|
||||
filament_cost = 208.01
|
||||
filament_density = 1.35
|
||||
extrusion_multiplier = 1.03
|
||||
first_layer_temperature = 275
|
||||
temperature = 285
|
||||
first_layer_bed_temperature = 90
|
||||
bed_temperature = 90
|
||||
fan_below_layer_time = 10
|
||||
compatible_printers_condition = printer_model!="MINI" and ! single_extruder_multi_material
|
||||
max_fan_speed = 15
|
||||
min_fan_speed = 15
|
||||
filament_type = PA
|
||||
filament_max_volumetric_speed = 6
|
||||
|
||||
[filament:Taulman T-Glase]
|
||||
inherits = *PET*
|
||||
filament_vendor = Taulman
|
||||
@ -4889,6 +5095,13 @@ renamed_from = "Prusa PET MMU1"; "Prusa PETG MMU1"
|
||||
[filament:Prusament PETG @MMU1]
|
||||
inherits = Prusament PETG; *PETMMU1*
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @MMU1]
|
||||
inherits = Prusament PETG @MMU1
|
||||
first_layer_temperature = 260
|
||||
temperature = 265
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Taulman T-Glase @MMU1]
|
||||
inherits = Taulman T-Glase; *PETMMU1*
|
||||
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
|
||||
@ -5016,6 +5229,19 @@ fan_always_on = 1
|
||||
max_fan_speed = 15
|
||||
min_fan_speed = 15
|
||||
|
||||
[filament:Fiberthree F3 PA-GF30 Pro @MINI]
|
||||
inherits = Fiberthree F3 PA-GF30 Pro
|
||||
filament_vendor = Fiberthree
|
||||
first_layer_temperature = 275
|
||||
temperature = 280
|
||||
compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI"
|
||||
filament_retract_length = nil
|
||||
filament_retract_speed = nil
|
||||
filament_retract_lift = nil
|
||||
filament_retract_before_travel = nil
|
||||
filament_wipe = nil
|
||||
filament_type = PA
|
||||
|
||||
[filament:Kimya ABS Carbon @MINI]
|
||||
inherits = Kimya ABS Carbon; *ABSMINI*
|
||||
filament_max_volumetric_speed = 6
|
||||
@ -5043,6 +5269,15 @@ inherits = Verbatim ABS; *ABSMINI*
|
||||
inherits = Prusament PETG; *PETMINI*
|
||||
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @MINI]
|
||||
inherits = Prusament PETG @MINI
|
||||
first_layer_temperature = 260
|
||||
temperature = 265
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]>=0.4 and nozzle_diameter[0]!=0.8 and nozzle_diameter[0]!=0.6
|
||||
|
||||
[filament:Kimya PETG Carbon @MINI]
|
||||
inherits = Kimya PETG Carbon; *PETMINI*
|
||||
filament_max_volumetric_speed = 6
|
||||
@ -5053,6 +5288,14 @@ compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI
|
||||
[filament:Prusament PETG @0.6 nozzle MINI]
|
||||
inherits = Prusament PETG; *PETMINI06*
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @0.6 nozzle MINI]
|
||||
inherits = Prusament PETG @0.6 nozzle MINI
|
||||
first_layer_temperature = 260
|
||||
temperature = 265
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Generic PETG @0.6 nozzle MINI]
|
||||
inherits = Generic PETG; *PETMINI06*
|
||||
renamed_from = "Generic PET 0.6 nozzle MINI"; "Generic PETG 0.6 nozzle MINI"
|
||||
@ -5358,6 +5601,14 @@ filament_retract_lift = 0.2
|
||||
slowdown_below_layer_time = 20
|
||||
compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @0.8 nozzle]
|
||||
inherits = Prusament PETG @0.8 nozzle
|
||||
first_layer_temperature = 265
|
||||
temperature = 270
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Prusament ASA @0.8 nozzle]
|
||||
inherits = Prusament ASA
|
||||
first_layer_temperature = 265
|
||||
@ -5437,6 +5688,14 @@ temperature = 240
|
||||
slowdown_below_layer_time = 20
|
||||
filament_ramming_parameters = "120 140 5.51613 5.6129 5.70968 5.77419 5.77419 5.74194 5.80645 5.93548 6.06452 6.19355 6.3871 6.74194 7.25806 7.87097 8.54839 9.22581 10 10.8387| 0.05 5.5032 0.45 5.63868 0.95 5.8 1.45 5.7839 1.95 6.02257 2.45 6.25811 2.95 7.08395 3.45 8.43875 3.95 9.92258 4.45 11.3419 4.95 7.6"
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @MMU2 0.8 nozzle]
|
||||
inherits = Prusament PETG @MMU2 0.8 nozzle
|
||||
first_layer_temperature = 265
|
||||
temperature = 270
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Generic PLA @MMU2 0.8 nozzle]
|
||||
inherits = Generic PLA @MMU2
|
||||
compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
|
||||
@ -5520,6 +5779,14 @@ filament_retract_lift = 0.25
|
||||
slowdown_below_layer_time = 20
|
||||
compatible_printers_condition = nozzle_diameter[0]==0.8 and printer_model=="MINI"
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber @0.8 nozzle MINI]
|
||||
inherits = Prusament PETG @0.8 nozzle MINI
|
||||
first_layer_temperature = 265
|
||||
temperature = 270
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Prusament ASA @0.8 nozzle MINI]
|
||||
inherits = Prusament ASA @MINI
|
||||
first_layer_temperature = 265
|
||||
@ -10039,7 +10306,7 @@ default_filament_profile = "Prusament PLA"
|
||||
default_print_profile = 0.15mm QUALITY @MINI
|
||||
gcode_flavor = marlin2
|
||||
machine_max_acceleration_e = 5000
|
||||
machine_max_acceleration_extruding = 1250
|
||||
machine_max_acceleration_extruding = 2000
|
||||
machine_max_acceleration_retracting = 1250
|
||||
machine_max_acceleration_travel = 2500
|
||||
machine_max_acceleration_x = 2500
|
||||
|
@ -1,2 +1,3 @@
|
||||
min_slic3r_version = 2.6.0-alpha0
|
||||
1.0.1 Added Prusament PETG Carbon Fiber, Fiberthree F3 PA-GF30 Pro.
|
||||
1.0.0 Initial
|
||||
|
@ -2,14 +2,12 @@
|
||||
|
||||
[vendor]
|
||||
name = Templates
|
||||
config_version = 1.0.0
|
||||
config_version = 1.0.1
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Templates/
|
||||
templates_profile = 1
|
||||
|
||||
## Generic filament profiles
|
||||
|
||||
# Print profiles for the Prusa Research printers.
|
||||
|
||||
[filament:*common*]
|
||||
cooling = 1
|
||||
compatible_printers =
|
||||
@ -1547,6 +1545,16 @@ filament_density = 1.27
|
||||
filament_spool_weight = 201
|
||||
filament_type = PETG
|
||||
|
||||
[filament:Prusament PETG Carbon Fiber]
|
||||
inherits = Prusament PETG
|
||||
filament_vendor = Prusa Polymers
|
||||
first_layer_temperature = 260
|
||||
temperature = 265
|
||||
extrusion_multiplier = 1.03
|
||||
filament_cost = 54.99
|
||||
filament_density = 1.27
|
||||
filament_colour = #BBBBBB
|
||||
|
||||
[filament:Prusa PLA]
|
||||
inherits = *PLA*
|
||||
filament_vendor = Made for Prusa
|
||||
@ -2055,6 +2063,21 @@ fan_always_on = 1
|
||||
max_fan_speed = 15
|
||||
min_fan_speed = 15
|
||||
|
||||
[filament:Fiberthree F3 PA-GF30 Pro]
|
||||
inherits = Prusament PC Blend Carbon Fiber
|
||||
filament_vendor = Fiberthree
|
||||
filament_cost = 208.01
|
||||
filament_density = 1.35
|
||||
extrusion_multiplier = 1.03
|
||||
first_layer_temperature = 275
|
||||
temperature = 285
|
||||
first_layer_bed_temperature = 90
|
||||
bed_temperature = 90
|
||||
fan_below_layer_time = 10
|
||||
max_fan_speed = 15
|
||||
min_fan_speed = 15
|
||||
filament_type = PA
|
||||
|
||||
[filament:Taulman T-Glase]
|
||||
inherits = *PET*
|
||||
filament_vendor = Taulman
|
||||
|
@ -382,7 +382,7 @@ int CLI::run(int argc, char **argv)
|
||||
} else if (opt_key == "align_xy") {
|
||||
const Vec2d &p = m_config.option<ConfigOptionPoint>("align_xy")->value;
|
||||
for (auto &model : m_models) {
|
||||
BoundingBoxf3 bb = model.bounding_box();
|
||||
BoundingBoxf3 bb = model.bounding_box_exact();
|
||||
// this affects volumes:
|
||||
model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z());
|
||||
}
|
||||
@ -423,7 +423,7 @@ int CLI::run(int argc, char **argv)
|
||||
} else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") {
|
||||
std::vector<Model> new_models;
|
||||
for (auto &model : m_models) {
|
||||
model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0
|
||||
model.translate(0, 0, -model.bounding_box_exact().min.z()); // align to z = 0
|
||||
size_t num_objects = model.objects.size();
|
||||
for (size_t i = 0; i < num_objects; ++ i) {
|
||||
|
||||
|
@ -860,14 +860,26 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||
rotation_90_degrees = true;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const Vec3d row = v.row(i).cwiseAbs();
|
||||
size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
||||
size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
||||
const size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
||||
const size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
||||
if (num_zeros != 2 || num_ones != 1) {
|
||||
rotation_90_degrees = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
skew = ! rotation_90_degrees;
|
||||
// Detect skew by brute force: check if the axes are still orthogonal after transformation
|
||||
const Matrix3d trafo_linear = trafo.linear();
|
||||
const std::array<Vec3d, 3> axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
|
||||
std::array<Vec3d, 3> transformed_axes;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
transformed_axes[i] = trafo_linear * axes[i];
|
||||
}
|
||||
skew = std::abs(transformed_axes[0].dot(transformed_axes[1])) > EPSILON ||
|
||||
std::abs(transformed_axes[1].dot(transformed_axes[2])) > EPSILON ||
|
||||
std::abs(transformed_axes[2].dot(transformed_axes[0])) > EPSILON;
|
||||
|
||||
// This following old code does not work under all conditions. The v matrix can become non diagonal (see SPE-1492)
|
||||
// skew = ! rotation_90_degrees;
|
||||
} else
|
||||
skew = false;
|
||||
}
|
||||
@ -918,4 +930,30 @@ double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_t
|
||||
return atan2(vx.y(), vx.x());
|
||||
}
|
||||
|
||||
bool trafos_differ_in_rotation_by_z_and_mirroring_by_xy_only(const Transform3d &t1, const Transform3d &t2)
|
||||
{
|
||||
if (std::abs(t1.translation().z() - t2.translation().z()) > EPSILON)
|
||||
// One of the object is higher than the other above the build plate (or below the build plate).
|
||||
return false;
|
||||
Matrix3d m1 = t1.matrix().block<3, 3>(0, 0);
|
||||
Matrix3d m2 = t2.matrix().block<3, 3>(0, 0);
|
||||
Matrix3d m = m2.inverse() * m1;
|
||||
Vec3d z = m.block<3, 1>(0, 2);
|
||||
if (std::abs(z.x()) > EPSILON || std::abs(z.y()) > EPSILON || std::abs(z.z() - 1.) > EPSILON)
|
||||
// Z direction or length changed.
|
||||
return false;
|
||||
// Z still points in the same direction and it has the same length.
|
||||
Vec3d x = m.block<3, 1>(0, 0);
|
||||
Vec3d y = m.block<3, 1>(0, 1);
|
||||
if (std::abs(x.z()) > EPSILON || std::abs(y.z()) > EPSILON)
|
||||
return false;
|
||||
double lx2 = x.squaredNorm();
|
||||
double ly2 = y.squaredNorm();
|
||||
if (lx2 - 1. > EPSILON * EPSILON || ly2 - 1. > EPSILON * EPSILON)
|
||||
return false;
|
||||
// Verify whether the vectors x, y are still perpendicular.
|
||||
double d = x.dot(y);
|
||||
return std::abs(d * d) < EPSILON * lx2 * ly2;
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::Geometry
|
||||
|
@ -584,6 +584,13 @@ inline bool is_rotation_ninety_degrees(const Vec3d &rotation)
|
||||
return is_rotation_ninety_degrees(rotation.x()) && is_rotation_ninety_degrees(rotation.y()) && is_rotation_ninety_degrees(rotation.z());
|
||||
}
|
||||
|
||||
// Returns true if one transformation may be converted into another transformation by
|
||||
// rotation around Z and by mirroring in X / Y only. Two objects sharing such transformation
|
||||
// may share support structures and they share Z height.
|
||||
bool trafos_differ_in_rotation_by_z_and_mirroring_by_xy_only(const Transform3d &t1, const Transform3d &t2);
|
||||
inline bool trafos_differ_in_rotation_by_z_and_mirroring_by_xy_only(const Transformation &t1, const Transformation &t2)
|
||||
{ return trafos_differ_in_rotation_by_z_and_mirroring_by_xy_only(t1.get_matrix(), t2.get_matrix()); }
|
||||
|
||||
template <class Tout = double, class Tin>
|
||||
std::pair<Tout, Tout> dir_to_spheric(const Vec<3, Tin> &n, Tout norm = 1.)
|
||||
{
|
||||
|
@ -323,14 +323,30 @@ bool Model::add_default_instances()
|
||||
}
|
||||
|
||||
// this returns the bounding box of the *transformed* instances
|
||||
BoundingBoxf3 Model::bounding_box() const
|
||||
BoundingBoxf3 Model::bounding_box_approx() const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
for (ModelObject *o : this->objects)
|
||||
bb.merge(o->bounding_box());
|
||||
bb.merge(o->bounding_box_approx());
|
||||
return bb;
|
||||
}
|
||||
|
||||
BoundingBoxf3 Model::bounding_box_exact() const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
for (ModelObject *o : this->objects)
|
||||
bb.merge(o->bounding_box_exact());
|
||||
return bb;
|
||||
}
|
||||
|
||||
double Model::max_z() const
|
||||
{
|
||||
double z = 0;
|
||||
for (ModelObject *o : this->objects)
|
||||
z = std::max(z, o->max_z());
|
||||
return z;
|
||||
}
|
||||
|
||||
unsigned int Model::update_print_volume_state(const BuildVolume &build_volume)
|
||||
{
|
||||
unsigned int num_printable = 0;
|
||||
@ -377,7 +393,7 @@ void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
|
||||
ModelObject* object = this->objects.front();
|
||||
object->clear_instances();
|
||||
|
||||
Vec3d ext_size = object->bounding_box().size() + dist * Vec3d::Ones();
|
||||
Vec3d ext_size = object->bounding_box_exact().size() + dist * Vec3d::Ones();
|
||||
|
||||
for (size_t x_copy = 1; x_copy <= x; ++x_copy) {
|
||||
for (size_t y_copy = 1; y_copy <= y; ++y_copy) {
|
||||
@ -548,13 +564,13 @@ void Model::adjust_min_z()
|
||||
if (objects.empty())
|
||||
return;
|
||||
|
||||
if (bounding_box().min(2) < 0.0)
|
||||
if (this->bounding_box_exact().min.z() < 0.0)
|
||||
{
|
||||
for (ModelObject* obj : objects)
|
||||
{
|
||||
if (obj != nullptr)
|
||||
{
|
||||
coordf_t obj_min_z = obj->bounding_box().min(2);
|
||||
coordf_t obj_min_z = obj->min_z();
|
||||
if (obj_min_z < 0.0)
|
||||
obj->translate_instances(Vec3d(0.0, 0.0, -obj_min_z));
|
||||
}
|
||||
@ -627,12 +643,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
||||
this->printable = rhs.printable;
|
||||
this->origin_translation = rhs.origin_translation;
|
||||
this->cut_id.copy(rhs.cut_id);
|
||||
m_bounding_box = rhs.m_bounding_box;
|
||||
m_bounding_box_valid = rhs.m_bounding_box_valid;
|
||||
m_raw_bounding_box = rhs.m_raw_bounding_box;
|
||||
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
|
||||
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
|
||||
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
|
||||
this->copy_transformation_caches(rhs);
|
||||
|
||||
this->clear_volumes();
|
||||
this->volumes.reserve(rhs.volumes.size());
|
||||
@ -668,12 +679,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||
this->printable = std::move(rhs.printable);
|
||||
this->origin_translation = std::move(rhs.origin_translation);
|
||||
m_bounding_box = std::move(rhs.m_bounding_box);
|
||||
m_bounding_box_valid = std::move(rhs.m_bounding_box_valid);
|
||||
m_raw_bounding_box = rhs.m_raw_bounding_box;
|
||||
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
|
||||
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
|
||||
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
|
||||
this->copy_transformation_caches(rhs);
|
||||
|
||||
this->clear_volumes();
|
||||
this->volumes = std::move(rhs.volumes);
|
||||
@ -864,16 +870,73 @@ void ModelObject::clear_instances()
|
||||
|
||||
// Returns the bounding box of the transformed instances.
|
||||
// This bounding box is approximate and not snug.
|
||||
const BoundingBoxf3& ModelObject::bounding_box() const
|
||||
const BoundingBoxf3& ModelObject::bounding_box_approx() const
|
||||
{
|
||||
if (! m_bounding_box_valid) {
|
||||
m_bounding_box_valid = true;
|
||||
if (! m_bounding_box_approx_valid) {
|
||||
m_bounding_box_approx_valid = true;
|
||||
BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box();
|
||||
m_bounding_box.reset();
|
||||
m_bounding_box_approx.reset();
|
||||
for (const ModelInstance *i : this->instances)
|
||||
m_bounding_box.merge(i->transform_bounding_box(raw_bbox));
|
||||
m_bounding_box_approx.merge(i->transform_bounding_box(raw_bbox));
|
||||
}
|
||||
return m_bounding_box_approx;
|
||||
}
|
||||
|
||||
// Returns the bounding box of the transformed instances.
|
||||
// This bounding box is approximate and not snug.
|
||||
const BoundingBoxf3& ModelObject::bounding_box_exact() const
|
||||
{
|
||||
if (! m_bounding_box_exact_valid) {
|
||||
m_bounding_box_exact_valid = true;
|
||||
m_min_max_z_valid = true;
|
||||
BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box();
|
||||
m_bounding_box_exact.reset();
|
||||
for (size_t i = 0; i < this->instances.size(); ++ i)
|
||||
m_bounding_box_exact.merge(this->instance_bounding_box(i));
|
||||
}
|
||||
return m_bounding_box_exact;
|
||||
}
|
||||
|
||||
double ModelObject::min_z() const
|
||||
{
|
||||
const_cast<ModelObject*>(this)->update_min_max_z();
|
||||
return m_bounding_box_exact.min.z();
|
||||
}
|
||||
|
||||
double ModelObject::max_z() const
|
||||
{
|
||||
const_cast<ModelObject*>(this)->update_min_max_z();
|
||||
return m_bounding_box_exact.max.z();
|
||||
}
|
||||
|
||||
void ModelObject::update_min_max_z()
|
||||
{
|
||||
assert(! this->instances.empty());
|
||||
if (! m_min_max_z_valid && ! this->instances.empty()) {
|
||||
m_min_max_z_valid = true;
|
||||
const Transform3d mat_instance = this->instances.front()->get_transformation().get_matrix();
|
||||
double global_min_z = std::numeric_limits<double>::max();
|
||||
double global_max_z = - std::numeric_limits<double>::max();
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part()) {
|
||||
const Transform3d m = mat_instance * v->get_matrix();
|
||||
const Vec3d row_z = m.linear().row(2).cast<double>();
|
||||
const double shift_z = m.translation().z();
|
||||
double this_min_z = std::numeric_limits<double>::max();
|
||||
double this_max_z = - std::numeric_limits<double>::max();
|
||||
for (const Vec3f &p : v->mesh().its.vertices) {
|
||||
double z = row_z.dot(p.cast<double>());
|
||||
this_min_z = std::min(this_min_z, z);
|
||||
this_max_z = std::max(this_max_z, z);
|
||||
}
|
||||
this_min_z += shift_z;
|
||||
this_max_z += shift_z;
|
||||
global_min_z = std::min(global_min_z, this_min_z);
|
||||
global_max_z = std::max(global_max_z, this_max_z);
|
||||
}
|
||||
m_bounding_box_exact.min.z() = global_min_z;
|
||||
m_bounding_box_exact.max.z() = global_max_z;
|
||||
}
|
||||
return m_bounding_box;
|
||||
}
|
||||
|
||||
// A mesh containing all transformed instances of this object.
|
||||
@ -1031,19 +1094,19 @@ void ModelObject::ensure_on_bed(bool allow_negative_z)
|
||||
|
||||
if (allow_negative_z) {
|
||||
if (parts_count() == 1) {
|
||||
const double min_z = get_min_z();
|
||||
const double max_z = get_max_z();
|
||||
const double min_z = this->min_z();
|
||||
const double max_z = this->max_z();
|
||||
if (min_z >= SINKING_Z_THRESHOLD || max_z < 0.0)
|
||||
z_offset = -min_z;
|
||||
}
|
||||
else {
|
||||
const double max_z = get_max_z();
|
||||
const double max_z = this->max_z();
|
||||
if (max_z < SINKING_MIN_Z_THRESHOLD)
|
||||
z_offset = SINKING_MIN_Z_THRESHOLD - max_z;
|
||||
}
|
||||
}
|
||||
else
|
||||
z_offset = -get_min_z();
|
||||
z_offset = -this->min_z();
|
||||
|
||||
if (z_offset != 0.0)
|
||||
translate_instances(z_offset * Vec3d::UnitZ());
|
||||
@ -1070,8 +1133,10 @@ void ModelObject::translate(double x, double y, double z)
|
||||
v->translate(x, y, z);
|
||||
}
|
||||
|
||||
if (m_bounding_box_valid)
|
||||
m_bounding_box.translate(x, y, z);
|
||||
if (m_bounding_box_approx_valid)
|
||||
m_bounding_box_approx.translate(x, y, z);
|
||||
if (m_bounding_box_exact_valid)
|
||||
m_bounding_box_exact.translate(x, y, z);
|
||||
}
|
||||
|
||||
void ModelObject::scale(const Vec3d &versor)
|
||||
@ -1866,32 +1931,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
this->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
double ModelObject::get_min_z() const
|
||||
{
|
||||
if (instances.empty())
|
||||
return 0.0;
|
||||
else {
|
||||
double min_z = DBL_MAX;
|
||||
for (size_t i = 0; i < instances.size(); ++i) {
|
||||
min_z = std::min(min_z, get_instance_min_z(i));
|
||||
}
|
||||
return min_z;
|
||||
}
|
||||
}
|
||||
|
||||
double ModelObject::get_max_z() const
|
||||
{
|
||||
if (instances.empty())
|
||||
return 0.0;
|
||||
else {
|
||||
double max_z = -DBL_MAX;
|
||||
for (size_t i = 0; i < instances.size(); ++i) {
|
||||
max_z = std::max(max_z, get_instance_max_z(i));
|
||||
}
|
||||
return max_z;
|
||||
}
|
||||
}
|
||||
|
||||
double ModelObject::get_instance_min_z(size_t instance_idx) const
|
||||
{
|
||||
double min_z = DBL_MAX;
|
||||
@ -2268,7 +2307,7 @@ void ModelVolume::scale(const Vec3d& scaling_factors)
|
||||
|
||||
void ModelObject::scale_to_fit(const Vec3d &size)
|
||||
{
|
||||
Vec3d orig_size = this->bounding_box().size();
|
||||
Vec3d orig_size = this->bounding_box_exact().size();
|
||||
double factor = std::min(
|
||||
size.x() / orig_size.x(),
|
||||
std::min(
|
||||
@ -2373,37 +2412,6 @@ void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) cons
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const
|
||||
{
|
||||
// Rotate around mesh origin.
|
||||
TriangleMesh copy(mesh);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
copy.transform(get_transformation().get_rotation_matrix());
|
||||
#else
|
||||
copy.transform(get_matrix(true, false, true, true));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
BoundingBoxf3 bbox = copy.bounding_box();
|
||||
|
||||
if (!empty(bbox)) {
|
||||
// Scale the bounding box along the three axes.
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (std::abs(get_scaling_factor((Axis)i)-1.0) > EPSILON)
|
||||
{
|
||||
bbox.min(i) *= get_scaling_factor((Axis)i);
|
||||
bbox.max(i) *= get_scaling_factor((Axis)i);
|
||||
}
|
||||
}
|
||||
|
||||
// Translate the bounding box.
|
||||
if (! dont_translate) {
|
||||
bbox.min += get_offset();
|
||||
bbox.max += get_offset();
|
||||
}
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
|
||||
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
|
@ -168,7 +168,7 @@ private:
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
// Create an object for deserialization, don't allocate IDs for ModelMaterial and its config.
|
||||
ModelMaterial() : ObjectBase(-1), config(-1), m_model(nullptr) { assert(this->id().invalid()); assert(this->config.id().invalid()); }
|
||||
ModelMaterial() : ObjectBase(-1), config(-1) { assert(this->id().invalid()); assert(this->config.id().invalid()); }
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
assert(this->id().invalid()); assert(this->config.id().invalid());
|
||||
Internal::StaticSerializationWrapper<ModelConfigObject> config_wrapper(config);
|
||||
@ -343,7 +343,7 @@ public:
|
||||
// The pairs of <z, layer_height> are packed into a 1D array.
|
||||
LayerHeightProfile layer_height_profile;
|
||||
// Whether or not this object is printable
|
||||
bool printable;
|
||||
bool printable { true };
|
||||
|
||||
// This vector holds position of selected support points for SLA. The data are
|
||||
// saved in mesh coordinates to allow using them for several instances.
|
||||
@ -397,11 +397,22 @@ public:
|
||||
void delete_last_instance();
|
||||
void clear_instances();
|
||||
|
||||
// Returns the bounding box of the transformed instances.
|
||||
// This bounding box is approximate and not snug.
|
||||
// This bounding box is being cached.
|
||||
const BoundingBoxf3& bounding_box() const;
|
||||
void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; }
|
||||
// Returns the bounding box of the transformed instances. This bounding box is approximate and not snug, it is being cached.
|
||||
const BoundingBoxf3& bounding_box_approx() const;
|
||||
// Returns an exact bounding box of the transformed instances. The result it is being cached.
|
||||
const BoundingBoxf3& bounding_box_exact() const;
|
||||
// Return minimum / maximum of a printable object transformed into the world coordinate system.
|
||||
// All instances share the same min / max Z.
|
||||
double min_z() const;
|
||||
double max_z() const;
|
||||
|
||||
void invalidate_bounding_box() {
|
||||
m_bounding_box_approx_valid = false;
|
||||
m_bounding_box_exact_valid = false;
|
||||
m_min_max_z_valid = false;
|
||||
m_raw_bounding_box_valid = false;
|
||||
m_raw_mesh_bounding_box_valid = false;
|
||||
}
|
||||
|
||||
// A mesh containing all transformed instances of this object.
|
||||
TriangleMesh mesh() const;
|
||||
@ -477,8 +488,6 @@ public:
|
||||
// Rotation and mirroring is being baked in. In case the instance scaling was non-uniform, it is baked in as well.
|
||||
void bake_xy_rotation_into_meshes(size_t instance_idx);
|
||||
|
||||
double get_min_z() const;
|
||||
double get_max_z() const;
|
||||
double get_instance_min_z(size_t instance_idx) const;
|
||||
double get_instance_max_z(size_t instance_idx) const;
|
||||
|
||||
@ -500,14 +509,13 @@ public:
|
||||
private:
|
||||
friend class Model;
|
||||
// This constructor assigns new ID to this ModelObject and its config.
|
||||
explicit ModelObject(Model* model) : m_model(model), printable(true), origin_translation(Vec3d::Zero()),
|
||||
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
|
||||
explicit ModelObject(Model* model) : m_model(model), origin_translation(Vec3d::Zero())
|
||||
{
|
||||
assert(this->id().valid());
|
||||
assert(this->config.id().valid());
|
||||
assert(this->layer_height_profile.id().valid());
|
||||
}
|
||||
explicit ModelObject(int) : ObjectBase(-1), config(-1), layer_height_profile(-1), m_model(nullptr), printable(true), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
|
||||
explicit ModelObject(int) : ObjectBase(-1), config(-1), layer_height_profile(-1), origin_translation(Vec3d::Zero())
|
||||
{
|
||||
assert(this->id().invalid());
|
||||
assert(this->config.id().invalid());
|
||||
@ -585,15 +593,31 @@ private:
|
||||
OBJECTBASE_DERIVED_COPY_MOVE_CLONE(ModelObject)
|
||||
|
||||
// Parent object, owning this ModelObject. Set to nullptr here, so the macros above will have it initialized.
|
||||
Model *m_model = nullptr;
|
||||
Model *m_model { nullptr };
|
||||
|
||||
// Bounding box, cached.
|
||||
mutable BoundingBoxf3 m_bounding_box;
|
||||
mutable bool m_bounding_box_valid;
|
||||
mutable BoundingBoxf3 m_bounding_box_approx;
|
||||
mutable bool m_bounding_box_approx_valid { false };
|
||||
mutable BoundingBoxf3 m_bounding_box_exact;
|
||||
mutable bool m_bounding_box_exact_valid { false };
|
||||
mutable bool m_min_max_z_valid { false };
|
||||
mutable BoundingBoxf3 m_raw_bounding_box;
|
||||
mutable bool m_raw_bounding_box_valid;
|
||||
mutable bool m_raw_bounding_box_valid { false };
|
||||
mutable BoundingBoxf3 m_raw_mesh_bounding_box;
|
||||
mutable bool m_raw_mesh_bounding_box_valid;
|
||||
mutable bool m_raw_mesh_bounding_box_valid { false };
|
||||
|
||||
// Only use this method if now the source and dest ModelObjects are equal, for example they were synchronized by Print::apply().
|
||||
void copy_transformation_caches(const ModelObject &src) {
|
||||
m_bounding_box_approx = src.m_bounding_box_approx;
|
||||
m_bounding_box_approx_valid = src.m_bounding_box_approx_valid;
|
||||
m_bounding_box_exact = src.m_bounding_box_exact;
|
||||
m_bounding_box_exact_valid = src.m_bounding_box_exact_valid;
|
||||
m_min_max_z_valid = src.m_min_max_z_valid;
|
||||
m_raw_bounding_box = src.m_raw_bounding_box;
|
||||
m_raw_bounding_box_valid = src.m_raw_bounding_box_valid;
|
||||
m_raw_mesh_bounding_box = src.m_raw_mesh_bounding_box;
|
||||
m_raw_mesh_bounding_box_valid = src.m_raw_mesh_bounding_box_valid;
|
||||
}
|
||||
|
||||
// Called by Print::apply() to set the model pointer after making a copy.
|
||||
friend class Print;
|
||||
@ -605,8 +629,7 @@ private:
|
||||
friend class UndoRedo::StackImpl;
|
||||
// Used for deserialization -> Don't allocate any IDs for the ModelObject or its config.
|
||||
ModelObject() :
|
||||
ObjectBase(-1), config(-1), layer_height_profile(-1),
|
||||
m_model(nullptr), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {
|
||||
ObjectBase(-1), config(-1), layer_height_profile(-1) {
|
||||
assert(this->id().invalid());
|
||||
assert(this->config.id().invalid());
|
||||
assert(this->layer_height_profile.id().invalid());
|
||||
@ -617,12 +640,17 @@ private:
|
||||
Internal::StaticSerializationWrapper<LayerHeightProfile> layer_heigth_profile_wrapper(layer_height_profile);
|
||||
ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper,
|
||||
sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation,
|
||||
m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid,
|
||||
m_bounding_box_approx, m_bounding_box_approx_valid,
|
||||
m_bounding_box_exact, m_bounding_box_exact_valid, m_min_max_z_valid,
|
||||
m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid,
|
||||
cut_connectors, cut_id);
|
||||
}
|
||||
|
||||
// Called by Print::validate() from the UI thread.
|
||||
unsigned int update_instances_print_volume_state(const BuildVolume &build_volume);
|
||||
|
||||
// Called by min_z(), max_z()
|
||||
void update_min_max_z();
|
||||
};
|
||||
|
||||
enum class EnforcerBlockerType : int8_t {
|
||||
@ -1106,7 +1134,7 @@ public:
|
||||
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
|
||||
ModelInstanceEPrintVolumeState print_volume_state;
|
||||
// Whether or not this instance is printable
|
||||
bool printable;
|
||||
bool printable { true };
|
||||
|
||||
ModelObject* get_object() const { return this->object; }
|
||||
|
||||
@ -1156,9 +1184,7 @@ public:
|
||||
|
||||
// To be called on an external mesh
|
||||
void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const;
|
||||
// Calculate a bounding box of a transformed mesh. To be called on an external mesh.
|
||||
BoundingBoxf3 transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate = false) const;
|
||||
// Transform an external bounding box.
|
||||
// Transform an external bounding box, thus the resulting bounding box is no more snug.
|
||||
BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const;
|
||||
// Transform an external vector.
|
||||
Vec3d transform_vector(const Vec3d& v, bool dont_translate = false) const;
|
||||
@ -1201,7 +1227,7 @@ private:
|
||||
ModelObject* object;
|
||||
|
||||
// Constructor, which assigns a new unique ID.
|
||||
explicit ModelInstance(ModelObject* object) : print_volume_state(ModelInstancePVS_Inside), printable(true), object(object) { assert(this->id().valid()); }
|
||||
explicit ModelInstance(ModelObject* object) : print_volume_state(ModelInstancePVS_Inside), object(object) { assert(this->id().valid()); }
|
||||
// Constructor, which assigns a new unique ID.
|
||||
explicit ModelInstance(ModelObject *object, const ModelInstance &other) :
|
||||
m_transformation(other.m_transformation), print_volume_state(ModelInstancePVS_Inside), printable(other.printable), object(object) { assert(this->id().valid() && this->id() != other.id()); }
|
||||
@ -1316,8 +1342,12 @@ public:
|
||||
void delete_material(t_model_material_id material_id);
|
||||
void clear_materials();
|
||||
bool add_default_instances();
|
||||
// Returns approximate axis aligned bounding box of this model
|
||||
BoundingBoxf3 bounding_box() const;
|
||||
// Returns approximate axis aligned bounding box of this model.
|
||||
BoundingBoxf3 bounding_box_approx() const;
|
||||
// Returns exact axis aligned bounding box of this model.
|
||||
BoundingBoxf3 bounding_box_exact() const;
|
||||
// Return maximum height of all printable objects.
|
||||
double max_z() const;
|
||||
// Set the print_volume_state of PrintObject::instances,
|
||||
// return total number of printable objects.
|
||||
unsigned int update_print_volume_state(const BuildVolume &build_volume);
|
||||
|
@ -875,6 +875,38 @@ namespace client
|
||||
output.it_range = boost::iterator_range<Iterator>(opt.it_range.begin(), it_end);
|
||||
}
|
||||
|
||||
// Return a boolean value, true if the scalar variable referenced by "opt" is nullable and it has a nil value.
|
||||
template <typename Iterator>
|
||||
static void is_nil_test_scalar(
|
||||
const MyContext *ctx,
|
||||
OptWithPos<Iterator> &opt,
|
||||
expr<Iterator> &output)
|
||||
{
|
||||
if (opt.opt->is_vector())
|
||||
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
|
||||
output.set_b(opt.opt->is_nil());
|
||||
output.it_range = opt.it_range;
|
||||
}
|
||||
|
||||
// Return a boolean value, true if an element of a vector variable referenced by "opt[index]" is nullable and it has a nil value.
|
||||
template <typename Iterator>
|
||||
static void is_nil_test_vector(
|
||||
const MyContext *ctx,
|
||||
OptWithPos<Iterator> &opt,
|
||||
int &index,
|
||||
Iterator it_end,
|
||||
expr<Iterator> &output)
|
||||
{
|
||||
if (opt.opt->is_scalar())
|
||||
ctx->throw_exception("Referencing a scalar variable when vector is expected", opt.it_range);
|
||||
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
|
||||
if (vec->empty())
|
||||
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
|
||||
size_t idx = (index < 0) ? 0 : (index >= int(vec->size())) ? 0 : size_t(index);
|
||||
output.set_b(static_cast<const ConfigOptionVectorBase*>(opt.opt)->is_nil(idx));
|
||||
output.it_range = boost::iterator_range<Iterator>(opt.it_range.begin(), it_end);
|
||||
}
|
||||
|
||||
// Verify that the expression returns an integer, which may be used
|
||||
// to address a vector.
|
||||
template <typename Iterator>
|
||||
@ -973,6 +1005,7 @@ namespace client
|
||||
{ "unary_expression", "Expecting an expression." },
|
||||
{ "optional_parameter", "Expecting a closing brace or an optional parameter." },
|
||||
{ "scalar_variable_reference", "Expecting a scalar variable reference."},
|
||||
{ "is_nil_test", "Expecting a scalar variable reference."},
|
||||
{ "variable_reference", "Expecting a variable reference."},
|
||||
{ "regular_expression", "Expecting a regular expression."}
|
||||
};
|
||||
@ -1259,6 +1292,7 @@ namespace client
|
||||
[ px::bind(&expr<Iterator>::template digits<true>, _val, _2, _3) ]
|
||||
| (kw["int"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ]
|
||||
| (kw["round"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::round, _1, _val) ]
|
||||
| (kw["is_nil"] > '(' > is_nil_test(_r1) > ')') [_val = _1]
|
||||
| (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ]
|
||||
| (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ]
|
||||
| (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ]
|
||||
@ -1286,6 +1320,15 @@ namespace client
|
||||
[ px::bind(&MyContext::resolve_variable<Iterator>, _r1, _1, _val) ];
|
||||
variable_reference.name("variable reference");
|
||||
|
||||
is_nil_test =
|
||||
variable_reference(_r1)[_a=_1] >>
|
||||
(
|
||||
('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index<Iterator>, _1, _b)] > ']' >
|
||||
iter_pos[px::bind(&MyContext::is_nil_test_vector<Iterator>, _r1, _a, _b, _1, _val)])
|
||||
| eps[px::bind(&MyContext::is_nil_test_scalar<Iterator>, _r1, _a, _val)]
|
||||
);
|
||||
is_nil_test.name("is_nil test");
|
||||
|
||||
regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']];
|
||||
regular_expression.name("regular_expression");
|
||||
|
||||
@ -1295,6 +1338,7 @@ namespace client
|
||||
("zdigits")
|
||||
("if")
|
||||
("int")
|
||||
("is_nil")
|
||||
//("inf")
|
||||
("else")
|
||||
("elsif")
|
||||
@ -1329,6 +1373,7 @@ namespace client
|
||||
debug(optional_parameter);
|
||||
debug(scalar_variable_reference);
|
||||
debug(variable_reference);
|
||||
debug(is_nil_test);
|
||||
debug(regular_expression);
|
||||
}
|
||||
}
|
||||
@ -1374,6 +1419,8 @@ namespace client
|
||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> scalar_variable_reference;
|
||||
// Rule to translate an identifier to a ConfigOption, or to fail.
|
||||
qi::rule<Iterator, OptWithPos<Iterator>(const MyContext*), spirit_encoding::space_type> variable_reference;
|
||||
// Evaluating whether a nullable variable is nil.
|
||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> is_nil_test;
|
||||
|
||||
qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool, bool>, spirit_encoding::space_type> if_else_output;
|
||||
// qi::rule<Iterator, std::string(const MyContext*), qi::locals<expr<Iterator>, bool, std::string>, spirit_encoding::space_type> switch_output;
|
||||
|
@ -879,7 +879,7 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
||||
// Insert a new profile.
|
||||
Preset &preset = this->load_preset(path, new_name, std::move(cfg), select == LoadAndSelect::Always);
|
||||
preset.is_external = true;
|
||||
if (&this->get_selected_preset() == &preset)
|
||||
if (this->m_idx_selected != size_t(-1) && &this->get_selected_preset() == &preset)
|
||||
this->get_edited_preset().is_external = true;
|
||||
|
||||
return std::make_pair(&preset, false);
|
||||
|
@ -1250,7 +1250,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
l->get_transformation().get_matrix().isApprox(r->get_transformation().get_matrix()); })) {
|
||||
// If some of the instances changed, the bounding box of the updated ModelObject is likely no more valid.
|
||||
// This is safe as the ModelObject's bounding box is only accessed from this function, which is called from the main thread only.
|
||||
model_object.invalidate_bounding_box();
|
||||
// Synchronize the content of instances.
|
||||
auto new_instance = model_object_new.instances.begin();
|
||||
for (auto old_instance = model_object.instances.begin(); old_instance != model_object.instances.end(); ++ old_instance, ++ new_instance) {
|
||||
@ -1259,6 +1258,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
(*old_instance)->printable = (*new_instance)->printable;
|
||||
}
|
||||
}
|
||||
// Source / dest object share the same bounding boxes, just copy them.
|
||||
model_object.copy_transformation_caches(model_object_new);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3270,9 +3270,6 @@ void PrintConfigDef::init_sla_support_params(const std::string &prefix)
|
||||
{
|
||||
ConfigOptionDef* def;
|
||||
|
||||
constexpr const char * pretext_unavailable = L("Unavailable for this method.\n");
|
||||
std::string pretext;
|
||||
|
||||
def = this->add(prefix + "support_head_front_diameter", coFloat);
|
||||
def->label = L("Pinhead front diameter");
|
||||
def->category = L("Supports");
|
||||
@ -3322,13 +3319,9 @@ void PrintConfigDef::init_sla_support_params(const std::string &prefix)
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionPercent(50));
|
||||
|
||||
pretext = "";
|
||||
if (prefix == "branching")
|
||||
pretext = pretext_unavailable;
|
||||
|
||||
def = this->add(prefix + "support_max_bridges_on_pillar", coInt);
|
||||
def->label = L("Max bridges on a pillar");
|
||||
def->tooltip = pretext + L(
|
||||
def->tooltip = L(
|
||||
"Maximum number of bridges that can be placed on a pillar. Bridges "
|
||||
"hold support point pinheads and connect to pillars as small branches.");
|
||||
def->min = 0;
|
||||
@ -3336,14 +3329,10 @@ void PrintConfigDef::init_sla_support_params(const std::string &prefix)
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInt(prefix == "branching" ? 2 : 3));
|
||||
|
||||
pretext = "";
|
||||
if (prefix.empty())
|
||||
pretext = pretext_unavailable;
|
||||
|
||||
def = this->add(prefix + "support_max_weight_on_model", coFloat);
|
||||
def->label = L("Max weight on model");
|
||||
def->category = L("Supports");
|
||||
def->tooltip = pretext + L(
|
||||
def->tooltip = L(
|
||||
"Maximum weight of sub-trees that terminate on the model instead of the print bed. The weight is the sum of the lenghts of all "
|
||||
"branches emanating from the endpoint.");
|
||||
def->sidetext = L("mm");
|
||||
@ -3351,13 +3340,9 @@ void PrintConfigDef::init_sla_support_params(const std::string &prefix)
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(10.));
|
||||
|
||||
pretext = "";
|
||||
if (prefix == "branching")
|
||||
pretext = pretext_unavailable;
|
||||
|
||||
def = this->add(prefix + "support_pillar_connection_mode", coEnum);
|
||||
def->label = L("Pillar connection mode");
|
||||
def->tooltip = pretext + L("Controls the bridge type between two neighboring pillars."
|
||||
def->tooltip = L("Controls the bridge type between two neighboring pillars."
|
||||
" Can be zig-zag, cross (double zig-zag) or dynamic which"
|
||||
" will automatically switch between the first two depending"
|
||||
" on the distance of the two pillars.");
|
||||
@ -3378,11 +3363,7 @@ void PrintConfigDef::init_sla_support_params(const std::string &prefix)
|
||||
def->label = L("Pillar widening factor");
|
||||
def->category = L("Supports");
|
||||
|
||||
pretext = "";
|
||||
if (prefix.empty())
|
||||
pretext = pretext_unavailable;
|
||||
|
||||
def->tooltip = pretext +
|
||||
def->tooltip =
|
||||
L("Merging bridges or pillars into another pillars can "
|
||||
"increase the radius. Zero means no increase, one means "
|
||||
"full increase. The exact amount of increase is unspecified and can "
|
||||
@ -3449,14 +3430,10 @@ void PrintConfigDef::init_sla_support_params(const std::string &prefix)
|
||||
|
||||
def->set_default_value(new ConfigOptionFloat(default_val));
|
||||
|
||||
pretext = "";
|
||||
if (prefix == "branching")
|
||||
pretext = pretext_unavailable;
|
||||
|
||||
def = this->add(prefix + "support_max_pillar_link_distance", coFloat);
|
||||
def->label = L("Max pillar linking distance");
|
||||
def->category = L("Supports");
|
||||
def->tooltip = pretext + L("The max distance of two pillars to get linked with each other."
|
||||
def->tooltip = L("The max distance of two pillars to get linked with each other."
|
||||
" A zero value will prohibit pillar cascading.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0; // 0 means no linking
|
||||
|
@ -87,6 +87,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transfor
|
||||
m_center_offset = Point::new_scale(bbox_center.x(), bbox_center.y());
|
||||
// Size of the transformed mesh. This bounding may not be snug in XY plane, but it is snug in Z.
|
||||
m_size = (bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
|
||||
m_size.z() = model_object->max_z();
|
||||
|
||||
this->set_instances(std::move(instances));
|
||||
}
|
||||
@ -1736,7 +1737,7 @@ void PrintObject::update_slicing_parameters()
|
||||
{
|
||||
if (!m_slicing_params.valid)
|
||||
m_slicing_params = SlicingParameters::create_from_config(
|
||||
this->print()->config(), m_config, this->model_object()->bounding_box().max.z(), this->object_extruders());
|
||||
this->print()->config(), m_config, this->model_object()->max_z(), this->object_extruders());
|
||||
}
|
||||
|
||||
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
|
||||
|
@ -141,6 +141,7 @@ std::pair<bool, long> create_ground_pillar(
|
||||
if (head_id >= 0) builder.head(head_id).bridge_id = br.id;
|
||||
endp = diffbr->endp;
|
||||
radius = diffbr->end_r;
|
||||
end_radius = diffbr->end_r;
|
||||
builder.add_junction(endp, radius);
|
||||
non_head = true;
|
||||
dir = diffbr->get_dir();
|
||||
|
@ -2954,7 +2954,7 @@ SupportGeneratorLayersPtr generate_raft_base(
|
||||
Polygons columns;
|
||||
Polygons first_layer;
|
||||
if (columns_base != nullptr) {
|
||||
if (columns_base->print_z > slicing_params.raft_contact_top_z - EPSILON) {
|
||||
if (columns_base->bottom_print_z() > slicing_params.raft_interface_top_z - EPSILON) {
|
||||
// Classic supports with colums above the raft interface.
|
||||
base = columns_base->polygons;
|
||||
columns = base;
|
||||
|
@ -130,8 +130,10 @@ TreeSupportSettings::TreeSupportSettings(const TreeSupportMeshGroupSettings& mes
|
||||
this->raft_layers.emplace_back(z);
|
||||
}
|
||||
// Raft contact layer
|
||||
if (slicing_params.raft_layers() > 1) {
|
||||
z = slicing_params.raft_contact_top_z;
|
||||
this->raft_layers.emplace_back(z);
|
||||
}
|
||||
if (double dist_to_go = slicing_params.object_print_z_min - z; dist_to_go > EPSILON) {
|
||||
// Layers between the raft contacts and bottom of the object.
|
||||
auto nsteps = int(ceil(dist_to_go / slicing_params.max_suport_layer_height));
|
||||
@ -991,6 +993,30 @@ inline SupportGeneratorLayer& layer_allocate(
|
||||
return layer_initialize(layer_storage.back(), layer_type, slicing_params, config, layer_idx);
|
||||
}
|
||||
|
||||
int generate_raft_contact(
|
||||
const PrintObject &print_object,
|
||||
const TreeSupportSettings &config,
|
||||
SupportGeneratorLayersPtr &top_contacts,
|
||||
SupportGeneratorLayerStorage &layer_storage)
|
||||
{
|
||||
int raft_contact_layer_idx = -1;
|
||||
if (print_object.has_raft() && print_object.layer_count() > 0) {
|
||||
// Produce raft contact layer outside of the tree support loop, so that no trees will be generated for the raft contact layer.
|
||||
// Raft layers supporting raft contact interface will be produced by the classic raft generator.
|
||||
// Find the raft contact layer.
|
||||
raft_contact_layer_idx = int(config.raft_layers.size()) - 1;
|
||||
while (raft_contact_layer_idx > 0 && config.raft_layers[raft_contact_layer_idx] > print_object.slicing_parameters().raft_contact_top_z + EPSILON)
|
||||
-- raft_contact_layer_idx;
|
||||
// Create the raft contact layer.
|
||||
SupportGeneratorLayer &raft_contact_layer = layer_allocate(layer_storage, SupporLayerType::TopContact, print_object.slicing_parameters(), config, raft_contact_layer_idx);
|
||||
top_contacts[raft_contact_layer_idx] = &raft_contact_layer;
|
||||
const ExPolygons &lslices = print_object.get_layer(0)->lslices;
|
||||
double expansion = print_object.config().raft_expansion.value;
|
||||
raft_contact_layer.polygons = expansion > 0 ? expand(lslices, scaled<float>(expansion)) : to_polygons(lslices);
|
||||
}
|
||||
return raft_contact_layer_idx;
|
||||
}
|
||||
|
||||
using SupportElements = std::deque<SupportElement>;
|
||||
/*!
|
||||
* \brief Creates the initial influence areas (that can later be propagated down) by placing them below the overhang.
|
||||
@ -1064,24 +1090,7 @@ static void generate_initial_areas(
|
||||
const size_t num_raft_layers = config.raft_layers.size();
|
||||
const size_t num_support_layers = size_t(std::max(0, int(print_object.layer_count()) + int(num_raft_layers) - int(z_distance_delta)));
|
||||
const size_t first_support_layer = std::max(int(num_raft_layers) - int(z_distance_delta), 1);
|
||||
size_t first_tree_layer = 0;
|
||||
|
||||
size_t raft_contact_layer_idx = std::numeric_limits<size_t>::max();
|
||||
if (num_raft_layers > 0 && print_object.layer_count() > 0) {
|
||||
// Produce raft contact layer outside of the tree support loop, so that no trees will be generated for the raft contact layer.
|
||||
// Raft layers supporting raft contact interface will be produced by the classic raft generator.
|
||||
// Find the raft contact layer.
|
||||
raft_contact_layer_idx = config.raft_layers.size() - 1;
|
||||
while (raft_contact_layer_idx > 0 && config.raft_layers[raft_contact_layer_idx] > print_object.slicing_parameters().raft_contact_top_z + EPSILON)
|
||||
-- raft_contact_layer_idx;
|
||||
// Create the raft contact layer.
|
||||
SupportGeneratorLayer &raft_contact_layer = layer_allocate(layer_storage, SupporLayerType::TopContact, print_object.slicing_parameters(), config, raft_contact_layer_idx);
|
||||
top_contacts[raft_contact_layer_idx] = &raft_contact_layer;
|
||||
const ExPolygons &lslices = print_object.get_layer(0)->lslices;
|
||||
double expansion = print_object.config().raft_expansion.value;
|
||||
raft_contact_layer.polygons = expansion > 0 ? expand(lslices, scaled<float>(expansion)) : to_polygons(lslices);
|
||||
first_tree_layer = print_object.slicing_parameters().raft_layers() - 1;
|
||||
}
|
||||
const int raft_contact_layer_idx = generate_raft_contact(print_object, config, top_contacts, layer_storage);
|
||||
|
||||
std::mutex mutex_layer_storage, mutex_movebounds;
|
||||
std::vector<std::unordered_set<Point, PointHash>> already_inserted(num_support_layers);
|
||||
@ -1434,13 +1443,15 @@ static void generate_initial_areas(
|
||||
}
|
||||
});
|
||||
|
||||
if (raft_contact_layer_idx >= 0) {
|
||||
const size_t first_tree_layer = print_object.slicing_parameters().raft_layers() - 1;
|
||||
// Remove tree tips that start below the raft contact,
|
||||
// remove interface layers below the raft contact.
|
||||
for (size_t i = 0; i < first_tree_layer; ++i) {
|
||||
top_contacts[i] = nullptr;
|
||||
move_bounds[i].clear();
|
||||
}
|
||||
if (raft_contact_layer_idx != std::numeric_limits<size_t>::max() && print_object.config().raft_expansion.value > 0) {
|
||||
if (raft_contact_layer_idx >= 0 && print_object.config().raft_expansion.value > 0) {
|
||||
// If any tips at first_tree_layer now are completely inside the expanded raft layer, remove them as well before they are propagated to the ground.
|
||||
Polygons &raft_polygons = top_contacts[raft_contact_layer_idx]->polygons;
|
||||
EdgeGrid::Grid grid(get_extents(raft_polygons).inflated(SCALED_EPSILON));
|
||||
@ -1457,7 +1468,7 @@ static void generate_initial_areas(
|
||||
}
|
||||
return false;
|
||||
}), first_layer_move_bounds.end());
|
||||
#if 0
|
||||
#if 0
|
||||
// Remove the remaining tips from the raft: Closing operation on tip circles.
|
||||
if (! first_layer_move_bounds.empty()) {
|
||||
const double eps = 0.1;
|
||||
@ -1474,7 +1485,8 @@ static void generate_initial_areas(
|
||||
}
|
||||
raft_polygons = diff(raft_polygons, offset(union_(circles), - closing_distance));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4201,9 +4213,15 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
|
||||
std::vector<Polygons> overhangs = generate_overhangs(config, *print.get_object(processing.second.front()), throw_on_cancel);
|
||||
|
||||
// ### Precalculate avoidances, collision etc.
|
||||
size_t num_support_layers = precalculate(print, overhangs, processing.first, processing.second, volumes, throw_on_cancel);
|
||||
if (num_support_layers == 0)
|
||||
continue;
|
||||
|
||||
SupportGeneratorLayerStorage layer_storage;
|
||||
SupportGeneratorLayersPtr top_contacts;
|
||||
SupportGeneratorLayersPtr bottom_contacts;
|
||||
SupportGeneratorLayersPtr top_interface_layers;
|
||||
SupportGeneratorLayersPtr intermediate_layers;
|
||||
|
||||
if (size_t num_support_layers = precalculate(print, overhangs, processing.first, processing.second, volumes, throw_on_cancel);
|
||||
num_support_layers > 0) {
|
||||
|
||||
auto t_precalc = std::chrono::high_resolution_clock::now();
|
||||
|
||||
@ -4211,17 +4229,16 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
|
||||
std::vector<SupportElements> move_bounds(num_support_layers);
|
||||
|
||||
// ### Place tips of the support tree
|
||||
SupportGeneratorLayersPtr bottom_contacts(num_support_layers, nullptr);
|
||||
SupportGeneratorLayersPtr top_contacts(num_support_layers, nullptr);
|
||||
SupportGeneratorLayersPtr top_interface_layers(num_support_layers, nullptr);
|
||||
SupportGeneratorLayersPtr intermediate_layers(num_support_layers, nullptr);
|
||||
SupportGeneratorLayerStorage layer_storage;
|
||||
top_contacts .assign(num_support_layers, nullptr);
|
||||
bottom_contacts .assign(num_support_layers, nullptr);
|
||||
top_interface_layers.assign(num_support_layers, nullptr);
|
||||
intermediate_layers .assign(num_support_layers, nullptr);
|
||||
|
||||
for (size_t mesh_idx : processing.second)
|
||||
generate_initial_areas(*print.get_object(mesh_idx), volumes, config, overhangs, move_bounds, top_contacts, top_interface_layers, layer_storage, throw_on_cancel);
|
||||
auto t_gen = std::chrono::high_resolution_clock::now();
|
||||
|
||||
#ifdef TREESUPPORT_DEBUG_SVG
|
||||
#ifdef TREESUPPORT_DEBUG_SVG
|
||||
for (size_t layer_idx = 0; layer_idx < move_bounds.size(); ++layer_idx) {
|
||||
Polygons polys;
|
||||
for (auto& area : move_bounds[layer_idx])
|
||||
@ -4232,7 +4249,7 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
|
||||
{ "wall_restricrictions", "gray", 0.5f } },
|
||||
{ { union_ex(polys) }, { "parent", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
|
||||
}
|
||||
#endif // TREESUPPORT_DEBUG_SVG
|
||||
#endif // TREESUPPORT_DEBUG_SVG
|
||||
|
||||
// ### Propagate the influence areas downwards. This is an inherently serial operation.
|
||||
create_layer_pathing(volumes, config, move_bounds, throw_on_cancel);
|
||||
@ -4270,10 +4287,16 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
|
||||
"Influence area creation: " << dur_path << "ms "
|
||||
"Placement of Points in InfluenceAreas: " << dur_place << "ms "
|
||||
"Drawing result as support " << dur_draw << " ms";
|
||||
// if (config.branch_radius==2121)
|
||||
// BOOST_LOG_TRIVIAL(error) << "Why ask questions when you already know the answer twice.\n (This is not a real bug, please dont report it.)";
|
||||
// if (config.branch_radius==2121)
|
||||
// BOOST_LOG_TRIVIAL(error) << "Why ask questions when you already know the answer twice.\n (This is not a real bug, please dont report it.)";
|
||||
|
||||
move_bounds.clear();
|
||||
} else {
|
||||
top_contacts.assign(config.raft_layers.size(), nullptr);
|
||||
if (generate_raft_contact(print_object, config, top_contacts, layer_storage) < 0)
|
||||
// No raft.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto remove_undefined_layers = [](SupportGeneratorLayersPtr &layers) {
|
||||
layers.erase(std::remove_if(layers.begin(), layers.end(), [](const SupportGeneratorLayer* ptr) { return ptr == nullptr; }), layers.end());
|
||||
@ -4341,7 +4364,9 @@ void fff_tree_support_generate(PrintObject &print_object, std::function<void()>
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
FFFTreeSupport::generate_support_areas(*print_object.print(), BuildVolume(Pointfs{ Vec2d{ -300., -300. }, Vec2d{ -300., +300. }, Vec2d{ +300., +300. }, Vec2d{ +300., -300. } }, 0.), { idx }, throw_on_cancel);
|
||||
FFFTreeSupport::generate_support_areas(*print_object.print(),
|
||||
BuildVolume(Pointfs{ Vec2d{ -300., -300. }, Vec2d{ -300., +300. }, Vec2d{ +300., +300. }, Vec2d{ +300., -300. } }, 0.), { idx },
|
||||
throw_on_cancel);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -175,24 +175,20 @@ void Field::on_back_to_sys_value()
|
||||
|
||||
wxString Field::get_tooltip_text(const wxString& default_string)
|
||||
{
|
||||
wxString tooltip_text("");
|
||||
wxString tooltip = _(m_opt.tooltip);
|
||||
edit_tooltip(tooltip);
|
||||
if (m_opt.tooltip.empty())
|
||||
return "";
|
||||
|
||||
std::string opt_id = m_opt_id;
|
||||
auto hash_pos = opt_id.find("#");
|
||||
auto hash_pos = opt_id.find('#');
|
||||
if (hash_pos != std::string::npos) {
|
||||
opt_id.replace(hash_pos, 1,"[");
|
||||
opt_id += "]";
|
||||
}
|
||||
|
||||
if (tooltip.length() > 0)
|
||||
tooltip_text = tooltip + "\n" + _(L("default value")) + "\t: " +
|
||||
return from_u8(m_opt.tooltip) + "\n" + _L("default value") + "\t: " +
|
||||
(boost::iends_with(opt_id, "_gcode") ? "\n" : "") + default_string +
|
||||
(boost::iends_with(opt_id, "_gcode") ? "" : "\n") +
|
||||
_(L("parameter name")) + "\t: " + opt_id;
|
||||
|
||||
return tooltip_text;
|
||||
_L("parameter name") + "\t: " + opt_id;
|
||||
}
|
||||
|
||||
bool Field::is_matched(const std::string& string, const std::string& pattern)
|
||||
|
@ -2246,7 +2246,7 @@ void GCodeViewer::load_shells(const Print& print)
|
||||
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) {
|
||||
// adds wipe tower's volume
|
||||
const double max_z = print.objects()[0]->model_object()->get_model()->bounding_box().max(2);
|
||||
const double max_z = print.objects()[0]->model_object()->get_model()->max_z();
|
||||
const PrintConfig& config = print.config();
|
||||
const size_t extruders_count = config.nozzle_diameter.size();
|
||||
if (extruders_count > 1 && config.wipe_tower && !config.complete_objects) {
|
||||
|
@ -140,7 +140,7 @@ void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
|
||||
// Maximum height of an object changes when the object gets rotated or scaled.
|
||||
// Changing maximum height of an object will invalidate the layer heigth editing profile.
|
||||
// m_model_object->bounding_box() is cached, therefore it is cheap even if this method is called frequently.
|
||||
const float new_max_z = (model_object_new == nullptr) ? 0.0f : static_cast<float>(model_object_new->bounding_box().max.z());
|
||||
const float new_max_z = (model_object_new == nullptr) ? 0.0f : static_cast<float>(model_object_new->max_z());
|
||||
if (m_model_object != model_object_new || this->last_object_id != object_id || m_object_max_z != new_max_z ||
|
||||
(model_object_new != nullptr && m_model_object->id() != model_object_new->id())) {
|
||||
m_layer_height_profile.clear();
|
||||
@ -1977,7 +1977,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
|
||||
if (extruders_count > 1 && wt && !co) {
|
||||
// Height of a print (Show at least a slab)
|
||||
const double height = std::max(m_model->bounding_box().max.z(), 10.0);
|
||||
const double height = std::max(m_model->max_z(), 10.0);
|
||||
|
||||
const float x = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_x"))->value;
|
||||
const float y = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_y"))->value;
|
||||
@ -3746,12 +3746,22 @@ void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
|
||||
if (!snapshot_type.empty())
|
||||
wxGetApp().plater()->take_snapshot(_(snapshot_type));
|
||||
|
||||
// stores current min_z of instances
|
||||
std::map<std::pair<int, int>, double> min_zs;
|
||||
if (!snapshot_type.empty()) {
|
||||
for (int i = 0; i < static_cast<int>(m_model->objects.size()); ++i) {
|
||||
const ModelObject* obj = m_model->objects[i];
|
||||
for (int j = 0; j < static_cast<int>(obj->instances.size()); ++j) {
|
||||
min_zs[{ i, j }] = obj->instance_bounding_box(j).min.z();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::pair<int, int>> done; // keeps track of modified instances
|
||||
|
||||
const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
|
||||
Selection::EMode selection_mode = m_selection.get_mode();
|
||||
|
||||
for (unsigned int id : idxs) {
|
||||
const GLVolume* v = m_volumes.volumes[id];
|
||||
for (const GLVolume* v : m_volumes.volumes) {
|
||||
int object_idx = v->object_idx();
|
||||
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
|
||||
continue;
|
||||
@ -3761,14 +3771,30 @@ void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
|
||||
|
||||
done.insert(std::pair<int, int>(object_idx, instance_idx));
|
||||
|
||||
// Mirror instances/volumes
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
else if (selection_mode == Selection::Volume)
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
}
|
||||
|
||||
// Fixes sinking/flying instances
|
||||
for (const std::pair<int, int>& i : done) {
|
||||
ModelObject* m = m_model->objects[i.first];
|
||||
double shift_z = m->get_instance_min_z(i.second);
|
||||
// leave sinking instances as sinking
|
||||
if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) {
|
||||
Vec3d shift(0.0, 0.0, -shift_z);
|
||||
m_selection.translate(i.first, i.second, shift);
|
||||
m->translate_instance(i.second, shift);
|
||||
}
|
||||
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
|
||||
}
|
||||
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_RESET_SKEW));
|
||||
|
||||
m_dirty = true;
|
||||
@ -4990,9 +5016,11 @@ void GLCanvas3D::_refresh_if_shown_on_screen()
|
||||
// frequently enough, we call render() here directly when we can.
|
||||
render();
|
||||
assert(m_initialized);
|
||||
if (requires_reload_scene)
|
||||
if (requires_reload_scene) {
|
||||
if (wxGetApp().plater()->is_view3D_shown())
|
||||
reload_scene(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::_picking_pass()
|
||||
|
@ -480,6 +480,8 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
|
||||
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
|
||||
|
||||
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv, ".pwmx"sv } },
|
||||
|
||||
/* FT_ZIP */ { "Zip files"sv, { ".zip"sv } },
|
||||
};
|
||||
|
||||
#if ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
@ -885,13 +887,9 @@ wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas)
|
||||
|
||||
bool GUI_App::init_opengl()
|
||||
{
|
||||
#ifdef __linux__
|
||||
bool status = m_opengl_mgr.init_gl();
|
||||
m_opengl_initialized = true;
|
||||
return status;
|
||||
#else
|
||||
return m_opengl_mgr.init_gl();
|
||||
#endif
|
||||
}
|
||||
|
||||
// gets path to PrusaSlicer.ini, returns semver from first line comment
|
||||
@ -1368,12 +1366,15 @@ bool GUI_App::on_init_inner()
|
||||
|
||||
// An ugly solution to GH #5537 in which GUI_App::init_opengl (normally called from events wxEVT_PAINT
|
||||
// and wxEVT_SET_FOCUS before GUI_App::post_init is called) wasn't called before GUI_App::post_init and OpenGL wasn't initialized.
|
||||
#ifdef __linux__
|
||||
if (! m_post_initialized && m_opengl_initialized) {
|
||||
// Since issue #9774 Where same problem occured on MacOS Ventura, we decided to have this check on MacOS as well.
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
if (!m_post_initialized && m_opengl_initialized) {
|
||||
#else
|
||||
if (! m_post_initialized) {
|
||||
if (!m_post_initialized) {
|
||||
#endif
|
||||
m_post_initialized = true;
|
||||
|
||||
#ifdef WIN32
|
||||
this->mainframe->register_win32_callbacks();
|
||||
#endif
|
||||
@ -1977,6 +1978,17 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
|
||||
dialog.GetPaths(input_files);
|
||||
}
|
||||
|
||||
void GUI_App::import_zip(wxWindow* parent, wxString& input_file) const
|
||||
{
|
||||
wxFileDialog dialog(parent ? parent : GetTopWindow(),
|
||||
_L("Choose ZIP file:"),
|
||||
from_u8(app_config->get_last_dir()), "",
|
||||
file_wildcards(FT_ZIP), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
input_file = dialog.GetPath();
|
||||
}
|
||||
|
||||
void GUI_App::load_gcode(wxWindow* parent, wxString& input_file) const
|
||||
{
|
||||
input_file.Clear();
|
||||
|
@ -73,6 +73,8 @@ enum FileType
|
||||
|
||||
FT_SL1,
|
||||
|
||||
FT_ZIP,
|
||||
|
||||
FT_SIZE,
|
||||
};
|
||||
|
||||
@ -125,9 +127,7 @@ private:
|
||||
bool m_last_app_conf_lower_version{ false };
|
||||
EAppMode m_app_mode{ EAppMode::Editor };
|
||||
bool m_is_recreating_gui{ false };
|
||||
#ifdef __linux__
|
||||
bool m_opengl_initialized{ false };
|
||||
#endif
|
||||
|
||||
wxColour m_color_label_modified;
|
||||
wxColour m_color_label_sys;
|
||||
@ -252,6 +252,7 @@ public:
|
||||
void keyboard_shortcuts();
|
||||
void load_project(wxWindow *parent, wxString& input_file) const;
|
||||
void import_model(wxWindow *parent, wxArrayString& input_files) const;
|
||||
void import_zip(wxWindow* parent, wxString& input_file) const;
|
||||
void load_gcode(wxWindow* parent, wxString& input_file) const;
|
||||
|
||||
static bool catch_error(std::function<void()> cb, const std::string& err);
|
||||
|
@ -446,7 +446,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
m_reset_rotation_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
selection.setup_cache();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
||||
@ -468,9 +468,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
else
|
||||
return;
|
||||
|
||||
// Update rotation at the GLVolumes.
|
||||
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
|
||||
// Synchronize instances/volumes.
|
||||
|
||||
selection.synchronize_unselected_instances(Selection::SyncRotationType::RESET);
|
||||
selection.synchronize_unselected_volumes();
|
||||
|
||||
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
canvas->do_rotate(L("Reset Rotation"));
|
||||
|
||||
@ -490,6 +492,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
selection.setup_cache();
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
||||
Geometry::Transformation trafo = vol->get_volume_transformation();
|
||||
@ -506,6 +509,10 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
else
|
||||
return;
|
||||
|
||||
// Synchronize instances/volumes.
|
||||
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
|
||||
canvas->do_scale(L("Reset scale"));
|
||||
UpdateAndShow(true);
|
||||
#else
|
||||
@ -750,7 +757,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
||||
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_scale = volume->get_instance_scaling_factor() * 100.0;
|
||||
m_new_scale = m_new_size.cwiseQuotient(selection.get_full_unscaled_instance_local_bounding_box().size()) * 100.0;
|
||||
}
|
||||
|
||||
m_new_enabled = true;
|
||||
|
@ -996,6 +996,8 @@ void GLGizmoCut3D::update_raycasters_for_picking_transform()
|
||||
const Vec3d& instance_offset = mo->instances[inst_id]->get_offset();
|
||||
const double sla_shift = double(m_c->selection_info()->get_sla_shift());
|
||||
|
||||
const bool looking_forward = is_looking_forward();
|
||||
|
||||
for (size_t i = 0; i < connectors.size(); ++i) {
|
||||
const CutConnector& connector = connectors[i];
|
||||
|
||||
@ -1004,9 +1006,8 @@ void GLGizmoCut3D::update_raycasters_for_picking_transform()
|
||||
Vec3d pos = connector.pos + instance_offset;
|
||||
if (connector.attribs.type == CutConnectorType::Dowel &&
|
||||
connector.attribs.style == CutConnectorStyle::Prism) {
|
||||
if (is_looking_forward())
|
||||
pos -= static_cast<double>(height - 0.05f) * m_clp_normal;
|
||||
else
|
||||
height = 0.05f;
|
||||
if (!looking_forward)
|
||||
pos += 0.05 * m_clp_normal;
|
||||
}
|
||||
pos[Z] += sla_shift;
|
||||
@ -2065,6 +2066,8 @@ void GLGizmoCut3D::render_connectors()
|
||||
m_has_invalid_connector = false;
|
||||
m_info_stats.invalidate();
|
||||
|
||||
const bool looking_forward = is_looking_forward();
|
||||
|
||||
for (size_t i = 0; i < connectors.size(); ++i) {
|
||||
const CutConnector& connector = connectors[i];
|
||||
|
||||
@ -2093,20 +2096,19 @@ void GLGizmoCut3D::render_connectors()
|
||||
if (connector.attribs.type == CutConnectorType::Dowel &&
|
||||
connector.attribs.style == CutConnectorStyle::Prism) {
|
||||
if (m_connectors_editing) {
|
||||
if (is_looking_forward())
|
||||
pos -= static_cast<double>(height-0.05f) * m_clp_normal;
|
||||
else
|
||||
height = 0.05f;
|
||||
if (!looking_forward)
|
||||
pos += 0.05 * m_clp_normal;
|
||||
}
|
||||
else {
|
||||
if (is_looking_forward())
|
||||
if (looking_forward)
|
||||
pos -= static_cast<double>(height) * m_clp_normal;
|
||||
else
|
||||
pos += static_cast<double>(height) * m_clp_normal;
|
||||
height *= 2;
|
||||
}
|
||||
}
|
||||
else if (!is_looking_forward())
|
||||
else if (!looking_forward)
|
||||
pos += 0.05 * m_clp_normal;
|
||||
|
||||
const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(pos) * m_rotation_m *
|
||||
|
@ -667,7 +667,7 @@ void GLGizmoEmboss::on_set_state()
|
||||
get_model_volume(m_volume_id, m_parent.get_selection().get_model()->objects) == nullptr ) {
|
||||
// reopen gizmo when new object is created
|
||||
GLGizmoBase::m_state = GLGizmoBase::Off;
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
if (wxGetApp().get_mode() == comSimple || wxGetApp().obj_list()->has_selected_cut_object())
|
||||
// It's impossible to add a part in simple mode
|
||||
return;
|
||||
// start creating new object
|
||||
|
@ -238,13 +238,7 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system();
|
||||
m_bounding_box = box;
|
||||
m_center = box_trafo.translation();
|
||||
m_orient_matrix = Geometry::translation_transform(m_center);
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates() || m_force_local_coordinate) {
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
m_orient_matrix = m_orient_matrix * v.get_instance_transformation().get_rotation_matrix();
|
||||
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates() || m_force_local_coordinate)
|
||||
m_orient_matrix = m_orient_matrix * v.get_volume_transformation().get_rotation_matrix();
|
||||
}
|
||||
m_orient_matrix = box_trafo;
|
||||
|
||||
m_radius = Offset + m_bounding_box.radius();
|
||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||
|
@ -1293,6 +1293,10 @@ void MainFrame::init_menubar_as_editor()
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
|
||||
[this](){return m_plater != nullptr && m_plater->get_ui_job_worker().is_idle(); }, this);
|
||||
|
||||
append_menu_item(import_menu, wxID_ANY, _L("Import ZIP Achive") + dots, _L("Load a zip achive"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->import_zip_archive(); }, "import_plater", nullptr,
|
||||
[this]() {return m_plater != nullptr; }, this);
|
||||
|
||||
import_menu->AppendSeparator();
|
||||
append_menu_item(import_menu, wxID_ANY, _L("Import &Config") + dots + "\tCtrl+L", _L("Load exported configuration file"),
|
||||
[this](wxCommandEvent&) { load_config_file(); }, "import_config", nullptr,
|
||||
|
@ -118,6 +118,20 @@ OptionsGroup::OptionsGroup( wxWindow* _parent, const wxString& title,
|
||||
{
|
||||
}
|
||||
|
||||
Option::Option(const ConfigOptionDef& _opt, t_config_option_key id) : opt(_opt), opt_id(id)
|
||||
{
|
||||
if (!opt.tooltip.empty()) {
|
||||
wxString tooltip;
|
||||
if (opt.opt_key.rfind("branching", 0) == 0)
|
||||
tooltip = _L("Unavailable for this method.") + "\n";
|
||||
tooltip += _(opt.tooltip);
|
||||
|
||||
edit_tooltip(tooltip);
|
||||
|
||||
opt.tooltip = into_u8(tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
void Line::clear()
|
||||
{
|
||||
if (near_label_widget_win)
|
||||
@ -517,9 +531,8 @@ void OptionsGroup::clear(bool destroy_custom_ctrl)
|
||||
|
||||
Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const
|
||||
{
|
||||
wxString tooltip = _(option.opt.tooltip);
|
||||
edit_tooltip(tooltip);
|
||||
Line retval{ _(option.opt.label), tooltip };
|
||||
Line retval{ _(option.opt.label), from_u8(option.opt.tooltip) };
|
||||
|
||||
retval.label_path = path;
|
||||
retval.append_option(option);
|
||||
return retval;
|
||||
|
@ -47,8 +47,7 @@ struct Option {
|
||||
return (rhs.opt_id == this->opt_id);
|
||||
}
|
||||
|
||||
Option(const ConfigOptionDef& _opt, t_config_option_key id) :
|
||||
opt(_opt), opt_id(id) {}
|
||||
Option(const ConfigOptionDef& _opt, t_config_option_key id);
|
||||
};
|
||||
using t_option = std::unique_ptr<Option>; //!
|
||||
|
||||
|
@ -547,18 +547,19 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change)
|
||||
} link, connect;
|
||||
// allowed models are: all MINI, all MK3 and newer, MK2.5 and MK2.5S
|
||||
auto model_supports_prusalink = [](const std::string& model) {
|
||||
return model.size() >= 3 &&
|
||||
return model.size() >= 2 &&
|
||||
(( boost::starts_with(model, "MK") && model[2] > '2' && model[2] <= '9')
|
||||
|| boost::starts_with(model, "MINI")
|
||||
|| boost::starts_with(model, "MK2.5")
|
||||
//|| boost::starts_with(model, "MK2.5S")
|
||||
|| boost::starts_with(model, "XL")
|
||||
);
|
||||
};
|
||||
// allowed models are: all MK3/S and MK2.5/S
|
||||
auto model_supports_prusaconnect = [](const std::string& model) {
|
||||
return model.size() >= 3 &&
|
||||
(boost::starts_with(model, "MK3")
|
||||
return model.size() >= 2 &&
|
||||
((boost::starts_with(model, "MK") && model[2] > '2' && model[2] <= '9')
|
||||
|| boost::starts_with(model, "MK2.5")
|
||||
|| boost::starts_with(model, "XL")
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2683,6 +2683,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
instance->set_offset(-model_object->origin_translation);
|
||||
}
|
||||
}
|
||||
if (!model_object->instances.empty())
|
||||
model_object->ensure_on_bed(is_project_file);
|
||||
}
|
||||
|
||||
@ -3520,7 +3521,7 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
|
||||
ModelObject* old_model_object = model.objects[object_idx];
|
||||
ModelVolume* old_volume = old_model_object->volumes[volume_idx];
|
||||
|
||||
bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
|
||||
bool sinking = old_model_object->min_z() < SINKING_Z_THRESHOLD;
|
||||
|
||||
ModelObject* new_model_object = new_model.objects.front();
|
||||
old_model_object->add_volume(*new_model_object->volumes.front());
|
||||
@ -3835,7 +3836,7 @@ void Plater::priv::reload_from_disk()
|
||||
ModelObject* old_model_object = model.objects[obj_idx];
|
||||
ModelVolume* old_volume = old_model_object->volumes[vol_idx];
|
||||
|
||||
bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
|
||||
bool sinking = old_model_object->min_z() < SINKING_Z_THRESHOLD;
|
||||
|
||||
bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string());
|
||||
bool has_name = !old_volume->name.empty() && boost::algorithm::iequals(old_volume->name, fs::path(path).filename().string());
|
||||
@ -4816,7 +4817,7 @@ bool Plater::priv::layers_height_allowed() const
|
||||
return false;
|
||||
|
||||
int obj_idx = get_selected_object_idx();
|
||||
return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->bounding_box().max.z() > SINKING_Z_THRESHOLD &&
|
||||
return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->max_z() > SINKING_Z_THRESHOLD &&
|
||||
config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed();
|
||||
}
|
||||
|
||||
@ -5478,6 +5479,17 @@ void Plater::add_model(bool imperial_units/* = false*/)
|
||||
wxGetApp().mainframe->update_title();
|
||||
}
|
||||
|
||||
void Plater::import_zip_archive()
|
||||
{
|
||||
wxString input_file;
|
||||
wxGetApp().import_zip(this, input_file);
|
||||
if (input_file.empty())
|
||||
return;
|
||||
|
||||
fs::path path = into_path(input_file);
|
||||
preview_zip_archive(path);
|
||||
}
|
||||
|
||||
void Plater::import_sl1_archive()
|
||||
{
|
||||
auto &w = get_ui_job_worker();
|
||||
@ -6936,18 +6948,19 @@ void Plater::send_gcode()
|
||||
upload_job.printhost->get_groups(groups);
|
||||
}
|
||||
// PrusaLink specific: Query the server for the list of file groups.
|
||||
wxArrayString storage;
|
||||
wxArrayString storage_paths;
|
||||
wxArrayString storage_names;
|
||||
{
|
||||
wxBusyCursor wait;
|
||||
try {
|
||||
upload_job.printhost->get_storage(storage);
|
||||
upload_job.printhost->get_storage(storage_paths, storage_names);
|
||||
} catch (const Slic3r::IOError& ex) {
|
||||
show_error(this, ex.what(), false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->get_post_upload_actions(), groups, storage);
|
||||
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->get_post_upload_actions(), groups, storage_paths, storage_names);
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
upload_job.upload_data.upload_path = dlg.filename();
|
||||
upload_job.upload_data.post_action = dlg.post_action();
|
||||
@ -7435,7 +7448,7 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
|
||||
|
||||
for (size_t obj_idx : object_idxs) {
|
||||
if (obj_idx < p->model.objects.size()) {
|
||||
if (p->model.objects[obj_idx]->bounding_box().min.z() >= SINKING_Z_THRESHOLD)
|
||||
if (p->model.objects[obj_idx]->min_z() >= SINKING_Z_THRESHOLD)
|
||||
// re - align to Z = 0
|
||||
p->model.objects[obj_idx]->ensure_on_bed();
|
||||
}
|
||||
|
@ -166,6 +166,7 @@ public:
|
||||
void load_project();
|
||||
void load_project(const wxString& filename);
|
||||
void add_model(bool imperial_units = false);
|
||||
void import_zip_archive();
|
||||
void import_sl1_archive();
|
||||
void extract_config_from_project();
|
||||
void load_gcode();
|
||||
|
@ -38,13 +38,14 @@ static const char *CONFIG_KEY_PATH = "printhost_path";
|
||||
static const char *CONFIG_KEY_GROUP = "printhost_group";
|
||||
static const char* CONFIG_KEY_STORAGE = "printhost_storage";
|
||||
|
||||
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUploadActions post_actions, const wxArrayString &groups, const wxArrayString& storage)
|
||||
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUploadActions post_actions, const wxArrayString &groups, const wxArrayString& storage_paths, const wxArrayString& storage_names)
|
||||
: MsgDialog(static_cast<wxWindow*>(wxGetApp().mainframe), _L("Send G-Code to printer host"), _L("Upload to Printer Host with the following filename:"), 0) // Set style = 0 to avoid default creation of the "OK" button.
|
||||
// All buttons will be added later in this constructor
|
||||
, txt_filename(new wxTextCtrl(this, wxID_ANY))
|
||||
, combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr)
|
||||
, combo_storage(storage.GetCount() > 1 ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, storage, wxCB_READONLY) : nullptr)
|
||||
, combo_storage(storage_names.GetCount() > 1 ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, storage_names, wxCB_READONLY) : nullptr)
|
||||
, post_upload_action(PrintHostPostUploadAction::None)
|
||||
, m_paths(storage_paths)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
txt_filename->OSXDisableAllSmartSubstitutions();
|
||||
@ -73,15 +74,15 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo
|
||||
auto* label_group = new wxStaticText(this, wxID_ANY, _L("Upload to storage:"));
|
||||
content_sizer->Add(label_group);
|
||||
content_sizer->Add(combo_storage, 0, wxBOTTOM, 2 * VERT_SPACING);
|
||||
combo_storage->SetValue(storage.front());
|
||||
combo_storage->SetValue(storage_names.front());
|
||||
wxString recent_storage = from_u8(app_config->get("recent", CONFIG_KEY_STORAGE));
|
||||
if (!recent_storage.empty())
|
||||
combo_storage->SetValue(recent_storage);
|
||||
} else if (storage.GetCount() == 1){
|
||||
} else if (storage_names.GetCount() == 1){
|
||||
// PrusaLink specific: Show which storage has been detected.
|
||||
auto* label_group = new wxStaticText(this, wxID_ANY, _L("Upload to storage: ") + storage.front());
|
||||
auto* label_group = new wxStaticText(this, wxID_ANY, _L("Upload to storage: ") + storage_names.front());
|
||||
content_sizer->Add(label_group);
|
||||
m_preselected_storage = storage.front();
|
||||
m_preselected_storage = storage_paths.front();
|
||||
}
|
||||
|
||||
|
||||
@ -196,7 +197,9 @@ std::string PrintHostSendDialog::storage() const
|
||||
{
|
||||
if (!combo_storage)
|
||||
return GUI::format("%1%", m_preselected_storage);
|
||||
return boost::nowide::narrow(combo_storage->GetValue());
|
||||
if (combo_storage->GetSelection() < 0 || combo_storage->GetSelection() >= m_paths.size())
|
||||
return {};
|
||||
return boost::nowide::narrow(m_paths[combo_storage->GetSelection()]);
|
||||
}
|
||||
|
||||
void PrintHostSendDialog::EndModal(int ret)
|
||||
@ -226,8 +229,6 @@ void PrintHostSendDialog::EndModal(int ret)
|
||||
MsgDialog::EndModal(ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event);
|
||||
|
@ -26,7 +26,7 @@ namespace GUI {
|
||||
class PrintHostSendDialog : public GUI::MsgDialog
|
||||
{
|
||||
public:
|
||||
PrintHostSendDialog(const boost::filesystem::path &path, PrintHostPostUploadActions post_actions, const wxArrayString& groups, const wxArrayString& storage);
|
||||
PrintHostSendDialog(const boost::filesystem::path &path, PrintHostPostUploadActions post_actions, const wxArrayString& groups, const wxArrayString& storage_paths, const wxArrayString& storage_names);
|
||||
boost::filesystem::path filename() const;
|
||||
PrintHostPostUploadAction post_action() const;
|
||||
std::string group() const;
|
||||
@ -40,6 +40,7 @@ private:
|
||||
PrintHostPostUploadAction post_upload_action;
|
||||
wxString m_valid_suffix;
|
||||
wxString m_preselected_storage;
|
||||
wxArrayString m_paths;
|
||||
};
|
||||
|
||||
|
||||
|
@ -918,7 +918,7 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor
|
||||
v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement);
|
||||
}
|
||||
else
|
||||
transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center);
|
||||
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center);
|
||||
}
|
||||
else {
|
||||
if (transformation_type.local() && transformation_type.absolute()) {
|
||||
@ -998,24 +998,32 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||
|
||||
assert(transformation_type.relative() || (transformation_type.absolute() && transformation_type.local()));
|
||||
|
||||
Transform3d rotation_matrix = Geometry::rotation_transform(rotation);
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
Transform3d rotation_matrix = Geometry::rotation_transform(rotation);
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
||||
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
||||
if (m_mode == Instance && !is_wipe_tower()) {
|
||||
assert(is_from_fully_selected_instance(i));
|
||||
if (transformation_type.instance()) {
|
||||
const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset();
|
||||
const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot;
|
||||
Matrix3d inst_rotation, inst_scale;
|
||||
inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale);
|
||||
const Transform3d trafo = inst_trafo.get_rotation_matrix() * rotation_matrix;
|
||||
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * inst_trafo.get_offset_matrix() * trafo * Transform3d(inst_scale) * Geometry::translation_transform(-local_inst_pivot));
|
||||
// ensure that the instance rotates as a rigid body
|
||||
Transform3d inst_rotation_matrix = inst_trafo.get_rotation_matrix();
|
||||
if (inst_trafo.is_left_handed()) {
|
||||
Geometry::TransformationSVD inst_svd(inst_trafo);
|
||||
inst_rotation_matrix = inst_svd.u * inst_svd.v.transpose();
|
||||
// ensure the rotation has the proper direction
|
||||
if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX()))
|
||||
rotation_matrix = rotation_matrix.inverse();
|
||||
}
|
||||
else
|
||||
transform_instance_relative_world(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
||||
|
||||
const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset();
|
||||
rotation_matrix = inst_matrix_no_offset.inverse() * inst_rotation_matrix * rotation_matrix * inst_rotation_matrix.inverse() * inst_matrix_no_offset;
|
||||
|
||||
// rotate around selection center
|
||||
const Vec3d inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * (m_cache.dragging_center - inst_trafo.get_offset());
|
||||
rotation_matrix = Geometry::translation_transform(inst_pivot) * rotation_matrix * Geometry::translation_transform(-inst_pivot);
|
||||
}
|
||||
transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
||||
}
|
||||
else {
|
||||
if (!is_single_volume_or_modifier()) {
|
||||
@ -1024,49 +1032,38 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||
}
|
||||
else {
|
||||
if (transformation_type.instance()) {
|
||||
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
||||
const Geometry::Transformation world_trafo = inst_trafo * vol_trafo;
|
||||
// ensure proper sign of rotation for mirrored objects
|
||||
if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX()))
|
||||
rotation_matrix = rotation_matrix.inverse();
|
||||
|
||||
// ensure that the volume rotates as a rigid body
|
||||
const Geometry::TransformationSVD world_svd(world_trafo);
|
||||
if (world_svd.anisotropic_scale) {
|
||||
const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix();
|
||||
rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix;
|
||||
}
|
||||
const Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix();
|
||||
rotation_matrix = vol_rotation_matrix.inverse() * rotation_matrix * vol_rotation_matrix;
|
||||
|
||||
v.set_volume_transformation(vol_trafo.get_matrix() * rotation_matrix);
|
||||
const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix();
|
||||
rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix;
|
||||
}
|
||||
else {
|
||||
if (transformation_type.local()) {
|
||||
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
||||
const Geometry::Transformation world_trafo = inst_trafo * vol_trafo;
|
||||
// ensure proper sign of rotation for mirrored objects
|
||||
if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX()))
|
||||
rotation_matrix = rotation_matrix.inverse();
|
||||
|
||||
// ensure that the volume rotates as a rigid body
|
||||
const Geometry::TransformationSVD svd(world_trafo);
|
||||
if (svd.anisotropic_scale) {
|
||||
const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix();
|
||||
rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix;
|
||||
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
||||
const Transform3d vol_matrix_no_offset = vol_trafo.get_matrix_no_offset();
|
||||
const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix();
|
||||
Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix();
|
||||
if (vol_trafo.is_left_handed()) {
|
||||
Geometry::TransformationSVD vol_svd(vol_trafo);
|
||||
vol_rotation_matrix = vol_svd.u * vol_svd.v.transpose();
|
||||
// ensure the rotation has the proper direction
|
||||
if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX()))
|
||||
rotation_matrix = rotation_matrix.inverse();
|
||||
}
|
||||
rotation_matrix = vol_matrix_no_offset.inverse() * inst_scale_matrix.inverse() * vol_rotation_matrix * rotation_matrix *
|
||||
vol_rotation_matrix.inverse() * inst_scale_matrix * vol_matrix_no_offset;
|
||||
}
|
||||
}
|
||||
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance) {
|
||||
int rot_axis_max = 0;
|
||||
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
||||
synchronize_unselected_instances((transformation_type.world() && rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL);
|
||||
synchronize_unselected_instances((rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL);
|
||||
}
|
||||
else if (m_mode == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
@ -1468,7 +1465,7 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation
|
||||
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot));
|
||||
}
|
||||
else
|
||||
transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
|
||||
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
|
||||
}
|
||||
else {
|
||||
if (!is_single_volume_or_modifier()) {
|
||||
@ -1553,6 +1550,15 @@ void Selection::reset_skew()
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
// even if there is no rotation, we pass SyncRotationType::GENERAL to force
|
||||
// synchronize_unselected_instances() to remove skew from the other instances
|
||||
synchronize_unselected_instances(SyncRotationType::GENERAL);
|
||||
else if (m_mode == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
ensure_on_bed();
|
||||
set_bounding_boxes_dirty();
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
@ -2771,6 +2777,7 @@ void Selection::render_debug_window() const
|
||||
return;
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
|
||||
imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
|
||||
|
||||
auto volume_name = [this](size_t id) {
|
||||
@ -3010,7 +3017,12 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
|
||||
const Transform3d& old_inst_trafo_j = m_cache.volumes_data[j].get_instance_transform().get_matrix();
|
||||
assert(is_rotation_xy_synchronized(old_inst_trafo_i, old_inst_trafo_j));
|
||||
Transform3d new_inst_trafo_j = volume_j->get_instance_transformation().get_matrix();
|
||||
if (sync_rotation_type != SyncRotationType::NONE || mirrored)
|
||||
if (sync_rotation_type == SyncRotationType::RESET) {
|
||||
Geometry::Transformation new_inst_trafo_j_no_rotation(new_inst_trafo_j);
|
||||
new_inst_trafo_j_no_rotation.reset_rotation();
|
||||
new_inst_trafo_j = new_inst_trafo_j_no_rotation.get_matrix();
|
||||
}
|
||||
else if (sync_rotation_type != SyncRotationType::NONE || mirrored)
|
||||
new_inst_trafo_j.linear() = (old_inst_trafo_j.linear() * old_inst_trafo_i.linear().inverse()) * curr_inst_trafo_i.linear();
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||
new_inst_trafo_j.translation().z() = curr_inst_trafo_i.translation().z();
|
||||
@ -3326,16 +3338,21 @@ void Selection::paste_objects_from_clipboard()
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
void Selection::transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
const Transform3d& transform, const Vec3d& world_pivot)
|
||||
{
|
||||
assert(transformation_type.relative());
|
||||
assert(transformation_type.world());
|
||||
|
||||
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
||||
if (transformation_type.world()) {
|
||||
const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot;
|
||||
const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot);
|
||||
volume.set_instance_transformation(trafo * inst_trafo.get_matrix());
|
||||
}
|
||||
else if (transformation_type.instance())
|
||||
volume.set_instance_transformation(inst_trafo.get_matrix() * transform);
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
|
@ -500,6 +500,10 @@ public:
|
||||
NONE = 0,
|
||||
// Synchronize after rotation by an axis not parallel with Z.
|
||||
GENERAL = 1,
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Synchronize after rotation reset.
|
||||
RESET = 2
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
|
||||
void synchronize_unselected_volumes();
|
||||
@ -513,7 +517,7 @@ private:
|
||||
void paste_objects_from_clipboard();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
void transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
const Transform3d& transform, const Vec3d& world_pivot);
|
||||
void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
const Transform3d& transform, const Vec3d& world_pivot);
|
||||
|
@ -273,7 +273,6 @@ bool OctoPrint::test(wxString& msg) const
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
wxString OctoPrint::get_test_ok_msg () const
|
||||
{
|
||||
return _(L("Connection to OctoPrint works correctly."));
|
||||
@ -685,7 +684,7 @@ bool PrusaLink::test(wxString& msg) const
|
||||
return res;
|
||||
}
|
||||
|
||||
bool PrusaLink::get_storage(wxArrayString& output) const
|
||||
bool PrusaLink::get_storage(wxArrayString& storage_path, wxArrayString& storage_name) const
|
||||
{
|
||||
const char* name = get_name();
|
||||
|
||||
@ -693,17 +692,22 @@ bool PrusaLink::get_storage(wxArrayString& output) const
|
||||
auto url = make_url("api/v1/storage");
|
||||
wxString error_msg;
|
||||
|
||||
struct StorageInfo{
|
||||
struct StorageInfo {
|
||||
wxString path;
|
||||
wxString name;
|
||||
bool read_only;
|
||||
long long free_space;
|
||||
bool read_only = false;
|
||||
long long free_space = -1;
|
||||
};
|
||||
std::vector<StorageInfo> storage;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get storage at: %2%") % name % url;
|
||||
|
||||
wxString wlang = GUI::wxGetApp().current_language_code();
|
||||
std::string lang = GUI::format(wlang.SubString(0, 1));
|
||||
|
||||
auto http = Http::get(std::move(url));
|
||||
set_auth(http);
|
||||
http.header("Accept-Language", lang);
|
||||
http.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting storage: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
|
||||
error_msg = L"\n\n" + boost::nowide::widen(error);
|
||||
@ -731,6 +735,7 @@ bool PrusaLink::get_storage(wxArrayString& output) const
|
||||
}
|
||||
// each storage has own subtree of storage_list
|
||||
for (const auto& section : ptree.front().second) {
|
||||
const auto name = section.second.get_optional<std::string>("name");
|
||||
const auto path = section.second.get_optional<std::string>("path");
|
||||
const auto space = section.second.get_optional<std::string>("free_space");
|
||||
const auto read_only = section.second.get_optional<bool>("read_only");
|
||||
@ -738,7 +743,8 @@ bool PrusaLink::get_storage(wxArrayString& output) const
|
||||
const auto available = section.second.get_optional<bool>("available");
|
||||
if (path && (!available || *available)) {
|
||||
StorageInfo si;
|
||||
si.name = boost::nowide::widen(*path);
|
||||
si.path = boost::nowide::widen(*path);
|
||||
si.name = name ? boost::nowide::widen(*name) : wxString();
|
||||
// If read_only is missing, assume it is NOT read only.
|
||||
// si.read_only = read_only ? *read_only : false; // version without "ro"
|
||||
si.read_only = (read_only ? *read_only : (ro ? *ro : false));
|
||||
@ -759,16 +765,17 @@ bool PrusaLink::get_storage(wxArrayString& output) const
|
||||
.perform_sync();
|
||||
|
||||
for (const auto& si : storage) {
|
||||
if (!si.read_only && si.free_space > 0)
|
||||
output.push_back(si.name);
|
||||
if (!si.read_only && si.free_space > 0) {
|
||||
storage_path.push_back(si.path);
|
||||
storage_name.push_back(si.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (res && output.empty())
|
||||
{
|
||||
if (res && storage_path.empty()) {
|
||||
if (!storage.empty()) { // otherwise error_msg is already filled
|
||||
error_msg = L"\n\n" + _L("Storages found:") + L" \n";
|
||||
for (const auto& si : storage) {
|
||||
error_msg += si.name + L" : " + (si.read_only ? _L("read only") : _L("no free space")) + L"\n";
|
||||
error_msg += si.path + L" : " + (si.read_only ? _L("read only") : _L("no free space")) + L"\n";
|
||||
}
|
||||
}
|
||||
std::string message = GUI::format(_L("Upload has failed. There is no suitable storage found at %1%.%2%"), m_host, error_msg);
|
||||
|
@ -94,7 +94,7 @@ public:
|
||||
virtual PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
|
||||
|
||||
// gets possible storage to be uploaded to. This allows different printer to have different storage. F.e. local vs sdcard vs usb.
|
||||
bool get_storage(wxArrayString& /* storage */) const override;
|
||||
bool get_storage(wxArrayString& storage_path, wxArrayString& storage_name) const override;
|
||||
protected:
|
||||
bool test(wxString& curl_msg) const override;
|
||||
bool validate_version_text(const boost::optional<std::string>& version_text) const override;
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
virtual bool get_printers(wxArrayString & /* printers */) const { return false; }
|
||||
// Support for PrusaLink uploading to different storage. Not supported by other print hosts.
|
||||
// Returns false if not supported or fail.
|
||||
virtual bool get_storage(wxArrayString& /* storage */) const { return false; }
|
||||
virtual bool get_storage(wxArrayString& /*storage_path*/, wxArrayString& /*storage_name*/) const { return false; }
|
||||
|
||||
static PrintHost* get_print_host(DynamicPrintConfig *config);
|
||||
|
||||
|
@ -24,6 +24,8 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||
// a percent to what.
|
||||
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->value = 50.;
|
||||
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->percent = true;
|
||||
ConfigOptionFloatsNullable *opt_filament_retract_length = config.option<ConfigOptionFloatsNullable>("filament_retract_length", true);
|
||||
opt_filament_retract_length->values = { 5., ConfigOptionFloatsNullable::nil_value(), 3. };
|
||||
|
||||
parser.apply_config(config);
|
||||
parser.set("foo", 0);
|
||||
@ -33,6 +35,9 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||
SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[temperature_[foo]]") == "357"); }
|
||||
SECTION("array reference") { REQUIRE(parser.process("{temperature[foo]}") == "357"); }
|
||||
SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ temperature_ [foo] ] \n hu") == "test 357 \n hu"); }
|
||||
SECTION("nullable is not null") { REQUIRE(parser.process("{is_nil(filament_retract_length[0])}") == "false"); }
|
||||
SECTION("nullable is null") { REQUIRE(parser.process("{is_nil(filament_retract_length[1])}") == "true"); }
|
||||
SECTION("nullable is not null 2") { REQUIRE(parser.process("{is_nil(filament_retract_length[2])}") == "false"); }
|
||||
|
||||
// Test the math expressions.
|
||||
SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user