Merge remote-tracking branch 'origin/master' into pm_anchor_bridges_on_sparse_infill

This commit is contained in:
PavelMikus 2023-03-01 16:45:26 +01:00
commit 5b0c270b30
24 changed files with 703 additions and 237 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -881,6 +881,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>
@ -979,6 +1011,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."}
};
@ -1265,6 +1298,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) ]
@ -1292,6 +1326,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");
@ -1301,6 +1344,7 @@ namespace client
("zdigits")
("if")
("int")
("is_nil")
//("inf")
("else")
("elsif")
@ -1335,6 +1379,7 @@ namespace client
debug(optional_parameter);
debug(scalar_variable_reference);
debug(variable_reference);
debug(is_nil_test);
debug(regular_expression);
}
}
@ -1380,6 +1425,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;

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -130,8 +130,10 @@ TreeSupportSettings::TreeSupportSettings(const TreeSupportMeshGroupSettings& mes
this->raft_layers.emplace_back(z);
}
// Raft contact layer
z = slicing_params.raft_contact_top_z;
this->raft_layers.emplace_back(z);
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,47 +1443,50 @@ static void generate_initial_areas(
}
});
// 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 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));
grid.create(raft_polygons, Polylines{}, coord_t(scale_(10.)));
SupportElements &first_layer_move_bounds = move_bounds[first_tree_layer];
double threshold = scaled<double>(print_object.config().raft_expansion.value) * 2.;
first_layer_move_bounds.erase(std::remove_if(first_layer_move_bounds.begin(), first_layer_move_bounds.end(),
[&grid, threshold](const SupportElement &el) {
coordf_t dist;
if (grid.signed_distance_edges(el.state.result_on_layer, threshold, dist)) {
assert(std::abs(dist) < threshold + SCALED_EPSILON);
// Support point is inside the expanded raft, remove it.
return dist < - 0.;
}
return false;
}), first_layer_move_bounds.end());
#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;
// All tips supporting this layer are expected to have the same radius.
double radius = config.getRadius(first_layer_move_bounds.front().state);
// Connect the tips with the following closing radius.
double closing_distance = radius;
Polygon circle = make_circle(radius + closing_distance, eps);
Polygons circles;
circles.reserve(first_layer_move_bounds.size());
for (const SupportElement &el : first_layer_move_bounds) {
circles.emplace_back(circle);
circles.back().translate(el.state.result_on_layer);
}
raft_polygons = diff(raft_polygons, offset(union_(circles), - closing_distance));
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 >= 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));
grid.create(raft_polygons, Polylines{}, coord_t(scale_(10.)));
SupportElements &first_layer_move_bounds = move_bounds[first_tree_layer];
double threshold = scaled<double>(print_object.config().raft_expansion.value) * 2.;
first_layer_move_bounds.erase(std::remove_if(first_layer_move_bounds.begin(), first_layer_move_bounds.end(),
[&grid, threshold](const SupportElement &el) {
coordf_t dist;
if (grid.signed_distance_edges(el.state.result_on_layer, threshold, dist)) {
assert(std::abs(dist) < threshold + SCALED_EPSILON);
// Support point is inside the expanded raft, remove it.
return dist < - 0.;
}
return false;
}), first_layer_move_bounds.end());
#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;
// All tips supporting this layer are expected to have the same radius.
double radius = config.getRadius(first_layer_move_bounds.front().state);
// Connect the tips with the following closing radius.
double closing_distance = radius;
Polygon circle = make_circle(radius + closing_distance, eps);
Polygons circles;
circles.reserve(first_layer_move_bounds.size());
for (const SupportElement &el : first_layer_move_bounds) {
circles.emplace_back(circle);
circles.back().translate(el.state.result_on_layer);
}
raft_polygons = diff(raft_polygons, offset(union_(circles), - closing_distance));
}
#endif
}
#endif
}
}
@ -4207,79 +4219,90 @@ 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;
auto t_precalc = std::chrono::high_resolution_clock::now();
// value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in draw_areas
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;
SupportGeneratorLayersPtr top_contacts;
SupportGeneratorLayersPtr bottom_contacts;
SupportGeneratorLayersPtr top_interface_layers;
SupportGeneratorLayersPtr intermediate_layers;
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();
if (size_t num_support_layers = precalculate(print, overhangs, processing.first, processing.second, volumes, throw_on_cancel);
num_support_layers > 0) {
#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])
append(polys, area.influence_area);
if (auto begin = move_bounds[layer_idx].begin(); begin != move_bounds[layer_idx].end())
SVG::export_expolygons(debug_out_path("treesupport-initial_areas-%d.svg", layer_idx),
{ { { union_ex(volumes.getWallRestriction(config.getCollisionRadius(begin->state), layer_idx, begin->state.use_min_xy_dist)) },
{ "wall_restricrictions", "gray", 0.5f } },
{ { union_ex(polys) }, { "parent", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
auto t_precalc = std::chrono::high_resolution_clock::now();
// value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in draw_areas
std::vector<SupportElements> move_bounds(num_support_layers);
// ### Place tips of the support tree
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
for (size_t layer_idx = 0; layer_idx < move_bounds.size(); ++layer_idx) {
Polygons polys;
for (auto& area : move_bounds[layer_idx])
append(polys, area.influence_area);
if (auto begin = move_bounds[layer_idx].begin(); begin != move_bounds[layer_idx].end())
SVG::export_expolygons(debug_out_path("treesupport-initial_areas-%d.svg", layer_idx),
{ { { union_ex(volumes.getWallRestriction(config.getCollisionRadius(begin->state), layer_idx, begin->state.use_min_xy_dist)) },
{ "wall_restricrictions", "gray", 0.5f } },
{ { union_ex(polys) }, { "parent", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
}
#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);
auto t_path = std::chrono::high_resolution_clock::now();
// ### Set a point in each influence area
create_nodes_from_area(volumes, config, move_bounds, throw_on_cancel);
auto t_place = std::chrono::high_resolution_clock::now();
// ### draw these points as circles
if (print_object.config().support_material_style == smsTree)
draw_areas(*print.get_object(processing.second.front()), volumes, config, overhangs, move_bounds,
bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel);
else {
assert(print_object.config().support_material_style == smsOrganic);
indexed_triangle_set branches = draw_branches(*print.get_object(processing.second.front()), volumes, config, move_bounds, throw_on_cancel);
// Reduce memory footprint. After this point only slice_branches() will use volumes and from that only collisions with zero radius will be used.
volumes.clear_all_but_object_collision();
slice_branches(*print.get_object(processing.second.front()), volumes, config, overhangs, move_bounds, branches,
bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel);
}
auto t_draw = std::chrono::high_resolution_clock::now();
auto dur_pre_gen = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_precalc - t_start).count();
auto dur_gen = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_gen - t_precalc).count();
auto dur_path = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_path - t_gen).count();
auto dur_place = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_place - t_path).count();
auto dur_draw = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_draw - t_place).count();
auto dur_total = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_draw - t_start).count();
BOOST_LOG_TRIVIAL(info) <<
"Total time used creating Tree support for the currently grouped meshes: " << dur_total << " ms. "
"Different subtasks:\nCalculating Avoidance: " << dur_pre_gen << " ms "
"Creating inital influence areas: " << dur_gen << " ms "
"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.)";
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;
}
#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);
auto t_path = std::chrono::high_resolution_clock::now();
// ### Set a point in each influence area
create_nodes_from_area(volumes, config, move_bounds, throw_on_cancel);
auto t_place = std::chrono::high_resolution_clock::now();
// ### draw these points as circles
if (print_object.config().support_material_style == smsTree)
draw_areas(*print.get_object(processing.second.front()), volumes, config, overhangs, move_bounds,
bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel);
else {
assert(print_object.config().support_material_style == smsOrganic);
indexed_triangle_set branches = draw_branches(*print.get_object(processing.second.front()), volumes, config, move_bounds, throw_on_cancel);
// Reduce memory footprint. After this point only slice_branches() will use volumes and from that only collisions with zero radius will be used.
volumes.clear_all_but_object_collision();
slice_branches(*print.get_object(processing.second.front()), volumes, config, overhangs, move_bounds, branches,
bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel);
}
auto t_draw = std::chrono::high_resolution_clock::now();
auto dur_pre_gen = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_precalc - t_start).count();
auto dur_gen = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_gen - t_precalc).count();
auto dur_path = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_path - t_gen).count();
auto dur_place = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_place - t_path).count();
auto dur_draw = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_draw - t_place).count();
auto dur_total = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_draw - t_start).count();
BOOST_LOG_TRIVIAL(info) <<
"Total time used creating Tree support for the currently grouped meshes: " << dur_total << " ms. "
"Different subtasks:\nCalculating Avoidance: " << dur_pre_gen << " ms "
"Creating inital influence areas: " << dur_gen << " ms "
"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.)";
move_bounds.clear();
auto remove_undefined_layers = [](SupportGeneratorLayersPtr &layers) {
layers.erase(std::remove_if(layers.begin(), layers.end(), [](const SupportGeneratorLayer* ptr) { return ptr == nullptr; }), layers.end());
@ -4347,7 +4370,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

View File

@ -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) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
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,8 +5016,10 @@ 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)
reload_scene(true);
if (requires_reload_scene) {
if (wxGetApp().plater()->is_view3D_shown())
reload_scene(true);
}
}
}

View File

@ -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.
#ifdef __linux__ || __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();

View File

@ -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);

View File

@ -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;

View File

@ -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 *

View File

@ -885,7 +885,7 @@ void GLGizmoEmboss::on_set_state()
priv::get_volume(m_parent.get_selection().get_model()->objects, m_volume_id) == 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

View File

@ -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;

View File

@ -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,

View File

@ -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")
);
};

View File

@ -2683,7 +2683,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
instance->set_offset(-model_object->origin_translation);
}
}
model_object->ensure_on_bed(is_project_file);
if (!model_object->instances.empty())
model_object->ensure_on_bed(is_project_file);
}
if (one_by_one) {
@ -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();

View File

@ -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();

View File

@ -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();
}
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);
}
else
transform_instance_relative_world(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
}
else {
if (!is_single_volume_or_modifier()) {
@ -1024,40 +1032,29 @@ 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);
}
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
}
}
}
@ -1066,7 +1063,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
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();
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());
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,

View File

@ -499,6 +499,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();
@ -512,7 +516,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);

View File

@ -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);
@ -34,6 +36,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"); }