diff --git a/bundled_deps/admesh/admesh/normals.cpp b/bundled_deps/admesh/admesh/normals.cpp index 9b656d4..60de43a 100644 --- a/bundled_deps/admesh/admesh/normals.cpp +++ b/bundled_deps/admesh/admesh/normals.cpp @@ -114,7 +114,7 @@ static bool check_normal_vector(stl_file *stl, int facet_num, int normal_fix_fla void stl_fix_normal_directions(stl_file *stl) { - // This may happen for malformed models, see: https://github.com/qidi3d/QIDISlicer/issues/2209 + // This may happen for malformed models, see: https://github.com/QIDITECH/QIDISlicer/issues/2209 if (stl->stats.number_of_facets == 0) return; diff --git a/resources/data/hints.ini b/resources/data/hints.ini index 2b4265c..eb3f145 100644 --- a/resources/data/hints.ini +++ b/resources/data/hints.ini @@ -12,7 +12,7 @@ # Hypertext must be max one per notification and must be closed by # # Notification can have documentation link: -# documentation_link = https://help.qidi3d.com/en/article/name-of-article +# documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/name-of-article # # If notification contains hypertext, it needs to be specified by hypertext_type var. # each type needs to be supported with one or more additional vars. @@ -83,16 +83,16 @@ hypertext_plater_item = arrange [hint:Negative volume] text = Negative volume\nDid you know that you can subtract one mesh from another using the Negative volume modifier? That way you can, for example, create easily resizable holes directly in QIDISlicer. Read more in the documentation. (Requires Advanced or Expert mode.) -documentation_link = https://help.qidi3d.com/en/article/negative-volume_238503 +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/negative-volume_238503 disabled_tags = SLA; simple [hint:Simplify mesh] text = Simplify mesh\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in the documentation. -documentation_link = https://help.qidi3d.com/en/article/simplify-mesh_238941 +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/simplify-mesh_238941 [hint:Reload from disk] text = Reload from disk\nDid you know that if you created a newer version of your model, you can simply reload it in QIDISlicer? Right-click the model in the 3D view and choose Reload from disk. Read more in the documentation. -documentation_link = https://help.qidi3d.com/en/article/reload-from-disk_120427 +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/reload-from-disk_120427 [hint:Hiding sidebar] text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut Shift+Tab? You can also enable the icon for this from thePreferences. @@ -135,7 +135,7 @@ hypertext_plater_item = undo [hint:Different layer height for each model] text = Different layer height for each model\nDid you know that you can print each model on the plater with a different layer height? Right-click the model in the 3D view, choose Layers and Perimeters and adjust the values in the right panel. Read more in the documentation. -documentation_link= https://help.qidi3d.com/en/article/per-model-settings_1674 +documentation_link= https://wiki.qidi3d.com/en/software/QIDISlicier/article/per-model-settings_1674 disabled_tags = SLA [hint:Solid infill threshold area] @@ -171,7 +171,7 @@ text = Load config from G-code\nDid you know that you can use File-Import-Import [hint:Ironing] text = Ironing\nDid you know that you can smooth top surfaces of prints using Ironing? The nozzle will run a special second infill phase at the same layer to fill in holes and flatten any lifted plastic. Read more in the documentation. (Requires Advanced or Expert mode.) -documentation_link = https://help.qidi3d.com/en/article/ironing_177488 +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/ironing_177488 disabled_tags = SLA; simple [hint:Paint-on supports] @@ -188,17 +188,17 @@ disabled_tags = SLA; simple [hint:Insert Pause] text = Insert Pause\nDid you know that you can schedule the print to pause at a specific layer? Right-click the layer slider in the Preview and select Add pause print (M601). This can be used to insert magnets, weights or nuts into your prints. Read more in the documentation. -documentation_link = https://help.qidi3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-pause-at-layer +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/insert-pause-or-custom-g-code-at-layer_120490#insert-pause-at-layer disabled_tags = SLA [hint:Insert Custom G-code] text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Left-click the layer in the Preview, Right-click the plus icon and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in the documentation. -documentation_link = https://help.qidi3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer disabled_tags = SLA [hint:Configuration snapshots] text = Configuration snapshots\nDid you know that you can roll back to a complete backup of all system and user profiles? You can view and move back and forth between snapshots using the Configuration - Configuration snapshots menu. -documentation_link = https://help.qidi3d.com/en/article/configuration-snapshots_1776 +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/configuration-snapshots_1776 hypertext_type = menubar hypertext_menubar_menu_name = &Configuration hypertext_menubar_item_name = &Configuration Snapshots @@ -219,40 +219,41 @@ hypertext_preferences_item = dlg_settings_layout_mode [hint:Adaptive infills] text = Adaptive infills\nDid you know that you can use the Adaptive cubic and Support cubic infills to decrease the print time and lower the filament consumption? Read more in the documentation. -documentation_link = https://help.qidi3d.com/en/article/infill-patterns_177130 +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/infill-patterns_177130 disabled_tags = SLA [hint:Lightning infill] text = Lightning infill\nDid you know that you can use the Lightning infill to support only the top surfaces, save a lot of the filament, and decrease the print time? Read more in the documentation. -documentation_link = https://help.qidi3d.com/en/article/infill-patterns_177130 +documentation_link = https://wiki.qidi3d.com/en/software/QIDISlicier/article/infill-patterns_177130 disabled_tags = SLA [hint:Fullscreen mode] text = Fullscreen mode\nDid you know that you can switch QIDISlicer to fullscreen mode? Use the F11 hotkey. enabled_tags = Windows -[hint:Printables integration] -text = Printables.com integration\nDid you know that when you are browsing Printables.com, you can send 3D model files to QIDISlicer with a single click? Learn more in the documentation. -documentation_link = https://wiki.qidi3d.com/en/home -weight = 3 +#Y +#[hint:Printables integration] +#text = Printables.com integration\nDid you know that when you are browsing Printables.com, you can send 3D model files to QIDISlicer with a single click? Learn more in the documentation. +#documentation_link = https://wiki.qidi3d.com/en/home +#weight = 3 [hint:Cut tool] text = Cut tool\nDid you know that you can cut a model at any angle and even create aligning pins with the updated Cut tool? Learn more in the documentation. -documentation_link = https://help.qidi3d.com/article/cut-tool_1779 +documentation_link = https://wiki.qidi3d.com/article/cut-tool_1779 hypertext_type = gizmo hypertext_gizmo_item = cut weight = 3 [hint:Measurement tool] text = Measurement tool\nDid you know that you can measure the distances between points, edges and planes, the radius of a hole or the angle between edges or planes? Learn more in the documentation. -documentation_link = https://help.qidi3d.com/article/measurement-tool_399451 +documentation_link = https://wiki.qidi3d.com/article/measurement-tool_399451 hypertext_type = gizmo hypertext_gizmo_item = measure weight = 3 [hint:Text tool] text = Text tool\nDid you know that you can add custom text labels to your models or even use the text as a modifier? Learn more in the documentation. -documentation_link = https://help.qidi3d.com/article/text-tool_399460 +documentation_link = https://wiki.qidi3d.com/article/text-tool_399460 weight = 3 #[hint:] diff --git a/resources/icons/lock_closed_blue.svg b/resources/icons/lock_closed_blue.svg deleted file mode 100644 index a720112..0000000 --- a/resources/icons/lock_closed_blue.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/resources/web/guide/filament_table.html b/resources/web/guide/filament_table.html index b629525..897d604 100644 --- a/resources/web/guide/filament_table.html +++ b/resources/web/guide/filament_table.html @@ -10,13 +10,13 @@ font-family: Arial, sans-serif; margin: 20px; width:100%; - max-width: 1400px; + max-width: 1600px; height:100%; overflow: hidden; } .table-container { width: 100%; - max-width: 1300px; + max-width: 1600px; min-width: 900px; height: auto; max-height: 85vh; @@ -94,6 +94,17 @@ z-index: 3; border-left: none; } + td:nth-child(2)::after, + th:nth-child(2)::after { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 0.1px; + background-color: #ccc; + z-index: 5; + } td:nth-child(2)::before { content: ''; position: absolute; @@ -242,12 +253,14 @@ - - - - - - + + + + + + + + @@ -271,12 +284,14 @@ ASA-Aero PA12-CF PAHT-CF - PC-ABS-FR - PET-CF - PETG Tough - PPS-CF - TPU 95A-HF - UltraPA + PAHT-GF + PC-ABS-FR + PET-CF + PET-GF + PETG Tough + PPS-CF + TPU 95A-HF + UltraPA @@ -769,8 +784,10 @@ document.write(''+ createProgressBar(50,"#0784FF")+ '');//asa aero document.write(''+ createProgressBar(25,"#0784FF")+ '');//pa12 cf document.write(''+ createProgressBar(50,"#0784FF")+ '');//paht cf + document.write(''+ createProgressBar(50,"#0784FF")+ '');//paht gf document.write(''+ createProgressBar(75,"#0784FF")+ '');//pc abs fr document.write(''+ createProgressBar(75,"#0784FF")+ '');//pet cf + document.write(''+ createProgressBar(75,"#0784FF")+ '');//pet gf document.write(''+ createProgressBar(75,"#0784FF")+ '');//petg document.write('/');//pps-cf document.write('/');//tpu @@ -794,8 +811,10 @@ document.write(''+ createProgressBar(25,"#5cb85c")+ '');//asa aero document.write(''+ createProgressBar(50,"#5cb85c")+ '');//pa12 cf document.write(''+ createProgressBar(75,"#5cb85c")+ '');//paht cf + document.write(''+ createProgressBar(75,"#5cb85c")+ '');//paht gf document.write(''+ createProgressBar(25,"#5cb85c")+ '');//pc abs fr document.write(''+ createProgressBar(75,"#5cb85c")+ '');//pet cf + document.write(''+ createProgressBar(75,"#5cb85c")+ '');//pet gf document.write(''+ createProgressBar(50,"#5cb85c")+ '');//petg document.write('/');//pps-cf document.write('/');//tpu @@ -819,8 +838,10 @@ document.write(''+ createProgressBar(50,"#CC6B36")+ '');//asa aero document.write(''+ createProgressBar(25,"#CC6B36")+ '');//pa12 cf document.write(''+ createProgressBar(75,"#CC6B36")+ '');//paht cf + document.write(''+ createProgressBar(75,"#CC6B36")+ '');//paht gf document.write(''+ createProgressBar(75,"#CC6B36")+ '');//pc abs fr document.write(''+ createProgressBar(75,"#CC6B36")+ '');//pet cf + document.write(''+ createProgressBar(75,"#CC6B36")+ '');//pet gf document.write(''+ createProgressBar(75,"#CC6B36")+ '');//petg document.write('/');//pps-cf document.write('/');//tpu @@ -844,8 +865,10 @@ document.write('70℃');//asa aero document.write('149.6℃');//pa12 cf document.write('192.3℃');//paht cf + document.write('83.4℃');//paht gf document.write('88℃');//pc abs fr document.write('148.8℃');//pet cf + document.write('120.3℃');//pet gf document.write('78℃');//petg document.write('242.7℃');//pps-cf document.write('/');//tpu @@ -869,8 +892,10 @@ document.write('55℃');//asa aero document.write('112.4℃');//pa12 cf document.write('121.7℃');//paht cf + document.write('79.5℃');//paht gf document.write('83℃');//pc abs fr document.write('112.1℃');//pet cf + document.write('99.1℃');//pet gf document.write('73℃');//petg document.write('/');//pps-cf document.write('/');//tpu @@ -894,8 +919,10 @@ document.write('8.25 ± 0.15 MPa
'+ createProgressBar(8.25/150*100,"#CCB70B")+ '');//asa aero document.write('87.49 ± 2.81 MPa
'+ createProgressBar(87.49/150*100,"#CCB70B")+ '');//pa12 cf document.write('104.90 ± 1.99 MPa
'+ createProgressBar(104.9/150*100,"#CCB70B")+ '');//paht cf + document.write('86.49 ± 1.03 MPa
'+ createProgressBar(86.49/150*100,"#CCB70B")+ '');//paht gf document.write('52.51 ± 0.28 MPa
'+ createProgressBar(52.51/150*100,"#CCB70B")+ '');//pc abs fr document.write('87.41 ± 3.57 MPa
'+ createProgressBar(87.41/150*100,"#CCB70B")+ '');//pet cf + document.write('70.86 ± 2.86 MPa
'+ createProgressBar(70.86/150*100,"#CCB70B")+ '');//pet gf document.write('40.3 ± 0.6 MPa
'+ createProgressBar(40.3/150*100,"#CCB70B")+ '');//petg document.write('60 MPa
'+ createProgressBar(60/150*100,"#CCB70B")+ '');//pps-cf document.write('31.81 MPa
'+ createProgressBar(31.81/150*100,"#CCB70B")+ '');//tpu @@ -919,8 +946,10 @@ document.write('593.99 ± 24.34 MPa
'+ createProgressBar(593.99/10000*100,"#CC0003")+ '');//asa aero document.write('5438.40 ± 282.82 MPa
'+ createProgressBar(5438.4/10000*100,"#CC0003")+ '');//pa12 cf document.write('8383.26 ± 419.53 MPa
'+ createProgressBar(8383.26/10000*100,"#CC0003")+ '');//paht cf + document.write('5118.97 ± 296.57 MPa
'+ createProgressBar(5118.97/10000*100,"#CC0003")+ '');//paht gf document.write('2588.73 ± 64.81 MPa
'+ createProgressBar(2588.73/10000*100,"#CC0003")+ '');//pc abs fr document.write('6025.53 ± 355.46 MPa
'+ createProgressBar(6025.53/10000*100,"#CC0003")+ '');//pet cf + document.write('4130.13 ± 107.00 MPa
'+ createProgressBar(4130.13/10000*100,"#CC0003")+ '');//pet gf document.write('1780 ± 80 MPa
'+ createProgressBar(1780/10000*100,"#CC0003")+ '');//petg document.write('4800 MPa
'+ createProgressBar(4800/10000*100,"#CC0003")+ '');//pps-cf document.write('/');//tpu @@ -944,9 +973,11 @@ document.write('11.52 ± 0.58%');//asa aero document.write('2.59 ± 0.19%');//pa12 cf document.write('1.60 ± 0.07%');//paht cf + document.write('2.71 ± 0.28%');//paht gf document.write('5.55 ± 0.99%');//pc abs fr document.write('1.99 ± 0.18%');//pet cf - document.write('4.0 ± 0.2%');//petg + document.write('2.56 ± 0.30%');//pet gf + document.write('4.0 ± 0.20%');//petg document.write('6%');//pps-cf document.write('471%');//tpu document.write('11.68 ± 3.36%');//ultra pa @@ -969,8 +1000,10 @@ document.write('14.31 ± 1.66 MPa
'+ createProgressBar(14.31/200*100,"#16417C")+ '');//asa aero document.write('133.17 ± 4.66 MPa
'+ createProgressBar(133.17/200*100,"#16417C")+ '');//pa12 cf document.write('147.70 ± 4.09 MPa
'+ createProgressBar(144.7/200*100,"#16417C")+ '');//paht cf + document.write('137.78 ± 2.35 MPa
'+ createProgressBar(137.78/200*100,"#16417C")+ '');//paht gf document.write('85.95 ± 0.83 MPa
'+ createProgressBar(85.95/200*100,"#16417C")+ '');//pc abs fr document.write('122.69 ± 5.19 MPa
'+ createProgressBar(122.69/200*100,"#16417C")+ '');//pet cf + document.write('114.87 ± 3.00 MPa
'+ createProgressBar(114.87/200*100,"#16417C")+ '');//pet gf document.write('62.8 ± 0.4 MPa
'+ createProgressBar(62.8/200*100,"#16417C")+ '');//petg document.write('105 MPa
'+ createProgressBar(105/200*100,"#16417C")+ '');//pps-cf document.write('/');//tpu @@ -994,8 +1027,10 @@ document.write('457.94 ± 20.84 MPa
'+ createProgressBar(457.94/8000*100,"#EA3FF7")+ '');//asa aero document.write('4667.43 ± 339.80 MPa
'+ createProgressBar(4667.43/8000*100,"#EA3FF7")+ '');//pa12 cf document.write('5969.35 ± 145.28 MPa
'+ createProgressBar(5969.33/8000*100,"#EA3FF7")+ '');//paht cf + document.write('4135.14 ± 64.91 MPa
'+ createProgressBar(4135.14/8000*100,"#EA3FF7")+ '');//paht gf document.write('2504.55 ± 22.88 MPa
'+ createProgressBar(2504.55/8000*100,"#EA3FF7")+ '');//pc abs fr document.write('5313.21 ± 197.89 MPa
'+ createProgressBar(5313.21/8000*100,"#EA3FF7")+ '');//pet cf + document.write('3650.32 ± 65.81 MPa
'+ createProgressBar(3650.32/8000*100,"#EA3FF7")+ '');//pet gf document.write('1919 ± 54 MPa
'+ createProgressBar(1919/8000*100,"#EA3FF7")+ '');//petg document.write('5500 MPa
'+ createProgressBar(5500/8000*100,"#EA3FF7")+ '');//pps-cf document.write('/');//tpu @@ -1019,8 +1054,10 @@ document.write('2.29 ± 0.13KJ/㎡
'+ createProgressBar(2.29/30*100,"#F77089")+ '');//asa aero document.write('6.11 ± 1.45KJ/㎡
'+ createProgressBar(6.11/30*100,"#F77089")+ '');//pa12 cf document.write('6.17 ± 0.2KJ/㎡
'+ createProgressBar(6.17/30*100,"#F77089")+ '');//paht cf + document.write('7.97 ± 1.75KJ/㎡
'+ createProgressBar(7.97/30*100,"#F77089")+ '');//paht gf document.write('8.39 ± 0.46KJ/㎡
'+ createProgressBar(8.39/30*100,"#F77089")+ '');//pc abs fr document.write('5.57 ± 0.58KJ/㎡
'+ createProgressBar(5.57/30*100,"#F77089")+ '');//pet cf + document.write('6.56 ± 0.68KJ/㎡
'+ createProgressBar(6.56/30*100,"#F77089")+ '');//pet gf document.write('13.9 ± 2.3KJ/㎡
'+ createProgressBar(13.9/30*100,"#F77089")+ '');//petg document.write('11KJ/㎡
'+ createProgressBar(11/30*100,"#F77089")+ '');//pps-cf document.write('/');//tpu @@ -1044,8 +1081,10 @@ document.write('' + getTranslation('Recommended drying', lang) + '');//asa aero document.write('' + getTranslation('Need to dry', lang) + '');//pa12 cf document.write('' + getTranslation('Need to dry', lang) + '');//paht cf + document.write('' + getTranslation('Need to dry', lang) + '');//paht gf document.write('' + getTranslation('Recommended drying', lang) + '');//pc abs fr document.write('' + getTranslation('Need to dry', lang) + '');//pet cf + document.write('' + getTranslation('Need to dry', lang) + '');//pet gf document.write('' + getTranslation('Recommended drying', lang) + '');//petg document.write('' + getTranslation('Need to dry', lang) + '');//pps-cf document.write('' + getTranslation('Need to dry', lang) + '');//tpu @@ -1069,8 +1108,10 @@ document.write('/');//asa aero document.write('110-120℃ 4-6h');//pa12 cf document.write('/');//paht cf + document.write('80-100℃ 4-6h');//paht gf document.write('/');//pc abs fr document.write('100℃ 4-6h');//pet cf + document.write('100-120℃ 4-6h');//pet gf document.write('60-70℃ 4-6h');//petg document.write('/');//pps-cf document.write('70-80℃ 4-6h');//tpu @@ -1094,8 +1135,10 @@ document.write('80-90℃');//asa aero document.write('40-80℃');//pa12 cf document.write('70-80℃');//paht cf + document.write('70-90℃');//paht gf document.write('100-110℃');//pc abs fr document.write('70-80℃');//pet cf + document.write('60-80℃');//pet gf document.write('70-80℃');//petg document.write('80-110℃');//pps-cf document.write('20-60℃');//tpu @@ -1119,8 +1162,10 @@ document.write('√');//asa aero document.write('×');//pa12 cf document.write('×');//paht cf + document.write('×');//paht gf document.write('√');//pc abs fr document.write('×');//pet cf + document.write('×');//pet gf document.write('×');//petg document.write('√');//pps-cf document.write('×');//tpu @@ -1144,8 +1189,10 @@ document.write('240-280℃');//asa aero document.write('280-300℃');//pa12 cf document.write('300-320℃');//paht cf + document.write('300-320℃');//paht gf document.write('240-270℃');//pc abs fr document.write('280-320℃');//pet cf + document.write('280-320℃');//pet gf document.write('240-280℃');//petg document.write('300-370℃');//pps-cf document.write('210-230℃');//tpu @@ -1169,8 +1216,10 @@ document.write('<90mm/s');//asa aero document.write('<60mm/s');//pa12 cf document.write('<160mm/s');//paht cf + document.write('<200mm/s');//paht gf document.write('<300mm/s');//pc abs fr document.write('<200mm/s');//pet cf + document.write('<200mm/s');//pet gf document.write('<300mm/s');//petg document.write('<200mm/s');//pps-cf document.write('<120mm/s');//tpu @@ -1194,8 +1243,10 @@ document.write('/');//asa aero document.write('80-100℃');//pa12 cf document.write('80-100℃');//paht cf + document.write('80-100℃');//paht gf document.write('/');//pc abs fr document.write('80-100℃');//pet cf + document.write('80-100℃');//pet gf document.write('/');//petg document.write('/');//pps-cf document.write('/');//tpu diff --git a/resources/web/guide/index.html b/resources/web/guide/index.html index f28afb6..712fbb8 100644 --- a/resources/web/guide/index.html +++ b/resources/web/guide/index.html @@ -369,10 +369,20 @@
https://qidi3d.com/collections/filaments
diff --git a/src/libslic3r/Algorithm/RegionExpansion.cpp b/src/libslic3r/Algorithm/RegionExpansion.cpp index 7dba823..03c15e9 100644 --- a/src/libslic3r/Algorithm/RegionExpansion.cpp +++ b/src/libslic3r/Algorithm/RegionExpansion.cpp @@ -281,7 +281,7 @@ std::vector wave_seeds( if (front == back && (front.z() < idx_boundary_end)) { // This should be a very rare exception. - // See https://github.com/qidi3d/QIDISlicer/issues/12469. + // See https://github.com/QIDITECH/QIDISlicer/issues/12469. // Segement is open, yet its first point seems to be part of boundary polygon. // Take the first point with src polygon index. for (const ClipperLib_Z::IntPoint &point : path) { diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index f2d9e9f..61377a7 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -90,8 +90,6 @@ void AppConfig::set_defaults() if (get("associate_stl").empty()) set("associate_stl", "0"); - if (get("tabs_as_menu").empty()) - set("tabs_as_menu", "0"); if (get("suppress_round_corners").empty()) set("suppress_round_corners", "1"); #endif // _WIN32 @@ -100,11 +98,6 @@ void AppConfig::set_defaults() if (!get("use_legacy_opengl").empty()) erase("", "use_legacy_opengl"); -#ifdef __APPLE__ - if (get("use_retina_opengl").empty()) - set("use_retina_opengl", "1"); -#endif - if (get("single_instance").empty()) set("single_instance", #ifdef __APPLE__ @@ -128,9 +121,10 @@ void AppConfig::set_defaults() if (get("auto_toolbar_size").empty()) set("auto_toolbar_size", "100"); - + if (get("use_binary_gcode_when_supported").empty()) - set("use_binary_gcode_when_supported", "0"); + set("use_binary_gcode_when_supported", "1"); + if (get("notify_release").empty()) set("notify_release", "all"); // or "none" or "release" @@ -151,6 +145,7 @@ void AppConfig::set_defaults() if (get("default_action_on_new_project").empty()) set("default_action_on_new_project", "none"); // , "keep(transfer)", "discard" or "save" + //y15 if (get("color_mapinulation_panel").empty()) set("color_mapinulation_panel", "1"); @@ -172,6 +167,11 @@ void AppConfig::set_defaults() #endif // _WIN32 } +#ifdef __APPLE__ + if (get("use_retina_opengl").empty()) + set("use_retina_opengl", "1"); +#endif // __APPLE__ + if (get("seq_top_layer_only").empty()) set("seq_top_layer_only", "1"); @@ -201,6 +201,22 @@ void AppConfig::set_defaults() if (get("wifi_config_dialog_declined").empty()) set("wifi_config_dialog_declined", "0"); + + if (get("connect_polling").empty()) + set("connect_polling", "1"); + + if (get("auth_login_dialog_confirmed").empty()) + set("auth_login_dialog_confirmed", "0"); + + if (get("show_estimated_times_in_dbl_slider").empty()) + set("show_estimated_times_in_dbl_slider", "1"); + + if (get("show_ruler_in_dbl_slider").empty()) + set("show_ruler_in_dbl_slider", "0"); + + if (get("show_ruler_bg_in_dbl_slider").empty()) + set("show_ruler_bg_in_dbl_slider", "1"); + #ifdef _WIN32 if (get("use_legacy_3DConnexion").empty()) set("use_legacy_3DConnexion", "0"); @@ -210,7 +226,6 @@ void AppConfig::set_defaults() if (get("sys_menu_enabled").empty()) set("sys_menu_enabled", "1"); - #endif // _WIN32 // B45 if (get("machine_list_minification").empty()) @@ -220,6 +235,10 @@ void AppConfig::set_defaults() if (get("user_token").empty()) set("user_token", ""); + //B64 + if (get("user_name").empty()) + set("user_name", ""); + //y5 if(get("user_head_url").empty()) set("user_head_url", ""); @@ -237,6 +256,11 @@ void AppConfig::set_defaults() if (get("machine_list_net").empty()) set("machine_list_net", "0"); + + //y14 + if (get("old_settings_layout_mode").empty()) + set("old_settings_layout_mode", "1"); + // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); @@ -385,12 +409,10 @@ std::string AppConfig::load(const std::string &path) if (! boost::starts_with(kvp.first, MODEL_PREFIX)) { continue; } const auto model_name = kvp.first.substr(MODEL_PREFIX.size()); std::vector variants; - //B9 if (! unescape_strings_cstyle(kvp.second.data(), variants)) { continue; } for (const auto &variant : variants) { vendor[model_name].insert(variant); } - //B19 } } else { // This must be a section name. Read the entries of a section. @@ -556,21 +578,6 @@ bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const auto it_m = it_v->second.find(model); return it_m == it_v->second.end() ? false : it_m->second.find(variant) != it_m->second.end(); } -//B19 -bool AppConfig::get_email(const std::string &vendor, const std::string &model, const std::string &email) const -{ - const auto it_v = m_vendors.find(vendor); - if (it_v == m_vendors.end()) { return false; } - const auto it_m = it_v->second.find(model); - return it_m == it_v->second.end() ? false : it_m->second.find(email) != it_m->second.end(); -} -bool AppConfig::get_skype(const std::string &vendor, const std::string &model, const std::string &skype) const -{ - const auto it_v = m_vendors.find(vendor); - if (it_v == m_vendors.end()) { return false; } - const auto it_m = it_v->second.find(model); - return it_m == it_v->second.end() ? false : it_m->second.find(skype) != it_m->second.end(); -} bool AppConfig::set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable) { @@ -594,52 +601,6 @@ bool AppConfig::set_variant(const std::string &vendor, const std::string &model, m_dirty = true; return true; } -//B19 -bool AppConfig::set_email(const std::string &vendor, const std::string &model, const std::string &email, bool enable) -{ - if (enable) { - if (get_email(vendor, model, email)) - return false; - m_vendors[vendor][model].insert(email); - } else { - auto it_v = m_vendors.find(vendor); - if (it_v == m_vendors.end()) - return false; - auto it_m = it_v->second.find(model); - if (it_m == it_v->second.end()) - return false; - auto it_var = it_m->second.find(email); - if (it_var == it_m->second.end()) - return false; - it_m->second.erase(it_var); - } - // If we got here, there was an update - m_dirty = true; - return true; -} -//B19 -bool AppConfig::set_skype(const std::string &vendor, const std::string &model, const std::string &skype, bool enable) -{ - if (enable) { - if (get_skype(vendor, model, skype)) - return false; - m_vendors[vendor][model].insert(skype); - } else { - auto it_v = m_vendors.find(vendor); - if (it_v == m_vendors.end()) - return false; - auto it_m = it_v->second.find(model); - if (it_m == it_v->second.end()) - return false; - auto it_var = it_m->second.find(skype); - if (it_var == it_m->second.end()) - return false; - it_m->second.erase(it_var); - } - // If we got here, there was an update - m_dirty = true; - return true; -} bool AppConfig::set_vendors(const VendorMap &vendors) { diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp index 178e7a9..f3e2637 100644 --- a/src/libslic3r/AppConfig.hpp +++ b/src/libslic3r/AppConfig.hpp @@ -103,14 +103,10 @@ public: { auto it = m_storage.find(section); assert(it != m_storage.end()); return it->second; } bool set_section(const std::string §ion, std::map data); bool clear_section(const std::string §ion); - //B19 + typedef std::map>> VendorMap; bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const; - bool get_email(const std::string &vendor, const std::string &model, const std::string &email) const; - bool get_skype(const std::string &vendor, const std::string &model, const std::string &skype) const; bool set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable); - bool set_email(const std::string &vendor, const std::string &model, const std::string &email, bool enable); - bool set_skype(const std::string &vendor, const std::string &model, const std::string &skype, bool enable); bool set_vendors(const AppConfig &from) { return this->set_vendors(from.vendors()); } bool set_vendors(const VendorMap &vendors); bool set_vendors(VendorMap &&vendors); diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index d0b7b54..cf95b9e 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -766,92 +766,4 @@ bool WallToolPaths::removeEmptyToolPaths(std::vector &toolpa return toolpaths.empty(); } - -WallToolPaths::ExtrusionLineSet WallToolPaths::getRegionOrder(const std::vector &input, const bool outer_to_inner) -{ - ExtrusionLineSet order_requirements; - - // We build a grid where we map toolpath vertex locations to toolpaths, - // so that we can easily find which two toolpaths are next to each other, - // which is the requirement for there to be an order constraint. - // - // We use a PointGrid rather than a LineGrid to save on computation time. - // In very rare cases two insets might lie next to each other without having neighboring vertices, e.g. - // \ . - // | / . - // | / . - // || . - // | \ . - // | \ . - // / . - // However, because of how Arachne works this will likely never be the case for two consecutive insets. - // On the other hand one could imagine that two consecutive insets of a very large circle - // could be simplify()ed such that the remaining vertices of the two insets don't align. - // In those cases the order requirement is not captured, - // which means that the PathOrderOptimizer *might* result in a violation of the user set path order. - // This problem is expected to be not so severe and happen very sparsely. - - coord_t max_line_w = 0u; - for (const ExtrusionLine *line : input) // compute max_line_w - for (const ExtrusionJunction &junction : *line) - max_line_w = std::max(max_line_w, junction.w); - if (max_line_w == 0u) - return order_requirements; - - struct LineLoc - { - ExtrusionJunction j; - const ExtrusionLine *line; - }; - struct Locator - { - Point operator()(const LineLoc &elem) { return elem.j.p; } - }; - - // How much farther two verts may be apart due to corners. - // This distance must be smaller than 2, because otherwise - // we could create an order requirement between e.g. - // wall 2 of one region and wall 3 of another region, - // while another wall 3 of the first region would lie in between those two walls. - // However, higher values are better against the limitations of using a PointGrid rather than a LineGrid. - constexpr float diagonal_extension = 1.9f; - const auto searching_radius = coord_t(max_line_w * diagonal_extension); - using GridT = SparsePointGrid; - GridT grid(searching_radius); - - for (const ExtrusionLine *line : input) - for (const ExtrusionJunction &junction : *line) grid.insert(LineLoc{junction, line}); - for (const std::pair &pair : grid) { - const LineLoc &lineloc_here = pair.second; - const ExtrusionLine *here = lineloc_here.line; - Point loc_here = pair.second.j.p; - std::vector nearby_verts = grid.getNearby(loc_here, searching_radius); - for (const LineLoc &lineloc_nearby : nearby_verts) { - const ExtrusionLine *nearby = lineloc_nearby.line; - if (nearby == here) - continue; - if (nearby->inset_idx == here->inset_idx) - continue; - if (nearby->inset_idx > here->inset_idx + 1) - continue; // not directly adjacent - if (here->inset_idx > nearby->inset_idx + 1) - continue; // not directly adjacent - if (!shorter_then(loc_here - lineloc_nearby.j.p, (lineloc_here.j.w + lineloc_nearby.j.w) / 2 * diagonal_extension)) - continue; // points are too far away from each other - if (here->is_odd || nearby->is_odd) { - if (here->is_odd && !nearby->is_odd && nearby->inset_idx < here->inset_idx) - order_requirements.emplace(std::make_pair(nearby, here)); - if (nearby->is_odd && !here->is_odd && here->inset_idx < nearby->inset_idx) - order_requirements.emplace(std::make_pair(here, nearby)); - } else if ((nearby->inset_idx < here->inset_idx) == outer_to_inner) { - order_requirements.emplace(std::make_pair(nearby, here)); - } else { - assert((nearby->inset_idx > here->inset_idx) == outer_to_inner); - order_requirements.emplace(std::make_pair(here, nearby)); - } - } - } - return order_requirements; -} - } // namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/WallToolPaths.hpp b/src/libslic3r/Arachne/WallToolPaths.hpp index 3fd6eb9..b56d1e0 100644 --- a/src/libslic3r/Arachne/WallToolPaths.hpp +++ b/src/libslic3r/Arachne/WallToolPaths.hpp @@ -85,8 +85,6 @@ public: using ExtrusionLineSet = ankerl::unordered_dense::set, boost::hash>>; - static ExtrusionLineSet getRegionOrder(const std::vector &input, bool outer_to_inner); - protected: /*! * Stitch the polylines together and form closed polygons. diff --git a/src/libslic3r/BuildVolume.cpp b/src/libslic3r/BuildVolume.cpp index e6947d1..230fd72 100644 --- a/src/libslic3r/BuildVolume.cpp +++ b/src/libslic3r/BuildVolume.cpp @@ -321,7 +321,6 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i } } -// B52 //B66 BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& volume_bbox, bool ignore_bottom) const { assert(m_type == Type::Rectangle); @@ -330,11 +329,9 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& vol build_volume.max.z() = std::numeric_limits::max(); if (ignore_bottom) build_volume.min.z() = -std::numeric_limits::max(); - - return build_volume.max.z() <= -SceneEpsilon ? ObjectState::Below : - build_volume.contains(volume_bbox) ? ObjectState::Inside : - build_volume.intersects(volume_bbox) ? ObjectState::Colliding : - ObjectState::Outside; + return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below : + build_volume.contains(volume_bbox) ? ObjectState::Inside : + build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside; } // B66 diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 21e8d6f..2c66238 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -74,8 +74,7 @@ namespace ClipperUtils { // Useful as an optimization for expensive ClipperLib operations, for example when clipping source polygons one by one // with a set of polygons covering the whole layer below. template - //w38 - inline void clip_clipper_polygon_with_subject_bbox_templ(const PointsType &src, const BoundingBox &bbox, PointsType &out,const bool get_entire_polygons=false) + inline void clip_clipper_polygon_with_subject_bbox_templ(const PointsType &src, const BoundingBox &bbox, PointsType &out) { using PointType = typename PointsType::value_type; @@ -130,8 +129,6 @@ namespace ClipperUtils { void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out) { clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); } - //w38 - void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out, const bool get_entire_polygons) { clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out, get_entire_polygons); } void clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox, ZPoints &out) { clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); } @@ -160,14 +157,6 @@ namespace ClipperUtils { return out; } - //w38 - [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, const bool get_entire_polygons) - { - Polygon out; - clip_clipper_polygon_with_subject_bbox(src.points, bbox, out.points, get_entire_polygons); - return out; - } - [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox) { Polygons out; @@ -191,36 +180,19 @@ namespace ClipperUtils { out.end()); return out; } - - //w38 - [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon & src, - const BoundingBox &bbox, - const bool get_entire_polygons) - { - Polygons out; - out.reserve(src.num_contours()); - out.emplace_back(clip_clipper_polygon_with_subject_bbox(src.contour, bbox, get_entire_polygons)); - for (const Polygon &p : src.holes) - out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox, get_entire_polygons)); - out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }), out.end()); - return out; - } - //w38 - [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons & src, - const BoundingBox &bbox, - const bool get_entire_polygons) + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox) { Polygons out; out.reserve(number_polygons(src)); for (const ExPolygon &p : src) { - Polygons temp = clip_clipper_polygons_with_subject_bbox(p, bbox, get_entire_polygons); + Polygons temp = clip_clipper_polygons_with_subject_bbox(p, bbox); out.insert(out.end(), temp.begin(), temp.end()); } out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) {return polygon.empty(); }), out.end()); return out; } - } +} static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree) { diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index ba728cd..ba1465e 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -341,23 +341,10 @@ namespace ClipperUtils { [[nodiscard]] ZPoints clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox); void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, Polygon &out); [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox); - - //w38 - [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon & src, - const BoundingBox &bbox, - const bool get_entire_polygons); [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox); [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox); - - //w38 - [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons & src, - const BoundingBox &bbox, - const bool get_entire_polygons); - [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon & src, - const BoundingBox &bbox, - const bool get_entire_polygons); - void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out, const bool get_entire_polygons); - } + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox); +} // offset Polygons // Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better. diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 0b34016..4b3cfe7 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -976,7 +976,7 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &filename // Look for the header across the whole file as the G-code may have been extended at the start by a post-processing script or the user. bool has_delimiters = false; { - static constexpr const char slic3r_gcode_header[] = "; generated by Slic3r "; + static constexpr const char slic3r_gcode_header[] = "; generated by Slic3r "; static constexpr const char qidislicer_gcode_header[] = "; generated by QIDISlicer "; std::string header; bool header_found = false; @@ -1049,8 +1049,7 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &filename } } if (! begin_found) - throw Slic3r::RuntimeError( - format("Configuration block opening tag \"; qidislicer_config = begin\" not found when reading %1%", filename)); + throw Slic3r::RuntimeError(format("Configuration block opening tag \"; qidislicer_config = begin\" not found when reading %1%", filename)); } else { @@ -1417,6 +1416,7 @@ t_config_option_keys DynamicConfig::equal(const DynamicConfig &other) const } #include // IWYU pragma: keep + CEREAL_REGISTER_TYPE(Slic3r::ConfigOption) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle) diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp index c9b3547..fea4ebf 100644 --- a/src/libslic3r/ElephantFootCompensation.cpp +++ b/src/libslic3r/ElephantFootCompensation.cpp @@ -1,5 +1,3 @@ -#include "clipper/clipper_z.hpp" - #include #include #include diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp index e33376d..7ff1d5b 100644 --- a/src/libslic3r/ExtrusionEntity.cpp +++ b/src/libslic3r/ExtrusionEntity.cpp @@ -114,22 +114,6 @@ Polyline ExtrusionMultiPath::as_polyline() const } return out; } -//w38 -bool ExtrusionLoop::make_clockwise() -{ - bool was_ccw = this->polygon().is_counter_clockwise(); - if (was_ccw) - this->reverse_loop(); - return was_ccw; -} - -bool ExtrusionLoop::make_counter_clockwise() -{ - bool was_cw = this->polygon().is_clockwise(); - if (was_cw) - this->reverse_loop(); - return was_cw; -} double ExtrusionLoop::area() const { diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index bb4b86d..0ebd228 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -215,7 +215,7 @@ public: void collect_points(Points &dst) const override { append(dst, this->polyline.points); } double total_volume() const override { return m_attributes.mm3_per_mm * unscale(length()); } //w21 - void set_width(float set_val) { m_attributes.width = set_val; } + void set_width(float set_val) { m_attributes.width = set_val; } void set_height(float set_val) { m_attributes.height = set_val; } void set_mm3_per_mm(float set_val) { m_attributes.mm3_per_mm = set_val; } @@ -360,9 +360,6 @@ public: append(dst, p.polyline.points); } double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } - //w38 - bool make_clockwise(); - bool make_counter_clockwise(); #ifndef NDEBUG bool validate() const { diff --git a/src/libslic3r/ExtrusionRole.hpp b/src/libslic3r/ExtrusionRole.hpp index c746082..140468f 100644 --- a/src/libslic3r/ExtrusionRole.hpp +++ b/src/libslic3r/ExtrusionRole.hpp @@ -97,13 +97,9 @@ struct ExtrusionRole : public ExtrusionRoleModifiers // Special flags describing loop enum ExtrusionLoopRole { - //w38 - elrDefault = 0x0, - // Loop for the hole, not for the contour - elrHole = 0x1, - // Loop that is the most closest to infill - elrInternal = 0x2, - elrSkirt = 0x4, + elrDefault, + elrContourInternalPerimeter, + elrSkirt, }; // Be careful when editing this list as many parts of the code depend diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index b805137..68b81a6 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -36,12 +36,12 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/ShortestPath.hpp" -////w11 -////w29 +//w11 +//w29 #include "FillConcentricInternal.hpp" #include "FillConcentric.hpp" #define NARROW_INFILL_AREA_THRESHOLD 3 -#define NARROW_INFILL_AREA_THRESHOLD_MIN 0.5 + namespace Slic3r { namespace FillAdaptive { struct Octree; @@ -150,7 +150,6 @@ static bool is_narrow_infill_area(const ExPolygon &expolygon) { //w29 ExPolygons offsets = offset_ex(expolygon, -scale_(NARROW_INFILL_AREA_THRESHOLD)); - //ExPolygons offsets_min = offset_ex(expolygon, -scale_(NARROW_INFILL_AREA_THRESHOLD_MIN)); if (offsets.empty() ) return true; @@ -565,7 +564,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: fill_concentric->print_config = &this->object()->print()->config(); fill_concentric->print_object_config = &this->object()->config(); } else if (surface_fill.params.pattern == ipLightning) - dynamic_cast(f.get())->generator = lightning_generator; + dynamic_cast(f.get())->generator = lightning_generator; // calculate flow spacing for infill pattern generation @@ -595,21 +594,21 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.anchor_length = surface_fill.params.anchor_length; params.anchor_length_max = surface_fill.params.anchor_length_max; params.resolution = resolution; - //w21 - params.use_arachne = (perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) || surface_fill.params.pattern == ipEnsuring || surface_fill.params.pattern == ipConcentric; + //w21 + params.use_arachne = (perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) || surface_fill.params.pattern == ipEnsuring || surface_fill.params.pattern == ipConcentric; params.layer_height = layerm.layer()->height; params.prefer_clockwise_movements = this->object()->print()->config().prefer_clockwise_movements; - //w21 - params.flow = surface_fill.params.flow; + //w21 + params.flow = surface_fill.params.flow; params.extrusion_role = surface_fill.params.extrusion_role; params.using_internal_flow = !surface_fill.surface.is_solid() && !surface_fill.params.bridge; for (ExPolygon &expoly : surface_fill.expolygons) { - // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. - f->spacing = surface_fill.params.spacing; - // w21 - f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes); - surface_fill.surface.expolygon = std::move(expoly); + // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. + f->spacing = surface_fill.params.spacing; + // w21 + f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes); + surface_fill.surface.expolygon = std::move(expoly); Polylines polylines; ThickPolylines thick_polylines; //w29 @@ -617,18 +616,18 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: if (!polylines.empty() || !thick_polylines.empty()) { // calculate actual flow from spacing (which might have been adjusted by the infill - // pattern generator) - double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm(); - double flow_width = surface_fill.params.flow.width(); - if (using_internal_flow) { - // if we used the internal flow we're not doing a solid infill - // so we can safely ignore the slight variation that might have - // been applied to f->spacing - } else { - Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing)); - flow_mm3_per_mm = new_flow.mm3_per_mm(); - flow_width = new_flow.width(); - } + // pattern generator) + double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm(); + double flow_width = surface_fill.params.flow.width(); + if (using_internal_flow) { + // if we used the internal flow we're not doing a solid infill + // so we can safely ignore the slight variation that might have + // been applied to f->spacing + } else { + Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing)); + flow_mm3_per_mm = new_flow.mm3_per_mm(); + flow_width = new_flow.width(); + } // Save into layer. ExtrusionEntityCollection *eec = new ExtrusionEntityCollection(); auto fill_begin = uint32_t(layerm.fills().size()); @@ -638,10 +637,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: for (const ThickPolyline &thick_polyline : thick_polylines) { Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing)); - ExtrusionMultiPath multi_path = PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, - surface_fill.params.extrusion_role, - new_flow, scaled(0.05), - float(SCALED_EPSILON)); + ExtrusionMultiPath multi_path = PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, surface_fill.params.extrusion_role, new_flow, scaled(0.05), float(SCALED_EPSILON)); // Append paths to collection. if (!multi_path.empty()) { if (multi_path.paths.front().first_point() == multi_path.paths.back().last_point()) @@ -655,6 +651,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: layerm.m_fills.entities.push_back(eec); else delete eec; + thick_polylines.clear(); } else { //w29 @@ -708,7 +705,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: layerm.m_fills.entities.push_back(eec); } insert_fills_into_islands(*this, uint32_t(surface_fill.region_id), fill_begin, uint32_t(layerm.fills().size())); - } + } } } @@ -814,7 +811,7 @@ ExtrusionPaths Layer::thick_polyline_to_extrusion_paths(const ThickPolyline &thi if (length > SCALED_EPSILON) { double w = sum / length; Flow new_flow = flow.with_width(unscale(w) + flow.height() * float(1. - 0.25 * PI)); - + //path.mm3_per_mm = new_flow.mm3_per_mm(); path.set_mm3_per_mm(new_flow.mm3_per_mm()); //path.width = new_flow.width(); @@ -896,8 +893,6 @@ ExtrusionPaths Layer::thick_polyline_to_extrusion_paths(const ThickPolyline &thi return paths; } - - Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator) const { std::vector surface_fills = group_fills(*this); @@ -934,9 +929,9 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc case ipHilbertCurve: case ipArchimedeanChords: case ipOctagramSpiral: - case ipZigZag: break; - // //w14 - // case ipConcentricInternal: break; + case ipZigZag: + //w14 + case ipConcentricInternal: break; } // Create the filler object. @@ -1045,8 +1040,8 @@ void Layer::make_ironing() bool operator==(const IroningParams &rhs) const { return this->extruder == rhs.extruder && this->just_infill == rhs.just_infill && - this->line_spacing == rhs.line_spacing && this->height == rhs.height && this->speed == rhs.speed && - this->angle == rhs.angle + this->line_spacing == rhs.line_spacing && this->height == rhs.height && this->speed == rhs.speed && + this->angle == rhs.angle //w33 && this->pattern == rhs.pattern; } @@ -1112,10 +1107,6 @@ void Layer::make_ironing() // Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent // from raft. //FIXME ironing does not take fill angle into account. Shall it? Does it matter? - //w33 - //fill.layer_id = this->id() - this->object()->get_layer(0)->id(); - //fill.z = this->print_z; - //fill.overlap = 0; fill_params.density = 1.; fill_params.monotonic = true; //w33 @@ -1201,14 +1192,10 @@ void Layer::make_ironing() // Create the filler object. //w33 - //fill.spacing = ironing_params.line_spacing; - //fill.angle = float(ironing_params.angle + 0.25 * M_PI); - //fill.link_max_length = (coord_t)scale_(3. * fill.spacing); - //double extrusion_height = ironing_params.height * fill.spacing / nozzle_dmr; f->spacing = ironing_params.line_spacing; f->angle = float(ironing_params.angle + 0.25 * M_PI); - f->link_max_length = (coord_t) scale_(3. * f->spacing); - double extrusion_height = ironing_params.height * f->spacing / nozzle_dmr; + f->link_max_length = (coord_t)scale_(3. * f->spacing); + double extrusion_height = ironing_params.height * f->spacing / nozzle_dmr; float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height)); double flow_mm3_per_mm = nozzle_dmr * extrusion_height; Surface surface_fill(stTop, ExPolygon()); @@ -1218,7 +1205,6 @@ void Layer::make_ironing() try { assert(!fill_params.use_arachne); //w33 - //polylines = fill.fill_surface(&surface_fill, fill_params); polylines = f->fill_surface(&surface_fill, fill_params); } catch (InfillFailedException &) { } diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/src/libslic3r/Fill/Fill3DHoneycomb.cpp index b927aa5..49db1a0 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -1,11 +1,11 @@ -#include "../ClipperUtils.hpp" -#include "../ShortestPath.hpp" -#include "../Surface.hpp" #include #include #include #include #include + +#include "../ClipperUtils.hpp" +#include "../ShortestPath.hpp" #include "Fill3DHoneycomb.hpp" #include "libslic3r/BoundingBox.hpp" #include "libslic3r/Fill/FillBase.hpp" @@ -15,40 +15,6 @@ namespace Slic3r { -//w36 -template int sgn(T val) { - return (T(0) < val) - (val < T(0)); -} -//w36 -static coordf_t triWave(coordf_t pos, coordf_t gridSize) -{ - float t = (pos / (gridSize * 2.)) + 0.25; - t = t - (int)t; - return((1. - abs(t * 8. - 4.)) * (gridSize / 4.) + (gridSize / 4.)); -} -//w36 -static coordf_t troctWave(coordf_t pos, coordf_t gridSize, coordf_t Zpos) -{ - coordf_t Zcycle = triWave(Zpos, gridSize); - coordf_t perpOffset = Zcycle / 2; - coordf_t y = triWave(pos, gridSize); - return ((abs(y) > abs(perpOffset)) ? (sgn(y) * perpOffset) : (y * sgn(perpOffset))); -} -//w36 -static std::vector getCriticalPoints(coordf_t Zpos, coordf_t gridSize) -{ - std::vector res = {0.}; - coordf_t perpOffset = abs(triWave(Zpos, gridSize) / 2.); - - coordf_t normalisedOffset = perpOffset / gridSize; - if (normalisedOffset > 0) { - res.push_back(gridSize * (0. + normalisedOffset)); - res.push_back(gridSize * (1. - normalisedOffset)); - res.push_back(gridSize * (1. + normalisedOffset)); - res.push_back(gridSize * (2. - normalisedOffset)); - } - return (res); -} /* Creates a contiguous sequence of points at a specified height that make up a horizontal slice of the edges of a space filling truncated @@ -63,47 +29,33 @@ Credits: David Eccles (gringer). // basic printing line (i.e. Y points for columns, X points for rows) // Note: a negative offset only causes a change in the perpendicular // direction -//w36 -static std::vector colinearPoints(const coordf_t Zpos, coordf_t gridSize, std::vector critPoints, - const size_t baseLocation, size_t gridLength) +static std::vector colinearPoints(const coordf_t offset, const size_t baseLocation, size_t gridLength) { - //w36 + const coordf_t offset2 = std::abs(offset / coordf_t(2.)); std::vector points; - //w36 - points.push_back(baseLocation); - for (coordf_t cLoc = baseLocation; cLoc < gridLength; cLoc += (gridSize * 2)) { - for (size_t pi = 0; pi < critPoints.size(); pi++) { - points.push_back(baseLocation + cLoc + critPoints[pi]); - } + points.push_back(baseLocation - offset2); + for (size_t i = 0; i < gridLength; ++i) { + points.push_back(baseLocation + i + offset2); + points.push_back(baseLocation + i + 1 - offset2); } - //w36 - points.push_back(gridLength); + points.push_back(baseLocation + gridLength + offset2); return points; } // Generate an array of points for the dimension that is perpendicular to // the basic printing line (i.e. X points for columns, Y points for rows) -//w36 -static std::vector perpendPoints(const coordf_t Zpos, - coordf_t gridSize, - std::vector critPoints, - size_t baseLocation, - size_t gridLength, - size_t offsetBase, - coordf_t perpDir) +static std::vector perpendPoints(const coordf_t offset, const size_t baseLocation, size_t gridLength) { - //w36 + coordf_t offset2 = offset / coordf_t(2.); + coord_t side = 2 * (baseLocation & 1) - 1; std::vector points; - //w36 - points.push_back(offsetBase); - for (coordf_t cLoc = baseLocation; cLoc < gridLength; cLoc += gridSize * 2) { - for (size_t pi = 0; pi < critPoints.size(); pi++) { - coordf_t offset = troctWave(critPoints[pi], gridSize, Zpos); - points.push_back(offsetBase + (offset * perpDir)); - } + points.push_back(baseLocation - offset2 * side); + for (size_t i = 0; i < gridLength; ++i) { + side = 2*((i+baseLocation) & 1) - 1; + points.push_back(baseLocation + offset2 * side); + points.push_back(baseLocation + offset2 * side); } - //w36 - points.push_back(offsetBase); + points.push_back(baseLocation - offset2 * side); return points; } @@ -131,32 +83,40 @@ static inline Pointfs zip(const std::vector &x, const std::vector makeActualGrid(coordf_t Zpos, coordf_t gridSize, size_t boundsX, size_t boundsY) +static std::vector makeNormalisedGrid(coordf_t z, size_t gridWidth, size_t gridHeight, size_t curveType) { - //w36 - std::vector points; - std::vector critPoints = getCriticalPoints(Zpos, gridSize); - coordf_t zCycle = fmod(Zpos + gridSize / 2, gridSize * 2.) / (gridSize * 2.); - bool printVert = zCycle < 0.5; - if (printVert) { - int perpDir = -1; - for (coordf_t x = 0; x <= (boundsX); x += gridSize, perpDir *= -1) { + // offset required to create a regular octagram + coordf_t octagramGap = coordf_t(0.5); + + // sawtooth wave function for range f($z) = [-$octagramGap .. $octagramGap] + coordf_t a = std::sqrt(coordf_t(2.)); // period + coordf_t wave = fabs(fmod(z, a) - a/2.)/a*4. - 1.; + coordf_t offset = wave * octagramGap; + + std::vector points; + if ((curveType & 1) != 0) { + for (size_t x = 0; x <= gridWidth; ++x) { points.push_back(Pointfs()); Pointfs &newPoints = points.back(); - newPoints = zip(perpendPoints(Zpos, gridSize, critPoints, 0, boundsY, x, perpDir), - colinearPoints(Zpos, gridSize, critPoints, 0, boundsY)); - if (perpDir == 1) + newPoints = zip( + perpendPoints(offset, x, gridHeight), + colinearPoints(offset, 0, gridHeight)); + // trim points to grid edges + trim(newPoints, coordf_t(0.), coordf_t(0.), coordf_t(gridWidth), coordf_t(gridHeight)); + if (x & 1) std::reverse(newPoints.begin(), newPoints.end()); } - } else { - int perpDir = 1; - for (coordf_t y = gridSize; y <= (boundsY); y += gridSize, perpDir *= -1) { + } + if ((curveType & 2) != 0) { + for (size_t y = 0; y <= gridHeight; ++y) { points.push_back(Pointfs()); Pointfs &newPoints = points.back(); - newPoints = zip(colinearPoints(Zpos, gridSize, critPoints, 0, boundsX), - perpendPoints(Zpos, gridSize, critPoints, 0, boundsX, y, perpDir)); - if (perpDir == -1) + newPoints = zip( + colinearPoints(offset, 0, gridWidth), + perpendPoints(offset, y, gridWidth)); + // trim points to grid edges + trim(newPoints, coordf_t(0.), coordf_t(0.), coordf_t(gridWidth), coordf_t(gridHeight)); + if (y & 1) std::reverse(newPoints.begin(), newPoints.end()); } } @@ -166,19 +126,18 @@ static std::vector makeActualGrid(coordf_t Zpos, coordf_t gridSize, siz // Generate a set of curves (array of array of 2d points) that describe a // horizontal slice of a truncated regular octahedron with a specified // grid square size. -//w36 -static Polylines makeGrid(coordf_t z, coordf_t gridSize, coordf_t boundWidth, coordf_t boundHeight, bool fillEvenly) +static Polylines makeGrid(coord_t z, coord_t gridSize, size_t gridWidth, size_t gridHeight, size_t curveType) { - //w36 - std::vector polylines = makeActualGrid(z, gridSize, boundWidth, boundHeight); - Polylines result; + coord_t scaleFactor = gridSize; + coordf_t normalisedZ = coordf_t(z) / coordf_t(scaleFactor); + std::vector polylines = makeNormalisedGrid(normalisedZ, gridWidth, gridHeight, curveType); + Polylines result; result.reserve(polylines.size()); - for (std::vector::const_iterator it_polylines = polylines.begin(); it_polylines != polylines.end(); ++it_polylines) { + for (std::vector::const_iterator it_polylines = polylines.begin(); it_polylines != polylines.end(); ++ it_polylines) { result.push_back(Polyline()); Polyline &polyline = result.back(); - //w36 - for (Pointfs::const_iterator it = it_polylines->begin(); it != it_polylines->end(); ++it) - polyline.points.push_back(Point(coord_t((*it)(0)), coord_t((*it)(1)))); + for (Pointfs::const_iterator it = it_polylines->begin(); it != it_polylines->end(); ++ it) + polyline.points.push_back(Point(coord_t((*it)(0) * scaleFactor), coord_t((*it)(1) * scaleFactor))); } return result; } @@ -191,67 +150,34 @@ void Fill3DHoneycomb::_fill_surface_single( Polylines &polylines_out) { // no rotation is supported for this infill pattern - //w36 - auto infill_angle = float(this->angle); - if (std::abs(infill_angle) >= EPSILON) - expolygon.rotate(-infill_angle); BoundingBox bb = expolygon.contour.bounding_box(); - //w36 + coord_t distance = coord_t(scale_(this->spacing) / params.density); + // align bounding box to a multiple of our honeycomb grid module - // (a module is 2*$distance since one $distance half-module is + // (a module is 2*$distance since one $distance half-module is // growing while the other $distance half-module is shrinking) - //w36 - coordf_t zScale = sqrt(2); - coordf_t gridSize = (scale_(this->spacing) * ((zScale + 1.) / 2.) / params.density); - - - coordf_t layerHeight = scale_(thickness_layers); - - coordf_t layersPerModule = floor((gridSize * 2) / (zScale * layerHeight) + 0.05); - if (params.density > 0.42) { - layersPerModule = 2; - gridSize = (scale_(this->spacing) * 1.1 / params.density); - zScale = (gridSize * 2) / (layersPerModule * layerHeight); - } else { - if (layersPerModule < 2) { - layersPerModule = 2; - } - zScale = (gridSize * 2) / (layersPerModule * layerHeight); - gridSize = (scale_(this->spacing) * ((zScale + 1.) / 2.) / params.density); - layersPerModule = floor((gridSize * 2) / (zScale * layerHeight) + 0.05); - if (layersPerModule < 2) { - layersPerModule = 2; - } - zScale = (gridSize * 2) / (layersPerModule * layerHeight); - } - - bb.merge(align_to_grid(bb.min, Point(gridSize * 4, gridSize * 4))); + bb.merge(align_to_grid(bb.min, Point(2*distance, 2*distance))); + + // generate pattern + Polylines polylines = makeGrid( + scale_(this->z), + distance, + ceil(bb.size()(0) / distance) + 1, + ceil(bb.size()(1) / distance) + 1, + ((this->layer_id/thickness_layers) % 2) + 1); - Polylines polylines = - makeGrid( - scale_(this->z) * zScale, - gridSize, - bb.size()(0), - bb.size()(1), - !params.dont_adjust); // move pattern in place - for (Polyline &pl : polylines) { - pl.translate(bb.min); - } - // clip pattern to boundaries, chain the clipped polylines - polylines = intersection_pl(polylines, to_polygons(expolygon)); - if (!polylines.empty()) { - int infill_start_idx = polylines_out.size(); - if (params.dont_connect() || polylines.size() <= 1) - append(polylines_out, chain_polylines(std::move(polylines))); - else - this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); + for (Polyline &pl : polylines) + pl.translate(bb.min); - if (std::abs(infill_angle) >= EPSILON) { - for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) - it->rotate(infill_angle); - } - } + // clip pattern to boundaries, chain the clipped polylines + polylines = intersection_pl(polylines, expolygon); + + // connect lines if needed + if (params.dont_connect() || polylines.size() <= 1) + append(polylines_out, chain_polylines(std::move(polylines))); + else + this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); } } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 670c7e2..79285c9 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -14,7 +14,6 @@ #include "../ClipperUtils.hpp" #include "../ExPolygon.hpp" -#include "../Surface.hpp" #include "../Geometry.hpp" #include "../Layer.hpp" #include "../Print.hpp" diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 1037bf7..4f9197f 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -35,8 +35,6 @@ //w32 #include "FillCrossHatch.hpp" -#include - // #define INFILL_DEBUG_OUTPUT namespace Slic3r { @@ -70,6 +68,7 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipConcentricInternal: return new FillConcentricInternal(); //w32 case ipCrossHatch: return new FillCrossHatch(); + case ipZigZag: return new FillZigZag(); default: throw Slic3r::InvalidArgument("unknown type"); } } diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 9c71a49..215e244 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -87,7 +87,6 @@ struct FillParams Flow flow; ExtrusionRole extrusion_role{ExtrusionRole::None}; bool using_internal_flow{false}; - //bool can_reverse{true}; }; static_assert(IsTriviallyCopyable::value, "FillParams class is not POD (and it should be - see constructor)."); diff --git a/src/libslic3r/Fill/FillCrossHatch.hpp b/src/libslic3r/Fill/FillCrossHatch.hpp index 112eaba..7365daa 100644 --- a/src/libslic3r/Fill/FillCrossHatch.hpp +++ b/src/libslic3r/Fill/FillCrossHatch.hpp @@ -12,8 +12,9 @@ namespace Slic3r { class FillCrossHatch : public Fill { public: - //Fill *clone() const override { return new FillCrossHatch(*this); }; + Fill *clone() const override { return new FillCrossHatch(*this); }; ~FillCrossHatch() override {} + bool is_self_crossing() override { return false; } protected: void _fill_surface_single(const FillParams & params, diff --git a/src/libslic3r/Fill/FillEnsuring.cpp b/src/libslic3r/Fill/FillEnsuring.cpp index c14457c..301609f 100644 --- a/src/libslic3r/Fill/FillEnsuring.cpp +++ b/src/libslic3r/Fill/FillEnsuring.cpp @@ -29,6 +29,244 @@ namespace Slic3r { +const constexpr coord_t MAX_LINE_LENGTH_TO_FILTER = scaled(4.); // 4 mm. +const constexpr size_t MAX_SKIPS_ALLOWED = 2; // Skip means propagation through long line. +const constexpr size_t MIN_DEPTH_FOR_LINE_REMOVING = 5; + +struct LineNode +{ + struct State + { + // The total number of long lines visited before this node was reached. + // We just need the minimum number of all possible paths to decide whether we can remove the line or not. + int min_skips_taken = 0; + // The total number of short lines visited before this node was reached. + int total_short_lines = 0; + // Some initial line is touching some long line. This information is propagated to neighbors. + bool initial_touches_long_lines = false; + bool initialized = false; + + void reset() { + this->min_skips_taken = 0; + this->total_short_lines = 0; + this->initial_touches_long_lines = false; + this->initialized = false; + } + }; + + explicit LineNode(const Line &line) : line(line) {} + + Line line; + // Pointers to line nodes in the previous and the next section that overlap with this line. + std::vector next_section_overlapping_lines; + std::vector prev_section_overlapping_lines; + + bool is_removed = false; + + State state; + + // Return true if some initial line is touching some long line and this information was propagated into the current line. + bool is_initial_line_touching_long_lines() const { + if (prev_section_overlapping_lines.empty()) + return false; + + for (LineNode *line_node : prev_section_overlapping_lines) { + if (line_node->state.initial_touches_long_lines) + return true; + } + + return false; + } + + // Return true if the current line overlaps with some long line in the previous section. + bool is_touching_long_lines_in_previous_layer() const { + if (prev_section_overlapping_lines.empty()) + return false; + + for (LineNode *line_node : prev_section_overlapping_lines) { + if (!line_node->is_removed && line_node->line.length() >= MAX_LINE_LENGTH_TO_FILTER) + return true; + } + + return false; + } + + // Return true if the current line overlaps with some line in the next section. + bool has_next_layer_neighbours() const { + if (next_section_overlapping_lines.empty()) + return false; + + for (LineNode *line_node : next_section_overlapping_lines) { + if (!line_node->is_removed) + return true; + } + + return false; + } +}; + +using LineNodes = std::vector; + +inline bool are_lines_overlapping_in_y_axes(const Line &first_line, const Line &second_line) { + return (second_line.a.y() <= first_line.a.y() && first_line.a.y() <= second_line.b.y()) + || (second_line.a.y() <= first_line.b.y() && first_line.b.y() <= second_line.b.y()) + || (first_line.a.y() <= second_line.a.y() && second_line.a.y() <= first_line.b.y()) + || (first_line.a.y() <= second_line.b.y() && second_line.b.y() <= first_line.b.y()); +} + +bool can_line_note_be_removed(const LineNode &line_node) { + return (line_node.line.length() < MAX_LINE_LENGTH_TO_FILTER) + && (line_node.state.total_short_lines > int(MIN_DEPTH_FOR_LINE_REMOVING) + || (!line_node.is_initial_line_touching_long_lines() && !line_node.has_next_layer_neighbours())); +} + +// Remove the node and propagate its removal to the previous sections. +void propagate_line_node_remove(const LineNode &line_node) { + std::queue line_node_queue; + for (LineNode *prev_line : line_node.prev_section_overlapping_lines) { + if (prev_line->is_removed) + continue; + + line_node_queue.emplace(prev_line); + } + + for (; !line_node_queue.empty(); line_node_queue.pop()) { + LineNode &line_to_check = *line_node_queue.front(); + + if (can_line_note_be_removed(line_to_check)) { + line_to_check.is_removed = true; + + for (LineNode *prev_line : line_to_check.prev_section_overlapping_lines) { + if (prev_line->is_removed) + continue; + + line_node_queue.emplace(prev_line); + } + } + } +} + +// Filter out short extrusions that could create vibrations. +static std::vector filter_vibrating_extrusions(const std::vector &lines_sections) { + // Initialize all line nodes. + std::vector line_nodes_sections(lines_sections.size()); + for (const Lines &lines_section : lines_sections) { + const size_t section_idx = &lines_section - lines_sections.data(); + + line_nodes_sections[section_idx].reserve(lines_section.size()); + for (const Line &line : lines_section) { + line_nodes_sections[section_idx].emplace_back(line); + } + } + + // Precalculate for each line node which line nodes in the previous and next section this line node overlaps. + for (auto curr_lines_section_it = line_nodes_sections.begin(); curr_lines_section_it != line_nodes_sections.end(); ++curr_lines_section_it) { + if (curr_lines_section_it != line_nodes_sections.begin()) { + const auto prev_lines_section_it = std::prev(curr_lines_section_it); + for (LineNode &curr_line : *curr_lines_section_it) { + for (LineNode &prev_line : *prev_lines_section_it) { + if (are_lines_overlapping_in_y_axes(curr_line.line, prev_line.line)) { + curr_line.prev_section_overlapping_lines.emplace_back(&prev_line); + } + } + } + } + + if (std::next(curr_lines_section_it) != line_nodes_sections.end()) { + const auto next_lines_section_it = std::next(curr_lines_section_it); + for (LineNode &curr_line : *curr_lines_section_it) { + for (LineNode &next_line : *next_lines_section_it) { + if (are_lines_overlapping_in_y_axes(curr_line.line, next_line.line)) { + curr_line.next_section_overlapping_lines.emplace_back(&next_line); + } + } + } + } + } + + // Select each section as the initial lines section and propagate line node states from this initial lines section to the last lines section. + // During this propagation, we remove those lines that meet the conditions for its removal. + // When some line is removed, we propagate this removal to previous layers. + for (size_t initial_line_section_idx = 0; initial_line_section_idx < line_nodes_sections.size(); ++initial_line_section_idx) { + // Stars from non-removed short lines. + for (LineNode &initial_line : line_nodes_sections[initial_line_section_idx]) { + if (initial_line.is_removed || initial_line.line.length() >= MAX_LINE_LENGTH_TO_FILTER) + continue; + + initial_line.state.reset(); + initial_line.state.total_short_lines = 1; + initial_line.state.initial_touches_long_lines = initial_line.is_touching_long_lines_in_previous_layer(); + initial_line.state.initialized = true; + } + + // Iterate from the initial lines section until the last lines section. + for (size_t propagation_line_section_idx = initial_line_section_idx; propagation_line_section_idx < line_nodes_sections.size(); ++propagation_line_section_idx) { + // Before we propagate node states into next lines sections, we reset the state of all line nodes in the next line section. + if (propagation_line_section_idx + 1 < line_nodes_sections.size()) { + for (LineNode &propagation_line : line_nodes_sections[propagation_line_section_idx + 1]) { + propagation_line.state.reset(); + } + } + + for (LineNode &propagation_line : line_nodes_sections[propagation_line_section_idx]) { + if (propagation_line.is_removed || !propagation_line.state.initialized) + continue; + + for (LineNode *neighbour_line : propagation_line.next_section_overlapping_lines) { + if (neighbour_line->is_removed) + continue; + + const bool is_short_line = neighbour_line->line.length() < MAX_LINE_LENGTH_TO_FILTER; + const bool is_skip_allowed = propagation_line.state.min_skips_taken < int(MAX_SKIPS_ALLOWED); + + if (!is_short_line && !is_skip_allowed) + continue; + + const int neighbour_total_short_lines = propagation_line.state.total_short_lines + int(is_short_line); + const int neighbour_min_skips_taken = propagation_line.state.min_skips_taken + int(!is_short_line); + + if (neighbour_line->state.initialized) { + // When the state of the node was previously filled, then we need to update data in such a way + // that will maximize the possibility of removing this node. + neighbour_line->state.min_skips_taken = std::max(neighbour_line->state.min_skips_taken, neighbour_total_short_lines); + neighbour_line->state.min_skips_taken = std::min(neighbour_line->state.min_skips_taken, neighbour_min_skips_taken); + + // We will keep updating neighbor initial_touches_long_lines until it is equal to false. + if (neighbour_line->state.initial_touches_long_lines) { + neighbour_line->state.initial_touches_long_lines = propagation_line.state.initial_touches_long_lines; + } + } else { + neighbour_line->state.total_short_lines = neighbour_total_short_lines; + neighbour_line->state.min_skips_taken = neighbour_min_skips_taken; + neighbour_line->state.initial_touches_long_lines = propagation_line.state.initial_touches_long_lines; + neighbour_line->state.initialized = true; + } + } + + if (can_line_note_be_removed(propagation_line)) { + // Remove the current node and propagate its removal to the previous sections. + propagation_line.is_removed = true; + propagate_line_node_remove(propagation_line); + } + } + } + } + + // Create lines sections without filtered-out lines. + std::vector lines_sections_out(line_nodes_sections.size()); + for (const std::vector &line_nodes_section : line_nodes_sections) { + const size_t section_idx = &line_nodes_section - line_nodes_sections.data(); + + for (const LineNode &line_node : line_nodes_section) { + if (!line_node.is_removed) { + lines_sections_out[section_idx].emplace_back(line_node.line); + } + } + } + + return lines_sections_out; +} + ThickPolylines make_fill_polylines( const Fill *fill, const Surface *surface, const FillParams ¶ms, bool stop_vibrations, bool fill_gaps, bool connect_extrusions) { @@ -45,11 +283,6 @@ ThickPolylines make_fill_polylines( } }; - auto segments_overlap = [](coord_t alow, coord_t ahigh, coord_t blow, coord_t bhigh) { - return (alow >= blow && alow <= bhigh) || (ahigh >= blow && ahigh <= bhigh) || (blow >= alow && blow <= ahigh) || - (bhigh >= alow && bhigh <= ahigh); - }; - const coord_t scaled_spacing = scaled(fill->spacing); double distance_limit_reconnection = 2.0 * double(scaled_spacing); double squared_distance_limit_reconnection = distance_limit_reconnection * distance_limit_reconnection; @@ -66,23 +299,24 @@ ThickPolylines make_fill_polylines( AABBTreeLines::LinesDistancer area_walls{to_lines(inner_area)}; - const size_t n_vlines = (bb.max.x() - bb.min.x() + scaled_spacing - 1) / scaled_spacing; - std::vector vertical_lines(n_vlines); - coord_t y_min = bb.min.y(); - coord_t y_max = bb.max.y(); + const size_t n_vlines = (bb.max.x() - bb.min.x() + scaled_spacing - 1) / scaled_spacing; + const coord_t y_min = bb.min.y(); + const coord_t y_max = bb.max.y(); + Lines vertical_lines(n_vlines); + for (size_t i = 0; i < n_vlines; i++) { coord_t x = bb.min.x() + i * double(scaled_spacing); vertical_lines[i].a = Point{x, y_min}; vertical_lines[i].b = Point{x, y_max}; } - if (vertical_lines.size() > 0) { + + if (!vertical_lines.empty()) { vertical_lines.push_back(vertical_lines.back()); vertical_lines.back().a = Point{coord_t(bb.min.x() + n_vlines * double(scaled_spacing) + scaled_spacing * 0.5), y_min}; vertical_lines.back().b = Point{vertical_lines.back().a.x(), y_max}; } - std::vector> polygon_sections(n_vlines); - + std::vector polygon_sections(n_vlines); for (size_t i = 0; i < n_vlines; i++) { const auto intersections = area_walls.intersections_with_line(vertical_lines[i]); @@ -98,87 +332,7 @@ ThickPolylines make_fill_polylines( } if (stop_vibrations) { - struct Node - { - int section_idx; - int line_idx; - int skips_taken = 0; - bool neighbours_explored = false; - std::vector> neighbours{}; - }; - - coord_t length_filter = scale_(4); - size_t skips_allowed = 2; - size_t min_removal_conut = 5; - for (int section_idx = 0; section_idx < int(polygon_sections.size()); ++ section_idx) { - for (int line_idx = 0; line_idx < int(polygon_sections[section_idx].size()); ++ line_idx) { - if (const Line &line = polygon_sections[section_idx][line_idx]; line.a != line.b && line.length() < length_filter) { - std::set> to_remove{{section_idx, line_idx}}; - std::vector to_visit{{section_idx, line_idx}}; - - bool initial_touches_long_lines = false; - if (section_idx > 0) { - for (int prev_line_idx = 0; prev_line_idx < int(polygon_sections[section_idx - 1].size()); ++ prev_line_idx) { - if (const Line &nl = polygon_sections[section_idx - 1][prev_line_idx]; - nl.a != nl.b && segments_overlap(line.a.y(), line.b.y(), nl.a.y(), nl.b.y())) { - initial_touches_long_lines = true; - } - } - } - - while (!to_visit.empty()) { - Node curr = to_visit.back(); - const Line &curr_l = polygon_sections[curr.section_idx][curr.line_idx]; - if (curr.neighbours_explored) { - bool is_valid_for_removal = (curr_l.length() < length_filter) && - ((int(to_remove.size()) - curr.skips_taken > int(min_removal_conut)) || - (curr.neighbours.empty() && !initial_touches_long_lines)); - if (!is_valid_for_removal) { - for (const auto &n : curr.neighbours) { - if (to_remove.find(n) != to_remove.end()) { - is_valid_for_removal = true; - break; - } - } - } - if (!is_valid_for_removal) { - to_remove.erase({curr.section_idx, curr.line_idx}); - } - to_visit.pop_back(); - } else { - to_visit.back().neighbours_explored = true; - int curr_index = to_visit.size() - 1; - bool can_use_skip = curr_l.length() <= length_filter && curr.skips_taken < int(skips_allowed); - if (curr.section_idx + 1 < int(polygon_sections.size())) { - for (int lidx = 0; lidx < int(polygon_sections[curr.section_idx + 1].size()); ++ lidx) { - if (const Line &nl = polygon_sections[curr.section_idx + 1][lidx]; - nl.a != nl.b && segments_overlap(curr_l.a.y(), curr_l.b.y(), nl.a.y(), nl.b.y()) && - (nl.length() < length_filter || can_use_skip)) { - to_visit[curr_index].neighbours.push_back({curr.section_idx + 1, lidx}); - to_remove.insert({curr.section_idx + 1, lidx}); - Node next_node{curr.section_idx + 1, lidx, curr.skips_taken + (nl.length() >= length_filter)}; - to_visit.push_back(next_node); - } - } - } - } - } - - for (const auto &pair : to_remove) { - Line &l = polygon_sections[pair.first][pair.second]; - l.a = l.b; - } - } - } - } - } - - for (size_t section_idx = 0; section_idx < polygon_sections.size(); section_idx++) { - polygon_sections[section_idx].erase(std::remove_if(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(), - [](const Line &s) { return s.a == s.b; }), - polygon_sections[section_idx].end()); - std::sort(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(), - [](const Line &a, const Line &b) { return a.a.y() < b.b.y(); }); + polygon_sections = filter_vibrating_extrusions(polygon_sections); } ThickPolylines thick_polylines; @@ -296,19 +450,9 @@ ThickPolylines make_fill_polylines( // svg.draw(to_lines(gaps_for_additional_filling), "green", scale_(0.2)); // svg.draw(vertical_lines, "black", scale_(0.1)); // svg.Close(); - //w11 - PrintObjectConfig config; - const coord_t threshold = scaled_spacing * 4.5; + for (ExPolygon &ex_poly : gaps_for_additional_filling) { - //w11 - if (ex_poly.contour.length() < threshold && config.detect_narrow_internal_solid_infill) { - continue; - } BoundingBox ex_bb = ex_poly.contour.bounding_box(); - //w11 - if ((ex_bb.size().x() < threshold || ex_bb.size().y() < threshold) && config.detect_narrow_internal_solid_infill) { - continue; - } coord_t loops_count = (std::max(ex_bb.size().x(), ex_bb.size().y()) + scaled_spacing - 1) / scaled_spacing; Polygons polygons = to_polygons(ex_poly); Arachne::WallToolPaths wall_tool_paths(polygons, scaled_spacing, scaled_spacing, loops_count, 0, params.layer_height, @@ -329,6 +473,10 @@ ThickPolylines make_fill_polylines( ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion); if (extrusion->is_closed) { + // Arachne produces contour with clockwise orientation and holes with counterclockwise orientation. + if (const bool extrusion_reverse = params.prefer_clockwise_movements ? !extrusion->is_contour() : extrusion->is_contour(); extrusion_reverse) + thick_polyline.reverse(); + thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, ex_bb.min)); thick_polyline.clip_end(scaled_spacing * 0.5); } diff --git a/src/libslic3r/Fill/Lightning/DistanceField.cpp b/src/libslic3r/Fill/Lightning/DistanceField.cpp index f0ccabe..3cb2c6e 100644 --- a/src/libslic3r/Fill/Lightning/DistanceField.cpp +++ b/src/libslic3r/Fill/Lightning/DistanceField.cpp @@ -16,7 +16,6 @@ #include "libslic3r/Line.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" -#include #ifdef LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT #include "../../SVG.hpp" diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 12810c2..3ac200b 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1193,7 +1193,7 @@ namespace Slic3r { // Replacing the legacy function with load_from_ini_string_commented leads to issues when // parsing 3MFs from before QIDISlicer 2.0.0 (which can have duplicated entries in the INI. - // See https://github.com/qidi3d/QIDISlicer/issues/7155. We'll revert it for now. + // See https://github.com/QIDITECH/QIDISlicer/issues/7155. We'll revert it for now. //config_substitutions.substitutions = config.load_from_ini_string_commented(std::move(buffer), config_substitutions.rule); ConfigBase::load_from_gcode_string_legacy(config, buffer.data(), config_substitutions); } diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 4fe3b5f..7f4b429 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -716,7 +716,7 @@ void AMFParserContext::endElement(const char * /* name */) // Replacing the legacy function with load_from_ini_string_commented leads to issues when // parsing 3MFs from before QIDISlicer 2.0.0 (which can have duplicated entries in the INI. - // See https://github.com/qidi3d/QIDISlicer/issues/7155. We'll revert it for now. + // See https://github.com/QIDITECH/QIDISlicer/issues/7155. We'll revert it for now. //m_config_substitutions->substitutions = m_config->load_from_ini_string_commented(std::move(m_value[1].c_str()), m_config_substitutions->rule); ConfigBase::load_from_gcode_string_legacy(*m_config, std::move(m_value[1].c_str()), *m_config_substitutions); } diff --git a/src/libslic3r/Format/STEP.hpp b/src/libslic3r/Format/STEP.hpp index e08695c..6884ac2 100644 --- a/src/libslic3r/Format/STEP.hpp +++ b/src/libslic3r/Format/STEP.hpp @@ -1,5 +1,3 @@ -// Original implementation of STEP format import created by Bambulab. -// https://github.com/bambulab/BambuStudio #ifndef slic3r_Format_STEP_hpp_ #define slic3r_Format_STEP_hpp_ diff --git a/src/libslic3r/Format/objparser.cpp b/src/libslic3r/Format/objparser.cpp index a905afe..638070c 100644 --- a/src/libslic3r/Format/objparser.cpp +++ b/src/libslic3r/Format/objparser.cpp @@ -355,7 +355,7 @@ bool objparse(const char *path, ObjData &data) while ((len = ::fread(buf + lenPrev, 1, half_buf-1, pFile)) != 0) { if (std::feof(pFile)) { // Fix issue with missing last trinagle in obj file: - // https://github.com/qidi3d/QIDISlicer/issues/12157 + // https://github.com/QIDITECH/QIDISlicer/issues/12157 // algorithm expect line endings after last face // but file format support it buf[len+lenPrev] = '\n'; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c7709be..81d2074 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -348,7 +348,7 @@ GCodeGenerator::ObjectsLayerToPrint GCodeGenerator::collect_layers_to_print(cons + layer_to_print.layer()->height + std::max(0., extra_gap); // Negative support_contact_z is not taken into account, it can result in false positives in cases - // where previous layer has object extrusions too (https://github.com/qidi3d/QIDISlicer/issues/2752) + // where previous layer has object extrusions too (https://github.com/QIDITECH/QIDISlicer/issues/2752) if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON) warning_ranges.emplace_back(std::make_pair((last_extrusion_layer ? last_extrusion_layer->print_z() : 0.), layers_to_print.back().print_z())); @@ -685,7 +685,7 @@ namespace DoExport { { // Minimal volumetric flow should not be calculated over ironing extrusions. // Use following lambda instead of the built-it method. - // https://github.com/qidi3d/QIDISlicer/issues/5082 + // https://github.com/QIDITECH/QIDISlicer/issues/5082 auto min_mm3_per_mm_no_ironing = [](const ExtrusionEntityCollection& eec) -> double { double min = std::numeric_limits::max(); for (const ExtrusionEntity* ee : eec.entities) @@ -1193,14 +1193,15 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id); - // this->_print_first_layer_chamber_temperature(file, print, start_gcode, config().chamber_temperature.get_at(initial_extruder_id), false, false); + //w42 + //this->_print_first_layer_chamber_temperature(file, print, start_gcode, config().chamber_temperature.get_at(initial_extruder_id), false, false); + this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true); this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false); // adds tag for processor file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), gcode_extrusion_role_to_string(GCodeExtrusionRole::Custom).c_str()); - //B41 if (this->config().gcode_flavor == gcfKlipper) file.write(set_object_range(print)); @@ -1214,6 +1215,10 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail file.writeln(start_gcode); this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true); + this->_print_first_layer_chamber_temperature(file, print, start_gcode, config().chamber_minimal_temperature.get_at(initial_extruder_id), true, false); + //w42 + //this->_print_first_layer_chamber_temperature(file, print, start_gcode, config().chamber_temperature.get_at(initial_extruder_id), false, false); + print.throw_if_canceled(); // Set other general things. @@ -1331,7 +1336,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail } } else { // This is not Marlin, M1 command is probably not supported. - // (See https://github.com/qidi3d/QIDISlicer/issues/5441.) + // (See https://github.com/QIDITECH/QIDISlicer/issues/5441.) if (overlap) { print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, _u8L("Your print is very close to the priming regions. " @@ -1365,7 +1370,6 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail file.write(gcode); } - file.write(m_writer.set_fan(0)); //B39 file.write("M106 P3 S0\n"); @@ -1913,22 +1917,22 @@ void GCodeGenerator::_print_first_layer_bed_temperature(GCodeOutputStream &file, // Only do that if the start G-code does not already contain any M-code controlling chamber temperature. // M141 - Set chamber Temperature // M191 - Set chamber Temperature and Wait -// void GCodeGenerator::_print_first_layer_chamber_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, int temp, bool wait, bool accurate) -// { -// if (temp == 0) -// return; -// bool autoemit = print.config().autoemit_temperature_commands; -// // Is the bed temperature set by the provided custom G-code? -// int temp_by_gcode = -1; -// bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 141, 191, false, temp_by_gcode); -// if (autoemit && temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) -// temp = temp_by_gcode; -// // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if -// // the custom start G-code emited these. -// std::string set_temp_gcode = m_writer.set_chamber_temperature(temp, wait, accurate); -// if (autoemit && ! temp_set_by_gcode) -// file.write(set_temp_gcode); -// } +void GCodeGenerator::_print_first_layer_chamber_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, int temp, bool wait, bool accurate) +{ + if (temp == 0) + return; + bool autoemit = print.config().autoemit_temperature_commands; + // Is the bed temperature set by the provided custom G-code? + int temp_by_gcode = -1; + bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 141, 191, false, temp_by_gcode); + if (autoemit && temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) + temp = temp_by_gcode; + // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if + // the custom start G-code emited these. + std::string set_temp_gcode = m_writer.set_chamber_temperature(temp, wait, accurate); + if (autoemit && ! temp_set_by_gcode) + file.write(set_temp_gcode); +} @@ -2153,14 +2157,14 @@ namespace Skirt { assert(valid); // This print_z has not been extruded yet (sequential print) // FIXME: The skirt_done should not be empty at this point. The check is a workaround - // of https://github.com/qidi3d/QIDISlicer/issues/5652, but it deserves a real fix. + // of https://github.com/QIDITECH/QIDISlicer/issues/5652, but it deserves a real fix. if (valid) { #if 0 // Prime just the first printing extruder. This is original Slic3r's implementation. skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair(0, print.config().skirts.value); #else // Prime all extruders planned for this layer, see - // https://github.com/qidi3d/QIDISlicer/issues/469#issuecomment-322450619 + // https://github.com/QIDITECH/QIDISlicer/issues/469#issuecomment-322450619 skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); #endif assert(!skirt_done.empty()); @@ -2322,12 +2326,13 @@ struct SmoothPathGenerator { // loop; if polyline was shorter than the clipping distance we'd get a null // polyline, so we discard it in that case. const auto nozzle_diameter{config.nozzle_diameter.get_at(extruder_id)}; - if (enable_loop_clipping) { - //Y21 - - clip_end(smooth_path, scale_(nozzle_diameter) * (config.seam_gap.value / 100), scaled(GCode::ExtrusionOrder::min_gcode_segment_length)); + clip_end( + smooth_path, + scale_(nozzle_diameter) * (config.seam_gap.value / 100), + scaled(GCode::ExtrusionOrder::min_gcode_segment_length) + ); } assert(validate_smooth_path(smooth_path, !enable_loop_clipping)); @@ -2547,8 +2552,8 @@ LayerResult GCodeGenerator::process_layer( gcode += m_writer.set_temperature(temperature, false, extruder.id()); } gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id)); - //B24 - gcode += m_writer.set_volume_temperature(print.config().volume_temperature.get_at(first_extruder_id)); + //B24 //w42 + gcode += m_writer.set_chamber_temperature(print.config().chamber_temperature.get_at(first_extruder_id), false, false); // Mark the temperature transition from 1st to 2nd layer to be finished. m_second_layer_things_done = true; } @@ -2867,11 +2872,10 @@ std::string GCodeGenerator::change_layer( gcode += this->retract_and_wipe(); } - //B38 //B46 - m_writer.add_object_change_labels(gcode); - m_previous_layer_last_position = this->last_position ? - std::optional{to_3d(this->point_to_gcode(*this->last_position), previous_layer_z)} : - std::nullopt; + // Update from after wipe. + from = to_3d(this->point_to_gcode(*this->last_position), previous_layer_z); + + gcode += this->get_ramping_layer_change_gcode(from, to, extruder_id); this->writer().update_position(to); this->last_position = this->gcode_to_point(unscaled(first_point)); @@ -2887,6 +2891,8 @@ std::string GCodeGenerator::change_layer( this->writer().update_position(position); } } + //B38 //B46 + m_writer.add_object_change_labels(gcode); // forget last wiping path as wiping after raising Z is pointless m_wipe.reset_path(); @@ -2905,68 +2911,40 @@ std::string GCodeGenerator::extrude_smooth_path( for (auto el_it = smooth_path.begin(); el_it != smooth_path.end(); ++el_it) { const auto next_el_it = next(el_it); - //w38 - if (m_config.spiral_vase && !is_hole) { - // if spiral vase, we have to ensure that all contour are in the same orientation. - new_loop_src.make_counter_clockwise(); - } - Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero(); - if (!m_config.spiral_vase && comment_is_perimeter(description)) { - assert(m_layer != nullptr); - //w38 - seam_point = m_seam_placer.place_seam(m_layer, new_loop_src, m_config.external_perimeters_first, seam_point); - } - // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, - // thus empty path segments will not be produced by G-code export. - //w38 - GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam( - new_loop_src, is_hole, m_scaled_resolution, seam_point, scaled(0.0015)); + // By default, GCodeGenerator::_extrude() emit markers _BRIDGE_FAN_START, _BRIDGE_FAN_END and _RESET_FAN_SPEED for every extrusion. + // Together with split extrusions because of different ExtrusionAttributes, this could flood g-code with those markers and then + // produce an unnecessary number of duplicity M106. + // To prevent this, we control when each marker should be emitted by EmitModifiers, which allows determining when a bridge starts and ends, + // even when it is split into several extrusions. + if (el_it->path_attributes.role.is_bridge()) { + emit_modifiers.emit_bridge_fan_start = !is_bridge_extruded; + emit_modifiers.emit_bridge_fan_end = next_el_it == smooth_path.end() || !next_el_it->path_attributes.role.is_bridge(); + is_bridge_extruded = true; + } else if (is_bridge_extruded) { + emit_modifiers.emit_bridge_fan_start = false; + emit_modifiers.emit_bridge_fan_end = false; + is_bridge_extruded = false; + } - // Clip the path to avoid the extruder to get exactly on the first point of the loop; - // if polyline was shorter than the clipping distance we'd get a null polyline, so - // we discard it in that case. - if (m_enable_loop_clipping) - //Y21 - clip_end(smooth_path, scaled(EXTRUDER_CONFIG(nozzle_diameter)) * (m_config.seam_gap.value / 100), scaled(min_gcode_segment_length)); - - if (smooth_path.empty()) - return {}; - - assert(validate_smooth_path(smooth_path, ! m_enable_loop_clipping)); - - // Apply the small perimeter speed. - //w38//Y27 - bool is_small_perimeter_length = false; - if (new_loop_src.paths.front().role().is_perimeter() && new_loop_src.length() <= SMALL_PERIMETER_LENGTH && speed == -1) { - speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); - is_small_perimeter_length = true; - } - - // Extrude along the smooth path. - std::string gcode; -//Y27 - for (const GCode::SmoothPathElement &el : smooth_path) { + // Ensure that just for the last extrusion from the smooth path, the fan speed will be reset back + // to the value calculated by the CoolingBuffer. + if (next_el_it == smooth_path.end()) { + emit_modifiers.emit_fan_speed_reset = true; + } + //w41 m_resonance_avoidance = !is_small_perimeter_length; - gcode += this->_extrude(el.path_attributes, el.path, description, speed); + gcode += this->_extrude(el_it->path_attributes, el_it->path, description, speed, emit_modifiers); } // reset acceleration gcode += m_writer.set_print_acceleration(fast_round_up(m_config.default_acceleration.value)); - if (m_wipe.enabled()) { - // Wipe will hide the seam. - m_wipe.set_path(std::move(smooth_path)); - } - //w38 - else if (new_loop_src.paths.back().role().is_external_perimeter() && m_layer != nullptr && m_config.perimeters.value > 1) { - - // Only wipe inside if the wipe along the perimeter is disabled. - // Make a little move inwards before leaving loop. - if (std::optional pt = wipe_hide_seam(smooth_path, is_hole, scale_(EXTRUDER_CONFIG(nozzle_diameter))); pt) { - // Generate the seam hiding travel move. - gcode += m_writer.travel_to_xy(this->point_to_gcode(*pt), "move inwards before travel"); - this->last_position = *pt; - } + if (is_loop) { + m_wipe.set_path(GCode::SmoothPath{smooth_path}); + } else { + GCode::SmoothPath reversed_smooth_path{smooth_path}; + GCode::reverse(reversed_smooth_path); + m_wipe.set_path(std::move(reversed_smooth_path)); } return gcode; @@ -3023,7 +3001,6 @@ std::string GCodeGenerator::extrude_perimeters( speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); is_small_perimeter_length = true; } - gcode += this->extrude_smooth_path(perimeter.smooth_path, true, comment_perimeter, speed); this->m_travel_obstacle_tracker.mark_extruded( perimeter.extrusion_entity, print_instance.object_layer_to_print_id, print_instance.instance_id @@ -3330,26 +3307,25 @@ std::string GCodeGenerator::_extrude( } } } - - ExtrusionProcessor::OverhangSpeeds dynamic_print_and_fan_speeds = {-1.f, -1.f}; if (path_attr.overhang_attributes.has_value()) { - double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed"); - if (external_perim_reference_speed == 0) - external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm; - external_perim_reference_speed = cap_speed( - external_perim_reference_speed, path_attr.mm3_per_mm, m_config, m_writer.extruder()->id() - ); + double external_perimeter_reference_speed = m_config.get_abs_value("external_perimeter_speed"); + if (external_perimeter_reference_speed == 0) { + external_perimeter_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm; + } - dynamic_speed_and_fan_speed = ExtrusionProcessor::calculate_overhang_speed(path_attr, this->m_config, m_writer.extruder()->id(), - external_perim_reference_speed, speed); + external_perimeter_reference_speed = cap_speed(external_perimeter_reference_speed, m_config, m_writer.extruder()->id(), path_attr); + dynamic_print_and_fan_speeds = ExtrusionProcessor::calculate_overhang_speed(path_attr, this->m_config, m_writer.extruder()->id(), + float(external_perimeter_reference_speed), float(speed), + m_current_dynamic_fan_speed); } -//Y27 + + //w41 if (path_attr.role == ExtrusionRole::ExternalPerimeter && m_config.opt_bool("resonance_avoidance")) { - if (dynamic_speed_and_fan_speed.first > -1) { - if (speed != dynamic_speed_and_fan_speed.first) { - double min_speed = cap_speed(speed, path_attr.mm3_per_mm, m_config, m_writer.extruder()->id()); + if (dynamic_print_and_fan_speeds.print_speed > -1) { + if (speed != dynamic_print_and_fan_speeds.print_speed) { + double min_speed = cap_speed(speed, m_config, m_writer.extruder()->id(),path_attr); if (min_speed > m_config.opt_float("max_resonance_avoidance_speed")) { m_resonance_avoidance = false; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 1c77386..cc9369b 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -453,6 +453,8 @@ private: //Y27 bool m_resonance_avoidance; + //w41 + bool is_small_perimeter_length = false; // Back-pointer to Print (const). const Print* m_print; @@ -476,7 +478,7 @@ private: std::string _extrude(const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, std::string_view description, double speed, const EmitModifiers &emit_modifiers = EmitModifiers()); void print_machine_envelope(GCodeOutputStream &file, const Print &print); - // void _print_first_layer_chamber_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, int temp, bool wait, bool accurate); + void _print_first_layer_chamber_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, int temp, bool wait, bool accurate); void _print_first_layer_bed_temperature(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, const Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); // On the first printing layer. This flag triggers first layer speeds. diff --git a/src/libslic3r/GCode/ConflictChecker.cpp b/src/libslic3r/GCode/ConflictChecker.cpp index c87cd29..878b4be 100644 --- a/src/libslic3r/GCode/ConflictChecker.cpp +++ b/src/libslic3r/GCode/ConflictChecker.cpp @@ -1,4 +1,4 @@ -// #include "libslic3r.h" + #include "ConflictChecker.hpp" #include diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 539669a..019020e 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -290,6 +290,9 @@ float new_feedrate_to_reach_time_stretch( } } } + + // Handle cases when all lines have feedrate below or equal to min_feedrate + // or when the accumulated sum of time is a very small number. assert(denom > 0); if (nomin <= 0 || denom <= EPSILON) return min_feedrate; @@ -833,13 +836,22 @@ std::string CoolingBuffer::apply_layer_cooldown( enable_auxiliary_fan = EXTRUDER_CONFIG(enable_auxiliary_fan_unseal); //B25 int enable_volume_fan = EXTRUDER_CONFIG(enable_volume_fan); - int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0; - std::pair custom_fan_speed_limits{fan_speed_new, 100 }; - int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers); + //B39 int disable_rapid_cooling_fan_first_layers = EXTRUDER_CONFIG(disable_rapid_cooling_fan_first_layers); // Is the fan speed ramp enabled? - int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer); + const int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer); + int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers); + int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0; + + struct FanSpeedRange + { + int min_speed; + int max_speed; + }; + + FanSpeedRange requested_fan_speed_limits{fan_speed_new, 100}; + if (disable_fan_first_layers <= 0 && full_fan_speed_layer > 0) { // When ramping up fan speed from disable_fan_first_layers to full_fan_speed_layer, force disable_fan_first_layers above zero, // so there will be a zero fan speed at least at the 1st layer. @@ -852,33 +864,42 @@ std::string CoolingBuffer::apply_layer_cooldown( if (EXTRUDER_CONFIG(cooling)) { if (layer_time < slowdown_below_layer_time) { // Layer time very short. Enable the fan to a full throttle. - fan_speed_new = max_fan_speed; - custom_fan_speed_limits.first = fan_speed_new; + fan_speed_new = max_fan_speed; + requested_fan_speed_limits.min_speed = max_fan_speed; } else if (layer_time < fan_below_layer_time) { // Layer time quite short. Enable the fan proportionally according to the current layer time. assert(layer_time >= slowdown_below_layer_time); - double t = (layer_time - slowdown_below_layer_time) / (fan_below_layer_time - slowdown_below_layer_time); - fan_speed_new = int(floor(t * min_fan_speed + (1. - t) * max_fan_speed) + 0.5); - custom_fan_speed_limits.first = fan_speed_new; + const double t = (layer_time - slowdown_below_layer_time) / (fan_below_layer_time - slowdown_below_layer_time); + + fan_speed_new = int(floor(t * min_fan_speed + (1. - t) * max_fan_speed) + 0.5); + requested_fan_speed_limits.min_speed = fan_speed_new; } } - bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed); + + bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed); if (int(layer_id) >= disable_fan_first_layers && int(layer_id) + 1 < full_fan_speed_layer) { // Ramp up the fan speed from disable_fan_first_layers to full_fan_speed_layer. - float factor = float(int(layer_id + 1) - disable_fan_first_layers) / float(full_fan_speed_layer - disable_fan_first_layers); - fan_speed_new = std::clamp(int(float(fan_speed_new) * factor + 0.5f), 0, 100); - bridge_fan_speed = std::clamp(int(float(bridge_fan_speed) * factor + 0.5f), 0, 100); - custom_fan_speed_limits.second = fan_speed_new; + const float factor = float(int(layer_id + 1) - disable_fan_first_layers) / float(full_fan_speed_layer - disable_fan_first_layers); + + fan_speed_new = std::clamp(int(float(fan_speed_new) * factor + 0.5f), 0, 100); + bridge_fan_speed = std::clamp(int(float(bridge_fan_speed) * factor + 0.5f), 0, 100); + requested_fan_speed_limits.max_speed = fan_speed_new; } #undef EXTRUDER_CONFIG bridge_fan_control = bridge_fan_speed > fan_speed_new; } else { // fan disabled - bridge_fan_control = false; - bridge_fan_speed = 0; - fan_speed_new = 0; - custom_fan_speed_limits.second = 0; + bridge_fan_control = false; + bridge_fan_speed = 0; + fan_speed_new = 0; + requested_fan_speed_limits.max_speed = 0; } + + requested_fan_speed_limits.min_speed = std::min(requested_fan_speed_limits.min_speed, requested_fan_speed_limits.max_speed); + if (requested_fan_speed >= 0) { + fan_speed_new = std::clamp(requested_fan_speed, requested_fan_speed_limits.min_speed, requested_fan_speed_limits.max_speed); + } + //B15 //B39 if (int(layer_id) == disable_rapid_cooling_fan_first_layers) { int auxiliary_fan_speed_new = 255 * enable_auxiliary_fan / 100; @@ -889,6 +910,7 @@ std::string CoolingBuffer::apply_layer_cooldown( new_gcode += fan_gcode.str(); } } + if (fan_speed_new != m_fan_speed) { m_fan_speed = fan_speed_new; new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, m_fan_speed); @@ -901,13 +923,12 @@ std::string CoolingBuffer::apply_layer_cooldown( fan_gcode << "M106 P3 S" << volume_fan_speed_new << "\n"; new_gcode += fan_gcode.str(); } - custom_fan_speed_limits.first = std::min(custom_fan_speed_limits.first, custom_fan_speed_limits.second); - return custom_fan_speed_limits; }; const char *pos = gcode.c_str(); int current_feedrate = 0; - std::pair fan_speed_limits = change_extruder_set_fan(); + + change_extruder_set_fan(); for (const CoolingLine *line : lines) { const char *line_start = gcode.c_str() + line->line_start; const char *line_end = gcode.c_str() + line->line_end; @@ -918,17 +939,13 @@ std::string CoolingBuffer::apply_layer_cooldown( auto res = std::from_chars(line_start + m_toolchange_prefix.size(), line_end, new_extruder); if (res.ec != std::errc::invalid_argument && new_extruder != m_current_extruder) { m_current_extruder = new_extruder; - fan_speed_limits = change_extruder_set_fan(); + change_extruder_set_fan(); } new_gcode.append(line_start, line_end - line_start); } else if (line->type & CoolingLine::TYPE_SET_FAN_SPEED) { - int new_speed = std::clamp(line->fan_speed, fan_speed_limits.first, fan_speed_limits.second); - if (m_fan_speed != new_speed) { - new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, new_speed); - m_fan_speed = new_speed; - } + change_extruder_set_fan(line->fan_speed); } else if (line->type & CoolingLine::TYPE_RESET_FAN_SPEED){ - fan_speed_limits = change_extruder_set_fan(); + change_extruder_set_fan(); } else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_START) { if (bridge_fan_control) new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, bridge_fan_speed); diff --git a/src/libslic3r/GCode/ExtrusionProcessor.cpp b/src/libslic3r/GCode/ExtrusionProcessor.cpp index 95ba220..0ab1e04 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.cpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.cpp @@ -177,10 +177,6 @@ static std::map calc_print_speed_sections(const ExtrusionAttribute const float external_perimeter_reference_speed, const float default_speed) { -// //w19 -// bool is_overhang = attributes.overhang_attributes->start_distance_from_prev_layer >= 0.25 * attributes.width && -// attributes.overhang_attributes->end_distance_from_prev_layer >= 0.25 * attributes.width;//&& -// //attributes.overhang_attributes->proximity_to_curled_lines > 0.05 ; struct OverhangWithSpeed { int percent; @@ -269,13 +265,10 @@ OverhangSpeeds calculate_overhang_speed(const ExtrusionAttributes &attributes, const float extrusion_speed = std::min(interpolate_speed(speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer), interpolate_speed(speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer)); //w19 - const float curled_base_speed = interpolate_speed(speed_sections, - attributes.width * attributes.overhang_attributes->proximity_to_curled_lines/tan(67.5)); + const float curled_base_speed = interpolate_speed(speed_sections, attributes.width * attributes.overhang_attributes->proximity_to_curled_lines/tan(67.5)); - float final_speed = std::min(curled_base_speed, extrusion_speed); - - float fan_speed = std::min(interpolate_speed(fan_speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer), - interpolate_speed(fan_speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer)); + const float fan_speed = std::min(interpolate_speed(fan_speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer), + interpolate_speed(fan_speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer)); OverhangSpeeds overhang_speeds = {std::min(curled_base_speed, extrusion_speed), fan_speed}; if (!config.enable_dynamic_overhang_speeds) { diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 38e606c..c17b29b 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1,4 +1,3 @@ -#include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" #include "libslic3r/Print.hpp" #include @@ -3367,7 +3366,7 @@ void GCodeProcessor::process_M108(const GCodeReader::GCodeLine& line) { // These M-codes are used by Sailfish to change active tool. // They have to be processed otherwise toolchanges will be unrecognised - // by the analyzer - see https://github.com/qidi3d/QIDISlicer/issues/2566 + // by the analyzer - see https://github.com/QIDITECH/QIDISlicer/issues/2566 if (m_flavor != gcfSailfish) return; @@ -3403,7 +3402,7 @@ void GCodeProcessor::process_M132(const GCodeReader::GCodeLine& line) { // This command is used by Makerbot to load the current home position from EEPROM // see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md - // Using this command to reset the axis origin to zero helps in fixing: https://github.com/qidi3d/QIDISlicer/issues/3082 + // Using this command to reset the axis origin to zero helps in fixing: https://github.com/QIDITECH/QIDISlicer/issues/3082 if (line.has('X')) m_origin[X] = 0.0f; @@ -3422,7 +3421,7 @@ void GCodeProcessor::process_M135(const GCodeReader::GCodeLine& line) { // These M-codes are used by MakerWare to change active tool. // They have to be processed otherwise toolchanges will be unrecognised - // by the analyzer - see https://github.com/qidi3d/QIDISlicer/issues/2566 + // by the analyzer - see https://github.com/QIDITECH/QIDISlicer/issues/2566 if (m_flavor != gcfMakerWare) return; @@ -3650,11 +3649,11 @@ void GCodeProcessor::process_T(const std::string_view command) if (command.length() > 1) { int eid = 0; if (! parse_number(command.substr(1), eid) || eid < 0 || eid > 255) { - // Specific to the MMU2 V2 (see https://www.help.qidi3d.com/en/article/qidi-specific-g-codes_112173): + // Specific to the MMU2 V2 (see https://www.wiki.qidi3d.com/en/article/qidi-specific-g-codes_112173): if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) && (command == "Tx" || command == "Tc" || command == "T?")) return; - // T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools) see https://github.com/qidi3d/QIDISlicer/issues/5677 + // T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools) see https://github.com/QIDITECH/QIDISlicer/issues/5677 if ((m_flavor != gcfRepRapFirmware && m_flavor != gcfRepRapSprinter) || eid != -1) BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange (" << command << ")."; } diff --git a/src/libslic3r/GCode/GCodeWriter.cpp b/src/libslic3r/GCode/GCodeWriter.cpp index 31951d3..f0ec47f 100644 --- a/src/libslic3r/GCode/GCodeWriter.cpp +++ b/src/libslic3r/GCode/GCodeWriter.cpp @@ -185,45 +185,25 @@ std::string GCodeWriter::set_pressure_advance(double pa) const return gcode.str(); } -//B24 -std::string GCodeWriter::set_volume_temperature(unsigned int temperature, bool wait) +std::string GCodeWriter::set_chamber_temperature(unsigned int temperature, bool wait, bool accurate) const { - if (temperature == m_last_volume_temperature && (! wait || m_last_volume_temperature_reached)) - return std::string(); - - m_last_volume_temperature = temperature; - m_last_volume_temperature_reached = wait; - - std::string code, comment; - code = "M141"; - comment = "set Volume temperature"; - // if (wait && FLAVOR_IS_NOT(gcfTeacup)) { - // if (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) { - // code = "M109"; - // } else { - // code = "M190"; - // } - // comment = "set bed temperature and wait for it to be reached"; - // } else { - // code = "M140"; - // comment = "set bed temperature"; - // } + std::string_view code, comment; + if (wait) { + code = "M191"sv; + comment = "set chamber temperature and wait for it to be reached"sv; + } else { + code = "M141"sv; + comment = "set chamber temperature"sv; + } std::ostringstream gcode; - gcode << code << " "; - if (FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMachinekit)) { - gcode << "P"; - } else { - gcode << "S"; - } - gcode << temperature << " ; " << comment << "\n"; - - // if (FLAVOR_IS(gcfTeacup) && wait) - // gcode << "M116 ; wait for bed temperature to be reached\n"; + gcode << code << (accurate ? " R" : " S") << temperature << " ; " << comment << "\n"; return gcode.str(); } + + std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration) { // Clamp the acceleration to the allowed maximum. @@ -589,7 +569,6 @@ std::string GCodeWriter::set_fan(unsigned int speed) const return GCodeWriter::set_fan(this->config.gcode_flavor, this->config.gcode_comments, speed); } - //B38 void GCodeWriter::add_object_start_labels(std::string &gcode) { @@ -613,7 +592,6 @@ void GCodeWriter::add_object_change_labels(std::string &gcode) add_object_start_labels(gcode); } - void GCodeFormatter::emit_axis(const char axis, const double v, size_t digits) { assert(digits <= 9); static constexpr const std::array pow_10{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; diff --git a/src/libslic3r/GCode/GCodeWriter.hpp b/src/libslic3r/GCode/GCodeWriter.hpp index 22b592e..1a02332 100644 --- a/src/libslic3r/GCode/GCodeWriter.hpp +++ b/src/libslic3r/GCode/GCodeWriter.hpp @@ -1,14 +1,21 @@ #ifndef slic3r_GCodeWriter_hpp_ #define slic3r_GCodeWriter_hpp_ -#include "../libslic3r.h" -#include "../Extruder.hpp" -#include "../Point.hpp" -#include "../PrintConfig.hpp" -#include "CoolingBuffer.hpp" +#include #include #include #include +#include +#include +#include +#include +#include + +#include "libslic3r/libslic3r.h" +#include "libslic3r/Extruder.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "CoolingBuffer.hpp" namespace Slic3r { @@ -21,12 +28,9 @@ public: multiple_extruders(false), m_extrusion_axis("E"), m_extruder(nullptr), m_single_extruder_multi_material(false), m_last_acceleration(0), m_max_acceleration(0), - m_last_bed_temperature(0), m_last_bed_temperature_reached(true), - //B24 - m_last_volume_temperature(0), m_last_volume_temperature_reached(true), - m_lifted(0) + m_last_bed_temperature(0), m_last_bed_temperature_reached(true), //B36 - , m_is_first_layer(true) + m_is_first_layer(true) {} Extruder* extruder() { return m_extruder; } const Extruder* extruder() const { return m_extruder; } @@ -48,10 +52,9 @@ public: std::string postamble() const; std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const; std::string set_bed_temperature(unsigned int temperature, bool wait = false); + std::string set_chamber_temperature(unsigned int temperature, bool wait, bool accurate) const; //B34 std::string set_pressure_advance(double pa) const; - //B24 - std::string set_volume_temperature(unsigned int temperature, bool wait = false); std::string set_print_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Print, acceleration); } std::string set_travel_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Travel, acceleration); } std::string reset_e(bool force = false); @@ -66,9 +69,11 @@ public: std::string toolchange_prefix() const; std::string toolchange(unsigned int extruder_id); std::string set_speed(double F, const std::string_view comment = {}, const std::string_view cooling_marker = {}) const; + std::string get_travel_to_xy_gcode(const Vec2d &point, const std::string_view comment) const; std::string travel_to_xy(const Vec2d &point, const std::string_view comment = {}); std::string travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, const std::string_view comment = {}); + /** * @brief Return gcode with all three axis defined. Optionally adds feedrate. * @@ -122,7 +127,6 @@ public: void add_object_end_labels(std::string &gcode); void add_object_change_labels(std::string &gcode); - private: // Extruders are sorted by their ID, so that binary search is possible. std::vector m_extruders; @@ -138,10 +142,6 @@ private: unsigned int m_last_bed_temperature; bool m_last_bed_temperature_reached; - //B24 - unsigned int m_last_volume_temperature; - bool m_last_volume_temperature_reached; - double m_lifted; Vec3d m_pos = Vec3d::Zero(); //B36 @@ -284,6 +284,7 @@ public: GCodeG2G3Formatter(const GCodeG2G3Formatter&) = delete; GCodeG2G3Formatter& operator=(const GCodeG2G3Formatter&) = delete; }; + } /* namespace Slic3r */ #endif /* slic3r_GCodeWriter_hpp_ */ diff --git a/src/libslic3r/GCode/SpiralVase.cpp b/src/libslic3r/GCode/SpiralVase.cpp index 2ed78f8..009daec 100644 --- a/src/libslic3r/GCode/SpiralVase.cpp +++ b/src/libslic3r/GCode/SpiralVase.cpp @@ -1,4 +1,5 @@ #include "SpiralVase.hpp" + #include #include diff --git a/src/libslic3r/GCode/Thumbnails.cpp b/src/libslic3r/GCode/Thumbnails.cpp index 26dbd84..c5c583b 100644 --- a/src/libslic3r/GCode/Thumbnails.cpp +++ b/src/libslic3r/GCode/Thumbnails.cpp @@ -98,7 +98,6 @@ std::unique_ptr compress_thumbnail_jpg(const ThumbnailDat std::string compress_thumbnail_qidi(const ThumbnailData &data) { auto out = std::make_unique(); - // BOOST_LOG_TRIVIAL(error) << data.width; int width = int(data.width); int height = int(data.height); @@ -107,10 +106,7 @@ std::string compress_thumbnail_qidi(const ThumbnailData &data) height = 500; } U16 color16[500 * 500]; - // U16 *color16 = new U16[data.width * data.height]; - // for (int i = 0; i < 200*200; i++) color16[i] = 522240; unsigned char outputdata[500 * 500 * 10]; - // unsigned char *outputdata = new unsigned char[data.width * data.height * 10]; std::vector rgba_pixels(data.pixels.size() * 4); size_t row_size = width * 4; @@ -120,7 +116,7 @@ std::string compress_thumbnail_qidi(const ThumbnailData &data) pixels = (const unsigned char *) rgba_pixels.data(); int rrrr = 0, gggg = 0, bbbb = 0, aaaa = 0, rgb = 0; - int time = width * height - 1; // 200*200-1; + int time = width * height - 1; for (unsigned int r = 0; r < height; ++r) { unsigned int rr = r * width; @@ -143,14 +139,10 @@ std::string compress_thumbnail_qidi(const ThumbnailData &data) int res = ColPic_EncodeStr(color16, width, height, outputdata, height * width * 10, 1024); std::string temp; - // for (unsigned char i : outputdata) { temp += i; } for (unsigned int i = 0; i < sizeof(outputdata); ++i) { temp += outputdata[i]; - // unsigned char strr = outputdata[i]; - // temp += strr; } - // out->data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &out->size, - // MZ_DEFAULT_LEVEL, 1); + return temp; } std::unique_ptr compress_thumbnail_qoi(const ThumbnailData &data) @@ -444,9 +436,11 @@ static int ColPicEncode(U16 *fromcolor16, int picw, int pich, U8 *outputdata, in U16 *l0 = (U16 *) &outputdata[sizeof(ColPicHead3)]; l0[i] = Listu16[i].colo16; } - enqty = Byte8bitEncode(fromcolor16, (U16 *) &outputdata[sizeof(ColPicHead3)], Head0->ListDataSize >> 1, dotsqty, - &outputdata[sizeof(ColPicHead3) + Head0->ListDataSize], - outputmaxtsize - sizeof(ColPicHead3) - Head0->ListDataSize); + enqty = Byte8bitEncode(fromcolor16, (U16 *) &outputdata[sizeof(ColPicHead3)], + Head0->ListDataSize >> 1, + dotsqty, + &outputdata[sizeof(ColPicHead3) + Head0->ListDataSize], + outputmaxtsize - sizeof(ColPicHead3) - Head0->ListDataSize); Head0->ColorDataSize = enqty; Head0->PicW = picw; Head0->PicH = pich; @@ -508,5 +502,4 @@ int ColPic_EncodeStr(U16 *fromcolor16, int picw, int pich, U8 *outputdata, int o return qty; } - } // namespace Slic3r::GCodeThumbnails diff --git a/src/libslic3r/GCode/Thumbnails.hpp b/src/libslic3r/GCode/Thumbnails.hpp index 2e63739..a800e82 100644 --- a/src/libslic3r/GCode/Thumbnails.hpp +++ b/src/libslic3r/GCode/Thumbnails.hpp @@ -31,7 +31,6 @@ class ConfigBase; ENABLE_ENUM_BITMASK_OPERATORS(ThumbnailError); } - //B3 typedef struct { @@ -77,7 +76,6 @@ std::pair make_and_check_thumbna std::string get_error_string(const ThumbnailErrors& errors); - //B3 std::string compress_qidi_thumbnail(const ThumbnailData &data, GCodeThumbnailsFormat format); int ColPic_EncodeStr(U16 *fromcolor16, int picw, int pich, U8 *outputdata, int outputmaxtsize, int colorsmax); @@ -89,57 +87,42 @@ inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, //B3 int count = 0; for (const auto& [format, size] : thumbnails_list) { - static constexpr const size_t max_row_length = 78; - //B54 - ThumbnailsList thumbnails = thumbnail_cb(ThumbnailsParams{{size}, true, false, false, false}); - for (const ThumbnailData& data : thumbnails) - if (data.is_valid()) { - switch (format) { - case GCodeThumbnailsFormat::QIDI: { - //auto compressed = compress_qidi_thumbnail(data, format); - - //if (count == 0) { - // output((boost::format("\n\n;gimage:%s\n\n") % compressed).str().c_str()); - // count++; - // break; - //} else { - // output((boost::format("\n\n;simage:%s\n\n") % compressed).str().c_str()); - // count++; - // break; - //} - break; - } - default: { - auto compressed = compress_thumbnail(data, format); - if (compressed->data && compressed->size) { - std::string encoded; - encoded.resize(boost::beast::detail::base64::encoded_size(compressed->size)); - encoded.resize(boost::beast::detail::base64::encode((void *) encoded.data(), (const void *) compressed->data, - compressed->size)); - - output((boost::format("\n;\n; %s begin %dx%d %d\n") % compressed->tag() % data.width % data.height % encoded.size()) - .str() - .c_str()); - - while (encoded.size() > max_row_length) { - output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str()); - encoded = encoded.substr(max_row_length); + static constexpr const size_t max_row_length = 78; + //B54 + ThumbnailsList thumbnails = thumbnail_cb(ThumbnailsParams{ {size}, true, false, false, false}); + for (const ThumbnailData& data : thumbnails) { + if (data.is_valid()) { + switch (format) { + case GCodeThumbnailsFormat::QIDI: { + break; } + default: { + auto compressed = compress_thumbnail(data, format); + if (compressed->data && compressed->size) { + std::string encoded; + encoded.resize(boost::beast::detail::base64::encoded_size(compressed->size)); + encoded.resize(boost::beast::detail::base64::encode((void*)encoded.data(), (const void*)compressed->data, compressed->size)); - if (encoded.size() > 0) - output((boost::format("; %s\n") % encoded).str().c_str()); + output((boost::format("\n;\n; %s begin %dx%d %d\n") % compressed->tag() % data.width % data.height % encoded.size()).str().c_str()); - output((boost::format("; %s end\n;\n") % compressed->tag()).str().c_str()); + while (encoded.size() > max_row_length) { + output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str()); + encoded = encoded.substr(max_row_length); + } + if (encoded.size() > 0) + output((boost::format("; %s\n") % encoded).str().c_str()); + + output((boost::format("; %s end\n;\n") % compressed->tag()).str().c_str()); + } + } } + throw_if_canceled(); } - - } - throw_if_canceled(); } + } } } -} //B3 template inline void export_qidi_thumbnails_to_file(ThumbnailsGeneratorCallback & thumbnail_cb, @@ -154,49 +137,27 @@ inline void export_qidi_thumbnails_to_file(ThumbnailsGeneratorCallback & for (const auto &[format, size] : thumbnails_list) { static constexpr const size_t max_row_length = 78; ThumbnailsList thumbnails = thumbnail_cb(ThumbnailsParams{{size}, true, false, false, true}); - for (const ThumbnailData &data : thumbnails) + for (const ThumbnailData &data : thumbnails) { if (data.is_valid()) { switch (format) { - case GCodeThumbnailsFormat::QIDI: { - auto compressed = compress_qidi_thumbnail(data, format); + case GCodeThumbnailsFormat::QIDI: { + auto compressed = compress_qidi_thumbnail(data, format); - if (count == 0) { - output((boost::format("\n\n;gimage:%s\n\n") % compressed).str().c_str()); - count++; - break; - } else { - output((boost::format("\n\n;simage:%s\n\n") % compressed).str().c_str()); - count++; - break; + if (count == 0) { + output((boost::format("\n\n;gimage:%s\n\n") % compressed).str().c_str()); + count++; + break; + } else { + output((boost::format("\n\n;simage:%s\n\n") % compressed).str().c_str()); + count++; + break; + } } - } - default: { - //auto compressed = compress_thumbnail(data, format); - //if (compressed->data && compressed->size) { - // std::string encoded; - // encoded.resize(boost::beast::detail::base64::encoded_size(compressed->size)); - // encoded.resize(boost::beast::detail::base64::encode((void *) encoded.data(), (const void *) compressed->data, - // compressed->size)); - - // output((boost::format("\n;\n; %s begin %dx%d %d\n") % compressed->tag() % data.width % data.height % - // encoded.size()) - // .str() - // .c_str()); - - // while (encoded.size() > max_row_length) { - // output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str()); - // encoded = encoded.substr(max_row_length); - // } - - // if (encoded.size() > 0) - // output((boost::format("; %s\n") % encoded).str().c_str()); - - // output((boost::format("; %s end\n;\n") % compressed->tag()).str().c_str()); - //} - } + default: { } } throw_if_canceled(); } + } } } } diff --git a/src/libslic3r/GCode/Wipe.cpp b/src/libslic3r/GCode/Wipe.cpp index 99e28ca..7062503 100644 --- a/src/libslic3r/GCode/Wipe.cpp +++ b/src/libslic3r/GCode/Wipe.cpp @@ -90,7 +90,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange) //w15 const double wipe_dist_max = gcodegen.writer().config.wipe_distance.get_at(extruder.id()); double wipe_dist = 0; - auto wipe_linear = [&gcode, &gcodegen, &retract_length, xy_to_e, wipe_dist_max, &wipe_dist,extruder](const Vec2d &prev_quantized, Vec2d &p) { + auto wipe_linear = [&gcode, &gcodegen, &retract_length, xy_to_e, wipe_dist_max, &wipe_dist,extruder](const Vec2d &prev_quantized, Vec2d &p) { Vec2d p_quantized = GCodeFormatter::quantize(p); if (p_quantized == prev_quantized) { p = p_quantized; @@ -99,7 +99,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange) double segment_length = (p_quantized - prev_quantized).norm(); // Quantize E axis as it is to be extruded as a whole segment. // w15 - double dE = retract_length * segment_length / wipe_dist_max; + double dE = retract_length * segment_length / wipe_dist_max; bool done = false; if (dE > retract_length - EPSILON) { if (dE > retract_length + EPSILON) @@ -139,13 +139,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange) float angle = Geometry::ArcWelder::arc_angle(prev_quantized.cast(), p_quantized.cast(), double(radius)); assert(angle > 0); double segment_length = angle * std::abs(radius); - wipe_dist += segment_length; - if (wipe_dist > wipe_dist_max) { - angle = angle * (wipe_dist_max - wipe_dist + segment_length) / segment_length; - segment_length = wipe_dist_max - wipe_dist + segment_length; - } double dE = GCodeFormatter::quantize_e(xy_to_e * segment_length); - dE = retract_length * segment_length / wipe_dist_max; bool done = false; if (dE > retract_length - EPSILON) { if (dE > retract_length + EPSILON) { @@ -154,12 +148,12 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange) angle = Geometry::ArcWelder::arc_angle(prev_quantized.cast(), p.cast(), double(radius)); segment_length = angle * std::abs(radius); //w15 - dE = retract_length* segment_length / wipe_dist_max ; + dE = retract_length* segment_length / wipe_dist_max; p = GCodeFormatter::quantize( Vec2d(center + Eigen::Rotation2D((ccw ? angle : -angle) * (retract_length / dE)) * (prev_quantized - center))); } else p = p_quantized; - //dE = retract_length; + dE = retract_length; done = true; } else p = p_quantized; @@ -207,8 +201,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange) } if (wiped) { // add tag for processor - Vec2d test = GCodeFormatter::quantize(p); - // assert(p == GCodeFormatter::quantize(p)); + assert(p == GCodeFormatter::quantize(p)); gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n"; gcodegen.last_position = gcodegen.gcode_to_point(p); } diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index d0398b5..e2bfdd4 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -370,7 +370,7 @@ public: // Let the firmware back up the active speed override value. WipeTowerWriter& speed_override_backup() { - // This is only supported by QIDI at this point (https://github.com/qidi3d/QIDISlicer/issues/3114) + // This is only supported by QIDI at this point (https://github.com/QIDITECH/QIDISlicer/issues/3114) if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware) m_gcode += "M220 B\n"; return *this; @@ -1085,7 +1085,7 @@ void WipeTower::toolchange_Change( // gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the // postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before. Vec2f current_pos = writer.pos_rotated(); - writer.feedrate(m_travel_speed * 60.f) // see https://github.com/qidi3d/QIDISlicer/issues/5483 + writer.feedrate(m_travel_speed * 60.f) // see https://github.com/QIDITECH/QIDISlicer/issues/5483 .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x()) + " Y" + Slic3r::float_to_string_decimal_point(current_pos.y()) + never_skip_tag() + "\n" diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index d7b25ea..14b54a7 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -68,7 +68,7 @@ public: // Pass a polyline so that normal G-code generator can do a wipe for us. // The wipe cannot be done by the wipe tower because it has to pass back // a loaded extruder, so it would have to either do a wipe with no retraction - // (leading to https://github.com/qidi3d/QIDISlicer/issues/2834) or do + // (leading to https://github.com/QIDITECH/QIDISlicer/issues/2834) or do // an extra retraction-unretraction pair. std::vector wipe_path; diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 402983d..e43f8ea 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -697,10 +697,7 @@ void Layer::make_perimeters() && config.infill_overlap == other_config.infill_overlap && config.fuzzy_skin == other_config.fuzzy_skin && config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness - && config.fuzzy_skin_point_dist == other_config.fuzzy_skin_point_dist - //w38 - && config.overhang_reverse == other_config.overhang_reverse - && config.overhang_reverse_threshold == other_config.overhang_reverse_threshold) + && config.fuzzy_skin_point_dist == other_config.fuzzy_skin_point_dist) { layer_region_reset_perimeters(*other_layerm); layer_region_ids.push_back(it - m_regions.begin()); diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index c0390f0..f42021b 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -125,47 +125,20 @@ void LayerRegion::make_perimeters( // Cummulative sum of polygons over all the regions. const ExPolygons *lower_slices = this->layer()->lower_layer ? &this->layer()->lower_layer->lslices : nullptr; - //w16 const ExPolygons *upper_slices = this->layer()->upper_layer ? &this->layer()->upper_layer->lslices : nullptr; // Cache for offsetted lower_slices Polygons lower_layer_polygons_cache; - //w16 - Polygons upper_layer_polygons_cache; - //w38 - params.lower_slices = lower_slices; for (const Surface &surface : slices) { auto perimeters_begin = uint32_t(m_perimeters.size()); auto gap_fills_begin = uint32_t(m_thin_fills.size()); auto fill_expolygons_begin = uint32_t(fill_expolygons.size()); if (this->layer()->object()->config().perimeter_generator.value == PerimeterGeneratorType::Arachne && !spiral_vase) - - //w16 - if (this->layer()->object()->config().top_one_wall_type == TopOneWallType::Alltop) - PerimeterGenerator::process_with_one_wall_arachne( + PerimeterGenerator::process_arachne( // input: params, surface, lower_slices, - //w16 - upper_slices, - lower_layer_polygons_cache, - upper_layer_polygons_cache, - // output: - m_perimeters, - m_thin_fills, - fill_expolygons, - //w21 - fill_no_overlap_expolygons, - //w23 - this->layer()->id()); - else - PerimeterGenerator::process_arachne( - // input: - params, - surface, - lower_slices, - //w16 upper_slices, lower_layer_polygons_cache, // output: @@ -173,28 +146,21 @@ void LayerRegion::make_perimeters( m_thin_fills, fill_expolygons, //w21 - fill_no_overlap_expolygons, - //w23 - this->layer()->id()); - + fill_no_overlap_expolygons); else PerimeterGenerator::process_classic( // input: params, surface, lower_slices, - //w16 upper_slices, lower_layer_polygons_cache, - upper_layer_polygons_cache, // output: m_perimeters, m_thin_fills, fill_expolygons, //w21 - fill_no_overlap_expolygons, - //w23 - this->layer()->id()); + fill_no_overlap_expolygons); perimeter_and_gapfill_ranges.emplace_back( ExtrusionRange{ perimeters_begin, uint32_t(m_perimeters.size()) }, ExtrusionRange{ gap_fills_begin, uint32_t(m_thin_fills.size()) }); @@ -224,25 +190,23 @@ static ExPolygons fill_surfaces_extract_expolygons(Surfaces &surfaces, std::init return out; } - - // Cache for detecting bridge orientation and merging regions with overlapping expansions. - struct Bridge { - ExPolygon expolygon; - uint32_t group_id; +// Cache for detecting bridge orientation and merging regions with overlapping expansions. +struct Bridge { + ExPolygon expolygon; + uint32_t group_id; std::vector::const_iterator bridge_expansion_begin; - std::optional angle{std::nullopt}; - }; +}; - // Group the bridge surfaces by overlaps. +// Group the bridge surfaces by overlaps. uint32_t group_id(std::vector &bridges, uint32_t src_id) { - uint32_t group_id = bridges[src_id].group_id; - while (group_id != src_id) { - src_id = group_id; - group_id = bridges[src_id].group_id; - } - bridges[src_id].group_id = group_id; - return group_id; - }; + uint32_t group_id = bridges[src_id].group_id; + while (group_id != src_id) { + src_id = group_id; + group_id = bridges[src_id].group_id; + } + bridges[src_id].group_id = group_id; + return group_id; +}; std::vector get_grouped_bridges( ExPolygons&& bridge_expolygons, @@ -258,8 +222,10 @@ std::vector get_grouped_bridges( for (ExPolygon& expolygon : bridge_expolygons) result.push_back({ std::move(expolygon), group_id ++, bridge_expansions.end() }); } - // Detect overlaps of bridge anchors inside their respective shell regions. - // bridge_expansions are sorted by boundary id and source id. + + + // Detect overlaps of bridge anchors inside their respective shell regions. + // bridge_expansions are sorted by boundary id and source id. for (auto expansion_iterator = bridge_expansions.begin(); expansion_iterator != bridge_expansions.end();) { auto boundary_region_begin = expansion_iterator; auto boundary_region_end = std::find_if( @@ -281,7 +247,8 @@ std::vector get_grouped_bridges( return get_extents(expansion.expolygon.contour); } ); - // For each bridge anchor of the current source: + + // For each bridge anchor of the current source: for (;expansion_iterator != boundary_region_end; ++expansion_iterator) { auto candidate_iterator = std::next(expansion_iterator); for (;candidate_iterator != boundary_region_end; ++candidate_iterator) { @@ -294,107 +261,66 @@ std::vector get_grouped_bridges( if ( expansion_iterator->src_id != candidate_iterator->src_id && current_bounding_box.overlap(candidate_bounding_box) - // One may ignore holes, they are irrelevant for intersection test. + // One may ignore holes, they are irrelevant for intersection test. && !intersection(expansion_iterator->expolygon.contour, candidate_iterator->expolygon.contour).empty() ) { - // The two bridge regions intersect. Give them the same (lower) group id. + // The two bridge regions intersect. Give them the same (lower) group id. uint32_t id = group_id(result, expansion_iterator->src_id); uint32_t id2 = group_id(result, candidate_iterator->src_id); - if (id < id2) + if (id < id2) result[id2].group_id = id; - else + else result[id].group_id = id2; - } + } } } } return result; } -void detect_bridge_directions( - const Algorithm::WaveSeeds& bridge_anchors, - std::vector& bridges, - const std::vector& expansion_zones -) { - if (expansion_zones.empty()) { - throw std::runtime_error("At least one expansion zone must exist!"); - } - auto it_bridge_anchor = bridge_anchors.begin(); - for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++ bridge_id) { - Bridge &bridge = bridges[bridge_id]; - Polygons anchor_areas; - int32_t last_anchor_id = -1; - for (; it_bridge_anchor != bridge_anchors.end() && it_bridge_anchor->src == bridge_id; ++ it_bridge_anchor) { - if (last_anchor_id != int(it_bridge_anchor->boundary)) { - last_anchor_id = int(it_bridge_anchor->boundary); - unsigned start_index{}; - unsigned end_index{}; - for (const ExpansionZone& expansion_zone: expansion_zones) { - end_index += expansion_zone.expolygons.size(); - if (last_anchor_id < static_cast(end_index)) { - append(anchor_areas, to_polygons(expansion_zone.expolygons[last_anchor_id - start_index])); - break; - } - start_index += expansion_zone.expolygons.size(); - } - } - } - Lines lines{to_lines(diff_pl(to_polylines(bridge.expolygon), expand(anchor_areas, float(SCALED_EPSILON))))}; - auto [bridging_dir, unsupported_dist] = detect_bridging_direction(lines, to_polygons(bridge.expolygon)); - bridge.angle = M_PI + std::atan2(bridging_dir.y(), bridging_dir.x()); - if constexpr (false) { - coordf_t stroke_width = scale_(0.06); - BoundingBox bbox = get_extents(anchor_areas); - bbox.merge(get_extents(bridge.expolygon)); - bbox.offset(scale_(1.)); - ::Slic3r::SVG - svg(debug_out_path(("bridge" + std::to_string(*bridge.angle) + "_" /* + std::to_string(this->layer()->bottom_z())*/).c_str()), - bbox); - svg.draw(bridge.expolygon, "cyan"); - svg.draw(lines, "green", stroke_width); - svg.draw(anchor_areas, "red"); - } - } - } - Surfaces merge_bridges( std::vector& bridges, const std::vector& bridge_expansions, const float closing_radius ) { - for (auto it = bridge_expansions.begin(); it != bridge_expansions.end(); ) { - bridges[it->src_id].bridge_expansion_begin = it; - uint32_t src_id = it->src_id; - for (++ it; it != bridge_expansions.end() && it->src_id == src_id; ++ it) ; - } + for (auto it = bridge_expansions.begin(); it != bridge_expansions.end(); ) { + bridges[it->src_id].bridge_expansion_begin = it; + uint32_t src_id = it->src_id; + for (++ it; it != bridge_expansions.end() && it->src_id == src_id; ++ it) ; + } + Surfaces result; for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++ bridge_id) { if (group_id(bridges, bridge_id) == bridge_id) { - // Head of the group. - Polygons acc; - for (uint32_t bridge_id2 = bridge_id; bridge_id2 < uint32_t(bridges.size()); ++ bridge_id2) + // Head of the group. + Polygons bridge_group; + Polygons expansions; + for (uint32_t bridge_id2 = bridge_id; bridge_id2 < uint32_t(bridges.size()); ++ bridge_id2) { if (group_id(bridges, bridge_id2) == bridge_id) { - append(acc, to_polygons(std::move(bridges[bridge_id2].expolygon))); - auto it_bridge_expansion = bridges[bridge_id2].bridge_expansion_begin; - assert(it_bridge_expansion == bridge_expansions.end() || it_bridge_expansion->src_id == bridge_id2); - for (; it_bridge_expansion != bridge_expansions.end() && it_bridge_expansion->src_id == bridge_id2; ++ it_bridge_expansion) - append(acc, to_polygons(it_bridge_expansion->expolygon)); - } - //FIXME try to be smart and pick the best bridging angle for all? - if (!bridges[bridge_id].angle) { - assert(false && "Bridge angle must be pre-calculated!"); + append(bridge_group, to_polygons(std::move(bridges[bridge_id2].expolygon))); + auto it_bridge_expansion = bridges[bridge_id2].bridge_expansion_begin; + assert(it_bridge_expansion == bridge_expansions.end() || it_bridge_expansion->src_id == bridge_id2); + for (; it_bridge_expansion != bridge_expansions.end() && it_bridge_expansion->src_id == bridge_id2; ++ it_bridge_expansion) + append(expansions, to_polygons(it_bridge_expansion->expolygon)); + } } - Surface templ{ stBottomBridge, {} }; - templ.bridge_angle = bridges[bridge_id].angle ? *bridges[bridge_id].angle : -1; - //NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy) - // without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface. - // look for narrow_ensure_vertical_wall_thickness_region_radius filter. - ExPolygons final = closing_ex(acc, closing_radius); - // without safety offset, artifacts are generated (GH #2494) - // union_safety_offset_ex(acc) - for (ExPolygon &ex : final) - result.emplace_back(templ, std::move(ex)); + append(bridge_group, expansions); + + //NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy) + // without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface. + // look for narrow_ensure_vertical_wall_thickness_region_radius filter. + ExPolygons merged_bridges = closing_ex(bridge_group, closing_radius); + // without safety offset, artifacts are generated (GH #2494) + // union_safety_offset_ex(acc) + + for (ExPolygon &bridge_expolygon : merged_bridges) { + Surface surface{ stBottomBridge, std::move(bridge_expolygon) }; + const Lines lines{to_lines(diff_pl(to_polylines(bridge_expolygon), expand(expansions, float(SCALED_EPSILON))))}; + auto [bridging_dir, unsupported_dist] = detect_bridging_direction(lines, to_polygons(bridge_expolygon)); + surface.bridge_angle = M_PI + std::atan2(bridging_dir.y(), bridging_dir.x()); + result.push_back(std::move(surface)); } + } } return result; } @@ -444,241 +370,85 @@ ExpansionResult expand_expolygons( // Extract bridging surfaces from "surfaces", expand them into "shells" using expansion_params, // detect bridges. // Trim "shells" by the expanded bridges. -//w36 -Surfaces expand_bridges_detect_orientations(Surfaces & surfaces, - ExPolygons & shells, - const Algorithm::RegionExpansionParameters &expansion_params_into_solid_infill, - ExPolygons & sparse, - const Algorithm::RegionExpansionParameters &expansion_params_into_sparse_infill, - const float closing_radius) +Surfaces expand_bridges_detect_orientations( + Surfaces &surfaces, + std::vector& expansion_zones, + const float closing_radius +) { using namespace Slic3r::Algorithm; - //w36 - double thickness; - ExPolygons bridges_ex = fill_surfaces_extract_expolygons(surfaces, {stBottomBridge}, thickness); - if (bridges_ex.empty()) + double thickness; + ExPolygons bridge_expolygons = fill_surfaces_extract_expolygons(surfaces, {stBottomBridge}, thickness); + if (bridge_expolygons.empty()) return {}; // Calculate bridge anchors and their expansions in their respective shell region. - //w36 - WaveSeeds bridge_anchors = wave_seeds(bridges_ex, shells, expansion_params_into_solid_infill.tiny_expansion, true); - std::vector bridge_expansions = propagate_waves_ex(bridge_anchors, shells, expansion_params_into_solid_infill); - bool expanded_into_shells = !bridge_expansions.empty(); - bool expanded_into_sparse = false; - { - WaveSeeds bridge_anchors_sparse = wave_seeds(bridges_ex, sparse, expansion_params_into_sparse_infill.tiny_expansion, true); - std::vector bridge_expansions_sparse = propagate_waves_ex(bridge_anchors_sparse, sparse, - expansion_params_into_sparse_infill); - if (!bridge_expansions_sparse.empty()) { - expanded_into_sparse = true; - for (WaveSeed &seed : bridge_anchors_sparse) - seed.boundary += uint32_t(shells.size()); - for (RegionExpansionEx &expansion : bridge_expansions_sparse) - expansion.boundary_id += uint32_t(shells.size()); - append(bridge_anchors, std::move(bridge_anchors_sparse)); - append(bridge_expansions, std::move(bridge_expansions_sparse)); - } - } + ExpansionResult expansion_result{expand_expolygons( + bridge_expolygons, + expansion_zones + )}; - // Cache for detecting bridge orientation and merging regions with overlapping expansions. - struct Bridge - { - ExPolygon expolygon; - uint32_t group_id; - std::vector::const_iterator bridge_expansion_begin; - double angle = -1; - }; - std::vector bridges; - { - bridges.reserve(bridges_ex.size()); - uint32_t group_id = 0; - for (ExPolygon &ex : bridges_ex) - bridges.push_back({std::move(ex), group_id++, bridge_expansions.end()}); - bridges_ex.clear(); - } + std::vector bridges{get_grouped_bridges( + std::move(bridge_expolygons), + expansion_result.expansions + )}; + bridge_expolygons.clear(); - // Group the bridge surfaces by overlaps. - auto group_id = [&bridges](uint32_t src_id) { - uint32_t group_id = bridges[src_id].group_id; - while (group_id != src_id) { - src_id = group_id; - group_id = bridges[src_id].group_id; - } - bridges[src_id].group_id = group_id; - return group_id; - }; - - { - // Cache of bboxes per expansion boundary. - std::vector bboxes; - // Detect overlaps of bridge anchors inside their respective shell regions. - // bridge_expansions are sorted by boundary id and source id. - for (auto it = bridge_expansions.begin(); it != bridge_expansions.end();) { - // For each boundary region: - auto it_begin = it; - auto it_end = std::next(it_begin); - for (; it_end != bridge_expansions.end() && it_end->boundary_id == it_begin->boundary_id; ++it_end) - ; - bboxes.clear(); - bboxes.reserve(it_end - it_begin); - for (auto it2 = it_begin; it2 != it_end; ++it2) - bboxes.emplace_back(get_extents(it2->expolygon.contour)); - // For each bridge anchor of the current source: - for (; it != it_end; ++it) { - // A grup id for this bridge. - for (auto it2 = std::next(it); it2 != it_end; ++it2) - if (it->src_id != it2->src_id && bboxes[it - it_begin].overlap(bboxes[it2 - it_begin]) && - // One may ignore holes, they are irrelevant for intersection test. - !intersection(it->expolygon.contour, it2->expolygon.contour).empty()) { - // The two bridge regions intersect. Give them the same (lower) group id. - uint32_t id = group_id(it->src_id); - uint32_t id2 = group_id(it2->src_id); - if (id < id2) - bridges[id2].group_id = id; - else - bridges[id].group_id = id2; - } - } - } - } - - // Detect bridge directions. - { - std::sort(bridge_anchors.begin(), bridge_anchors.end(), Algorithm::lower_by_src_and_boundary); - auto it_bridge_anchor = bridge_anchors.begin(); - Lines lines; - Polygons anchor_areas; - for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++bridge_id) { - Bridge &bridge = bridges[bridge_id]; - // lines.clear(); - anchor_areas.clear(); - int32_t last_anchor_id = -1; - for (; it_bridge_anchor != bridge_anchors.end() && it_bridge_anchor->src == bridge_id; ++it_bridge_anchor) { - if (last_anchor_id != int(it_bridge_anchor->boundary)) { - last_anchor_id = int(it_bridge_anchor->boundary); - append(anchor_areas, - to_polygons(last_anchor_id < int32_t(shells.size()) ? shells[last_anchor_id] : - sparse[last_anchor_id - int32_t(shells.size())])); - } - // if (Points &polyline = it_bridge_anchor->path; polyline.size() >= 2) { - // reserve_more_power_of_2(lines, polyline.size() - 1); - // for (size_t i = 1; i < polyline.size(); ++ i) - // lines.push_back({ polyline[i - 1], polyline[1] }); - // } - } - lines = to_lines(diff_pl(to_polylines(bridge.expolygon), expand(anchor_areas, float(SCALED_EPSILON)))); - auto [bridging_dir, unsupported_dist] = detect_bridging_direction(lines, to_polygons(bridge.expolygon)); - bridge.angle = M_PI + std::atan2(bridging_dir.y(), bridging_dir.x()); -#if 0 - coordf_t stroke_width = scale_(0.06); - BoundingBox bbox = get_extents(anchor_areas); - bbox.merge(get_extents(bridge.expolygon)); - bbox.offset(scale_(1.)); - ::Slic3r::SVG - svg(debug_out_path(("bridge" + std::to_string(bridge.angle) + "_" /* + std::to_string(this->layer()->bottom_z())*/).c_str()), - bbox); - svg.draw(bridge.expolygon, "cyan"); - svg.draw(lines, "green", stroke_width); - svg.draw(anchor_areas, "red"); -#endif - } - } + std::sort(expansion_result.anchors.begin(), expansion_result.anchors.end(), Algorithm::lower_by_src_and_boundary); // Merge the groups with the same group id, produce surfaces by merging source overhangs with their newly expanded anchors. - //w36 - Surfaces out; - { - Polygons acc; - Surface templ{stBottomBridge, {}}; - std::sort(bridge_expansions.begin(), bridge_expansions.end(), - [](auto &l, auto &r) { return l.src_id < r.src_id || (l.src_id == r.src_id && l.boundary_id < r.boundary_id); }); - for (auto it = bridge_expansions.begin(); it != bridge_expansions.end();) { - bridges[it->src_id].bridge_expansion_begin = it; - uint32_t src_id = it->src_id; - for (++it; it != bridge_expansions.end() && it->src_id == src_id; ++it) - ; - } - for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++bridge_id) - if (group_id(bridge_id) == bridge_id) { - // Head of the group. - acc.clear(); - for (uint32_t bridge_id2 = bridge_id; bridge_id2 < uint32_t(bridges.size()); ++bridge_id2) - if (group_id(bridge_id2) == bridge_id) { - append(acc, to_polygons(std::move(bridges[bridge_id2].expolygon))); - auto it_bridge_expansion = bridges[bridge_id2].bridge_expansion_begin; - assert(it_bridge_expansion == bridge_expansions.end() || it_bridge_expansion->src_id == bridge_id2); - for (; it_bridge_expansion != bridge_expansions.end() && it_bridge_expansion->src_id == bridge_id2; - ++it_bridge_expansion) - append(acc, to_polygons(std::move(it_bridge_expansion->expolygon))); - } - // FIXME try to be smart and pick the best bridging angle for all? - templ.bridge_angle = bridges[bridge_id].angle; - // NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy) - // without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface. - // look for narrow_ensure_vertical_wall_thickness_region_radius filter. - ExPolygons final = closing_ex(acc, closing_radius); - // without safety offset, artifacts are generated (GH #2494) - // union_safety_offset_ex(acc) - for (ExPolygon &ex : final) - out.emplace_back(templ, std::move(ex)); - } - } + std::sort(expansion_result.expansions.begin(), expansion_result.expansions.end(), [](auto &l, auto &r) { + return l.src_id < r.src_id || (l.src_id == r.src_id && l.boundary_id < r.boundary_id); + }); + Surfaces out{merge_bridges(bridges, expansion_result.expansions, closing_radius)}; // Clip by the expanded bridges. - //w36 - if (expanded_into_shells) - shells = diff_ex(shells, out); - if (expanded_into_sparse) - sparse = diff_ex(sparse, out); + for (ExpansionZone& expansion_zone : expansion_zones) + if (expansion_zone.expanded_into) + expansion_zone.expolygons = diff_ex(expansion_zone.expolygons, out); return out; } -//w36 - Surfaces expand_merge_surfaces(Surfaces & surfaces, - SurfaceType surface_type, - ExPolygons & shells, - const Algorithm::RegionExpansionParameters &expansion_params_into_solid_infill, - ExPolygons & sparse, - const Algorithm::RegionExpansionParameters &expansion_params_into_sparse_infill, - const float closing_radius, - const double bridge_angle ) +Surfaces expand_merge_surfaces( + Surfaces &surfaces, + SurfaceType surface_type, + std::vector& expansion_zones, + const float closing_radius, + const double bridge_angle +) { using namespace Slic3r::Algorithm; - double thickness; + double thickness; ExPolygons src = fill_surfaces_extract_expolygons(surfaces, {surface_type}, thickness); if (src.empty()) return {}; - //w36 + unsigned processed_expolygons_count = 0; + std::vector expansions; + for (ExpansionZone& expansion_zone : expansion_zones) { + std::vector zone_expansions = propagate_waves(src, expansion_zone.expolygons, expansion_zone.parameters); + expansion_zone.expanded_into = !zone_expansions.empty(); - std::vector expansions = propagate_waves(src, shells, expansion_params_into_solid_infill); - bool expanded_into_shells = !expansions.empty(); - bool expanded_into_sparse = false; - { - std::vector expansions2 = propagate_waves(src, sparse, expansion_params_into_sparse_infill); - if (!expansions2.empty()) { - expanded_into_sparse = true; - for (RegionExpansion &expansion : expansions2) - expansion.boundary_id += uint32_t(shells.size()); - append(expansions, std::move(expansions2)); - } + for (RegionExpansion &expansion : zone_expansions) + expansion.boundary_id += processed_expolygons_count; + + processed_expolygons_count += expansion_zone.expolygons.size(); + append(expansions, std::move(zone_expansions)); } std::vector expanded = merge_expansions_into_expolygons(std::move(src), std::move(expansions)); - // NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy) + //NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy) // without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface. // look for narrow_ensure_vertical_wall_thickness_region_radius filter. expanded = closing_ex(expanded, closing_radius); - // Trim the shells by the expanded expolygons. - //w36 - if (expanded_into_shells) - shells = diff_ex(shells, expanded); - if (expanded_into_sparse) - sparse = diff_ex(sparse, expanded); + // Trim the zones by the expanded expolygons. + for (ExpansionZone& expansion_zone : expansion_zones) + if (expansion_zone.expanded_into) + expansion_zone.expolygons = diff_ex(expansion_zone.expolygons, expanded); - Surface templ{surface_type, {}}; + Surface templ{ surface_type, {} }; templ.bridge_angle = bridge_angle; Surfaces out; out.reserve(expanded.size()); @@ -696,54 +466,52 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ // Width of the perimeters. - float shell_width = 0; + float shell_width = 0; float expansion_min = 0; if (int num_perimeters = this->region().config().perimeters; num_perimeters > 0) { Flow external_perimeter_flow = this->flow(frExternalPerimeter); Flow perimeter_flow = this->flow(frPerimeter); - shell_width = 0.5f * external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing(); + shell_width = 0.5f * external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing(); shell_width += perimeter_flow.scaled_spacing() * (num_perimeters - 1); expansion_min = perimeter_flow.scaled_spacing(); } else { // TODO: Maybe there is better solution when printing with zero perimeters, but this works reasonably well, given the situation shell_width = float(SCALED_EPSILON); - expansion_min = float(SCALED_EPSILON); - ; + expansion_min = float(SCALED_EPSILON);; } // Scaled expansions of the respective external surfaces. - float expansion_top = shell_width * sqrt(2.); - float expansion_bottom = expansion_top; - float expansion_bottom_bridge = expansion_top; + float expansion_top = shell_width * sqrt(2.); + float expansion_bottom = expansion_top; + float expansion_bottom_bridge = expansion_top; // Expand by waves of expansion_step size (expansion_step is scaled), but with no more steps than max_nr_expansion_steps. - static constexpr const float expansion_step = scaled(0.1); + static constexpr const float expansion_step = scaled(0.1); // Don't take more than max_nr_steps for small expansion_step. - static constexpr const size_t max_nr_expansion_steps = 5; - // Radius (with added epsilon) to absorb empty regions emering from regularization of ensuring, viz const float - // narrow_ensure_vertical_wall_thickness_region_radius = 0.5f * 0.65f * min_perimeter_infill_spacing; + static constexpr const size_t max_nr_expansion_steps = 5; + // Radius (with added epsilon) to absorb empty regions emering from regularization of ensuring, viz const float narrow_ensure_vertical_wall_thickness_region_radius = 0.5f * 0.65f * min_perimeter_infill_spacing; const float closing_radius = 0.55f * 0.65f * 1.05f * this->flow(frSolidInfill).scaled_spacing(); // Expand the top / bottom / bridge surfaces into the shell thickness solid infills. double layer_thickness; - //w36 - ExPolygons shells = union_ex(fill_surfaces_extract_expolygons(m_fill_surfaces.surfaces, {stInternalSolid}, layer_thickness)); - ExPolygons sparse = union_ex(fill_surfaces_extract_expolygons(m_fill_surfaces.surfaces, {stInternal}, layer_thickness)); + ExPolygons shells = union_ex(fill_surfaces_extract_expolygons(m_fill_surfaces.surfaces, { stInternalSolid }, layer_thickness)); + ExPolygons sparse = union_ex(fill_surfaces_extract_expolygons(m_fill_surfaces.surfaces, { stInternal }, layer_thickness)); + ExPolygons top_expolygons = union_ex(fill_surfaces_extract_expolygons(m_fill_surfaces.surfaces, { stTop }, layer_thickness)); + const auto expansion_params_into_sparse_infill = RegionExpansionParameters::build(expansion_min, expansion_step, max_nr_expansion_steps); + const auto expansion_params_into_solid_infill = RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step, max_nr_expansion_steps); + + std::vector expansion_zones{ + ExpansionZone{std::move(shells), expansion_params_into_solid_infill}, + ExpansionZone{std::move(sparse), expansion_params_into_sparse_infill}, + ExpansionZone{std::move(top_expolygons), expansion_params_into_solid_infill}, + }; SurfaceCollection bridges; - //w36 - const auto expansion_params_into_sparse_infill = RegionExpansionParameters::build(expansion_min, expansion_step, max_nr_expansion_steps); { BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges. layer" << this->layer()->print_z; - //w36 - const double custom_angle = this->region().config().bridge_angle.value; - const auto expansion_params_into_solid_infill = RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step, - max_nr_expansion_steps); - bridges.surfaces = custom_angle > 0 ? - expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, shells, expansion_params_into_solid_infill, - sparse, expansion_params_into_sparse_infill, closing_radius, - Geometry::deg2rad(custom_angle)) : - expand_bridges_detect_orientations(m_fill_surfaces.surfaces, shells, expansion_params_into_solid_infill, - sparse, expansion_params_into_sparse_infill, closing_radius); + const double custom_angle = this->region().config().bridge_angle.value; + bridges.surfaces = custom_angle > 0 ? + expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, expansion_zones, closing_radius, Geometry::deg2rad(custom_angle)) : + expand_bridges_detect_orientations(m_fill_surfaces.surfaces, expansion_zones, closing_radius); BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done"; #if 0 { @@ -752,30 +520,37 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly } #endif } - //w36 - Surfaces bottoms = expand_merge_surfaces(m_fill_surfaces.surfaces, stBottom, shells, - RegionExpansionParameters::build(expansion_bottom, expansion_step, max_nr_expansion_steps), - sparse, expansion_params_into_sparse_infill, closing_radius); - Surfaces tops = expand_merge_surfaces(m_fill_surfaces.surfaces, stTop, shells, - RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps), sparse, - expansion_params_into_sparse_infill, closing_radius); + m_fill_surfaces.remove_types({ stTop }); + { + Surface top_templ(stTop, {}); + top_templ.thickness = layer_thickness; + m_fill_surfaces.append(std::move(expansion_zones.back().expolygons), top_templ); + } - // m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternal, stInternalSolid }); + expansion_zones.pop_back(); + + expansion_zones.at(0).parameters = RegionExpansionParameters::build(expansion_bottom, expansion_step, max_nr_expansion_steps); + Surfaces bottoms = expand_merge_surfaces(m_fill_surfaces.surfaces, stBottom, expansion_zones, closing_radius); + + expansion_zones.at(0).parameters = RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps); + Surfaces tops = expand_merge_surfaces(m_fill_surfaces.surfaces, stTop, expansion_zones, closing_radius); + +// m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternal, stInternalSolid }); m_fill_surfaces.clear(); - //w36 - reserve_more(m_fill_surfaces.surfaces, shells.size() + sparse.size() + bridges.size() + bottoms.size() + tops.size()); + unsigned zones_expolygons_count = 0; + for (const ExpansionZone& zone : expansion_zones) + zones_expolygons_count += zone.expolygons.size(); + reserve_more(m_fill_surfaces.surfaces, zones_expolygons_count + bridges.size() + bottoms.size() + tops.size()); { Surface solid_templ(stInternalSolid, {}); solid_templ.thickness = layer_thickness; - //w36 - m_fill_surfaces.append(std::move(shells), solid_templ); + m_fill_surfaces.append(std::move(expansion_zones[0].expolygons), solid_templ); } { Surface sparse_templ(stInternal, {}); sparse_templ.thickness = layer_thickness; - //w36 - m_fill_surfaces.append(std::move(sparse), sparse_templ); + m_fill_surfaces.append(std::move(expansion_zones[1].expolygons), sparse_templ); } m_fill_surfaces.append(std::move(bridges.surfaces)); m_fill_surfaces.append(std::move(bottoms)); diff --git a/src/libslic3r/LayerRegion.hpp b/src/libslic3r/LayerRegion.hpp index c7e2d3d..af77729 100644 --- a/src/libslic3r/LayerRegion.hpp +++ b/src/libslic3r/LayerRegion.hpp @@ -127,7 +127,7 @@ public: // All fill areas produced for all input slices above. ExPolygons &fill_expolygons, // Ranges of fill areas above per input slice. - std::vector &fill_expolygons_ranges, + std::vector &fill_expolygons_ranges, //w21 ExPolygons &fill_no_overlap_expolygons); void process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered); @@ -221,44 +221,23 @@ struct ExpansionZone { * detect bridges. * Trim "shells" by the expanded bridges. */ -// w36 -/* Surfaces expand_bridges_detect_orientations( +Surfaces expand_bridges_detect_orientations( Surfaces &surfaces, std::vector& expansion_zones, const float closing_radius -);*/ - -//w36 -Surfaces expand_bridges_detect_orientations(Surfaces & surfaces, - ExPolygons & shells, - const Algorithm::RegionExpansionParameters &expansion_params_into_solid_infill, - ExPolygons & sparse, - const Algorithm::RegionExpansionParameters &expansion_params_into_sparse_infill, - const float closing_radius); +); /** * Extract bridging surfaces from "surfaces", expand them into "shells" using expansion_params. * Trim "shells" by the expanded bridges. */ - -// w36 -/* Surfaces expand_merge_surfaces( +Surfaces expand_merge_surfaces( Surfaces &surfaces, SurfaceType surface_type, std::vector& expansion_zones, const float closing_radius, const double bridge_angle = -1 -);*/ - -// w36 -Surfaces expand_merge_surfaces(Surfaces & surfaces, - SurfaceType surface_type, - ExPolygons & shells, - const Algorithm::RegionExpansionParameters &expansion_params_into_solid_infill, - ExPolygons & sparse, - const Algorithm::RegionExpansionParameters &expansion_params_into_sparse_infill, - const float closing_radius, - const double bridge_angle = -1.); +); } diff --git a/src/libslic3r/MutablePolygon.cpp b/src/libslic3r/MutablePolygon.cpp index 33ea7e8..897d3f2 100644 --- a/src/libslic3r/MutablePolygon.cpp +++ b/src/libslic3r/MutablePolygon.cpp @@ -1,4 +1,5 @@ #include "MutablePolygon.hpp" + #include #include #include diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 72cfcef..ac188f2 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1,5 +1,18 @@ #include "PerimeterGenerator.hpp" -#include "AABBTreeIndirect.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "AABBTreeLines.hpp" #include "BoundingBox.hpp" #include "BridgeDetector.hpp" @@ -7,55 +20,29 @@ #include "ExPolygon.hpp" #include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" -#include "Geometry/MedialAxis.hpp" -#include "KDTreeIndirect.hpp" -#include "MultiPoint.hpp" #include "Point.hpp" #include "Polygon.hpp" #include "Polyline.hpp" #include "PrintConfig.hpp" #include "ShortestPath.hpp" #include "Surface.hpp" - #include "Geometry/ConvexHull.hpp" -#include "SurfaceCollection.hpp" #include "clipper/clipper_z.hpp" - #include "Arachne/PerimeterOrder.hpp" #include "Arachne/WallToolPaths.hpp" #include "Arachne/utils/ExtrusionLine.hpp" #include "Arachne/utils/ExtrusionJunction.hpp" #include "libslic3r.h" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Line.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// #define ARACHNE_DEBUG +//#define ARACHNE_DEBUG #ifdef ARACHNE_DEBUG #include "SVG.hpp" #include "Utils.hpp" #endif -#include "SVG.hpp" - namespace Slic3r { ExtrusionMultiPath PerimeterGenerator::thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance) @@ -286,62 +273,12 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine &ext_lines, double fuzzy using PerimeterGeneratorLoops = std::vector; -//w38 -template -static bool detect_steep_overhang(const PrintRegionConfig &config, - bool is_contour, - const BoundingBox & extrusion_bboxs, - double extrusion_width, - const _T extrusion, - const ExPolygons * lower_slices, - bool & steep_overhang_contour, - bool & steep_overhang_hole) -{ - double threshold = config.overhang_reverse_threshold.get_abs_value(extrusion_width); - // Special case: reverse on every odd layer - if (threshold < EPSILON) { - if (is_contour) { - steep_overhang_contour = true; - } else { - steep_overhang_hole = true; - } - - return true; - } - - Polygons lower_slcier_chopped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, extrusion_bboxs); - - // All we need to check is whether we have lines outside `threshold` - double off = threshold - 0.5 * extrusion_width; - - auto limiton_polygons = offset(lower_slcier_chopped, float(scale_(off))); - - auto remain_polylines = diff_pl(extrusion, limiton_polygons); - if (!remain_polylines.empty()) { - if (is_contour) { - steep_overhang_contour = true; - } else { - steep_overhang_hole = true; - } - - return true; - } - - return false; -} - -//w38 -static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls, - bool & steep_overhang_contour, - bool & steep_overhang_hole) +static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) { // loops is an arrayref of ::Loop objects // turn each one into an ExtrusionLoop object ExtrusionEntityCollection coll; Polygon fuzzified; - //w38 - bool overhangs_reverse = params.config.overhang_reverse && - params.layer_id % 2 == 1; for (const PerimeterGeneratorLoop &loop : loops) { bool is_external = loop.is_external(); @@ -352,24 +289,13 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator // Note that we set loop role to ContourInternalPerimeter // also when loop is both internal and external (i.e. // there's only one contour loop). - //w38 - loop_role = elrInternal;//loop_role = elrContourInternalPerimeter; + loop_role = elrContourInternalPerimeter; } else { - //w38 - loop_role = loop.is_contour? elrDefault : elrHole;//loop_role = elrDefault; + loop_role = elrDefault; } // detect overhanging/bridging perimeters ExtrusionPaths paths; - //w38 - double extrusion_width; - if (is_external) { - - extrusion_width = params.ext_perimeter_flow.width(); - } else { - extrusion_width = params.perimeter_flow.width(); - } - const Polygon &polygon = loop.fuzzify ? fuzzified : loop.polygon; if (loop.fuzzify) { fuzzified = loop.polygon; @@ -380,28 +306,15 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator params.object_config.support_material_contact_distance.value == 0)) { BoundingBox bbox(polygon.points); bbox.offset(SCALED_EPSILON); - //w38 - if (overhangs_reverse && params.config.fuzzy_skin != FuzzySkinType::None) { - if (loop.is_contour) { - steep_overhang_contour = true; - } else if (params.config.fuzzy_skin != FuzzySkinType::External) { - steep_overhang_hole = true; - } - } - bool found_steep_overhang = (loop.is_contour && steep_overhang_contour) || (!loop.is_contour && steep_overhang_hole); - if (overhangs_reverse && !found_steep_overhang) { - detect_steep_overhang(params.config, loop.is_contour, bbox, extrusion_width, Polygons{polygon}, - params.lower_slices, steep_overhang_contour, steep_overhang_hole); - } Polygons lower_slices_polygons_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(lower_slices_polygons_cache, bbox); // get non-overhang paths by intersecting this loop with the grown lower slices extrusion_paths_append( paths, intersection_pl({ polygon }, lower_slices_polygons_clipped), ExtrusionAttributes{ - role_normal, + role_normal, ExtrusionFlow{ is_external ? params.ext_mm3_per_mm : params.mm3_per_mm, - is_external ? params.ext_perimeter_flow.width() : params.perimeter_flow.width(), + is_external ? params.ext_perimeter_flow.width() : params.perimeter_flow.width(), float(params.layer_height) } }); @@ -412,7 +325,7 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator paths, diff_pl({ polygon }, lower_slices_polygons_clipped), ExtrusionAttributes{ - role_overhang, + role_overhang, ExtrusionFlow{ params.mm3_per_mm_overhang, params.overhang_flow.width(), params.overhang_flow.height() } }); @@ -430,7 +343,7 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator } }); } - + coll.append(ExtrusionLoop(std::move(paths), loop_role)); } @@ -456,13 +369,10 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator } else { const PerimeterGeneratorLoop &loop = loops[idx.first]; assert(thin_walls.empty()); - //w38 - ExtrusionEntityCollection children = traverse_loops_classic(params, lower_slices_polygons_cache, loop.children, thin_walls,steep_overhang_contour, steep_overhang_hole); + ExtrusionEntityCollection children = traverse_loops_classic(params, lower_slices_polygons_cache, loop.children, thin_walls); out.entities.reserve(out.entities.size() + children.entities.size() + 1); ExtrusionLoop *eloop = static_cast(coll.entities[idx.first]); coll.entities[idx.first] = nullptr; - //w38 - //eloop->make_counter_clockwise(); if (loop.is_contour) { if (eloop->is_clockwise()) eloop->reverse_loop(); @@ -574,32 +484,15 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path &subject, con return clipped_paths; } -struct PerimeterGeneratorArachneExtrusion +static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, Arachne::PerimeterOrder::PerimeterExtrusions &pg_extrusions) { - Arachne::ExtrusionLine *extrusion = nullptr; - // Indicates if closed ExtrusionLine is a contour or a hole. Used it only when ExtrusionLine is a closed loop. - bool is_contour = false; - // Should this extrusion be fuzzyfied on path generation? - bool fuzzify = false; -}; - -//w38 -static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters & params, - const Polygons & lower_slices_polygons_cache, - Arachne::PerimeterOrder::PerimeterExtrusions &pg_extrusions, - bool & steep_overhang_contour, - bool & steep_overhang_hole) -{ - //w38 - bool overhangs_reverse = params.config.overhang_reverse && - params.layer_id % 2 == 1; ExtrusionEntityCollection extrusion_coll; for (Arachne::PerimeterOrder::PerimeterExtrusion &pg_extrusion : pg_extrusions) { Arachne::ExtrusionLine &extrusion = pg_extrusion.extrusion; if (extrusion.empty()) continue; - const bool is_external = extrusion.inset_idx == 0; + const bool is_external = extrusion.inset_idx == 0; ExtrusionRole role_normal = is_external ? ExtrusionRole::ExternalPerimeter : ExtrusionRole::Perimeter; ExtrusionRole role_overhang = role_normal | ExtrusionRoleModifier::Bridge; @@ -642,40 +535,6 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role_normal, is_external ? params.ext_perimeter_flow : params.perimeter_flow); - //w38 - if (overhangs_reverse && params.config.fuzzy_skin != FuzzySkinType::None) { - if (pg_extrusion.is_contour()) { - steep_overhang_contour = true; - } else if (params.config.fuzzy_skin != FuzzySkinType::External) { - steep_overhang_hole = true; - } - } - bool found_steep_overhang = (pg_extrusion.is_contour() && steep_overhang_contour) || - (!pg_extrusion.is_contour() && steep_overhang_hole); - if (overhangs_reverse && !found_steep_overhang) { - std::map recognization_paths; - for (const ExtrusionPath &path : paths) { - if (recognization_paths.count(path.width())) - recognization_paths[path.width()].emplace_back(std::move(path)); - else - recognization_paths.insert(std::pair(path.width(), {std::move(path)})); - } - for (const auto &it : recognization_paths) { - Polylines be_clipped; - - for (const ExtrusionPath &p : it.second) { - be_clipped.emplace_back(std::move(p.polyline)); - } - - BoundingBox extrusion_bboxs = get_extents(be_clipped); - - if (detect_steep_overhang(params.config, pg_extrusion.is_contour(), extrusion_bboxs, it.first, be_clipped, - params.lower_slices, steep_overhang_contour, steep_overhang_hole)) { - break; - } - } - } - // get overhang paths by checking what parts of this loop fall // outside the grown lower slices (thus where the distance between // the loop centerline and original lower slices is >= half nozzle diameter @@ -691,9 +550,6 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P // Especially for open extrusion, we need to select a starting point that is at the start // or the end of the extrusions to make one continuous line. Also, we prefer a non-overhang // starting point. - //w38 - //ExtrusionLoop extrusion_loop(std::move(paths), pg_extrusion.is_contour ? elrDefault : elrHole); - //extrusion_loop.make_counter_clockwise(); struct PointInfo { size_t occurrence = 0; @@ -779,7 +635,7 @@ static void export_perimeters_to_svg(const std::string &path, const Polygons &co svg.draw(infill_area, "cyan"); - for (const Arachne::VariableWidthLines &perimeter : perimeters) + for (const Arachne::Perimeter &perimeter : perimeters) for (const Arachne::ExtrusionLine &extrusion_line : perimeter) { ThickPolyline thick_polyline = to_thick_polyline(extrusion_line); svg.draw({thick_polyline}, "green", "blue", stroke_width); @@ -1192,69 +1048,6 @@ std::tuple, Polygons> generate_extra_perimeters_over return {extra_perims, diff(inset_overhang_area, inset_overhang_area_left_unfilled)}; } - -//w16 -void PerimeterGenerator::add_infill_contour_for_arachne(ExPolygons infill_contour, - int loops, - coord_t ext_perimeter_spacing, - coord_t perimeter_spacing, - coord_t min_perimeter_infill_spacing, - coord_t spacing, - bool is_inner_part, - const Parameters ¶ms, - ExPolygons &infill_areas, - ExPolygons & out_fill_expolygons, - //w21 - ExPolygons & out_fill_no_overlap) -{ - if (offset_ex(infill_contour, -float(spacing / 2.)).empty()) { - infill_contour.clear(); - } - coord_t insert = (loops < 0) ? 0 : ext_perimeter_spacing; - if (is_inner_part || loops > 0) - insert = perimeter_spacing; - - insert = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale(insert)))); - Polygons inner_pp; - for (ExPolygon &ex : infill_contour) - ex.simplify_p(params.scaled_resolution, &inner_pp); - ExPolygons inner_union = union_ex(inner_pp); - float offset1 = -min_perimeter_infill_spacing / 2.; - float offset2 = insert + min_perimeter_infill_spacing / 2.; - infill_areas = offset2_ex(inner_union, offset1, offset2); - append(out_fill_expolygons, offset2_ex(union_ex(inner_pp), float(-min_perimeter_infill_spacing / 2.), float(insert + min_perimeter_infill_spacing / 2.))); - //w21 - append(out_fill_no_overlap,offset2_ex(inner_union, float(-min_perimeter_infill_spacing / 2.), float(min_perimeter_infill_spacing / 2.))); -} - - -//w38 -static void reorient_perimeters(ExtrusionEntityCollection &entities, bool steep_overhang_contour, bool steep_overhang_hole, bool reverse_internal_only) -{ - if (steep_overhang_hole || steep_overhang_contour) { - for (auto entity : entities) { - if (entity->is_loop()) { - ExtrusionLoop *eloop = static_cast(entity); - bool need_reverse = ((eloop->loop_role() & elrHole) == elrHole) ? steep_overhang_hole : steep_overhang_contour; - bool isExternal = false; - if (reverse_internal_only) { - for (auto path : eloop->paths) { - if (path.role().is_external_perimeter()) { - isExternal = true; - break; - } - } - } - - if (need_reverse && !isExternal) { - eloop->make_clockwise(); - } - } - } - } -} - - // Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper // "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling" void PerimeterGenerator::process_arachne( @@ -1273,12 +1066,11 @@ void PerimeterGenerator::process_arachne( // Infills without the gap fills ExPolygons &out_fill_expolygons, //w21 - ExPolygons &out_fill_no_overlap, - //w23 - const size_t layer_id) + ExPolygons &out_fill_no_overlap) { // other perimeters - coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing(); + coord_t perimeter_width = params.perimeter_flow.scaled_width(); + coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing(); // external perimeters coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width(); coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing(); @@ -1298,35 +1090,100 @@ void PerimeterGenerator::process_arachne( // we need to process each island separately because we might have different // extra perimeters for each one // detect how many perimeters must be generated for this island - int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops + int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops + if (loop_number > 0 && ((params.config.top_one_perimeter_type == TopOnePerimeterType::TopmostOnly && upper_slices == nullptr) || (params.config.only_one_perimeter_first_layer && params.layer_id == 0))) + loop_number = 0; + + // Calculate how many inner loops remain when TopSurfaces is selected. + const int inner_loop_number = (params.config.top_one_perimeter_type == TopOnePerimeterType::TopSurfaces && upper_slices != nullptr) ? loop_number - 1 : -1; + + // Set one perimeter when TopSurfaces is selected. + if (params.config.top_one_perimeter_type == TopOnePerimeterType::TopSurfaces) + loop_number = 0; //w39 - //ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); double surface_simplify_resolution = (params.print_config.arc_fitting != ArcFittingType::Disabled && params.config.fuzzy_skin == FuzzySkinType::None) ? 0.2 * scale_(params.print_config.resolution) : params.print_config.resolution; auto apply_precise_outer_wall = params.config.precise_outer_wall && !params.config.external_perimeters_first; - ExPolygons last = apply_precise_outer_wall? offset_ex(surface.expolygon.simplify_p(surface_simplify_resolution), - -float(ext_perimeter_width - ext_perimeter_spacing) ) :offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - -float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); - coord_t wall_0_inset = 0; + ExPolygons last = apply_precise_outer_wall ? offset_ex(surface.expolygon.simplify_p(surface_simplify_resolution) , -float(ext_perimeter_width - ext_perimeter_spacing) ): + offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); + coord_t wall_0_inset = 0; if (apply_precise_outer_wall) wall_0_inset = -coord_t(ext_perimeter_width / 2 - ext_perimeter_spacing / 2); - Polygons last_p = to_polygons(last); - //w16 - //w23 - if ((upper_slices == nullptr && params.object_config.top_one_wall_type == TopOneWallType::Onlytopmost)||(params.object_config.only_one_wall_first_layer && layer_id == 0)) - loop_number = 0; + //ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); + Polygons last_p = to_polygons(last); //w39 - Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), wall_0_inset, params.layer_height, params.object_config, params.print_config); - std::vector perimeters = wallToolPaths.getToolPaths(); + Arachne::WallToolPaths wall_tool_paths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), wall_0_inset, params.layer_height, params.object_config, params.print_config); + Arachne::Perimeters perimeters = wall_tool_paths.getToolPaths(); + ExPolygons infill_contour = union_ex(wall_tool_paths.getInnerContour()); + + // Check if there are some remaining perimeters to generate (the number of perimeters + // is greater than one together with enabled the single perimeter on top surface feature). + if (inner_loop_number >= 0) { + assert(upper_slices != nullptr); + + // Infill contour bounding box. + BoundingBox infill_contour_bbox = get_extents(infill_contour); + infill_contour_bbox.offset(SCALED_EPSILON); + + // Get top ExPolygons from current infill contour. + const Polygons upper_slices_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*upper_slices, infill_contour_bbox); + ExPolygons top_expolygons = diff_ex(infill_contour, upper_slices_clipped); + + if (!top_expolygons.empty()) { + if (lower_slices != nullptr) { + const float bridge_offset = float(std::max(ext_perimeter_spacing, perimeter_width)); + const Polygons lower_slices_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, infill_contour_bbox); + const ExPolygons current_slices_bridges = offset_ex(diff_ex(top_expolygons, lower_slices_clipped), bridge_offset); + + // Remove bridges from top surface polygons. + top_expolygons = diff_ex(top_expolygons, current_slices_bridges); + } + + // Filter out areas that are too thin and expand top surface polygons a bit to hide the wall line. + const float top_surface_min_width = std::max(float(ext_perimeter_spacing) / 4.f + scaled(0.00001), float(perimeter_width) / 4.f); + top_expolygons = offset2_ex(top_expolygons, -top_surface_min_width, top_surface_min_width + float(perimeter_width)); + + // Get the not-top ExPolygons (including bridges) from current slices and expanded real top ExPolygons (without bridges). + const ExPolygons not_top_expolygons = diff_ex(infill_contour, top_expolygons); + + // Get final top ExPolygons. + top_expolygons = intersection_ex(top_expolygons, infill_contour); + + const Polygons not_top_polygons = to_polygons(not_top_expolygons); + Arachne::WallToolPaths inner_wall_tool_paths(not_top_polygons, perimeter_spacing, perimeter_spacing, coord_t(inner_loop_number + 1), 0, params.layer_height, params.object_config, params.print_config); + Arachne::Perimeters inner_perimeters = inner_wall_tool_paths.getToolPaths(); + + // Recalculate indexes of inner perimeters before merging them. + if (!perimeters.empty()) { + for (Arachne::VariableWidthLines &inner_perimeter : inner_perimeters) { + if (inner_perimeter.empty()) + continue; + + for (Arachne::ExtrusionLine &el : inner_perimeter) + ++el.inset_idx; + } + } + + perimeters.insert(perimeters.end(), inner_perimeters.begin(), inner_perimeters.end()); + infill_contour = union_ex(top_expolygons, inner_wall_tool_paths.getInnerContour()); + } else { + // There is no top surface ExPolygon, so we call Arachne again with parameters + // like when the single perimeter feature is disabled. + Arachne::WallToolPaths no_single_perimeter_tool_paths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(inner_loop_number + 2), 0, params.layer_height, params.object_config, params.print_config); + perimeters = no_single_perimeter_tool_paths.getToolPaths(); + infill_contour = union_ex(no_single_perimeter_tool_paths.getInnerContour()); + } + } + loop_number = int(perimeters.size()) - 1; #ifdef ARACHNE_DEBUG { static int iRun = 0; - export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour())); + export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", params.layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour())); } #endif @@ -1334,107 +1191,20 @@ void PerimeterGenerator::process_arachne( // But in rare cases, Arachne produce ExtrusionLine marked as closed but without // equal the first and the last point. assert([&perimeters = std::as_const(perimeters)]() -> bool { - for (const Arachne::VariableWidthLines &perimeter : perimeters) + for (const Arachne::Perimeter &perimeter : perimeters) for (const Arachne::ExtrusionLine &el : perimeter) if (el.is_closed && el.junctions.front().p != el.junctions.back().p) return false; return true; }()); - int start_perimeter = int(perimeters.size()) - 1; - int end_perimeter = -1; - int direction = -1; - - if (params.config.external_perimeters_first) { - start_perimeter = 0; - end_perimeter = int(perimeters.size()); - direction = 1; - } - - std::vector all_extrusions; - for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) { - if (perimeters[perimeter_idx].empty()) - continue; - for (Arachne::ExtrusionLine &wall : perimeters[perimeter_idx]) - all_extrusions.emplace_back(&wall); - } - - // Find topological order with constraints from extrusions_constrains. - std::vector blocked(all_extrusions.size(), 0); // Value indicating how many extrusions it is blocking (preceding extrusions) an extrusion. - std::vector> blocking(all_extrusions.size()); // Each extrusion contains a vector of extrusions that are blocked by this extrusion. - ankerl::unordered_dense::map map_extrusion_to_idx; - for (size_t idx = 0; idx < all_extrusions.size(); idx++) - map_extrusion_to_idx.emplace(all_extrusions[idx], idx); - - Arachne::WallToolPaths::ExtrusionLineSet extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, params.config.external_perimeters_first); - for (auto [before, after] : extrusions_constrains) { - auto after_it = map_extrusion_to_idx.find(after); - ++blocked[after_it->second]; - blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second); - } - - std::vector processed(all_extrusions.size(), false); // Indicate that the extrusion was already processed. - Point current_position = all_extrusions.empty() ? Point::Zero() : all_extrusions.front()->junctions.front().p; // Some starting position. - std::vector ordered_extrusions; // To store our result in. At the end we'll std::swap. - ordered_extrusions.reserve(all_extrusions.size()); - - while (ordered_extrusions.size() < all_extrusions.size()) { - size_t best_candidate = 0; - double best_distance_sqr = std::numeric_limits::max(); - bool is_best_closed = false; - - std::vector available_candidates; - for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) { - if (processed[candidate] || blocked[candidate]) - continue; // Not a valid candidate. - available_candidates.push_back(candidate); - } - - std::sort(available_candidates.begin(), available_candidates.end(), [&all_extrusions](const size_t a_idx, const size_t b_idx) -> bool { - return all_extrusions[a_idx]->is_closed < all_extrusions[b_idx]->is_closed; - }); - - for (const size_t candidate_path_idx : available_candidates) { - auto& path = all_extrusions[candidate_path_idx]; - - if (path->junctions.empty()) { // No vertices in the path. Can't find the start position then or really plan it in. Put that at the end. - if (best_distance_sqr == std::numeric_limits::max()) { - best_candidate = candidate_path_idx; - is_best_closed = path->is_closed; - } - continue; - } - - const Point candidate_position = path->junctions.front().p; - double distance_sqr = (current_position - candidate_position).cast().norm(); - if (distance_sqr < best_distance_sqr) { // Closer than the best candidate so far. - if (path->is_closed || (!path->is_closed && best_distance_sqr != std::numeric_limits::max()) || (!path->is_closed && !is_best_closed)) { - best_candidate = candidate_path_idx; - best_distance_sqr = distance_sqr; - is_best_closed = path->is_closed; - } - } - } - - auto &best_path = all_extrusions[best_candidate]; - ordered_extrusions.push_back({best_path, best_path->is_contour(), false}); - processed[best_candidate] = true; - for (size_t unlocked_idx : blocking[best_candidate]) - blocked[unlocked_idx]--; - - if (!best_path->junctions.empty()) { //If all paths were empty, the best path is still empty. We don't upate the current position then. - if(best_path->is_closed) - current_position = best_path->junctions[0].p; //We end where we started. - else - current_position = best_path->junctions.back().p; //Pick the other end from where we started. - } - } + Arachne::PerimeterOrder::PerimeterExtrusions ordered_extrusions = Arachne::PerimeterOrder::ordered_perimeter_extrusions(perimeters, params.config.external_perimeters_first); if (params.layer_id > 0 && params.config.fuzzy_skin != FuzzySkinType::None) { - std::vector closed_loop_extrusions; - for (PerimeterGeneratorArachneExtrusion &extrusion : ordered_extrusions) - if (extrusion.extrusion->inset_idx == 0) { - if (extrusion.extrusion->is_closed && params.config.fuzzy_skin == FuzzySkinType::External) { + std::vector closed_loop_extrusions; + for (Arachne::PerimeterOrder::PerimeterExtrusion &extrusion : ordered_extrusions) + if (extrusion.extrusion.inset_idx == 0) { + if (extrusion.extrusion.is_closed && params.config.fuzzy_skin == FuzzySkinType::External) { closed_loop_extrusions.emplace_back(&extrusion); } else { extrusion.fuzzify = true; @@ -1470,32 +1240,13 @@ void PerimeterGenerator::process_arachne( } } - //w38 - bool steep_overhang_contour = false; - bool steep_overhang_hole = false; - if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions, - steep_overhang_contour, steep_overhang_hole); - !extrusion_coll.empty()) { - reorient_perimeters(extrusion_coll, steep_overhang_contour, steep_overhang_hole, params.config.overhang_reverse_internal_only); + if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions); !extrusion_coll.empty()) out_loops.append(extrusion_coll); - } - ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); - //w17 - ExPolygons the_layer_surface = infill_contour; - const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing; + const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing; if (offset_ex(infill_contour, -float(spacing / 2.)).empty()) infill_contour.clear(); // Infill region is too small, so let's filter it out. - if (params.object_config.top_one_wall_type != TopOneWallType::Disable) { - coord_t perimeter_width = params.perimeter_flow.scaled_width(); - double min_width_top_surface = (params.object_config.top_area_threshold / 100) * - std::max(double(ext_perimeter_spacing / 4 + 10), double(perimeter_width / 4)); - infill_contour = offset2_ex(infill_contour, -min_width_top_surface, min_width_top_surface + perimeter_width); - ExPolygons surface_not_export_to_top = diff_ex(the_layer_surface, infill_contour); - } - // BBS: get real top surface - infill_contour = intersection_ex(infill_contour, the_layer_surface); // create one more offset to be used as boundary for fill // we offset by half the perimeter spacing (to get to the actual infill boundary) // and then we offset back and forth by half the infill spacing to only consider the @@ -1543,413 +1294,6 @@ void PerimeterGenerator::process_arachne( append(out_fill_expolygons, std::move(infill_areas)); //w21 append(out_fill_no_overlap, offset2_ex(union_ex(pp),float(-min_perimeter_infill_spacing / 2.), float( min_perimeter_infill_spacing / 2.))); - append(out_fill_expolygons, std::move(infill_areas)); -} - -void PerimeterGenerator::process_with_one_wall_arachne( - // Inputs: - const Parameters ¶ms, - const Surface &surface, - const ExPolygons *lower_slices, - //w16 - const ExPolygons *upper_slices, - // Cache: - Polygons &lower_slices_polygons_cache, - Polygons &upper_slices_polygons_cache, - // Output: - // Loops with the external thin walls - ExtrusionEntityCollection &out_loops, - // Gaps without the thin walls - ExtrusionEntityCollection & /* out_gap_fill */, - // Infills without the gap fills - ExPolygons &out_fill_expolygons, - //w21 - ExPolygons &out_fill_no_overlap, - //w23 - const size_t layer_id) -{ - // other perimeters - coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing(); - // external perimeters - coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width(); - coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing(); - coord_t ext_perimeter_spacing2 = scaled(0.5f * (params.ext_perimeter_flow.spacing() + params.perimeter_flow.spacing())); - // solid infill - coord_t solid_infill_spacing = params.solid_infill_flow.scaled_spacing(); - - // prepare grown lower layer slices for overhang detection - if (params.config.overhangs && lower_slices != nullptr && lower_slices_polygons_cache.empty()) { - // We consider overhang any part where the entire nozzle diameter is not supported by the - // lower layer, so we take lower slices and offset them by half the nozzle diameter used - // in the current layer - double nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder-1); - lower_slices_polygons_cache = offset(*lower_slices, float(scale_(+nozzle_diameter/2))); - } - if ( upper_slices != nullptr && upper_slices_polygons_cache.empty()) { - double upper_nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder - 1); - upper_slices_polygons_cache = offset(*upper_slices, float(scale_(EPSILON))); - } - - - // we need to process each island separately because we might have different - // extra perimeters for each one - // detect how many perimeters must be generated for this island - int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops - //w23 - if (params.object_config.only_one_wall_first_layer && layer_id == 0) - loop_number = 0; - //w39 - //ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); - double surface_simplify_resolution = (params.print_config.arc_fitting != ArcFittingType::Disabled && - params.config.fuzzy_skin == FuzzySkinType::None) ? - 0.2 * scale_(params.print_config.resolution) : - params.print_config.resolution; - auto apply_precise_outer_wall = params.config.precise_outer_wall && !params.config.external_perimeters_first; - ExPolygons last = apply_precise_outer_wall ? offset_ex(surface.expolygon.simplify_p(surface_simplify_resolution), - -float(ext_perimeter_width - ext_perimeter_spacing)) : - offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - -float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); - coord_t wall_0_inset = 0; - if (apply_precise_outer_wall) - wall_0_inset = -coord_t(ext_perimeter_width / 2 - ext_perimeter_spacing / 2); - Polygons last_p = to_polygons(last); - - int remain_loops = -1; - if (params.object_config.top_one_wall_type == TopOneWallType::Alltop) { - if (upper_slices != nullptr) - remain_loops = loop_number - 1; - - loop_number = 0; - } - //w39 - Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), wall_0_inset, params.layer_height, params.object_config, params.print_config); - std::vector perimeters = wallToolPaths.getToolPaths(); - loop_number = int(perimeters.size()) - 1; - - - - //w16 - ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); - ExPolygons inner_infill_contour; - - if (remain_loops >= 0) { - - ExPolygons the_layer_surface = infill_contour; - BoundingBox infill_contour_box = get_extents(infill_contour); - infill_contour_box.offset(SCALED_EPSILON); - Polygons upper_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(upper_slices_polygons_cache, - infill_contour_box); - - infill_contour = diff_ex(infill_contour, upper_polygons_series_clipped); - - coord_t perimeter_width = params.perimeter_flow.scaled_width(); - if (lower_slices != nullptr) { - BoundingBox infill_contour_box = get_extents(infill_contour); - infill_contour_box.offset(SCALED_EPSILON); - Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(lower_slices_polygons_cache, - infill_contour_box); - - ExPolygons bridge_area = offset_ex(diff_ex(infill_contour, lower_polygons_series_clipped), - std::max(ext_perimeter_spacing, perimeter_width)); - infill_contour = diff_ex(infill_contour, bridge_area); - } - //w17 - // double min_width_top_surface = std::max(double(ext_perimeter_spacing / 4 + 10), double(perimeter_width / 4)); - double min_width_top_surface = (params.object_config.top_area_threshold / 100) * std::max(double(ext_perimeter_spacing / 4 + 10), double(perimeter_width / 4)); - infill_contour = offset2_ex(infill_contour, -min_width_top_surface, min_width_top_surface + perimeter_width); - - ExPolygons surface_not_export_to_top = diff_ex(the_layer_surface, infill_contour); - - infill_contour = intersection_ex(infill_contour, the_layer_surface); - Polygons surface_not_export_to_top_p = to_polygons(surface_not_export_to_top); - Arachne::WallToolPaths innerWallToolPaths(surface_not_export_to_top_p, perimeter_spacing, perimeter_spacing, - coord_t(remain_loops + 1), 0, params.layer_height, params.object_config, params.print_config); - - std::vector perimeters_inner = innerWallToolPaths.getToolPaths(); - remain_loops = int(perimeters_inner.size()) - 1; - if (!perimeters.empty()) { - for (int perimeter_idx = 0; perimeter_idx < perimeters_inner.size(); perimeter_idx++) { - if (perimeters_inner[perimeter_idx].empty()) - continue; - - for (Arachne::ExtrusionLine &wall : perimeters_inner[perimeter_idx]) { - wall.inset_idx++; - } - } - } - perimeters.insert(perimeters.end(), perimeters_inner.begin(), perimeters_inner.end()); - - inner_infill_contour = union_ex(innerWallToolPaths.getInnerContour()); - } - -#ifdef ARACHNE_DEBUG - { - static int iRun = 0; - export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour())); - } -#endif - - // All closed ExtrusionLine should have the same the first and the last point. - // But in rare cases, Arachne produce ExtrusionLine marked as closed but without - // equal the first and the last point. - assert([&perimeters = std::as_const(perimeters)]() -> bool { - for (const Arachne::VariableWidthLines &perimeter : perimeters) - for (const Arachne::ExtrusionLine &el : perimeter) - if (el.is_closed && el.junctions.front().p != el.junctions.back().p) - return false; - return true; - }()); - - int start_perimeter = int(perimeters.size()) - 1; - int end_perimeter = -1; - int direction = -1; - - if (params.config.external_perimeters_first) { - start_perimeter = 0; - end_perimeter = int(perimeters.size()); - direction = 1; - } - - std::vector all_extrusions; - for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) { - if (perimeters[perimeter_idx].empty()) - continue; - for (Arachne::ExtrusionLine &wall : perimeters[perimeter_idx]) - all_extrusions.emplace_back(&wall); - } - - // Find topological order with constraints from extrusions_constrains. - std::vector blocked(all_extrusions.size(), 0); // Value indicating how many extrusions it is blocking (preceding extrusions) an extrusion. - std::vector> blocking(all_extrusions.size()); // Each extrusion contains a vector of extrusions that are blocked by this extrusion. - ankerl::unordered_dense::map map_extrusion_to_idx; - for (size_t idx = 0; idx < all_extrusions.size(); idx++) - map_extrusion_to_idx.emplace(all_extrusions[idx], idx); - - Arachne::WallToolPaths::ExtrusionLineSet extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, params.config.external_perimeters_first); - for (auto [before, after] : extrusions_constrains) { - auto after_it = map_extrusion_to_idx.find(after); - ++blocked[after_it->second]; - blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second); - } - - std::vector processed(all_extrusions.size(), false); // Indicate that the extrusion was already processed. - Point current_position = all_extrusions.empty() ? Point::Zero() : all_extrusions.front()->junctions.front().p; // Some starting position. - std::vector ordered_extrusions; // To store our result in. At the end we'll std::swap. - ordered_extrusions.reserve(all_extrusions.size()); - - while (ordered_extrusions.size() < all_extrusions.size()) { - size_t best_candidate = 0; - double best_distance_sqr = std::numeric_limits::max(); - bool is_best_closed = false; - - std::vector available_candidates; - for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) { - if (processed[candidate] || blocked[candidate]) - continue; // Not a valid candidate. - available_candidates.push_back(candidate); - } - - std::sort(available_candidates.begin(), available_candidates.end(), [&all_extrusions](const size_t a_idx, const size_t b_idx) -> bool { - return all_extrusions[a_idx]->is_closed < all_extrusions[b_idx]->is_closed; - }); - - for (const size_t candidate_path_idx : available_candidates) { - auto& path = all_extrusions[candidate_path_idx]; - - if (path->junctions.empty()) { // No vertices in the path. Can't find the start position then or really plan it in. Put that at the end. - if (best_distance_sqr == std::numeric_limits::max()) { - best_candidate = candidate_path_idx; - is_best_closed = path->is_closed; - } - continue; - } - - const Point candidate_position = path->junctions.front().p; - double distance_sqr = (current_position - candidate_position).cast().norm(); - if (distance_sqr < best_distance_sqr) { // Closer than the best candidate so far. - if (path->is_closed || (!path->is_closed && best_distance_sqr != std::numeric_limits::max()) || (!path->is_closed && !is_best_closed)) { - best_candidate = candidate_path_idx; - best_distance_sqr = distance_sqr; - is_best_closed = path->is_closed; - } - } - } - - auto &best_path = all_extrusions[best_candidate]; - ordered_extrusions.push_back({best_path, best_path->is_contour(), false}); - processed[best_candidate] = true; - for (size_t unlocked_idx : blocking[best_candidate]) - blocked[unlocked_idx]--; - - if (!best_path->junctions.empty()) { //If all paths were empty, the best path is still empty. We don't upate the current position then. - if(best_path->is_closed) - current_position = best_path->junctions[0].p; //We end where we started. - else - current_position = best_path->junctions.back().p; //Pick the other end from where we started. - } - } - - if (params.layer_id > 0 && params.config.fuzzy_skin != FuzzySkinType::None) { - std::vector closed_loop_extrusions; - for (PerimeterGeneratorArachneExtrusion &extrusion : ordered_extrusions) - if (extrusion.extrusion->inset_idx == 0) { - if (extrusion.extrusion->is_closed && params.config.fuzzy_skin == FuzzySkinType::External) { - closed_loop_extrusions.emplace_back(&extrusion); - } else { - extrusion.fuzzify = true; - } - } - - if (params.config.fuzzy_skin == FuzzySkinType::External) { - ClipperLib_Z::Paths loops_paths; - loops_paths.reserve(closed_loop_extrusions.size()); - for (const auto &cl_extrusion : closed_loop_extrusions) { - assert(cl_extrusion->extrusion->junctions.front() == cl_extrusion->extrusion->junctions.back()); - size_t loop_idx = &cl_extrusion - &closed_loop_extrusions.front(); - ClipperLib_Z::Path loop_path; - loop_path.reserve(cl_extrusion->extrusion->junctions.size() - 1); - for (auto junction_it = cl_extrusion->extrusion->junctions.begin(); junction_it != std::prev(cl_extrusion->extrusion->junctions.end()); ++junction_it) - loop_path.emplace_back(junction_it->p.x(), junction_it->p.y(), loop_idx); - loops_paths.emplace_back(loop_path); - } - - ClipperLib_Z::Clipper clipper; - clipper.AddPaths(loops_paths, ClipperLib_Z::ptSubject, true); - ClipperLib_Z::PolyTree loops_polytree; - clipper.Execute(ClipperLib_Z::ctUnion, loops_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd); - - for (const ClipperLib_Z::PolyNode *child_node : loops_polytree.Childs) { - // The whole contour must have the same index. - coord_t polygon_idx = child_node->Contour.front().z(); - bool has_same_idx = std::all_of(child_node->Contour.begin(), child_node->Contour.end(), - [&polygon_idx](const ClipperLib_Z::IntPoint &point) -> bool { return polygon_idx == point.z(); }); - if (has_same_idx) - closed_loop_extrusions[polygon_idx]->fuzzify = true; - } - } - } - - //w38 - bool steep_overhang_contour = false; - bool steep_overhang_hole = false; - if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions, - steep_overhang_contour, steep_overhang_hole); - !extrusion_coll.empty()) { - reorient_perimeters(extrusion_coll, steep_overhang_contour, steep_overhang_hole, params.config.overhang_reverse_internal_only); - out_loops.append(extrusion_coll); - } - - - //w16 - if (remain_loops >= 0) { - const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing; - if (offset_ex(infill_contour, -float(spacing / 2.)).empty()) - infill_contour.clear(); - coord_t inset = (loop_number < 0) ? 0 : - (loop_number == 0) ? - // one loop - ext_perimeter_spacing : - // two or more loops? - perimeter_spacing; - - inset = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale(inset)))); - Polygons pp; - for (ExPolygon &ex : infill_contour) - ex.simplify_p(params.scaled_resolution, &pp); - // collapse too narrow infill areas - const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE)); - // append infill areas to fill_surfaces - ExPolygons infill_areas = offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.), - float(inset + min_perimeter_infill_spacing / 2.)); - // ExPolygons infill_areas; - - if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs && - params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) { - // Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material - auto [extra_perimeters, filled_area] = generate_extra_perimeters_over_overhangs(infill_areas, lower_slices_polygons_cache, - loop_number + 1, params.overhang_flow, - params.scaled_resolution, params.object_config, - params.print_config); - if (!extra_perimeters.empty()) { - ExtrusionEntityCollection &this_islands_perimeters = static_cast(*out_loops.entities.back()); - ExtrusionEntitiesPtr old_entities; - old_entities.swap(this_islands_perimeters.entities); - for (ExtrusionPaths &paths : extra_perimeters) - this_islands_perimeters.append(std::move(paths)); - append(this_islands_perimeters.entities, old_entities); - infill_areas = diff_ex(infill_areas, filled_area); - } - } - - inset = (loop_number < 0) ? 0 : - (loop_number == 0) ? - // one loop - ext_perimeter_spacing : - // two or more loops? - perimeter_spacing; - - inset = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale(inset)))); - for (ExPolygon &ex : infill_contour) - ex.simplify_p(params.scaled_resolution, &pp); - // collapse too narrow infill areas - - - if (remain_loops >= 0) { - //w21 - add_infill_contour_for_arachne(infill_contour, loop_number, ext_perimeter_spacing, perimeter_spacing, - min_perimeter_infill_spacing, spacing, true, params, infill_areas, out_fill_expolygons,out_fill_no_overlap); - } - - - if (remain_loops >= 0) { - if (!inner_infill_contour.empty()) - //w21 - add_infill_contour_for_arachne(inner_infill_contour, remain_loops, ext_perimeter_spacing, perimeter_spacing, - min_perimeter_infill_spacing, spacing, true, params, infill_areas, out_fill_expolygons,out_fill_no_overlap); - } - //w21 - append(out_fill_no_overlap, - offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.), float(min_perimeter_infill_spacing / 2.))); - append(out_fill_expolygons, std::move(infill_areas)); - } else { - infill_contour = union_ex(wallToolPaths.getInnerContour()); - const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing; - if (offset_ex(infill_contour, -float(spacing / 2.)).empty()) - infill_contour.clear(); // Infill region is too small, so let's filter it out. - - coord_t inset = (loop_number < 0) ? 0 : (loop_number == 0) ? ext_perimeter_spacing : perimeter_spacing; - - inset = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale(inset)))); - Polygons pp; - for (ExPolygon &ex : infill_contour) - ex.simplify_p(params.scaled_resolution, &pp); - // collapse too narrow infill areas - const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE)); - // append infill areas to fill_surfaces - ExPolygons infill_areas = offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.), - float(inset + min_perimeter_infill_spacing / 2.)); - - if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs && - params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) { - // Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material - auto [extra_perimeters, filled_area] = generate_extra_perimeters_over_overhangs(infill_areas, lower_slices_polygons_cache, - loop_number + 1, params.overhang_flow, - params.scaled_resolution, params.object_config, - params.print_config); - if (!extra_perimeters.empty()) { - ExtrusionEntityCollection &this_islands_perimeters = static_cast(*out_loops.entities.back()); - ExtrusionEntitiesPtr old_entities; - old_entities.swap(this_islands_perimeters.entities); - for (ExtrusionPaths &paths : extra_perimeters) - this_islands_perimeters.append(std::move(paths)); - append(this_islands_perimeters.entities, old_entities); - infill_areas = diff_ex(infill_areas, filled_area); - } - } - //w21 - append(out_fill_no_overlap,offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.), float(min_perimeter_infill_spacing / 2.))); - append(out_fill_expolygons, std::move(infill_areas)); - } } void PerimeterGenerator::process_classic( @@ -1957,11 +1301,9 @@ void PerimeterGenerator::process_classic( const Parameters ¶ms, const Surface &surface, const ExPolygons *lower_slices, - //w16 const ExPolygons *upper_slices, // Cache: - Polygons &lower_layer_polygons_cache, - Polygons &upper_layer_polygons_cache, + Polygons &lower_slices_polygons_cache, // Output: // Loops with the external thin walls ExtrusionEntityCollection &out_loops, @@ -1970,9 +1312,7 @@ void PerimeterGenerator::process_classic( // Infills without the gap fills ExPolygons &out_fill_expolygons, //w21 - ExPolygons &out_fill_no_overlap, - //w23 - const size_t layer_id) + ExPolygons &out_fill_no_overlap) { // other perimeters coord_t perimeter_width = params.perimeter_flow.scaled_width(); @@ -1980,13 +1320,12 @@ void PerimeterGenerator::process_classic( // external perimeters coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width(); coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing(); - coord_t ext_perimeter_spacing2; //= scaled(0.5f * (params.ext_perimeter_flow.spacing() + params.perimeter_flow.spacing())); + coord_t ext_perimeter_spacing2 = scaled(0.5f * (params.ext_perimeter_flow.spacing() + params.perimeter_flow.spacing())); //w39 if (params.config.precise_outer_wall && !params.config.external_perimeters_first) ext_perimeter_spacing2 = scaled(0.5f * (params.ext_perimeter_flow.width() + params.perimeter_flow.width())); else ext_perimeter_spacing2 = scaled(0.5f * (params.ext_perimeter_flow.spacing() + params.perimeter_flow.spacing())); - // solid infill coord_t solid_infill_spacing = params.solid_infill_flow.scaled_spacing(); @@ -2005,33 +1344,27 @@ void PerimeterGenerator::process_classic( bool has_gap_fill = params.config.gap_fill_enabled.value && params.config.gap_fill_speed.value > 0; // prepare grown lower layer slices for overhang detection - if (params.config.overhangs && lower_slices != nullptr && lower_layer_polygons_cache.empty()) { + if (params.config.overhangs && lower_slices != nullptr && lower_slices_polygons_cache.empty()) { // We consider overhang any part where the entire nozzle diameter is not supported by the // lower layer, so we take lower slices and offset them by half the nozzle diameter used // in the current layer double nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder-1); - lower_layer_polygons_cache = offset(*lower_slices, float(scale_(+nozzle_diameter / 2))); + lower_slices_polygons_cache = offset(*lower_slices, float(scale_(+nozzle_diameter/2))); } // we need to process each island separately because we might have different // extra perimeters for each one // detect how many perimeters must be generated for this island int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops - ExPolygons last = union_ex(surface.expolygon.simplify_p(params.scaled_resolution)); - ExPolygons gaps; - //w16 - ExPolygons fill_clip; - ExPolygons top_fills; - //w16 - - if ( upper_slices != nullptr && upper_layer_polygons_cache.empty()) { - double upper_nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder - 1); - upper_layer_polygons_cache = offset(*upper_slices, float(scale_(+upper_nozzle_diameter / 2))); - } - //w16 - //w23 - if (loop_number > 0 && (params.object_config.top_one_wall_type != TopOneWallType::Disable && upper_slices == nullptr) || (params.object_config.only_one_wall_first_layer && layer_id == 0)) + + // Set the topmost layer to be one perimeter. + if (loop_number > 0 && ((params.config.top_one_perimeter_type != TopOnePerimeterType::None && upper_slices == nullptr) || (params.config.only_one_perimeter_first_layer && params.layer_id == 0))) loop_number = 0; + + ExPolygons last = union_ex(surface.expolygon.simplify_p(params.scaled_resolution)); + ExPolygons gaps; + ExPolygons top_fills; + ExPolygons fill_clip; if (loop_number >= 0) { // In case no perimeters are to be generated, loop_number will equal to -1. std::vector contours(loop_number+1); // depth => loops @@ -2071,22 +1404,17 @@ void PerimeterGenerator::process_classic( //FIXME Is this offset correct if the line width of the inner perimeters differs // from the line width of the infill? coord_t distance = (i == 1) ? ext_perimeter_spacing2 : perimeter_spacing; - //w16 - //offsets = params.config.thin_walls ? - // This path will ensure, that the perimeters do not overfill, as in - // qidi3d/Slic3r GH #32, but with the cost of rounding the perimeters + offsets = params.config.thin_walls ? // excessively, creating gaps, which then need to be filled in by the not very // reliable gap fill algorithm. // Also the offset2(perimeter, -x, x) may sometimes lead to a perimeter, which is larger than // the original. - //offset2_ex(last, - // - float(distance + min_spacing / 2. - 1.), - // float(min_spacing / 2. - 1.)) : + offset2_ex(last, + - float(distance + min_spacing / 2. - 1.), + float(min_spacing / 2. - 1.)) : // If "detect thin walls" is not enabled, this paths will be entered, which - // leads to overflows, as in qidi3d/Slic3r GH #32 - // offset_ex(last, - float(distance)); + offset_ex(last, - float(distance)); // look for gaps - offsets = offset2_ex(last, -float(distance + min_spacing / 2. - 1.), float(min_spacing / 2. - 1.)); if (has_gap_fill) // not using safety offset here would "detect" very narrow gaps // (but still long enough to escape the area threshold) that gap fill @@ -2125,50 +1453,62 @@ void PerimeterGenerator::process_classic( } last = std::move(offsets); - //w16 - if (i == 0 && i != loop_number && params.object_config.top_one_wall_type == TopOneWallType::Alltop && - upper_slices != nullptr) { - coord_t offset_top_surface = scale_( - 1.5 * (params.config.perimeters.value == 0 ? - 0. : - unscaled(double(ext_perimeter_width + perimeter_spacing * int(int(params.config.perimeters.value) - int(1)))))); - if (offset_top_surface > 0.9 * (params.config.perimeters.value <= 1 ? 0. : (perimeter_spacing * (params.config.perimeters.value - 1)))) - offset_top_surface -= coord_t( - 0.9 * (params.config.perimeters.value <= 1 ? 0. : (perimeter_spacing * (params.config.perimeters.value - 1)))); - else - offset_top_surface = 0; - //w17 - double min_width_top_surface = (params.object_config.top_area_threshold/100 ) * - std::max(double(ext_perimeter_spacing / 2 + 10), 1.0 * (double(perimeter_width))); - BoundingBox last_box = get_extents(last); - last_box.offset(SCALED_EPSILON); - Polygons upper_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(upper_layer_polygons_cache, - last_box); - upper_polygons_series_clipped = offset(upper_polygons_series_clipped, min_width_top_surface); - fill_clip = offset_ex(last, -double(ext_perimeter_spacing)); - ExPolygons bridge_checker; + // Store surface for top infill if top_one_perimeter_type is set to TopSurfaces. + if (i == 0 && i != loop_number && params.config.top_one_perimeter_type == TopOnePerimeterType::TopSurfaces && upper_slices != nullptr) { + // Split the polygons with top/not_top. + + // Get the offset from solid surface anchor. + const coordf_t total_perimeter_spacing = coordf_t(perimeter_spacing * (params.config.perimeters.value - 1)); + const coordf_t top_surface_offset_threshold = params.config.perimeters.value <= 1 ? 0. : 0.9 * total_perimeter_spacing; + coordf_t top_surface_offset = params.config.perimeters.value == 0 ? 0. : 1.5 * coordf_t(ext_perimeter_width + total_perimeter_spacing); + + // If possible, try to not push the extra perimeters inside the sparse infill. + if (top_surface_offset > top_surface_offset_threshold) { + top_surface_offset -= top_surface_offset_threshold; + } else + top_surface_offset = 0.; + + // Don't take into account too thin areas. + const float top_surface_min_width = std::max(float(ext_perimeter_spacing) / 2.f + scaled(0.00001), float(perimeter_width)); + + // Current slices bounding box. + BoundingBox current_perimeters_bbox = get_extents(last); + current_perimeters_bbox.offset(SCALED_EPSILON); + + ExPolygons current_slices_without_bridges; if (lower_slices != nullptr) { - Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(lower_layer_polygons_cache, - last_box); - - double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width))); - bridge_checker = offset_ex(diff_ex(last, lower_polygons_series_clipped, ApplySafetyOffset::Yes), 1.5 * bridge_offset); + const float bridge_offset = 1.5f * float(std::max(ext_perimeter_spacing, perimeter_width)); + const Polygons lower_slices_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, current_perimeters_bbox); + const ExPolygons current_slices_bridges = offset_ex(diff_ex(last, lower_slices_clipped, ApplySafetyOffset::Yes), bridge_offset); + current_slices_without_bridges = diff_ex(last, current_slices_bridges, ApplySafetyOffset::Yes); + } else { + current_slices_without_bridges = last; } - ExPolygons delete_bridge = diff_ex(last, bridge_checker, ApplySafetyOffset::Yes); - ExPolygons top_polygons = diff_ex(delete_bridge, upper_polygons_series_clipped, ApplySafetyOffset::Yes); - ExPolygons temp_gap = diff_ex(top_polygons, fill_clip); - ExPolygons inner_polygons = diff_ex(last, - offset_ex(top_polygons, offset_top_surface + min_width_top_surface - - double(ext_perimeter_spacing / 2)), - ApplySafetyOffset::Yes); - top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes); - top_fills = union_ex(top_fills, top_polygons); - double infill_spacing_unscaled = params.config.infill_extrusion_width.value; // this->config->sparse_infill_line_width.value; - fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2)); - last = intersection_ex(inner_polygons, last); - if (has_gap_fill) - last = union_ex(last, temp_gap); + // Get top ExPolygons (including external perimeters) from current slices without bridges. + const Polygons upper_slices_clipped = expand(ClipperUtils::clip_clipper_polygons_with_subject_bbox(*upper_slices, current_perimeters_bbox), top_surface_min_width); + const ExPolygons top_polygons = diff_ex(current_slices_without_bridges, upper_slices_clipped, ApplySafetyOffset::Yes); + + if (!top_polygons.empty()) { + // Set the clip to a virtual second perimeter. + fill_clip = offset_ex(last, -float(ext_perimeter_spacing)); + + // Get the not-top ExPolygons (including bridges) from current slices and expanded real top ExPolygons (without bridges). + const ExPolygons not_top_polygons = diff_ex(last, offset_ex(top_polygons, float(top_surface_offset) + top_surface_min_width - (float(ext_perimeter_spacing) / 2.f)), ApplySafetyOffset::Yes); + + // Get difference between top ExPolygons without bridges and the area defined by the virtual second perimeter. + const ExPolygons top_gap = diff_ex(top_polygons, fill_clip); + + // Get top infill surface ExPolygons (without bridges) using the difference between the area defined by the virtual second perimeter and non-top ExPolygons. + top_fills = diff_ex(fill_clip, not_top_polygons, ApplySafetyOffset::Yes); + + // Set the clip to the external perimeter but go back inside by infill_extrusion_width/2 to ensure the extrusion won't go outside even with a 100% overlap. + fill_clip = offset_ex(last, float((coordf_t(ext_perimeter_spacing) / 2.) - params.config.infill_extrusion_width.get_abs_value(params.solid_infill_flow.nozzle_diameter()) / 2.)); + last = intersection_ex(not_top_polygons, last); + + if (has_gap_fill) + last = union_ex(last, top_gap); + } } if (i == loop_number && (! has_gap_fill || params.config.fill_density.value == 0)) { @@ -2233,11 +1573,7 @@ void PerimeterGenerator::process_classic( } } // at this point, all loops should be in contours[0] - //w38 - bool steep_overhang_contour = false; - bool steep_overhang_hole = false; - ExtrusionEntityCollection entities = traverse_loops_classic(params, lower_layer_polygons_cache, contours.front(), thin_walls,steep_overhang_contour, steep_overhang_hole); - reorient_perimeters(entities, steep_overhang_contour, steep_overhang_hole, params.config.overhang_reverse_internal_only); + ExtrusionEntityCollection entities = traverse_loops_classic(params, lower_slices_polygons_cache, contours.front(), thin_walls); // if brim will be printed, reverse the order of perimeters so that // we continue inwards after having finished the brim // TODO: add test for perimeter order @@ -2290,7 +1626,11 @@ void PerimeterGenerator::process_classic( perimeter_spacing / 2; //w21 coord_t infill_peri_overlap = 0; - // only apply infill overlap if we actually have one perimeter + + // Only apply infill overlap if we actually have one perimeter. + const coord_t infill_perimeter_overlap = (inset > 0) ? coord_t(params.config.get_abs_value("infill_overlap", coordf_t(inset + solid_infill_spacing / 2.))) : 0; + inset -= infill_perimeter_overlap; + //w21 if (inset > 0) { infill_peri_overlap = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale( solid_infill_spacing / 2)))); @@ -2309,34 +1649,34 @@ void PerimeterGenerator::process_classic( float(- inset - min_perimeter_infill_spacing / 2.), float(min_perimeter_infill_spacing / 2.)); - ExPolygons top_infill_exp = intersection_ex(fill_clip, offset_ex(top_fills, double(ext_perimeter_spacing / 2))); - //w21 + // Apply single perimeter feature. if (!top_fills.empty()) { - infill_areas = union_ex(infill_areas, offset_ex(top_infill_exp, double(infill_peri_overlap))); + const ExPolygons top_infill_areas = intersection_ex(fill_clip, offset_ex(top_fills, float(ext_perimeter_spacing) / 2.f)); + infill_areas = union_ex(infill_areas, offset_ex(top_infill_areas, float(infill_perimeter_overlap))); + } + + //w21 + { + ExPolygons polyWithoutOverlap; + if (min_perimeter_infill_spacing / 2 > infill_peri_overlap) + polyWithoutOverlap = offset2_ex( + union_ex(pp), + float(-inset - min_perimeter_infill_spacing / 2.), + float(min_perimeter_infill_spacing / 2 - infill_peri_overlap)); + else + polyWithoutOverlap = offset_ex( + union_ex(pp), + double(-inset - infill_peri_overlap)); + if (!top_fills.empty()) + polyWithoutOverlap = union_ex(polyWithoutOverlap, intersection_ex(fill_clip, offset_ex(top_fills, float(ext_perimeter_spacing) / 2.f))); + out_fill_no_overlap.insert(out_fill_no_overlap.end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end()); } - - //w21 - { - ExPolygons polyWithoutOverlap; - if (min_perimeter_infill_spacing / 2 > infill_peri_overlap) - polyWithoutOverlap = offset2_ex( - union_ex(pp), - float(-inset - min_perimeter_infill_spacing / 2.), - float(min_perimeter_infill_spacing / 2 - infill_peri_overlap)); - else - polyWithoutOverlap = offset_ex( - union_ex(pp), - double(-inset - infill_peri_overlap)); - if (!top_fills.empty()) - polyWithoutOverlap = union_ex(polyWithoutOverlap, top_infill_exp); - out_fill_no_overlap.insert(out_fill_no_overlap.end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end()); - } if (lower_slices != nullptr && params.config.overhangs && params.config.extra_perimeters_on_overhangs && params.config.perimeters > 0 && params.layer_id > params.object_config.raft_layers) { // Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material auto [extra_perimeters, filled_area] = generate_extra_perimeters_over_overhangs(infill_areas, - lower_layer_polygons_cache, + lower_slices_polygons_cache, loop_number + 1, params.overhang_flow, params.scaled_resolution, params.object_config, params.print_config); @@ -2352,6 +1692,6 @@ void PerimeterGenerator::process_classic( } append(out_fill_expolygons, std::move(infill_areas)); +} } -} diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index d326c39..606afbd 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -1,15 +1,23 @@ #ifndef slic3r_PerimeterGenerator_hpp_ #define slic3r_PerimeterGenerator_hpp_ -#include "libslic3r.h" #include + +#include "libslic3r.h" #include "ExtrusionEntityCollection.hpp" #include "Flow.hpp" #include "Polygon.hpp" #include "PrintConfig.hpp" #include "SurfaceCollection.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/ExtrusionRole.hpp" +#include "libslic3r/Point.hpp" namespace Slic3r { +class ExtrusionEntityCollection; +class Surface; +struct ThickPolyline; namespace PerimeterGenerator { @@ -39,9 +47,7 @@ struct Parameters { scaled_resolution(scaled(print_config.gcode_resolution.value)), mm3_per_mm(perimeter_flow.mm3_per_mm()), ext_mm3_per_mm(ext_perimeter_flow.mm3_per_mm()), - mm3_per_mm_overhang(overhang_flow.mm3_per_mm()), - //w38 - lower_slices(lower_slices) + mm3_per_mm_overhang(overhang_flow.mm3_per_mm()) { } @@ -55,8 +61,6 @@ struct Parameters { const PrintRegionConfig &config; const PrintObjectConfig &object_config; const PrintConfig &print_config; - //w38 - const ExPolygons * lower_slices; // Derived parameters bool spiral_vase; @@ -74,11 +78,9 @@ void process_classic( const Parameters ¶ms, const Surface &surface, const ExPolygons *lower_slices, - //w16 const ExPolygons *upper_slices, // Cache: - Polygons &lower_layer_polygons_cache, - Polygons &upper_layer_polygons_cache, + Polygons &lower_slices_polygons_cache, // Output: // Loops with the external thin walls ExtrusionEntityCollection &out_loops, @@ -87,41 +89,16 @@ void process_classic( // Infills without the gap fills ExPolygons &out_fill_expolygons, //w21 - ExPolygons &out_fill_no_overlap, - //w23 - const size_t layer_id ); + ExPolygons &out_fill_no_overlap); void process_arachne( - // Inputs: - const Parameters ¶ms, - const Surface & surface, - const ExPolygons *lower_slices, - //w16 - const ExPolygons *upper_slices, - // Cache: - Polygons &lower_slices_polygons_cache, - // Output: - // Loops with the external thin walls - ExtrusionEntityCollection &out_loops, - // Gaps without the thin walls - ExtrusionEntityCollection &out_gap_fill, - // Infills without the gap fills - ExPolygons &out_fill_expolygons, - //w21 - ExPolygons &out_fill_no_overlap, - //w23 - const size_t layer_id); - -void process_with_one_wall_arachne( // Inputs: const Parameters ¶ms, const Surface &surface, const ExPolygons *lower_slices, - //w16 const ExPolygons *upper_slices, // Cache: Polygons &lower_slices_polygons_cache, - Polygons &upper_slices_polygons_cache, // Output: // Loops with the external thin walls ExtrusionEntityCollection &out_loops, @@ -130,23 +107,7 @@ void process_with_one_wall_arachne( // Infills without the gap fills ExPolygons &out_fill_expolygons, //w21 - ExPolygons &out_fill_no_overlap, - //w23 - const size_t layer_id); - -//w16 -void add_infill_contour_for_arachne(ExPolygons infill_contour, - int loops, - coord_t ext_perimeter_spacing, - coord_t perimeter_spacing, - coord_t min_perimeter_infill_spacing, - coord_t spacing, - bool is_inner_part, - const Parameters ¶ms, - ExPolygons & infill_areas, - ExPolygons & out_fill_expolygons, - //w21 - ExPolygons & out_fill_no_overlap); + ExPolygons &out_fill_no_overlap); ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 2e91b53..59f418c 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -334,7 +334,6 @@ std::string Preset::remove_invalid_keys(DynamicPrintConfig &config, const Dynami std::string incorrect_keys; for (const std::string &key : config.keys()) if (! default_config.has(key)) { - BOOST_LOG_TRIVIAL(error) << key; if (incorrect_keys.empty()) incorrect_keys = key; else { @@ -479,7 +478,7 @@ static std::vector s_Preset_print_options { "elefant_foot_compensation", "xy_size_compensation", "resolution", "gcode_resolution", "arc_fitting", "wipe_tower", "wipe_tower_x", "wipe_tower_y", //w12 - "elefant_foot_compensation", "xy_size_compensation", "xy_contour_compensation", "xy_hole_compensation", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", + "xy_contour_compensation", "xy_hole_compensation", "wipe_tower_width", "wipe_tower_cone_angle", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth", "wipe_tower_extruder", "wipe_tower_no_sparse_layers", "wipe_tower_extra_flow", "wipe_tower_extra_spacing", "compatible_printers", "compatible_printers_condition", "inherits", "perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", @@ -507,8 +506,6 @@ static std::vector s_Preset_print_options { "top_solid_infill_flow_ratio", "bottom_solid_infill_flow_ratio", //w33 "ironing_pattern", - //w38 - "overhang_reverse", "overhang_reverse_internal_only", "overhang_reverse_threshold", //w39 "precise_outer_wall", //Y27 @@ -523,7 +520,7 @@ static std::vector s_Preset_filament_options { "filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "temperature", "idle_temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", - "start_filament_gcode", "end_filament_gcode", "enable_dynamic_fan_speeds", + "start_filament_gcode", "end_filament_gcode", "enable_dynamic_fan_speeds", "chamber_temperature", "chamber_minimal_temperature", "overhang_fan_speed_0", "overhang_fan_speed_1", "overhang_fan_speed_2", "overhang_fan_speed_3", // Retract overrides "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", @@ -531,12 +528,12 @@ static std::vector s_Preset_filament_options { "filament_travel_slope", "filament_travel_max_lift", "filament_travel_lift_before_obstacle", // Profile compatibility "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits", + // Shrinkage compensation + "filament_shrinkage_compensation_xy", "filament_shrinkage_compensation_z", //B15 "enable_auxiliary_fan", //Y26 "enable_auxiliary_fan_unseal", - //B24 - "volume_temperature", //B25 "enable_volume_fan", //B26 @@ -547,8 +544,6 @@ static std::vector s_Preset_filament_options { "smooth_time", //B39 "disable_rapid_cooling_fan_first_layers", - //Y23 - "filament_shrink", //Y26 "seal_print", //Y28 @@ -568,7 +563,7 @@ static std::vector s_Preset_machine_limits_options { static std::vector s_Preset_printer_options { "printer_technology", "autoemit_temperature_commands", "bed_shape", "bed_custom_texture", "bed_custom_model", "binary_gcode", "z_offset", "gcode_flavor", "use_relative_e_distances", - "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", + "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "prefer_clockwise_movements", //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. "host_type", "print_host", "printhost_apikey", "printhost_cafile", "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", @@ -578,12 +573,13 @@ static std::vector s_Preset_printer_options { "max_print_height", "default_print_profile", "inherits", "remaining_times", "silent_mode", "machine_limits_usage", "thumbnails", "thumbnails_format", + "nozzle_high_flow", //Y20 //B52 "bed_exclude_area", //Y25 "wipe_device", //Y16 - "chamber_temperature", "auxiliary_fan", "chamber_fan" + "chamber_temperature_control", "auxiliary_fan", "chamber_fan" }; static std::vector s_Preset_sla_print_options { @@ -810,7 +806,7 @@ void PresetCollection::load_presets( PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule substitution_rule) { // Don't use boost::filesystem::canonical() on Windows, it is broken in regard to reparse points, - // see https://github.com/qidi3d/QIDISlicer/issues/732 + // see https://github.com/QIDITECH/QIDISlicer/issues/732 boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred(); m_dir_path = dir.string(); std::string errors_cummulative; @@ -1331,8 +1327,8 @@ size_t PresetCollection::get_preset_idx_by_name(const std::string name) const size_t PresetCollection::first_visible_idx() const { size_t first_visible = -1; - size_t idx = m_default_suppressed ? m_num_default_presets : 0; - for (; idx < m_presets.size(); ++idx) + size_t idx = m_default_suppressed ? m_num_default_presets : 0; + for (; idx < m_presets.size(); ++ idx) if (m_presets[idx].is_visible) { if (first_visible == -1) first_visible = idx; @@ -1978,7 +1974,7 @@ void PhysicalPrinterCollection::load_printers( PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule substitution_rule) { // Don't use boost::filesystem::canonical() on Windows, it is broken in regard to reparse points, - // see https://github.com/qidi3d/QIDISlicer/issues/732 + // see https://github.com/QIDITECH/QIDISlicer/issues/732 boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred(); m_dir_path = dir.string(); std::string errors_cummulative; diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index c560d4c..316e9ac 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -1764,14 +1764,8 @@ void PresetBundle::update_multi_material_filament_presets() size_t num_extruders = nozzle_diameter->values.size(); // Verify validity of the current filament presets. //B40 - for (size_t i = 0; i < std::min(this->extruders_filaments.size(), num_extruders); ++i) { - this->extruders_filaments[i].select_filament(this->filaments - .find_preset(this->filaments.get_selected_idx() == size_t(-1) ? - this->filaments.first_visible().name : - this->extruders_filaments[i].get_selected_preset_name(), - true) - ->name); - } + for (size_t i = 0; i < std::min(this->extruders_filaments.size(), num_extruders); ++i) + this->extruders_filaments[i].select_filament(this->filaments.find_preset(this->filaments.get_selected_idx() == size_t(-1) ? this->filaments.first_visible().name : this->extruders_filaments[i].get_selected_preset_name(), true)->name); if (this->extruders_filaments.size() > num_extruders) this->extruders_filaments.resize(num_extruders); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 1b2b4b0..699aee5 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -69,13 +69,13 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "binary_gcode", "bridge_acceleration", "bridge_fan_speed", - //B15 - // "auxiliary_fan_speed", "enable_dynamic_fan_speeds", "overhang_fan_speed_0", "overhang_fan_speed_1", "overhang_fan_speed_2", "overhang_fan_speed_3", + "chamber_temperature", + "chamber_minimal_temperature", "colorprint_heights", "cooling", "default_acceleration", @@ -195,8 +195,6 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n } else if ( opt_key == "first_layer_height" || opt_key == "nozzle_diameter" - //Y23 - || opt_key == "filament_shrink" || opt_key == "resolution" // Spiral Vase forces different kind of slicing than the normal model: // In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer. @@ -227,6 +225,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "filament_multitool_ramming_volume" || opt_key == "filament_multitool_ramming_flow" || opt_key == "filament_max_volumetric_speed" + || opt_key == "filament_infill_max_speed" + || opt_key == "filament_infill_max_crossing_speed" || opt_key == "gcode_flavor" || opt_key == "high_current_on_filament_swap" || opt_key == "infill_first" @@ -591,12 +591,19 @@ std::string Print::validate(std::vector* warnings) const //w27 if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx), print_object.config().precise_z_height.value); ! layers.empty() && layers.back() > this->config().max_print_height + EPSILON) { - return - // Test whether the last slicing plane is below or above the print volume. - 0.5 * (layers[layers.size() - 2] + layers.back()) > this->config().max_print_height + EPSILON ? - format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name) : - format(_u8L("While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height."), print_object.model_object()->name) + - " " + _u8L("You might want to reduce the size of your model or change current print settings and retry."); + + const double shrinkage_compensation_z = this->shrinkage_compensation().z(); + if (shrinkage_compensation_z != 1. && layers.back() > (this->config().max_print_height / shrinkage_compensation_z + EPSILON)) { + // The object exceeds the maximum build volume height because of shrinkage compensation. + return format(_u8L("While the object %1% itself fits the build volume, it exceeds the maximum build volume height because of material shrinkage compensation."), print_object.model_object()->name); + } else if (0.5 * (layers[layers.size() - 2] + layers.back()) > this->config().max_print_height + EPSILON) { + // The last slicing plane is below the print volume. + return format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name); + } else { + // The last slicing plane is above the print volume. + return format(_u8L("While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height."), print_object.model_object()->name) + + " " + _u8L("You might want to reduce the size of your model or change current print settings and retry."); + } } } @@ -1509,7 +1516,7 @@ void Print::_make_wipe_tower() // Check whether there are any layers in m_tool_ordering, which are marked with has_wipe_tower, // they print neither object, nor support. These layers are above the raft and below the object, and they // shall be added to the support layers to be printed. - // see https://github.com/qidi3d/QIDISlicer/issues/607 + // see https://github.com/QIDITECH/QIDISlicer/issues/607 { size_t idx_begin = size_t(-1); size_t idx_end = m_wipe_tower_data.tool_ordering.layer_tools().size(); diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 191b665..ce538f1 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1011,7 +1011,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides); t_config_option_keys full_config_diff = full_print_config_diffs(m_full_print_config, new_full_config); // If just a physical printer was changed, but printer preset is the same, then there is no need to apply whole print - // see https://github.com/qidi3d/QIDISlicer/issues/8800 + // see https://github.com/QIDITECH/QIDISlicer/issues/8800 if (full_config_diff.size() == 1 && full_config_diff[0] == "physical_printer_settings_id") full_config_diff.clear(); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 9ce7865..9b76274 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1,12 +1,5 @@ #include "PrintConfig.hpp" -#include "Config.hpp" -#include "I18N.hpp" -#include "format.hpp" -#include "SLA/SupportTree.hpp" -#include "GCode/Thumbnails.hpp" - -#include #include #include #include @@ -20,6 +13,7 @@ #include #include #include + #include "Config.hpp" #include "I18N.hpp" #include "format.hpp" @@ -27,7 +21,6 @@ #include "libslic3r/SLA/SupportTreeStrategies.hpp" #include "libslic3r/enum_bitmask.hpp" #include "libslic3r/libslic3r.h" -#include namespace Slic3r { @@ -54,6 +47,7 @@ static const t_config_enum_values s_keys_map_ArcFittingType { { "emit_center", int(ArcFittingType::EmitCenter) } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ArcFittingType) + static t_config_enum_values s_keys_map_PrinterTechnology { { "FFF", ptFFF }, { "SLA", ptSLA } @@ -235,6 +229,7 @@ static const t_config_enum_values s_keys_map_LabelObjectsStyle = { }; //B3 CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(LabelObjectsStyle) + static const t_config_enum_values s_keys_map_GCodeThumbnailsFormat = { { "QIDI", int(GCodeThumbnailsFormat::QIDI)}, { "PNG", int(GCodeThumbnailsFormat::PNG) }, @@ -256,11 +251,46 @@ static t_config_enum_values s_keys_map_PerimeterGeneratorType { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PerimeterGeneratorType) -//w16 -static t_config_enum_values s_keys_map_TopOneWallType{{"disable", int(TopOneWallType::Disable)}, - {"all_top", int(TopOneWallType::Alltop)}, - {"only_top_most", int(TopOneWallType::Onlytopmost)}}; -CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TopOneWallType) + +static t_config_enum_values s_keys_map_TopOnePerimeterType { + { "none", int(TopOnePerimeterType::None) }, + { "top", int(TopOnePerimeterType::TopSurfaces) }, + { "topmost", int(TopOnePerimeterType::TopmostOnly) } +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TopOnePerimeterType) + +static const t_config_enum_values s_keys_map_TowerSpeeds{ + { "layer1", tsLayer1 }, + { "layer2", tsLayer2 }, + { "layer3", tsLayer3 }, + { "layer4", tsLayer4 }, + { "layer5", tsLayer5 }, + { "layer8", tsLayer8 }, + { "layer11", tsLayer11 }, + { "layer14", tsLayer14 }, + { "layer18", tsLayer18 }, + { "layer22", tsLayer22 }, + { "layer24", tsLayer24 }, +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TowerSpeeds) + +static const t_config_enum_values s_keys_map_TiltSpeeds{ + { "move120", tsMove120 }, + { "layer200", tsLayer200 }, + { "move300", tsMove300 }, + { "layer400", tsLayer400 }, + { "layer600", tsLayer600 }, + { "layer800", tsLayer800 }, + { "layer1000", tsLayer1000 }, + { "layer1250", tsLayer1250 }, + { "layer1500", tsLayer1500 }, + { "layer1750", tsLayer1750 }, + { "layer2000", tsLayer2000 }, + { "layer2250", tsLayer2250 }, + { "move5120", tsMove5120 }, + { "move8000", tsMove8000 }, +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TiltSpeeds) static void assign_printer_technology_to_unknown(t_optiondef_map &options, PrinterTechnology printer_technology) { @@ -369,8 +399,8 @@ void PrintConfigDef::init_common_params() def->label = L("Format of G-code thumbnails"); def->tooltip = L("Format of G-code thumbnails: PNG for best quality, JPG for smallest size, QOI for low memory firmware"); def->mode = comExpert; - def->set_enum({"QIDI", "PNG", "JPG", "QOI"}); - def->set_default_value(new ConfigOptionEnum(GCodeThumbnailsFormat::QIDI)); + def->set_enum({"QIDI", "PNG", "JPG", "QOI" }); + def->set_default_value(new ConfigOptionEnum(GCodeThumbnailsFormat::PNG)); def = this->add("layer_height", coFloat); def->label = L("Layer height"); @@ -488,6 +518,7 @@ void PrintConfigDef::init_fff_params() }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(ArcFittingType::Disabled)); + // Maximum extruder temperature, bumped to 1500 to support printing of glass. const int max_temp = 1500; def = this->add("avoid_crossing_curled_overhangs", coBool); @@ -529,23 +560,37 @@ void PrintConfigDef::init_fff_params() def->max = 300; def->set_default_value(new ConfigOptionInts { 0 }); + def = this->add("chamber_temperature", coInts); + // TRN: Label of a configuration parameter: Nominal chamber temperature. + def->label = L("Nominal"); + def->full_label = L("Chamber temperature"); + def->tooltip = L("Required chamber temperature for the print.\nWhen set to zero, " + "the nominal chamber temperature is not set in the G-code."); + def->sidetext = L("°C"); + def->min = 0; + def->max = 1000; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts{ 0 }); + + def = this->add("chamber_minimal_temperature", coInts); + // TRN: Label of a configuration parameter: Minimal chamber temperature + def->label = L("Minimal"); + def->full_label = L("Chamber minimal temperature"); + def->tooltip = L("Minimal chamber temperature that the printer waits for before the print starts. This allows " + "to start the print before the nominal chamber temperature is reached.\nWhen set to zero, " + "the minimal chamber temperature is not set in the G-code."); + def->sidetext = L("°C"); + def->min = 0; + def->max = 1000; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts{ 0 }); + //Y16 - def = this->add("chamber_temperature", coBool); + def = this->add("chamber_temperature_control", coBool); def->label = L("Chamber Temperature"); def->tooltip = L("Enable chamber temperature control."); def->mode = comExpert; - def->set_default_value(new ConfigOptionBool(false)); - - //B24 - def = this->add("volume_temperature", coInts); - def->label = L("Chamber"); - def->tooltip = L("Chamber temperature for layers after the first one. " - "Set this to zero to disable bed temperature control commands in the output."); - def->sidetext = L("°C"); - def->full_label = L("Volume temperature"); - def->min = 0; - def->max = 65; - def->set_default_value(new ConfigOptionInts { 0 }); + def->set_default_value(new ConfigOptionBool(true)); //Y26 def = this->add("seal_print", coBool); @@ -1281,6 +1326,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloats { 0. }); + def = this->add("filament_cooling_moves", coInts); def->label = L("Number of cooling moves"); def->tooltip = L("Filament is cooled by being moved back and forth in the " @@ -1326,6 +1372,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionPercents { 100 }); + def = this->add("filament_load_time", coFloats); def->label = L("Filament load time"); def->tooltip = L("Time for the printer firmware (or the Multi Material Unit 2.0) to load a new filament during a tool change (when executing the T code). This time is added to the total print time by the G-code time estimator."); @@ -1381,19 +1428,6 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->set_default_value(new ConfigOptionFloats { 1.75 }); - //Y23 - def = this->add("filament_shrink", coPercents); - def->label = L("Shrinkage"); - def->tooltip = L("Enter the shrinkage percentage that the filament will get after cooling (94% if you measure 94mm instead of 100mm)." - " The part will be scaled in xy to compensate." - " Only the filament used for the perimeter is taken into account." - "\nBe sure to allow enough space between objects, as this compensation is done after the checks."); - def->sidetext = L("%"); - def->ratio_over = ""; - def->min = 10; - def->mode = comExpert; - def->set_default_value(new ConfigOptionPercents{ 100 }); - def = this->add("filament_density", coFloats); def->label = L("Density"); def->tooltip = L("Enter your filament density here. This is only for statistical information. " @@ -1431,15 +1465,20 @@ void PrintConfigDef::init_fff_params() "SCAFF" });*/ def->set_enum_values(ConfigOptionDef::GUIType::select_open, { - "ABS", + "ABS", "ABS-GF", "PA12-CF", "PAHT-CF", - "PET-CF", + "PET-CF", "PETG", "PLA", "UltraPA", - "TPU" + "TPU", + "PC/ABS-FR", + "ASA", + "PLA-CF", + "PPS-CF", + "ASA-Aero" }); def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings { "PLA" }); @@ -1836,6 +1875,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); + def = this->add("travel_acceleration", coFloat); def->label = L("Travel"); def->tooltip = L("This is the acceleration your printer will use for travel moves. Set zero to disable " @@ -2094,6 +2134,7 @@ void PrintConfigDef::init_fff_params() "To generate .bgcode files, make sure you have binary G-code enabled in Configuration->Preferences->Other."); def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("machine_limits_usage", coEnum); def->label = L("How to apply limits"); def->full_label = L("Purpose of Machine Limits"); @@ -2107,7 +2148,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(MachineLimitsUsage::TimeEstimateOnly)); - { struct AxisDefault { std::string name; @@ -2404,8 +2444,8 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Slic3r can upload G-code files to a printer host. This field must contain " "the kind of the host."); def->set_enum({ - { "qidilink", "QIDILink" }, - { "qidiconnect", "QIDIConnect" }, + { "qidilink", "QIDILink" }, + { "qidiconnect", "QIDIConnect" }, { "octoprint", "OctoPrint" }, { "moonraker", "Klipper (via QIDI)" }, { "moonraker2", "Klipper (via Moonraker)" }, @@ -2451,40 +2491,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); - //w38 - def = this->add("overhang_reverse", coBool); - def->label = L("Reverse on odd"); - def->category = L("Layers and Perimeters"); - def->tooltip = L("Extrude perimeters that have a part over an overhang in the reverse direction on odd layers. This alternating " - "pattern can drastically improve steep overhang."); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); - - def = this->add("overhang_reverse_internal_only", coBool); - def->label = L("Reverse only internal perimeters"); - def->category = L("Layers and Perimeters"); - def->tooltip = L("Apply the reverse perimeters logic only on internal perimeters. \n\nThis setting greatly reduces part stresses as " - "they are now distributed in alternating directions. This should reduce part warping while also maintaining external " - "wall quality. This feature can be very useful for warp prone material, like ABS/ASA, and also for elastic filaments, " - "like TPU and Silk PLA. It can also help reduce warping on floating regions over supports.\n\nFor this setting to be " - "the most effective, it is recomended to set the Reverse Threshold to 0 so that all internal walls print in " - "alternating directions on odd layers irrespective of their overhang degree."); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); - - //w38 - def = this->add("overhang_reverse_threshold", coFloatOrPercent); - def->label = L("Reverse threshold"); - def->category = L("Layers and Perimeters"); - def->tooltip = L("Number of mm the overhang need to be for the reversal to be considered useful. Can be a % of the perimeter width." - "\nValue 0 enables reversal on every odd layers regardless."); - def->sidetext = L("mm or %"); - def->ratio_over = "line_width"; - def->min = 0; - def->max_literal = 20; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(50, true)); - def = this->add("parking_pos_retraction", coFloat); def->label = L("Filament parking position"); def->tooltip = L("Distance of the extruder tip from the position where the filament is parked " @@ -2510,6 +2516,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm³"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(140.)); + def = this->add("perimeter_acceleration", coFloat); def->label = L("Perimeters"); def->tooltip = L("This is the acceleration your printer will use for perimeters. " @@ -2589,7 +2596,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Printer type"); def->tooltip = L("Type of the printer."); def->set_default_value(new ConfigOptionString()); - def->cli = ConfigOptionDef::nocli; +// def->cli = ConfigOptionDef::nocli; def = this->add("printer_notes", coString); def->label = L("Printer notes"); @@ -2610,7 +2617,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Printer variant"); def->tooltip = L("Name of the printer variant. For example, the printer variants may be differentiated by a nozzle diameter."); def->set_default_value(new ConfigOptionString()); - def->cli = ConfigOptionDef::nocli; +// def->cli = ConfigOptionDef::nocli; def = this->add("print_settings_id", coString); def->set_default_value(new ConfigOptionString("")); @@ -2709,6 +2716,7 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercents { 0. }); + //w15 def = this->add("wipe_distance", coFloats); def->label = L("Wipe Distance"); def->tooltip = L("Discribe how long the nozzle will move along the last path when retracting."); @@ -2716,7 +2724,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats{2.}); - def = this->add("retract_layer_change", coBools); def->label = L("Retract on layer change"); def->tooltip = L("This flag enforces a retraction whenever a Z move is done."); @@ -2774,6 +2781,13 @@ void PrintConfigDef::init_fff_params() "in case an obstacle might be hit during the initial phase of the travel."); def->mode = comExpert; def->set_default_value(new ConfigOptionBools{false}); + + def = this->add("nozzle_high_flow", coBools); + def->label = L("High flow nozzle"); + def->tooltip = L("High flow nozzles allow higher print speeds."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBools{false}); + def = this->add("retract_lift", coFloats); def->label = L("Lift height"); def->tooltip = L("Lift height applied before travel."); @@ -2781,7 +2795,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->max_literal = 1000; def->mode = comSimple; - def->set_default_value(new ConfigOptionFloats { 0. }); + def->set_default_value(new ConfigOptionFloats{0.}); def = this->add("retract_lift_above", coFloats); def->label = L("Above Z"); @@ -3037,16 +3051,17 @@ void PrintConfigDef::init_fff_params() def = this->add("autoemit_temperature_commands", coBool); def->label = L("Emit temperature commands automatically"); - def->tooltip = L("When enabled, QIDISlicer will check whether your Custom Start G-Code contains M104 or M190. " + def->tooltip = L("When enabled, QIDISlicer will check whether your custom Start G-Code contains G-codes to set " + "extruder, bed or chamber temperature (M104, M109, M140, M190, M141 and M191). " "If so, the temperatures will not be emitted automatically so you're free to customize " "the order of heating commands and other custom actions. Note that you can use " "placeholder variables for all QIDISlicer settings, so you can put " "a \"M109 S[first_layer_temperature]\" command wherever you want.\n" - "If your Custom Start G-Code does NOT contain M104 or M190, " - "QIDISlicer will execute the Start G-Code after bed reached its target temperature " - "and extruder just started heating.\n\n" - "When disabled, QIDISlicer will NOT emit commands to heat up extruder and bed, " - "leaving both to Custom Start G-Code."); + "If your custom Start G-Code does NOT contain these G-codes, " + "QIDISlicer will execute the Start G-Code after heated chamber was set to its temperature, " + "bed reached its target temperature and extruder just started heating.\n\n" + "When disabled, QIDISlicer will NOT emit commands to heat up extruder, bed or chamber, " + "leaving all to Custom Start G-Code."); def->mode = comExpert; def->set_default_value(new ConfigOptionBool(true)); @@ -3403,8 +3418,9 @@ void PrintConfigDef::init_fff_params() def->label = L("Synchronize with object layers"); def->category = L("Support material"); // TRN PrintSettings : "Synchronize with object layers" - //w34 - def->tooltip = L("If not checked, support layers to use layer heights that are independent of the object layer."); + def->tooltip = L("Synchronize support layers with the object print layers. This is useful " + "with multi-material printers, where the extruder switch is expensive. " + "This option is only available when top contact Z distance is set to zero."); def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); @@ -3557,7 +3573,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); - def = this->add("toolchange_gcode", coString); def->label = L("Tool change G-code"); def->tooltip = L("This custom code is inserted before every toolchange. Placeholder variables for all QIDISlicer settings " @@ -3667,6 +3682,12 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(true)); + def = this->add("prefer_clockwise_movements", coBool); + def->label = L("Prefer clockwise movements"); + def->tooltip = L("This setting makes the printer print loops clockwise instead of counterclockwise."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("wipe", coBools); def->label = L("Wipe while retracting"); def->tooltip = L("This flag will move the nozzle while retracting to minimize the possible blob " @@ -3681,7 +3702,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); - def = this->add("wiping_volumes_matrix", coFloats); def->label = L("Purging volumes - matrix"); def->tooltip = L("This matrix describes volumes (in cubic milimetres) required to purge the" @@ -3696,8 +3716,8 @@ void PrintConfigDef::init_fff_params() def->label = ""; def->tooltip = ""; def->set_default_value(new ConfigOptionBool{ false }); - def = this->add("wipe_tower_x", coFloat); + def = this->add("wipe_tower_x", coFloat); def->label = L("Position X"); def->tooltip = L("X coordinate of the left front corner of a wipe tower"); def->sidetext = L("mm"); @@ -3806,7 +3826,7 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionInt(0)); - def = this->add("xy_size_compensation", coFloat); + def = this->add("xy_size_compensation", coFloat); def->label = L("XY Size Compensation"); def->category = L("Advanced"); def->tooltip = L("The object will be grown/shrunk in the XY plane by the configured value " @@ -3860,37 +3880,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(PerimeterGeneratorType::Arachne)); - //w16 - def = this->add("top_one_wall_type", coEnum); - def->label = L("Only one wall on top surfaces"); - def->category = L("Layers and Perimeters"); - def->tooltip = L("Use only one wall on flat top surface, to give more space to the top infill pattern. Could be applyed on topmost surface or all top surface."); - def->set_enum({ - { "disable", L("Disable") }, - { "all_top", L("All top") }, - { "only_top_most", L("Only top most") } - }); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(TopOneWallType::Alltop)); - - //w17 - def = this->add("top_area_threshold", coPercent); - def->label = L("Top area threshold"); - def->tooltip = L("This factor affects the acreage of top area. The small the number the big the top area."); - def->sidetext = L("%"); - def->min = 0; - def->max = 500; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionPercent(100)); - - //w23 - def = this->add("only_one_wall_first_layer", coBool); - def->label = L("Only one wall on first layer"); - def->category = L("Advanced"); - def->tooltip = L("Use only one wall on the first layer of model"); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); - def = this->add("wall_transition_length", coFloatOrPercent); def->label = L("Perimeter transition length"); def->category = L("Advanced"); @@ -3971,7 +3960,6 @@ void PrintConfigDef::init_fff_params() "deretract_speed", "retract_restart_extra", "retract_before_travel", "retract_length_toolchange", "retract_restart_extra_toolchange", //w15 "wipe_distance", - "extrusion_multiplier", // bools "retract_layer_change", "wipe", "travel_lift_before_obstacle", "travel_ramping_lift", // percents @@ -4021,8 +4009,7 @@ void PrintConfigDef::init_extruder_option_keys() "retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe", "travel_slope", "travel_max_lift", "travel_ramping_lift", "travel_lift_before_obstacle", "retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour", - "extrusion_multiplier", - "default_filament_profile", + "default_filament_profile", "nozzle_high_flow", //w15 "wipe_distance" }; @@ -4033,7 +4020,6 @@ void PrintConfigDef::init_extruder_option_keys() "retract_before_wipe", "retract_layer_change", "retract_length", - "extrusion_multiplier", "retract_length_toolchange", "retract_lift", "retract_lift_above", @@ -4322,12 +4308,14 @@ void PrintConfigDef::init_sla_params() def->set_default_value(new ConfigOptionFloat(10.)); def = this->add("area_fill", coFloat); - def->label = L("Area fill"); - def->tooltip = L("The percentage of the bed area. \nIf the print area exceeds the specified value, \nthen a slow tilt will be used, otherwise - a fast tilt"); + def->label = L("Area fill threshold"); + def->tooltip = L("The value is expressed as a percentage of the bed area. If the area of a particular layer " + "is smaller than 'area_fill', then 'Below area fill threshold' parameters are used to determine the " + "layer separation (tearing) procedure. Otherwise 'Above area fill threshold' parameters are used."); def->sidetext = L("%"); def->min = 0; - def->mode = comExpert; - def->set_default_value(new ConfigOptionFloat(50.)); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(35.)); def = this->add("relative_correction", coFloats); def->label = L("Printer scaling correction"); @@ -4366,6 +4354,7 @@ void PrintConfigDef::init_sla_params() def->full_label = L("Printer absolute correction"); def->tooltip = L("Will inflate or deflate the sliced 2D polygons according " "to the sign of the correction."); + def->sidetext = L("mm"); def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.0)); @@ -4378,6 +4367,14 @@ void PrintConfigDef::init_sla_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.2)); + def = this->add("zcorrection_layers", coInt); + def->label = L("Z compensation"); + def->category = L("Advanced"); + def->tooltip = L("Number of layers to Z correct to avoid cross layer bleed"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInt(0)); + def = this->add("gamma_correction", coFloat); def->label = L("Printer gamma correction"); def->full_label = L("Printer gamma correction"); @@ -4834,6 +4831,7 @@ void PrintConfigDef::init_sla_params() def->min = float(SCALING_FACTOR); def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.001)); + // Declare retract values for material profile, overriding the print and printer profiles. for (const char* opt_key : { // float @@ -4841,8 +4839,7 @@ void PrintConfigDef::init_sla_params() "support_head_penetration", "branchingsupport_head_penetration", "support_head_width", "branchingsupport_head_width", "support_pillar_diameter", "branchingsupport_pillar_diameter", - "relative_correction_x", "relative_correction_y", "relative_correction_z", - "elefant_foot_compensation", + "elefant_foot_compensation", "absolute_correction", //w26 "elefant_foot_compensation_layers", // int @@ -4866,6 +4863,186 @@ void PrintConfigDef::init_sla_params() } } +// SLA Materials "sub-presets" settings +void PrintConfigDef::init_sla_tilt_params() +{ + ConfigOptionDef* def; + + def = this->add("delay_before_exposure", coFloats); + def->full_label = L("Delay before exposure"); + def->tooltip = L("Delay before exposure after previous layer separation."); + def->sidetext = L("s"); + def->min = 0; + def->max = 30; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats({ 3., 3.})); + + def = this->add("delay_after_exposure", coFloats); + def->full_label = L("Delay after exposure"); + def->tooltip = L("Delay after exposure before layer separation."); + def->sidetext = L("s"); + def->min = 0; + def->max = 30; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats({ 0., 0.})); + + def = this->add("tower_hop_height", coInts); + def->full_label = L("Tower hop height"); + def->tooltip = L("The height of the tower raise."); + def->sidetext = L("mm"); + def->min = 0; + def->max = 100; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts({ 0, 0})); + + def = this->add("tower_speed", coEnums); + def->full_label = L("Tower speed"); + def->tooltip = L("Tower speed used for tower raise."); + def->mode = comExpert; + def->sidetext = L("mm/s"); + def->set_enum({ + { "layer1", "1" }, + { "layer2", "2" }, + { "layer3", "3" }, + { "layer4", "4" }, + { "layer5", "5" }, + { "layer8", "8" }, + { "layer11", "11" }, + { "layer14", "14" }, + { "layer18", "18" }, + { "layer22", "22" }, + { "layer24", "24" }, + }); + def->set_default_value(new ConfigOptionEnums({ tsLayer22, tsLayer22 })); + + const std::initializer_list> tilt_speeds_il = { + { "move120", "120" }, + { "layer200", "200" }, + { "move300", "300" }, + { "layer400", "400" }, + { "layer600", "600" }, + { "layer800", "800" }, + { "layer1000", "1000" }, + { "layer1250", "1250" }, + { "layer1500", "1500" }, + { "layer1750", "1750" }, + { "layer2000", "2000" }, + { "layer2250", "2250" }, + { "move5120", "5120" }, + { "move8000", "8000" }, + }; + + def = this->add("tilt_down_initial_speed", coEnums); + def->full_label = L("Tilt down initial speed"); + def->tooltip = L("Tilt speed used for an initial portion of tilt down move."); + def->mode = comExpert; + def->sidetext = L("μ-steps/s"); + def->set_enum(tilt_speeds_il); + def->set_default_value(new ConfigOptionEnums({ tsLayer1750, tsLayer1750 })); + + def = this->add("tilt_down_finish_speed", coEnums); + def->full_label = L("Tilt down finish speed"); + def->tooltip = L("Tilt speed used for the rest of the tilt down move."); + def->mode = comExpert; + def->sidetext = L("μ-steps/s"); + def->set_enum(tilt_speeds_il); + def->set_default_value(new ConfigOptionEnums({ tsLayer1750, tsLayer1750 })); + + def = this->add("tilt_up_initial_speed", coEnums); + def->full_label = L("Tilt up initial speed"); + def->tooltip = L("Tilt speed used for an initial portion of tilt up move."); + def->mode = comExpert; + def->sidetext = L("μ-steps/s"); + def->set_enum(tilt_speeds_il); + def->set_default_value(new ConfigOptionEnums({ tsMove8000, tsMove8000 })); + + def = this->add("tilt_up_finish_speed", coEnums); + def->full_label = L("Tilt up finish speed"); + def->tooltip = L("Tilt speed used for the rest of the tilt-up."); + def->mode = comExpert; + def->sidetext = L("μ-steps/s"); + def->set_enum(tilt_speeds_il); + def->set_default_value(new ConfigOptionEnums({ tsLayer1750, tsLayer1750 })); + + def = this->add("use_tilt", coBools); + def->full_label = L("Use tilt"); + def->tooltip = L("If enabled, tilt is used for layer separation. Otherwise, all the parameters below are ignored."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBools({ true, true })); + + def = this->add("tilt_down_offset_steps", coInts); + def->full_label = L("Tilt down offset steps"); + def->tooltip = L("Number of steps to move down from the calibrated (horizontal) position with 'tilt_down_initial_speed'."); + def->sidetext = L("μ-steps"); + def->min = 0; + def->max = 10000; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts({ 0, 0 })); + + def = this->add("tilt_down_offset_delay", coFloats); + def->full_label = L("Tilt down offset delay"); + def->tooltip = L("Delay after the tilt reaches 'tilt_down_offset_steps' position."); + def->sidetext = L("s"); + def->min = 0; + def->max = 20; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloats({ 0., 0. })); + + def = this->add("tilt_down_cycles", coInts); + def->full_label = L("Tilt down cycles"); + def->tooltip = L("Number of cycles to split the rest of the tilt down move."); + def->min = 0; + def->max = 10; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts({ 1, 1 })); + + def = this->add("tilt_down_delay", coFloats); + def->full_label = L("Tilt down delay"); + def->tooltip = L("The delay between tilt-down cycles."); + def->sidetext = L("s"); + def->min = 0; + def->max = 20; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloats({ 0., 0. })); + + def = this->add("tilt_up_offset_steps", coInts); + def->full_label = L("Tilt up offset steps"); + def->tooltip = L("Move tilt up to calibrated (horizontal) position minus this offset."); + def->sidetext = L("μ-steps"); + def->min = 0; + def->max = 10000; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts({ 1200, 1200 })); + + def = this->add("tilt_up_offset_delay", coFloats); + def->full_label = L("Tilt up offset delay"); + def->tooltip = L("Delay after the tilt reaches 'tilt_up_offset_steps' position."); + def->sidetext = L("s"); + def->min = 0; + def->max = 20; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloats({ 0., 0. })); + + def = this->add("tilt_up_cycles", coInts); + def->full_label = L("Tilt up cycles"); + def->tooltip = L("Number of cycles to split the rest of the tilt-up."); + def->min = 0; + def->max = 10; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts({ 1, 1 })); + + def = this->add("tilt_up_delay", coFloats); + def->full_label = L("Tilt up delay"); + def->tooltip = L("The delay between tilt-up cycles."); + def->sidetext = L("s"); + def->min = 0; + def->max = 20; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloats({ 0., 0. })); + +} + + // Ignore the following obsolete configuration keys: static std::set PrintConfigDef_ignore = { "clip_multipart_objects", @@ -5016,6 +5193,7 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config) config.set_key_value("thumbnails", new ConfigOptionString(thumbnails_str)); } } + if (config.has("wiping_volumes_matrix") && !config.has("wiping_volumes_use_custom_matrix")) { // This is apparently some pre-2.7.3 config, where the wiping_volumes_matrix was always used. // The 2.7.3 introduced an option to use defaults derived from config. In case the matrix @@ -5138,6 +5316,87 @@ void DynamicPrintConfig::normalize_fdm() opt_wall_transition_length->value = std::max(opt_wall_transition_length->value, 0.001); } +// Default values containe option pair of values (Below and Above) for each titl modes +// (Slow, Fast, HighViscosity and NoTilt) -> used for SL1S and other vendors printers + +const std::map tilt_options_floats_defs = +{ + {"delay_before_exposure", ConfigOptionFloats({ 3., 3., 0., 1., 3.5, 3.5, 0., 0. }) } , + {"delay_after_exposure", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } , + {"tilt_down_offset_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } , + {"tilt_down_delay", ConfigOptionFloats({ 0., 0., 0., 0.5, 0., 0., 0., 0. }) } , + {"tilt_up_offset_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } , + {"tilt_up_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } , +}; + +const std::map tilt_options_ints_defs = +{ + {"tower_hop_height", ConfigOptionInts({ 0, 0, 0, 0, 5, 5, 0, 0 }) } , + {"tilt_down_offset_steps", ConfigOptionInts({ 0, 0, 0, 0, 2200, 2200, 0, 0 }) } , + {"tilt_down_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } , + {"tilt_up_offset_steps", ConfigOptionInts({ 1200, 1200, 600, 600, 2200, 2200, 0, 0 }) } , + {"tilt_up_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } , +}; + +const std::map tilt_options_bools_defs = +{ + {"use_tilt", ConfigOptionBools({ true, true, true, true, true, true, false, false })} , +}; + +const std::map> tower_tilt_options_enums_defs = +{ + {"tower_speed", ConfigOptionEnums({ tsLayer22, tsLayer22, tsLayer22, tsLayer22, tsLayer2, tsLayer2, tsLayer1, tsLayer1 })} , +}; + +const std::map> tilt_options_enums_defs = +{ + {"tilt_down_initial_speed", ConfigOptionEnums({ tsLayer1750, tsLayer1750, tsLayer1750, tsLayer1750, tsLayer800, tsLayer800, tsMove120, tsMove120 }) } , + {"tilt_down_finish_speed", ConfigOptionEnums({ tsLayer1750, tsLayer1750, tsMove8000, tsLayer1750, tsLayer1750, tsLayer1750, tsMove120, tsMove120 }) } , + {"tilt_up_initial_speed", ConfigOptionEnums({ tsMove8000, tsMove8000, tsMove8000, tsMove8000, tsLayer1750, tsLayer1750, tsMove120, tsMove120 }) } , + {"tilt_up_finish_speed", ConfigOptionEnums({ tsLayer1750, tsLayer1750, tsLayer1750, tsLayer1750, tsLayer800, tsLayer800, tsMove120, tsMove120 }) } , +}; + +// Default values containe option pair of values (Below and Above) for each titl modes +// (Slow, Fast, HighViscosity and NoTilt) -> used for SL1 printer + +const std::map tilt_options_floats_sl1_defs = +{ + {"delay_before_exposure", ConfigOptionFloats({ 3., 3., 0., 1., 3.5, 3.5, 0., 0. }) } , + {"delay_after_exposure", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } , + {"tilt_down_offset_delay", ConfigOptionFloats({ 1., 1., 0., 0., 0., 0., 0., 0. }) } , + {"tilt_down_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } , + {"tilt_up_offset_delay", ConfigOptionFloats({ 0., 0., 0., 0., 1., 1., 0., 0. }) } , + {"tilt_up_delay", ConfigOptionFloats({ 0., 0., 0., 0., 0., 0., 0., 0. }) } , +}; + +const std::map tilt_options_ints_sl1_defs = +{ + {"tower_hop_height", ConfigOptionInts({ 0, 0, 0, 0, 5, 5, 0, 0 }) } , + {"tilt_down_offset_steps", ConfigOptionInts({ 650, 650, 0, 0, 2200, 2200, 0, 0 }) } , + {"tilt_down_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } , + {"tilt_up_offset_steps", ConfigOptionInts({ 400, 400, 400, 400, 2200, 2200, 0, 0 }) } , + {"tilt_up_cycles", ConfigOptionInts({ 1, 1, 1, 1, 1, 1, 0, 0 }) } , +}; + +const std::map tilt_options_bools_sl1_defs = +{ + {"use_tilt", ConfigOptionBools({ true, true, true, true, true, true, false, false })} , +}; + + +const std::map> tower_tilt_options_enums_sl1_defs = +{ + {"tower_speed", ConfigOptionEnums({ tsLayer22, tsLayer22, tsLayer22, tsLayer22, tsLayer2, tsLayer2, tsLayer1, tsLayer1 })} , +}; + +const std::map> tilt_options_enums_sl1_defs = +{ + {"tilt_down_initial_speed", ConfigOptionEnums({ tsLayer400, tsLayer400, tsLayer400, tsLayer400, tsLayer600, tsLayer600, tsMove120, tsMove120 }) } , + {"tilt_down_finish_speed", ConfigOptionEnums({ tsLayer1500, tsLayer1500, tsLayer1750, tsLayer1500, tsLayer1500, tsLayer1500, tsMove120, tsMove120 }) } , + {"tilt_up_initial_speed", ConfigOptionEnums({ tsMove5120, tsMove5120, tsMove5120, tsMove5120, tsLayer1500, tsLayer1500, tsMove120, tsMove120 }) } , + {"tilt_up_finish_speed", ConfigOptionEnums({ tsLayer400, tsLayer400, tsLayer400, tsLayer400, tsLayer600, tsLayer600, tsMove120, tsMove120 }) } , +}; + void handle_legacy_sla(DynamicPrintConfig &config) { for (std::string corr : {"relative_correction", "material_correction"}) { @@ -5158,6 +5417,66 @@ void handle_legacy_sla(DynamicPrintConfig &config) } } } + + // Load default tilt options in config in respect to the print speed, if config is loaded from old PS + + if (config.has("material_print_speed") && + !config.has("tilt_down_offset_delay") // Config from old PS doesn't contain any of tilt options, so check it + ) { + int tilt_mode = config.option("material_print_speed")->getInt(); + + const bool is_sl1_model = config.opt_string("printer_model") == "SL1"; + + const std::map floats_defs = is_sl1_model ? tilt_options_floats_sl1_defs : tilt_options_floats_defs; + const std::map ints_defs = is_sl1_model ? tilt_options_ints_sl1_defs : tilt_options_ints_defs; + const std::map bools_defs = is_sl1_model ? tilt_options_bools_sl1_defs : tilt_options_bools_defs; + const std::map> tower_enums_defs = is_sl1_model ? tower_tilt_options_enums_sl1_defs : tower_tilt_options_enums_defs; + const std::map> tilt_enums_defs = is_sl1_model ? tilt_options_enums_sl1_defs : tilt_options_enums_defs; + + for (const std::string& opt_key : tilt_options()) { + switch (config.def()->get(opt_key)->type) { + case coFloats: { + ConfigOptionFloats values = floats_defs.at(opt_key); + double val1 = values.get_at(2 * tilt_mode); + double val2 = values.get_at(2 * tilt_mode + 1); + config.set_key_value(opt_key, new ConfigOptionFloats({ val1, val2 })); + } + break; + case coInts: { + auto values = ints_defs.at(opt_key); + int val1 = values.get_at(2 * tilt_mode); + int val2 = values.get_at(2 * tilt_mode + 1); + config.set_key_value(opt_key, new ConfigOptionInts({ val1, val2 })); + } + break; + case coBools: { + auto values = bools_defs.at(opt_key); + bool val1 = values.get_at(2 * tilt_mode); + bool val2 = values.get_at(2 * tilt_mode + 1); + config.set_key_value(opt_key, new ConfigOptionBools({ val1, val2 })); + } + break; + case coEnums: { + int val1, val2; + if (opt_key == "tower_speed") { + auto values = tower_enums_defs.at(opt_key); + val1 = values.get_at(2 * tilt_mode); + val2 = values.get_at(2 * tilt_mode + 1); + } + else { + auto values = tilt_enums_defs.at(opt_key); + val1 = values.get_at(2 * tilt_mode); + val2 = values.get_at(2 * tilt_mode + 1); + } + config.set_key_value(opt_key, new ConfigOptionEnumsGeneric({ val1, val2 })); + } + break; + case coNone: + default: + break; + } + } + } } void DynamicPrintConfig::set_num_extruders(unsigned int num_extruders) @@ -5294,7 +5613,7 @@ std::string validate(const FullPrintConfig &cfg) if (em <= 0) return "Invalid value for --extrusion-multiplier"; - // The following test was commented out after 482841b, see also https://github.com/qidi3d/QIDISlicer/pull/6743. + // The following test was commented out after 482841b, see also https://github.com/QIDITECH/QIDISlicer/pull/6743. // The backend should now handle this case correctly. I.e., zero default_acceleration behaves as if all others // were zero too. This is now consistent with what the UI said would happen. // The UI already grays the fields out, there is no more reason to reject it here. This function validates the @@ -5470,7 +5789,13 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->cli = "gcodeviewer"; def->set_default_value(new ConfigOptionBool(false)); -#if ENABLE_GL_CORE_PROFILE + def = this->add("opengl-aa", coBool); + def->label = L("Automatic OpenGL antialiasing samples number selection"); + def->tooltip = L("Automatically select the highest number of samples for OpenGL antialiasing."); + def->cli = "opengl-aa"; + def->set_default_value(new ConfigOptionBool(false)); + +#if !SLIC3R_OPENGL_ES def = this->add("opengl-version", coString); def->label = L("OpenGL version"); def->tooltip = L("Select a specific version of OpenGL"); @@ -5482,12 +5807,13 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->tooltip = L("Enable OpenGL compatibility profile"); def->cli = "opengl-compatibility"; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("opengl-debug", coBool); def->label = L("OpenGL debug output"); def->tooltip = L("Activate OpenGL debug output on graphic cards which support it (OpenGL 4.3 or higher)"); def->cli = "opengl-debug"; def->set_default_value(new ConfigOptionBool(false)); -#endif // ENABLE_GL_CORE_PROFILE +#endif // !SLIC3R_OPENGL_ES def = this->add("slice", coBool); def->label = L("Slice"); @@ -5655,6 +5981,10 @@ CLIMiscConfigDef::CLIMiscConfigDef() "or an existing QIDISlicer window is activated. " "Overrides the \"single_instance\" configuration value from application preferences."); + def = this->add("single_instance_on_url", coBool); + def->label = "Single instance mode for qidislicer url"; // Not translated on purpose - for internal use only. + def->tooltip = "Works as single_instance but only if qidislicer url is present."; + def = this->add("datadir", coString); def->label = L("Data directory"); def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage."); @@ -5663,29 +5993,84 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->label = L("Maximum number of threads"); def->tooltip = L("Sets the maximum number of threads the slicing process will use. If not defined, it will be decided automatically."); def->min = 1; + def = this->add("loglevel", coInt); def->label = L("Logging level"); def->tooltip = L("Sets logging sensitivity. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n" "For example. loglevel=2 logs fatal, error and warning level messages."); def->min = 0; + def = this->add("webdev", coBool); + def->label = "Enable webdev tools"; // Not translated on purpose - for internal use only. + def->tooltip = "Enable webdev tools"; + #if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(SLIC3R_GUI) def = this->add("sw_renderer", coBool); def->label = L("Render with a software renderer"); def->tooltip = L("Render with a software renderer. The bundled MESA software renderer is loaded instead of the default OpenGL driver."); def->min = 0; #endif /* _MSC_VER */ + + def = this->add("printer-profile", coString); + def->label = ("Printer preset name"); + def->tooltip = ("Name of the printer preset used for slicing."); + def->set_default_value(new ConfigOptionString()); + + def = this->add("print-profile", coString); + def->label = ("Print preset name"); + def->tooltip = ("Name of the print preset used for slicing."); + def->set_default_value(new ConfigOptionString()); + + def = this->add("material-profile", coStrings); + def->label = ("Material preset name(s)"); + def->tooltip = ("Name(s) of the material preset(s) used for slicing.\n" + "Could be filaments or sla_material preset name(s) depending on printer tochnology"); + def->set_default_value(new ConfigOptionStrings()); +} + +CLIProfilesSharingConfigDef::CLIProfilesSharingConfigDef() +{ + ConfigOptionDef* def; + + // Information from this def will be used just for console output. + // So, don't use L marker to label and tooltips values to avoid extract those phrases to translation. + + def = this->add("query-printer-models", coBool); + def->label = ("Get list of printer models"); + def->tooltip = ("Get list of installed printer models into JSON.\n" + "Note:\n" + "To print printer models for required technology use 'printer-technology' option with value FFF or SLA. By default printer_technology is FFF.\n" + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option."); + +/* + def = this->add("query-printer-profiles", coBool); + def->label = ("Get list of printer profiles for the selected printer model and printer variant"); + def->tooltip = ("Get list of printer profiles for the selected 'printer-model' and 'printer-variant' into JSON.\n" + "Note:\n" + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option."); +*/ + + def = this->add("query-print-filament-profiles", coBool); + def->label = ("Get list of print profiles and filament profiles for the selected printer profile"); + def->tooltip = ("Get list of print profiles and filament profiles for the selected 'printer-profile' into JSON.\n" + "Note:\n" + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option."); } const CLIActionsConfigDef cli_actions_config_def; const CLITransformConfigDef cli_transform_config_def; const CLIMiscConfigDef cli_misc_config_def; +const CLIProfilesSharingConfigDef cli_profiles_sharing_config_def; DynamicPrintAndCLIConfig::PrintAndCLIConfigDef DynamicPrintAndCLIConfig::s_def; void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std::string &value) const { if (cli_actions_config_def .options.find(opt_key) == cli_actions_config_def .options.end() && + cli_profiles_sharing_config_def.options.find(opt_key) == cli_profiles_sharing_config_def.options.end() && cli_transform_config_def.options.find(opt_key) == cli_transform_config_def.options.end() && cli_misc_config_def .options.find(opt_key) == cli_misc_config_def .options.end()) { PrintConfigDef::handle_legacy(opt_key, value); @@ -5994,6 +6379,7 @@ CustomGcodeSpecificConfigDef::CustomGcodeSpecificConfigDef() def = this->add("toolchange_z", coFloat); def->label = L("Toolchange Z"); def->tooltip = L("Height above the print bed when the toolchange takes place. Usually the same as layer_z, but can be different."); + def = this->add("color_change_extruder", coInt); // TRN: This is a label in custom g-code editor dialog, belonging to color_change_extruder. Denoted index of the extruder for which color change is performed. def->label = L("Color change extruder"); @@ -6001,6 +6387,7 @@ CustomGcodeSpecificConfigDef::CustomGcodeSpecificConfigDef() } const CustomGcodeSpecificConfigDef custom_gcode_specific_config_def; + uint64_t ModelConfig::s_last_timestamp = 1; static Points to_points(const std::vector &dpts) @@ -6070,6 +6457,7 @@ bool is_XL_printer(const PrintConfig &cfg) } // namespace Slic3r -#include +#include // IWYU pragma: keep + CEREAL_REGISTER_TYPE(Slic3r::DynamicPrintConfig) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index d7d7a65..6016658 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -161,6 +161,7 @@ enum DraftShield { enum class LabelObjectsStyle { Disabled, Octoprint, Firmware }; + enum class PerimeterGeneratorType { // Classic perimeter generator using Clipper offsets with constant extrusion width. @@ -169,6 +170,7 @@ enum class PerimeterGeneratorType // "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling" ported from Cura. Arachne }; + enum class TopOnePerimeterType { None, @@ -177,7 +179,9 @@ enum class TopOnePerimeterType Count }; //B3 -enum class GCodeThumbnailsFormat { QIDI,PNG, JPG, QOI }; +enum class GCodeThumbnailsFormat { + QIDI,PNG, JPG, QOI +}; enum TowerSpeeds : int { tsLayer1, @@ -598,8 +602,6 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, raft_first_layer_expansion)) ((ConfigOptionInt, raft_layers)) ((ConfigOptionEnum, seam_position)) - //Y21 - ((ConfigOptionPercent, seam_gap)) ((ConfigOptionBool, staggered_inner_seams)) // ((ConfigOptionFloat, seam_preferred_direction)) // ((ConfigOptionFloat, seam_preferred_direction_jitter)) @@ -661,14 +663,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, wipe_into_objects)) //w11 ((ConfigOptionBool, detect_narrow_internal_solid_infill)) - //w16 - ((ConfigOptionEnum, top_one_wall_type)) - //w17 - ((ConfigOptionPercent, top_area_threshold)) //w21 ((ConfigOptionFloat, filter_top_gap_infill)) - //w23 - ((ConfigOptionBool, only_one_wall_first_layer)) //w27 ((ConfigOptionBool, precise_z_height)) ) @@ -744,12 +740,12 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, top_solid_infill_flow_ratio)) ((ConfigOptionFloat, bottom_solid_infill_flow_ratio)) - //w38 - ((ConfigOptionBool, overhang_reverse)) - ((ConfigOptionBool, overhang_reverse_internal_only)) - ((ConfigOptionFloatOrPercent, overhang_reverse_threshold)) //w39 - ((ConfigOptionBool, precise_outer_wall))) + ((ConfigOptionBool, precise_outer_wall)) + // Single perimeter. + ((ConfigOptionEnum, top_one_perimeter_type)) + ((ConfigOptionBool, only_one_perimeter_first_layer)) +) PRINT_CONFIG_CLASS_DEFINE( MachineEnvelopeConfig, @@ -908,9 +904,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionPoints, bed_exclude_area)) ((ConfigOptionInts, bed_temperature)) //Y16 - ((ConfigOptionBool, chamber_temperature)) - //B24 - ((ConfigOptionInts, volume_temperature)) + ((ConfigOptionBool, chamber_temperature_control)) //Y26 ((ConfigOptionBool, seal_print)) ((ConfigOptionFloat, bridge_acceleration)) @@ -920,6 +914,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionInts, overhang_fan_speed_1)) ((ConfigOptionInts, overhang_fan_speed_2)) ((ConfigOptionInts, overhang_fan_speed_3)) + ((ConfigOptionInts, chamber_temperature)) + ((ConfigOptionInts, chamber_minimal_temperature)) ((ConfigOptionBool, complete_objects)) ((ConfigOptionFloats, colorprint_heights)) ((ConfigOptionBools, cooling)) @@ -947,8 +943,6 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionInts, fan_below_layer_time)) ((ConfigOptionStrings, filament_colour)) ((ConfigOptionStrings, filament_notes)) - //Y23 - ((ConfigOptionPercents, filament_shrink)) ((ConfigOptionFloat, first_layer_acceleration)) ((ConfigOptionInts, first_layer_bed_temperature)) ((ConfigOptionFloatOrPercent, first_layer_extrusion_width)) @@ -1018,6 +1012,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloats, wiping_volumes_matrix)) ((ConfigOptionBool, wiping_volumes_use_custom_matrix)) ((ConfigOptionFloat, z_offset)) + //Y21 + ((ConfigOptionPercent, seam_gap)) ) PRINT_CONFIG_CLASS_DERIVED_DEFINE0( @@ -1267,13 +1263,10 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloatNullable, material_ow_support_head_width)) ((ConfigOptionFloatNullable, material_ow_branchingsupport_head_width)) ((ConfigOptionIntNullable, material_ow_support_points_density_relative)) + ((ConfigOptionFloatNullable, material_ow_elefant_foot_compensation)) ((ConfigOptionFloatNullable, material_ow_absolute_correction)) ((ConfigOptionFloat, area_fill)) - ((ConfigOptionFloatNullable, material_ow_elefant_foot_compensation)) - ((ConfigOptionFloatNullable, material_ow_relative_correction_x)) - ((ConfigOptionFloatNullable, material_ow_relative_correction_y)) - ((ConfigOptionFloatNullable, material_ow_relative_correction_z)) //tilt params ((ConfigOptionFloats, delay_before_exposure)) ((ConfigOptionFloats, delay_after_exposure)) @@ -1440,6 +1433,7 @@ public: CustomGcodeSpecificConfigDef(); }; extern const CustomGcodeSpecificConfigDef custom_gcode_specific_config_def; + // This class defines the command line options representing actions. extern const CLIActionsConfigDef cli_actions_config_def; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 3d37a16..c076f13 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -873,17 +873,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "wall_transition_angle" || opt_key == "wall_distribution_count" || opt_key == "min_feature_size" - || opt_key == "min_bead_width" - //w16 - || opt_key == "top_one_wall_type" - //w17 - || opt_key == "top_area_threshold" - //w23 - || opt_key == "only_one_wall_first_layer" - //w38 - || opt_key == "overhang_reverse" - || opt_key == "overhang_reverse_internal_only" - || opt_key == "overhang_reverse_threshold") { + || opt_key == "min_bead_width") { steps.emplace_back(posSlice); } else if ( opt_key == "seam_position" @@ -1613,15 +1603,12 @@ void PrintObject::discover_vertical_shells() // Open to remove (filter out) regions narrower than a bit less than an infill extrusion line width. // Such narrow regions are difficult to fill in with a gap fill algorithm (or Arachne), however they are most likely // not needed for print stability / quality. - //W11 - const float narrow_ensure_vertical_wall_thickness_region_radius = 0.65f * 0.7f * min_perimeter_infill_spacing;//0.7f*0.75f may error in complex model/ original parameter 0.5f * 0.65f + const float narrow_ensure_vertical_wall_thickness_region_radius = 0.5f * 0.65f * min_perimeter_infill_spacing; // Then close gaps narrower than 1.2 * line width, such gaps are difficult to fill in with sparse infill, // thus they will be merged into the solid infill. - //W11 - const float narrow_sparse_infill_region_radius = 0.7f * 1.25f * min_perimeter_infill_spacing;//0.7f*1.25f may error in complex model /original parameter 0.5f * 1.2f + const float narrow_sparse_infill_region_radius = 0.5f * 1.2f * min_perimeter_infill_spacing; // Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions. - //W11 - const float tiny_overlap_radius = 0.19f * min_perimeter_infill_spacing;// original parameter 0.2f + const float tiny_overlap_radius = 0.2f * min_perimeter_infill_spacing; regularized_shell = shrink_ex(offset2_ex(union_ex(shell), // Open to remove (filter out) regions narrower than an infill extrusion line width. -narrow_ensure_vertical_wall_thickness_region_radius, @@ -1651,10 +1638,8 @@ void PrintObject::discover_vertical_shells() regularized_shell.erase(std::remove_if(regularized_shell.begin(), regularized_shell.end(), [&internal_volume, &min_perimeter_infill_spacing, &object_volume](const ExPolygon &p) { - //W11 - return (p.area() < min_perimeter_infill_spacing * scaled(2.0) ||//original parameter scaled(1.5) - //W11 - (p.area() < min_perimeter_infill_spacing * scaled(10.0) &&//original parameter scaled(8.0) + return (p.area() < min_perimeter_infill_spacing * scaled(1.5) || + (p.area() < min_perimeter_infill_spacing * scaled(8.0) && diff(to_polygons(p), object_volume).empty())) && diff(internal_volume, expand(to_polygons(p), min_perimeter_infill_spacing)) @@ -2373,17 +2358,11 @@ void PrintObject::bridge_over_infill() Polygons lightning_area; Polygons expansion_area; Polygons total_fill_area; - //w35 - Polygons top_area; for (const LayerRegion *region : layer->regions()) { Polygons internal_polys = to_polygons(region->fill_surfaces().filter_by_types({stInternal, stInternalSolid})); expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end()); Polygons fill_polys = to_polygons(region->fill_expolygons()); total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end()); - //w35 - Polygons top_polys = to_polygons(region->fill_surfaces().filter_by_type(stTop)); - top_area.insert(top_area.end(), top_polys.begin(), top_polys.end()); - if (region->region().config().fill_pattern == ipLightning) { Polygons l = to_polygons(region->fill_surfaces().filter_by_type(stInternal)); lightning_area.insert(lightning_area.end(), l.begin(), l.end()); @@ -2462,21 +2441,12 @@ void PrintObject::bridge_over_infill() bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle); } } - //w35 - bridging_area = opening(bridging_area, flow.scaled_spacing()); - bridging_area = closing(bridging_area, flow.scaled_spacing()); - bridging_area = intersection(bridging_area, limiting_area); - bridging_area = intersection(bridging_area, total_fill_area); - bridging_area = diff(bridging_area, top_area); - bridging_area = opening(bridging_area, flow.scaled_spacing()); - bridging_area = closing(bridging_area, flow.scaled_spacing()); - expansion_area = diff(expansion_area, bridging_area); - - //bridging_area = opening(bridging_area, flow.scaled_spacing()); - //bridging_area = closing(bridging_area, flow.scaled_spacing()); - //bridging_area = intersection(bridging_area, limiting_area); - //bridging_area = intersection(bridging_area, total_fill_area); - //expansion_area = diff(expansion_area, bridging_area); + + bridging_area = opening(bridging_area, flow.scaled_spacing()); + bridging_area = closing(bridging_area, flow.scaled_spacing()); + bridging_area = intersection(bridging_area, limiting_area); + bridging_area = intersection(bridging_area, total_fill_area); + expansion_area = diff(expansion_area, bridging_area); #ifdef DEBUG_BRIDGE_OVER_INFILL debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_expanded_bridging" + std::to_string(r), diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 2239bcb..fe22eb0 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -423,21 +423,6 @@ static std::vector> slices_to_regions( }); } -//Y23 - for (const std::unique_ptr& pr : print_object_regions.all_regions) { - if (pr.get()) { - std::vector& region_polys = slices_by_region[pr->print_object_region_id()]; - const size_t extruder_id = pr->extruder(FlowRole::frPerimeter) - 1; - double scale = print_config.filament_shrink.values[extruder_id] * 0.01; - if (scale != 1) { - scale = 1 / scale; - for (ExPolygons& polys : region_polys) - for (ExPolygon& poly : polys) - poly.scale(scale); - } - } - } - return slices_by_region; } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 9bd5096..8d14b73 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1,5 +1,5 @@ #include "SLAPrint.hpp" -#include "SLAPrintSteps.hpp" +#include "SLAPrintSteps.hpp" // IWYU pragma: keep #include "CSGMesh/CSGMeshCopy.hpp" #include "CSGMesh/PerformCSGMeshBooleans.hpp" #include "format.hpp" diff --git a/src/libslic3r/Support/SupportMaterial.cpp b/src/libslic3r/Support/SupportMaterial.cpp index 478ffe9..f35948d 100644 --- a/src/libslic3r/Support/SupportMaterial.cpp +++ b/src/libslic3r/Support/SupportMaterial.cpp @@ -1853,7 +1853,6 @@ static inline SupportGeneratorLayer* detect_bottom_contacts( // Allocate a new bottom contact layer. SupportGeneratorLayer &layer_new = layer_storage.allocate_unguarded(SupporLayerType::BottomContact); - //w34 Layer *upper_layer = layer.upper_layer; if (!object.config().support_material_synchronize_layers) { @@ -1875,11 +1874,11 @@ static inline SupportGeneratorLayer* detect_bottom_contacts( //w34 //layer_new.height = slicing_params.soluble_interface ? // Align the interface layer with the object's layer height. - // layer.upper_layer->height : + //layer.upper_layer->height : // Place a bridge flow interface layer or the normal flow interface layer over the top surface. - // support_params.support_material_bottom_interface_flow.height(); + //support_params.support_material_bottom_interface_flow.height(); //layer_new.print_z = slicing_params.soluble_interface ? layer.upper_layer->print_z : - // layer.print_z + layer_new.height + slicing_params.gap_object_support; + //layer.print_z + layer_new.height + slicing_params.gap_object_support; layer_new.bottom_z = layer.print_z; layer_new.idx_object_layer_below = layer_id; layer_new.bridging = !slicing_params.soluble_interface && object.config().thick_bridges; diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 34cd8af..aee4cef 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -270,7 +270,7 @@ static std::vector>> group_me for (const LayerRegion *layerm : current_layer.regions()) remove_bridges_from_contacts(print_config, lower_layer, *layerm, float(layerm->flow(frExternalPerimeter).scaled_width()), overhangs); - } + } //w28 else if (!config.dont_support_bridges && bridge_break) { for (const LayerRegion *layerm : current_layer.regions()) @@ -570,7 +570,7 @@ static std::optional> polyline_sample_next_point_at_dis if (part.front() == part.back()) { size_t optimal_start_index = 0; - // If the polyline was a polygon, there is a high chance it was an overhang. Overhangs that are <60� tend to be very thin areas, so lets get the beginning and end of them and ensure that they are supported. + // If the polyline was a polygon, there is a high chance it was an overhang. Overhangs that are <60?tend to be very thin areas, so lets get the beginning and end of them and ensure that they are supported. // The first point of the line will always be supported, so rotate the order of points in this polyline that one of the two corresponding points that are furthest from each other is in the beginning. // The other will be manually added (optimal_end_index) coord_t max_dist2_between_vertecies = 0; @@ -1187,7 +1187,7 @@ void sample_overhang_area( if (point_count <= min_support_points) { // add the outer wall (of the overhang) to ensure it is correct supported instead. Try placing the support points in a way that they fully support the outer wall, instead of just the with half of the the support line width. // I assume that even small overhangs are over one line width wide, so lets try to place the support points in a way that the full support area generated from them - // will support the overhang (if this is not done it may only be half). This WILL NOT be the case when supporting an angle of about < 60� so there is a fallback, + // will support the overhang (if this is not done it may only be half). This WILL NOT be the case when supporting an angle of about < 60?so there is a fallback, // as some support is better than none. Polygons reduced_overhang_area = offset(union_ex(overhang_area), - interface_placer.config.support_line_width / 2.2, jtMiter, 1.2); polylines = ensure_maximum_distance_polyline( @@ -3651,11 +3651,9 @@ void fff_tree_support_generate(PrintObject &print_object, std::function ++idx; } //B52 - FFFTreeSupport::generate_support_areas(*print_object.print(), - BuildVolume(Pointfs{Vec2d{-300., -300.}, Vec2d{-300., +300.}, Vec2d{+300., +300.}, - Vec2d{+300., -300.}}, - 0., Pointfs{Vec2d{0., 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., Pointfs{Vec2d{0., 0.}}), { idx }, + throw_on_cancel); } } // namespace Slic3r diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index fb72fbb..019a1f5 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -913,8 +913,7 @@ bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i &nei return true; } -void TriangleSelector::set_facet(int facet_idx, TriangleStateType state) -{ +void TriangleSelector::set_facet(int facet_idx, TriangleStateType state) { assert(facet_idx < m_orig_size_indices); undivide_triangle(facet_idx); assert(! m_triangles[facet_idx].is_split()); diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 0eb8d9b..e59d3a5 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -3,6 +3,7 @@ // #define QIDISLICER_TRIANGLE_SELECTOR_DEBUG + #include #include #include diff --git a/src/libslic3r/TriangleSelectorWrapper.cpp b/src/libslic3r/TriangleSelectorWrapper.cpp index 57421ab..e9c75b9 100644 --- a/src/libslic3r/TriangleSelectorWrapper.cpp +++ b/src/libslic3r/TriangleSelectorWrapper.cpp @@ -1,4 +1,5 @@ #include "TriangleSelectorWrapper.hpp" + #include #include #include diff --git a/src/libslic3r/TriangleSetSampling.cpp b/src/libslic3r/TriangleSetSampling.cpp index 65f1964..f4f9ebe 100644 --- a/src/libslic3r/TriangleSetSampling.cpp +++ b/src/libslic3r/TriangleSetSampling.cpp @@ -1,4 +1,5 @@ #include "TriangleSetSampling.hpp" + #include #include #include diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 5267ed2..a2a9b0f 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -100,7 +100,7 @@ extern CopyFileResult copy_file(const std::string &from, const std::string &to, extern CopyFileResult check_copy(const std::string& origin, const std::string& copy); // Ignore system and hidden files, which may be created by the DropBox synchronisation process. -// https://github.com/qidi3d/QIDISlicer/issues/1298 +// https://github.com/QIDITECH/QIDISlicer/issues/1298 extern bool is_plain_file(const boost::filesystem::directory_entry &path); extern bool is_ini_file(const boost::filesystem::directory_entry &path); extern bool is_idx_file(const boost::filesystem::directory_entry &path); diff --git a/src/libslic3r/miniz_extension.cpp b/src/libslic3r/miniz_extension.cpp index 43acbee..19d8b94 100644 --- a/src/libslic3r/miniz_extension.cpp +++ b/src/libslic3r/miniz_extension.cpp @@ -42,7 +42,7 @@ bool open_zip(mz_zip_archive *zip, const char *fname, bool isread) if (!res) // if we get here it means we tried to open a non-zip file // we need to close the file here because the call to mz_zip_get_cfile() made into close_zip() returns a null pointer - // see: https://github.com/qidi3d/QIDISlicer/issues/3536 + // see: https://github.com/QIDITECH/QIDISlicer/issues/3536 fclose(f); } else diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 6d56ead..d770fc8 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -35,7 +35,7 @@ #include #include -#include +#include // IWYU pragma: keep #include @@ -766,7 +766,7 @@ CopyFileResult check_copy(const std::string &origin, const std::string ©) } // Ignore system and hidden files, which may be created by the DropBox synchronisation process. -// https://github.com/qidi3d/QIDISlicer/issues/1298 +// https://github.com/QIDITECH/QIDISlicer/issues/1298 bool is_plain_file(const boost::filesystem::directory_entry &dir_entry) { if (! boost::filesystem::is_regular_file(dir_entry.status())) diff --git a/src/libvgcode/src/ViewerImpl.cpp b/src/libvgcode/src/ViewerImpl.cpp index bb8cd85..e38738d 100644 --- a/src/libvgcode/src/ViewerImpl.cpp +++ b/src/libvgcode/src/ViewerImpl.cpp @@ -893,7 +893,7 @@ void ViewerImpl::reset() // On some graphic cards texture buffers using GL_RGB32F format do not work, see: // https://dev.qidi3d.com/browse/SPE-2411 -// https://github.com/qidi3d/QIDISlicer/issues/12908 +// https://github.com/QIDITECH/QIDISlicer/issues/12908 // To let all drivers be happy, we use GL_RGBA32F format, so we need to add an extra (currently unused) float // to position and heights_widths_angles vectors using Vec4 = std::array;