diff --git a/README.md b/README.md index 43d89c66f0..6a11fd1ecb 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,14 @@ Orca Slicer's logo is designed by community member Justin Levine(@freejstnalxndr - Tools needed: Xcode, Cmake, git, gettext, libtool, automake, autoconf, texinfo - You can install most of them by running `brew install cmake gettext libtool automake autoconf texinfo` - run `build_release_macos.sh` + - To build and debug in XCode: + - run `XCode.app` + - open ``build_`arch`/OrcaSlicer.xcodeproj`` + - menu bar: Product => Scheme => OrcaSlicer + - menu bar: Product => Scheme => Edit Scheme... + - Run => Info tab => Build Configuration: `RelWithDebInfo` + - Run => Options tab => Document Versions: uncheck `Allow debugging when browsing versions` + - menu bar: Product => Run - Ubuntu - Dependencies **Will be auto installed with the shell script**: `libmspack-dev libgstreamerd-3-dev libsecret-1-dev libwebkit2gtk-4.0-dev libosmesa6-dev libssl-dev libcurl4-openssl-dev eglexternalplatform-dev libudev-dev libdbus-1-dev extra-cmake-modules libgtk2.0-dev libglew-dev libudev-dev libdbus-1-dev cmake git texinfo` diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index 106ded3853..7d341365c5 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -12046,7 +12046,7 @@ msgstr "" msgid "" "We would rename the presets as \"Vendor Type Serial @printer you " "selected\". \n" -"To add preset for more prinetrs, Please go to printer selection" +"To add preset for more printers, Please go to printer selection" msgstr "" msgid "Create Printer/Nozzle" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 5f19440cae..d3cbac6f5e 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -12756,7 +12756,7 @@ msgstr "" msgid "" "We would rename the presets as \"Vendor Type Serial @printer you " "selected\". \n" -"To add preset for more prinetrs, Please go to printer selection" +"To add preset for more printers, Please go to printer selection" msgstr "" msgid "Create Printer/Nozzle" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 517d1fcee3..d6ab001e41 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -12849,7 +12849,7 @@ msgstr "" msgid "" "We would rename the presets as \"Vendor Type Serial @printer you " "selected\". \n" -"To add preset for more prinetrs, Please go to printer selection" +"To add preset for more printers, Please go to printer selection" msgstr "" msgid "Create Printer/Nozzle" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 5db41b8bd8..a1baa54ec0 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -12473,7 +12473,7 @@ msgstr "" msgid "" "We would rename the presets as \"Vendor Type Serial @printer you " "selected\". \n" -"To add preset for more prinetrs, Please go to printer selection" +"To add preset for more printers, Please go to printer selection" msgstr "" msgid "Create Printer/Nozzle" diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 4d32b1672f..9a5da3997f 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -12963,7 +12963,7 @@ msgstr "" msgid "" "We would rename the presets as \"Vendor Type Serial @printer you " "selected\". \n" -"To add preset for more prinetrs, Please go to printer selection" +"To add preset for more printers, Please go to printer selection" msgstr "" msgid "Create Printer/Nozzle" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index b00ed9fb37..70bbf52d3b 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -12775,7 +12775,7 @@ msgstr "" msgid "" "We would rename the presets as \"Vendor Type Serial @printer you " "selected\". \n" -"To add preset for more prinetrs, Please go to printer selection" +"To add preset for more printers, Please go to printer selection" msgstr "" msgid "Create Printer/Nozzle" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index 2d437fefd8..c96a526e7f 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: OrcaSlicer\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-01-13 17:34+0100\n" -"PO-Revision-Date: 2024-01-05 21:10+0300\n" +"PO-Revision-Date: 2024-01-19 01:16+0300\n" "Last-Translator: Olcay ÖREN\n" "Language-Team: Türkçe\n" "Language: tr_TR\n" @@ -4546,6 +4546,9 @@ msgid "" "Hint: Make sure you have added the corresponding printer before importing " "the configs." msgstr "" +"\n" +"İpucu: Yapılandırmaları içe aktarmadan önce ilgili yazıcıyı " +"eklediğinizden emin olun." msgid "Import result" msgstr "Sonucu içe aktar" @@ -7808,13 +7811,13 @@ msgid "Gizmo FDM paint-on seam" msgstr "Gizmo FDM boyalı dikiş" msgid "Gizmo Text emboss / engrave" -msgstr "" +msgstr "Gizmo Metin kabartma / kazıma" msgid "Zoom in" -msgstr "" +msgstr "Yakınlaştır" msgid "Zoom out" -msgstr "" +msgstr "Uzaklaştır" msgid "Switch between Prepare/Preview" msgstr "Hazırlama/Önizleme arasında geçiş yap" @@ -9245,7 +9248,7 @@ msgstr "" "düşünün." msgid "Don't filter out small internal bridges (experimental)" -msgstr "" +msgstr "Küçük iç köprüleri filtrelemeyin (deneysel)" msgid "" "This option can help reducing pillowing on top surfaces in heavily slanted " @@ -9275,15 +9278,41 @@ msgid "" "overhang. This option is useful for heavily slanted top surface models. " "However, in most cases it creates too many unecessary bridges." msgstr "" +"Bu seçenek, aşırı eğimli veya kavisli modellerde üst yüzeylerdeki " +"yastıklamanın azaltılmasına yardımcı olabilir.\n" +"\n" +"Varsayılan olarak küçük iç köprüler filtrelenir ve iç katı dolgu " +"doğrudan seyrek dolgunun üzerine yazdırılır. Bu çoğu durumda işe yarar " +"ve üstün yüzey kalitesinden çok fazla ödün vermeden yazdırmayı " +"hızlandırır. \n" +"\n" +"Bununla birlikte, özellikle çok düşük seyrek dolgu yoğunluğunun kullanıldığı " +"aşırı eğimli veya kavisli modellerde, bu durum desteklenmeyen katı dolgunun " +"kıvrılmasına ve yastıklanmaya neden olmasına neden olabilir.\n" +"\n" +"Bu seçeneğin etkinleştirilmesi, iç köprü katmanını hafif desteklenmeyen " +"dahili katı dolgu üzerine yazdıracaktır. Aşağıdaki seçenekler filtreleme " +"miktarını, yani oluşturulan dahili köprülerin miktarını kontrol eder.\n" +"\n" +"Devre Dışı - Bu seçeneği devre dışı bırakır. Bu varsayılan davranıştır " +"ve çoğu durumda iyi çalışır.\n" +"\n" +"Sınırlı filtreleme - Aşırı eğimli yüzeylerde iç köprüler oluştururken " +"gereksiz iç köprülerin oluşmasını da önler. Bu, çoğu zor modelde " +"işe yarar.\n" +"\n" +"Filtreleme yok - Her potansiyel dahili çıkıntıda dahili köprüler " +"oluşturur. Bu seçenek, aşırı eğimli üst yüzey modelleri için kullanışlıdır. " +"Ancak çoğu durumda çok fazla gereksiz köprü oluşturur." msgid "Disabled" -msgstr "" +msgstr "Devredışı" msgid "Limited filtering" -msgstr "" +msgstr "Sınırlı filtreleme" msgid "No filtering" -msgstr "" +msgstr "Filtresiz" msgid "Max bridge length" msgstr "Maksimum köprü uzunluğu" @@ -10365,10 +10394,10 @@ msgid "Klipper" msgstr "Klipper" msgid "Support multi bed types" -msgstr "" +msgstr "Çoklu tabla" msgid "Enable this option if you want to use multiple bed types" -msgstr "" +msgstr "Birden fazla tabla tipi kullanmak istiyorsanız bu seçeneği etkinleştirin" msgid "Label objects" msgstr "Nesneleri etiketle" @@ -12368,7 +12397,7 @@ msgstr "" "üzerinden yüzde olarak ifade edilir" msgid "Minimum wall length" -msgstr "" +msgstr "Minimum duvar uzunluğu" msgid "" "Adjust this value to prevent short, unclosed walls from being printed, which " @@ -12380,6 +12409,14 @@ msgid "" "top-surface. 'One wall threshold' is only visibile if this setting is set " "above the default value of 0.5, or if single-wall top surfaces is enabled." msgstr "" +"Yazdırma süresini artırabilecek kısa, kapatılmamış duvarların yazdırılmasını önlemek için " +"bu değeri ayarlayın. Daha yüksek değerler daha fazla ve daha uzun duvarları kaldırır.\n" +"\n" +"NOT: Modelin dış kısmında görsel boşluk kalmaması için alt ve üst " +"yüzeyler bu değerden etkilenmeyecektir. Üst yüzey olarak kabul edilen şeyin " +"hassasiyetini ayarlamak için aşağıdaki Gelişmiş ayarlarda " +"'Tek duvar eşiği'ni ayarlayın. 'Tek duvar eşiği' yalnızca bu ayar varsayılan değer olan " +"0,5'in üzerine ayarlandığında veya tek duvarlı üst yüzeyler etkinleştirildiğinde görünür." msgid "First layer minimum wall width" msgstr "İlk katman minimum duvar genişliği" @@ -13993,6 +14030,8 @@ msgstr "" "Bu sistemde %s, sistem Sertifika Deposu veya Anahtar Zincirinden alınan " "HTTPS sertifikalarını kullanıyor." + + msgid "" "To use a custom CA file, please import your CA file into Certificate Store / " "Keychain." diff --git a/resources/profiles/Kingroon/machine/kingroon kp3s pro s1 0.4 nozzle.json b/resources/profiles/Kingroon/machine/Kingroon KP3S PRO S1 0.4 nozzle.json similarity index 96% rename from resources/profiles/Kingroon/machine/kingroon kp3s pro s1 0.4 nozzle.json rename to resources/profiles/Kingroon/machine/Kingroon KP3S PRO S1 0.4 nozzle.json index e6258abf7f..7c99007fd5 100644 --- a/resources/profiles/Kingroon/machine/kingroon kp3s pro s1 0.4 nozzle.json +++ b/resources/profiles/Kingroon/machine/Kingroon KP3S PRO S1 0.4 nozzle.json @@ -8,5 +8,6 @@ "default_print_profile": "0.20mm Standard @Kingroon KP3S PRO S1", "machine_end_gcode": "G1 E-1.0 F2100 ; retract\nG92 E0.0\nG1{if max_layer_z < max_print_height} Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} E-34.0 F720 ; move print head up & retract filament\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y105 F3000 ; park print head\nM84 ; disable motors", "machine_start_gcode": "G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nG28 ; home all\nG1 Y1.0 Z0.3 F1000 ; move print head up\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG92 E0.0\n; initial load\n M117 Purge extruder\n G1 X2 Y20 Z0.3 F5000.0 ; move to start-line position\n G1 X2 Y175.0 Z0.3 F1500.0 E15 ; draw 1st line\n G1 X2 Y175.0 Z0.4 F5000.0 ; move to side a little\n G1 X2 Y20 Z0.4 F1500.0 E30 ; draw 2nd line\n G92 E0 ; reset extruder\n G1 Z1.0 F3000 ; move z up little to prevent scratching of surface", - "type": "machine" + "type": "machine", + "nozzle_diameter": ["0.4"] } diff --git a/resources/profiles/Kingroon/machine/kingroon kp3s pro s1.json b/resources/profiles/Kingroon/machine/Kingroon KP3S PRO S1.json similarity index 100% rename from resources/profiles/Kingroon/machine/kingroon kp3s pro s1.json rename to resources/profiles/Kingroon/machine/Kingroon KP3S PRO S1.json diff --git a/resources/profiles/Kingroon/machine/Kingroon KP3S PRO V2 0.4 nozzle.json b/resources/profiles/Kingroon/machine/Kingroon KP3S PRO V2 0.4 nozzle.json index 4701bf624d..f9b9d316ae 100644 --- a/resources/profiles/Kingroon/machine/Kingroon KP3S PRO V2 0.4 nozzle.json +++ b/resources/profiles/Kingroon/machine/Kingroon KP3S PRO V2 0.4 nozzle.json @@ -36,5 +36,6 @@ "205x205", "0x205" ], -"printable_height": "200" +"printable_height": "200", +"nozzle_diameter": ["0.4"] } diff --git a/resources/profiles/Kingroon/process/0.08mm Standard @Kingroon KP3S PRO S1.json b/resources/profiles/Kingroon/process/0.08mm Standard @Kingroon KP3S PRO S1.json index b5d7f157cd..d90e558ac5 100644 --- a/resources/profiles/Kingroon/process/0.08mm Standard @Kingroon KP3S PRO S1.json +++ b/resources/profiles/Kingroon/process/0.08mm Standard @Kingroon KP3S PRO S1.json @@ -7,5 +7,6 @@ "line_width": "0.4", "inherits": "fdm_process_common", "name": "0.08mm Standard @Kingroon KP3S PRO S1", - "print_settings_id": "0.08mm Standard @Kingroon KP3S PRO S1" + "print_settings_id": "0.08mm Standard @Kingroon KP3S PRO S1", + "instantiation": "true" } \ No newline at end of file diff --git a/resources/profiles/Kingroon/process/0.12mm Standard @Kingroon KP3S PRO S1.json b/resources/profiles/Kingroon/process/0.12mm Standard @Kingroon KP3S PRO S1.json index e05d6f87bb..0f1da5e0d4 100644 --- a/resources/profiles/Kingroon/process/0.12mm Standard @Kingroon KP3S PRO S1.json +++ b/resources/profiles/Kingroon/process/0.12mm Standard @Kingroon KP3S PRO S1.json @@ -7,5 +7,6 @@ "layer_height": "0.12", "line_width": "0.4", "name": "0.12mm Standard @Kingroon KP3S PRO S1", - "print_settings_id": "0.12mm Standard @Kingroon KP3S PRO S1" + "print_settings_id": "0.12mm Standard @Kingroon KP3S PRO S1", + "instantiation": "true" } \ No newline at end of file diff --git a/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO S1.json b/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO S1.json index 9814d713df..01c5101152 100644 --- a/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO S1.json +++ b/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO S1.json @@ -8,5 +8,6 @@ "name": "0.20mm Standard @Kingroon KP3S PRO S1", "initial_layer_print_height": "0.2", "layer_height": "0.2", - "line_width": "0.42" + "line_width": "0.42", + "instantiation": "true" } \ No newline at end of file diff --git a/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO V2.json b/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO V2.json index 00c09592a9..24ecc68f05 100644 --- a/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO V2.json +++ b/resources/profiles/Kingroon/process/0.20mm Standard @Kingroon KP3S PRO V2.json @@ -8,5 +8,6 @@ "print_settings_id": "0.20mm Standard @Kingroon KP3S PRO V2", "initial_layer_print_height": "0.2", "layer_height": "0.2", - "line_width": "0.42" + "line_width": "0.42", + "instantiation": "true" } \ No newline at end of file diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 0a159d5d88..772395f9bc 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -67,7 +67,8 @@ Fill* Fill::new_from_type(const InfillPattern type) // BBS: for internal solid infill only case ipConcentricInternal: return new FillConcentricInternal(); // BBS: for bottom and top surface only - case ipMonotonicLine: return new FillMonotonicLineWGapFill(); + // Orca: Replace BBS implementation with Prusa implementation + case ipMonotonicLine: return new FillMonotonicLines(); default: throw Slic3r::InvalidArgument("unknown type"); } } @@ -173,6 +174,66 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para for (size_t i = idx; i < eec->entities.size(); i++) eec->entities[i]->set_reverse(); } + + // Orca: run gap fill + this->_create_gap_fill(surface, params, eec); + } +} + +// Orca: Dedicated function to calculate gap fill lines for the provided surface, according to the print object parameters +// and append them to the out ExtrusionEntityCollection. +void Fill::_create_gap_fill(const Surface* surface, const FillParams& params, ExtrusionEntityCollection* out){ + + //Orca: just to be safe, check against null pointer for the print object config and if NULL return. + if (this->print_object_config == nullptr) return; + + // Orca: Enable gap fill as per the user preference. Return early if gap fill is to not be applied. + if ((this->print_object_config->gap_fill_target.value == gftNowhere) || + (surface->surface_type == stInternalSolid && this->print_object_config->gap_fill_target.value != gftEverywhere)) + return; + + Flow new_flow = params.flow; + ExPolygons unextruded_areas; + unextruded_areas = diff_ex(this->no_overlap_expolygons, union_ex(out->polygons_covered_by_spacing(10))); + ExPolygons gapfill_areas = union_ex(unextruded_areas); + if (!this->no_overlap_expolygons.empty()) + gapfill_areas = intersection_ex(gapfill_areas, this->no_overlap_expolygons); + + if (gapfill_areas.size() > 0 && params.density >= 1) { + double min = 0.2 * new_flow.scaled_spacing() * (1 - INSET_OVERLAP_TOLERANCE); + double max = 2. * new_flow.scaled_spacing(); + ExPolygons gaps_ex = diff_ex( + opening_ex(gapfill_areas, float(min / 2.)), + offset2_ex(gapfill_areas, -float(max / 2.), float(max / 2. + ClipperSafetyOffset))); + //BBS: sort the gap_ex to avoid mess travel + Points ordering_points; + ordering_points.reserve(gaps_ex.size()); + ExPolygons gaps_ex_sorted; + gaps_ex_sorted.reserve(gaps_ex.size()); + for (const ExPolygon &ex : gaps_ex) + ordering_points.push_back(ex.contour.first_point()); + std::vector order2 = chain_points(ordering_points); + for (size_t i : order2) + gaps_ex_sorted.emplace_back(std::move(gaps_ex[i])); + + ThickPolylines polylines; + for (ExPolygon& ex : gaps_ex_sorted) { + //BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well. + ex.douglas_peucker(SCALED_RESOLUTION * 0.1); + ex.medial_axis(min, max, &polylines); + } + + if (!polylines.empty() && !is_bridge(params.extrusion_role)) { + polylines.erase(std::remove_if(polylines.begin(), polylines.end(), + [&](const ThickPolyline& p) { + return p.length() < scale_(params.config->filter_out_gap_fill.value); + }), polylines.end()); + + ExtrusionEntityCollection gap_fill; + variable_width(polylines, erGapFill, params.flow, gap_fill.entities); + auto gap = std::move(gap_fill.entities); + out->append(gap); + } } } diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index f4eaa20fb6..38f8c722b5 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -19,6 +19,7 @@ #include "../Flow.hpp" #include "../ExtrusionEntity.hpp" #include "../ExtrusionEntityCollection.hpp" +#include "../ShortestPath.hpp" namespace Slic3r { @@ -106,6 +107,7 @@ public: FillAdaptive::Octree* adapt_fill_octree = nullptr; // PrintConfig and PrintObjectConfig are used by infills that use Arachne (Concentric and FillEnsuring). + // Orca: also used by gap fill function. const PrintConfig *print_config = nullptr; const PrintObjectConfig *print_object_config = nullptr; @@ -134,7 +136,7 @@ public: // Perform the fill. virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms); virtual ThickPolylines fill_surface_arachne(const Surface* surface, const FillParams& params); - + // BBS: this method is used to fill the ExtrusionEntityCollection. // It call fill_surface by default virtual void fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out); @@ -172,6 +174,10 @@ protected: virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; } virtual std::pair _infill_direction(const Surface *surface) const; + + // Orca: Dedicated function to calculate gap fill lines for the provided surface, according to the print object parameters + // and append them to the out ExtrusionEntityCollection. + void _create_gap_fill(const Surface* surface, const FillParams& params, ExtrusionEntityCollection* out); public: static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams ¶ms); diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index c97de62aa3..dc9595eac4 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -3099,7 +3099,22 @@ Points sample_grid_pattern(const Polygons& polygons, coord_t spacing, const Boun return sample_grid_pattern(union_ex(polygons), spacing, global_bounding_box); } -void FillMonotonicLineWGapFill::fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out) +// Orca: Introduced FillMonotonicLines from Prusa slicer, inhereting from FillRectilinear +// This replaces the FillMonotonicLineWGapFill from BBS +Polylines FillMonotonicLines::fill_surface(const Surface *surface, const FillParams ¶ms) +{ + FillParams params2 = params; + params2.monotonic = true; + params2.anchor_length_max = 0.0f; + Polylines polylines_out; + if (! fill_surface_by_lines(surface, params2, 0.f, 0.f, polylines_out)) + BOOST_LOG_TRIVIAL(error) << "FillMonotonicLines::fill_surface() failed to fill a region."; + return polylines_out; +} + +// Orca: Replaced with FillMonotonicLines from Prusa slicer. Moved gap fill algorithm to +// FillBase to perform gap fill for all fill types. +/*void FillMonotonicLineWGapFill::fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out) { ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection(); coll_nosort->no_sort = this->no_sort(); @@ -3274,7 +3289,7 @@ void FillMonotonicLineWGapFill::fill_surface_by_lines(const Surface* surface, co //assert(! it->has_duplicate_points()); it->remove_duplicate_points(); } -} +}*/ } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index c1b1680431..f85dce07e8 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -119,7 +119,19 @@ protected: float _layer_angle(size_t idx) const override { return 0.f; } }; -class FillMonotonicLineWGapFill : public Fill +// Orca: Introduced FillMonotonicLines from Prusa slicer, inhereting from FillRectilinear +// This replaces the FillMonotonicLineWGapFill from BBS +class FillMonotonicLines : public FillRectilinear +{ +public: + Fill* clone() const override { return new FillMonotonicLines(*this); } + ~FillMonotonicLines() override = default; + Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; + bool no_sort() const override { return true; } +}; + +//Orca: Replaced with FillMonotonicLines, inheriting from FillRectilinear +/*class FillMonotonicLineWGapFill : public Fill { public: ~FillMonotonicLineWGapFill() override = default; @@ -131,7 +143,7 @@ protected: private: void fill_surface_by_lines(const Surface* surface, const FillParams& params, Polylines& polylines_out); -}; +};*/ Points sample_grid_pattern(const ExPolygon& expolygon, coord_t spacing, const BoundingBox& global_bounding_box); Points sample_grid_pattern(const ExPolygons& expolygons, coord_t spacing, const BoundingBox& global_bounding_box); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index bd872464c6..157a4c53be 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4473,7 +4473,7 @@ static std::unique_ptr calculate_layer_edge_grid(const Layer& la } -std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed) +std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters) { // get a copy; don't modify the orientation of the original loop object otherwise // next copies (if any) would not detect the correct orientation @@ -4518,8 +4518,12 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // extrude along the path std::string gcode; + // Orca: // Port of "wipe inside before extruding an external perimeter" feature from super slicer - if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter) { + // If region perimeters size not greater than or equal to 2, then skip the wipe inside move as we will extrude in mid air + // as no neighbouring perimeter exists. If an internal perimeter exists, we should find 2 perimeters touching the de-retraction point + // 1 - the currently printed external perimeter and 2 - the neighbouring internal perimeter. + if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter && region_perimeters.size() > 1) { const bool is_full_loop_ccw = loop.polygon().is_counter_clockwise(); bool is_hole_loop = (loop.loop_role() & ExtrusionLoopRole::elrHole) != 0; // loop.make_counter_clockwise(); const double nozzle_diam = EXTRUDER_CONFIG(nozzle_diameter); @@ -4560,11 +4564,28 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou pt.rotate(angle, current_point); pt = (current_pos + vec_dist * (2 * dist / vec_norm)).cast(); pt.rotate(angle, current_point); - - // use extrude instead of travel_to_xy to trigger the unretract - ExtrusionPath fake_path_wipe(Polyline{pt, current_point}, paths.front()); - fake_path_wipe.mm3_per_mm = 0; - gcode += extrude_path(fake_path_wipe, "move inwards before retraction/seam", speed); + + // Search region perimeters for lines that are touching the de-retraction point. + // If an internal perimeter exists, we should find 2 perimeters touching the de-retraction point + // 1: the currently printed external perimeter and 2: the neighbouring internal perimeter. + int discoveredTouchingLines = 0; + for (const ExtrusionEntity* ee : region_perimeters){ + auto potential_touching_line = ee->as_polyline(); + AABBTreeLines::LinesDistancer potential_touching_line_distancer{potential_touching_line.lines()}; + auto touching_line = potential_touching_line_distancer.all_lines_in_radius(pt, scale_(nozzle_diam)); + if(touching_line.size()){ + discoveredTouchingLines ++; + if(discoveredTouchingLines > 1) break; // found 2 touching lines. End the search early. + } + } + // found 2 perimeters touching the de-retraction point. Its safe to deretract as the point will be + // inside the model + if(discoveredTouchingLines > 1){ + // use extrude instead of travel_to_xy to trigger the unretract + ExtrusionPath fake_path_wipe(Polyline{pt, current_point}, paths.front()); + fake_path_wipe.mm3_per_mm = 0; + gcode += extrude_path(fake_path_wipe, "move inwards before retraction/seam", speed); + } } @@ -4657,14 +4678,14 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string return gcode; } -std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed) +std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters) { if (const ExtrusionPath* path = dynamic_cast(&entity)) return this->extrude_path(*path, description, speed); else if (const ExtrusionMultiPath* multipath = dynamic_cast(&entity)) return this->extrude_multi_path(*multipath, description, speed); else if (const ExtrusionLoop* loop = dynamic_cast(&entity)) - return this->extrude_loop(*loop, description, speed); + return this->extrude_loop(*loop, description, speed, region_perimeters); else throw Slic3r::InvalidArgument("Invalid argument supplied to extrude()"); return ""; @@ -4691,7 +4712,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vectorextrude_entity(*ee, "perimeter", -1.); + gcode += this->extrude_entity(*ee, "perimeter", -1., region.perimeters); } return gcode; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 1912dc4d2c..79a97abc70 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -348,8 +348,12 @@ private: std::string preamble(); // BBS std::string change_layer(coordf_t print_z); - std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1.); - std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1.); + // Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop + // should be executed + std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1., const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr()); + // Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop + // should be executed + std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1., const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr()); std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.); std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 84ef8d7522..db675a5193 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -768,10 +768,10 @@ bool Preset::has_cali_lines(PresetBundle* preset_bundle) static std::vector s_Preset_print_options { "layer_height", "initial_layer_print_height", "wall_loops", "alternate_extra_wall", "slice_closing_radius", "spiral_mode", "spiral_mode_smooth", "spiral_mode_max_xy_smoothing", "slicing_mode", "top_shell_layers", "top_shell_thickness", "bottom_shell_layers", "bottom_shell_thickness", - "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold","overhang_reverse_internal_only", + "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness","reduce_wall_solid_infill", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold","overhang_reverse_internal_only", "seam_position", "staggered_inner_seams", "wall_sequence", "is_infill_first", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "infill_direction", - "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern", + "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target", "ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "max_travel_detour_distance", "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", @@ -1125,11 +1125,6 @@ void PresetCollection::load_presets( std::string version_str = key_values[BBL_JSON_KEY_VERSION]; boost::optional version = Semver::parse(version_str); if (!version) continue; - Semver app_version = *(Semver::parse(SLIC3R_VERSION)); - if ( version->maj() != app_version.maj()) { - BOOST_LOG_TRIVIAL(warning) << "Preset incompatibla, not loading: " << name; - continue; - } preset.version = *version; if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end()) @@ -1574,11 +1569,6 @@ bool PresetCollection::load_user_preset(std::string name, std::mapmaj() != app_version.maj()) { - BOOST_LOG_TRIVIAL(warning)<< __FUNCTION__ << boost::format("version %1% mismatch with app version %2%, not loading for user preset %3%")%version_str %SLIC3R_VERSION %name; - return false; - } //setting_id if (preset_values.find(BBL_JSON_KEY_SETTING_ID) == preset_values.end()) { diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index d3c5377ad2..152e676894 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -768,11 +768,6 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s std::string version_str = key_values[BBL_JSON_KEY_VERSION]; boost::optional version = Semver::parse(version_str); if (!version) return false; - Semver app_version = *(Semver::parse(SoftFever_VERSION)); - if (version->maj() != app_version.maj()) { - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset incompatibla, not loading: " << name; - return false; - } PresetCollection *collection = nullptr; if (config.has("printer_settings_id")) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d963dc811b..7dd68dbb86 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -248,6 +248,7 @@ static t_config_enum_values s_keys_map_SeamPosition { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SeamPosition) +// Orca static t_config_enum_values s_keys_map_InternalBridgeFilter { { "disabled", ibfDisabled }, { "limited", ibfLimited }, @@ -255,6 +256,14 @@ static t_config_enum_values s_keys_map_InternalBridgeFilter { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InternalBridgeFilter) +// Orca +static t_config_enum_values s_keys_map_GapFillTarget { + { "everywhere", gftEverywhere }, + { "topbottom", gftTopBottom }, + { "nowhere", gftNowhere }, +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(GapFillTarget) + static const t_config_enum_values s_keys_map_SLADisplayOrientation = { { "landscape", sladoLandscape}, { "portrait", sladoPortrait} @@ -752,6 +761,26 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm"); def->min = 0; def->set_default_value(new ConfigOptionFloat(0.)); + + def = this->add("gap_fill_target", coEnum); + def->label = L("Apply gap fill"); + def->category = L("Strength"); + def->tooltip = L("Enables gap fill for the selected surfaces. The minimum gap length that will be filled can be controlled " + "from the filter out tiny gaps option below.\n\n" + "Options:\n" + "1. Everywhere: Applies gap fill to top, bottom and internal solid surfaces\n" + "2. Top and Bottom surfaces: Applies gap fill to top and bottom surfaces only\n" + "3. Nowhere: Disables gap fill\n"); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("everywhere"); + def->enum_values.push_back("topbottom"); + def->enum_values.push_back("nowhere"); + def->enum_labels.push_back(L("Everywhere")); + def->enum_labels.push_back(L("Top and bottom surfaces")); + def->enum_labels.push_back(L("Nowhere")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionEnum(gftEverywhere)); + def = this->add("enable_overhang_bridge_fan", coBools); def->label = L("Force cooling for overhang and bridge"); @@ -1297,6 +1326,16 @@ void PrintConfigDef::init_fff_params() "(top+bottom solid layers)"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("reduce_wall_solid_infill", coBool); + def->label = L("Further reduce solid infill on walls (experimental)"); + def->category = L("Strength"); + def->tooltip = L("Further reduces any solid infill applied to walls. As there will be very limited infill supporting" + " solid surfaces, make sure that you are using adequate number of walls to support the part on sloping surfaces.\n\n" + "For heavily sloped surfaces this option is not suitable as it will generate too thin of a top layer " + "and should be disabled."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); auto def_top_fill_pattern = def = this->add("top_surface_pattern", coEnum); def->label = L("Top surface pattern"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f921342496..6c5b10f806 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -152,10 +152,17 @@ enum SeamPosition { spNearest, spAligned, spRear, spRandom }; +//Orca enum InternalBridgeFilter { ibfDisabled, ibfLimited, ibfNofilter }; +//Orca +enum GapFillTarget { + gftEverywhere, gftTopBottom, gftNowhere + }; + + enum LiftType { NormalLift, SpiralLift, @@ -789,6 +796,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionPercent, tree_support_top_rate)) ((ConfigOptionFloat, tree_support_branch_diameter_organic)) ((ConfigOptionFloat, tree_support_branch_angle_organic)) + ((ConfigOptionEnum,gap_fill_target)) ((ConfigOptionFloat, min_length_factor)) // Move all acceleration and jerk settings to object @@ -824,6 +832,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, bridge_speed)) ((ConfigOptionFloatOrPercent, internal_bridge_speed)) ((ConfigOptionBool, ensure_vertical_shell_thickness)) + ((ConfigOptionBool, reduce_wall_solid_infill)) ((ConfigOptionEnum, top_surface_pattern)) ((ConfigOptionEnum, bottom_surface_pattern)) ((ConfigOptionEnum, internal_solid_infill_pattern)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index da0aff7963..ce64205aae 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -449,17 +449,6 @@ void PrintObject::prepare_infill() } // for each region #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ - // this will detect bridges and reverse bridges - // and rearrange top/bottom/internal surfaces - // It produces enlarged overlapping bridging areas. - // - // 1) stBottomBridge / stBottom infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap. - // 2) stTop is grown by 3mm and clipped by the grown bottom areas. The areas may overlap. - // 3) Clip the internal surfaces by the grown top/bottom surfaces. - // 4) Merge surfaces with the same style. This will mostly get rid of the overlaps. - //FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties. - this->process_external_surfaces(); - m_print->throw_if_canceled(); // Debugging output. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING @@ -478,9 +467,23 @@ void PrintObject::prepare_infill() // and to add a configurable number of solid layers above the BOTTOM / BOTTOMBRIDGE surfaces // to close these surfaces reliably. //FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters? + // Orca: Brought this function call before the process_external_surfaces, to allow bridges over holes to expand more than + // one perimeter. Example of this is the bridge over the benchy lettering. this->discover_horizontal_shells(); m_print->throw_if_canceled(); + // this will detect bridges and reverse bridges + // and rearrange top/bottom/internal surfaces + // It produces enlarged overlapping bridging areas. + // + // 1) stBottomBridge / stBottom infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap. + // 2) stTop is grown by 3mm and clipped by the grown bottom areas. The areas may overlap. + // 3) Clip the internal surfaces by the grown top/bottom surfaces. + // 4) Merge surfaces with the same style. This will mostly get rid of the overlaps. + //FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties. + this->process_external_surfaces(); + m_print->throw_if_canceled(); + #ifdef SLIC3R_DEBUG_SLICE_PROCESSING for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { for (const Layer *layer : m_layers) { @@ -3224,7 +3227,10 @@ void PrintObject::discover_horizontal_shells() // No internal solid needed on this layer. In order to decide whether to continue // searching on the next neighbor (thus enforcing the configured number of solid // layers, use different strategies according to configured infill density: - if (region_config.sparse_infill_density.value == 0) { + + // Orca: Also use the same strategy if the user has selected to further reduce + // the amount of solid infill on walls. + if (region_config.sparse_infill_density.value == 0 || region_config.reduce_wall_solid_infill) { // If user expects the object to be void (for example a hollow sloping vase), // don't continue the search. In this case, we only generate the external solid // shell if the object would otherwise show a hole (gap between perimeters of @@ -3237,12 +3243,19 @@ void PrintObject::discover_horizontal_shells() } } - if (region_config.sparse_infill_density.value == 0) { + if (region_config.sparse_infill_density.value == 0 || region_config.reduce_wall_solid_infill) { // if we're printing a hollow object we discard any solid shell thinner // than a perimeter width, since it's probably just crossing a sloping wall // and it's not wanted in a hollow print even if it would make sense when // obeying the solid shell count option strictly (DWIM!) - float margin = float(neighbor_layerm->flow(frExternalPerimeter).scaled_width()); + + // Orca: Also use the same strategy if the user has selected to reduce + // the amount of solid infill on walls. However reduce the margin to 20% overhang + // as we want to generate infill on sloped vertical surfaces but still keep a small amount of + // filtering. This is an arbitrary value to make this option safe + // by ensuring that top surfaces, especially slanted ones dont go **completely** unsupported + // especially when using single perimeter top layers. + float margin = region_config.reduce_wall_solid_infill? float(neighbor_layerm->flow(frExternalPerimeter).scaled_width()) * 0.2f : float(neighbor_layerm->flow(frExternalPerimeter).scaled_width()); Polygons too_narrow = diff( new_internal_solid, opening(new_internal_solid, margin, margin + ClipperSafetyOffset, jtMiter, 5)); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 3a0b5fe390..f6bbcecf09 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -510,6 +510,18 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co apply(config, &new_conf); } + // Orca: Hide the filter out tiny gaps field when gap fill target is nowhere as no gap fill will be applied. + bool have_gap_fill = config->opt_enum("gap_fill_target") != gftNowhere; + toggle_line("filter_out_gap_fill", have_gap_fill); + + bool have_ensure_vertical_thickness = config->opt_bool("ensure_vertical_shell_thickness"); + if(have_ensure_vertical_thickness) { + DynamicPrintConfig new_conf = *config; + new_conf.set_key_value("reduce_wall_solid_infill", new ConfigOptionBool(false)); + apply(config, &new_conf); + } + toggle_line("reduce_wall_solid_infill",!have_ensure_vertical_thickness); + bool have_perimeters = config->opt_int("wall_loops") > 0; for (auto el : { "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall", "seam_position", "staggered_inner_seams", "wall_sequence", "outer_wall_line_width", diff --git a/src/slic3r/GUI/CreatePresetsDialog.cpp b/src/slic3r/GUI/CreatePresetsDialog.cpp index 8f48923c4e..9b7fdee95e 100644 --- a/src/slic3r/GUI/CreatePresetsDialog.cpp +++ b/src/slic3r/GUI/CreatePresetsDialog.cpp @@ -1181,7 +1181,7 @@ void CreateFilamentPresetDialog::select_curr_radiobox(std::vectorSetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); } } else if (curr_selected_type == m_create_type.base_filament_preset) { - m_filament_preset_text->SetLabel(_L("We would rename the presets as \"Vendor Type Serial @printer you selected\". \nTo add preset for more prinetrs, Please go to printer selection")); + m_filament_preset_text->SetLabel(_L("We would rename the presets as \"Vendor Type Serial @printer you selected\". \nTo add preset for more printers, Please go to printer selection")); m_filament_preset_combobox->Hide(); if (_L("Select Type") != m_filament_type_combobox->GetLabel()) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 147c80dedc..b1fe396f21 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -74,10 +74,10 @@ std::string GLGizmoScale3D::get_tooltip() const return ""; } -void GLGizmoScale3D::enable_ununiversal_scale(bool enable) +static int constraint_id(int grabber_id) { - for (unsigned int i = 0; i < 6; ++i) - m_grabbers[i].enabled = enable; + static const std::vector id_map = { 1, 0, 3, 2, 5, 4, 8, 9, 6, 7 }; + return (0 <= grabber_id && grabber_id < (int)id_map.size()) ? id_map[grabber_id] : -1; } bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event) @@ -99,12 +99,27 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event) transformation_type.set_independent(); selection.scale(m_scale, transformation_type); - if (mouse_event.CmdDown()) selection.translate(m_offset, transformation_type); + if (m_starting.ctrl_down && m_hover_id < 6) { + // constrained scale: + // uses the performed scale to calculate the new position of the constrained grabber + // and from that calculates the offset (in world coordinates) to be applied to fullfill the constraint + update_render_data(); + const Vec3d constraint_position = m_grabbers[constraint_id(m_hover_id)].center; + // re-apply the scale because the selection always applies the transformations with respect to the initial state + // set into on_start_dragging() with the call to selection.setup_cache() + m_parent.get_selection().scale_and_translate(m_scale, m_starting.pivots[m_hover_id] - constraint_position, transformation_type); + } } } return use_grabbers(mouse_event); } +void GLGizmoScale3D::enable_ununiversal_scale(bool enable) +{ + for (unsigned int i = 0; i < 6; ++i) + m_grabbers[i].enabled = enable; +} + void GLGizmoScale3D::data_changed(bool is_serializing) { const Selection &selection = m_parent.get_selection(); bool enable_scale_xyz = selection.is_single_full_instance() || @@ -156,19 +171,20 @@ void GLGizmoScale3D::on_start_dragging() m_starting.plane_center = m_grabbers[4].center; m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center; m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL); - m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box(); + m_starting.box = m_box; - const Vec3d& center = m_starting.box.center(); - m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z()); - m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z()); - m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z()); - m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z()); - m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z()); - m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z()); + m_starting.pivots[0] = m_grabbers[1].center; + m_starting.pivots[1] = m_grabbers[0].center; + m_starting.pivots[2] = m_grabbers[3].center; + m_starting.pivots[3] = m_grabbers[2].center; + m_starting.pivots[4] = m_grabbers[5].center; + m_starting.pivots[5] = m_grabbers[4].center; } -void GLGizmoScale3D::on_stop_dragging() { +void GLGizmoScale3D::on_stop_dragging() +{ m_parent.do_scale(L("Gizmo-Scale")); + m_starting.ctrl_down = false; } void GLGizmoScale3D::on_dragging(const UpdateData& data) @@ -185,97 +201,14 @@ void GLGizmoScale3D::on_dragging(const UpdateData& data) void GLGizmoScale3D::on_render() { - const Selection& selection = m_parent.get_selection(); - - bool single_instance = selection.is_single_full_instance(); - bool single_volume = selection.is_single_volume_or_modifier(); - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glEnable(GL_DEPTH_TEST)); - m_box.reset(); - m_transform = Transform3d::Identity(); - // Transforms grabbers' offsets to world refefence system - Transform3d offsets_transform = Transform3d::Identity(); - m_offsets_transform = Transform3d::Identity(); - Vec3d angles = Vec3d::Zero(); - - if (single_instance) { - // calculate bounding box in instance local reference system - const Selection::IndicesList& idxs = selection.get_volume_idxs(); - for (unsigned int idx : idxs) { - const GLVolume* vol = selection.get_volume(idx); - m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix())); - } - - // gets transform from first selected volume - const GLVolume* v = selection.get_first_volume(); - m_transform = v->get_instance_transformation().get_matrix(); - // gets angles from first selected volume - angles = v->get_instance_rotation(); - // consider rotation+mirror only components of the transform for offsets - offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); - m_offsets_transform = offsets_transform; - } - else if (single_volume) { - const GLVolume* v = selection.get_first_volume(); - m_box = v->bounding_box(); - m_transform = v->world_matrix(); - angles = Geometry::extract_euler_angles(m_transform); - // consider rotation+mirror only components of the transform for offsets - offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); - m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v->get_volume_rotation(), Vec3d::Ones(), v->get_volume_mirror()); - } - else - m_box = selection.get_bounding_box(); - - const Vec3d& center = m_box.center(); - const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); - const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); - const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); - - const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); - - // x axis - m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z()); - m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z()); - - // y axis - m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z()); - m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z()); - - // z axis do not show 4 - m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z()); - m_grabbers[4].enabled = false; - - m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z()); - - // uniform - m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z()); - m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z()); - m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z()); - m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z()); - - for (int i = 0; i < 6; ++i) { - m_grabbers[i].color = AXES_COLOR[i/2]; - m_grabbers[i].hover_color = AXES_HOVER_COLOR[i/2]; - } - - for (int i = 6; i < 10; ++i) { - m_grabbers[i].color = GRABBER_UNIFORM_COL; - m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL; - } - - // sets grabbers orientation - for (int i = 0; i < 10; ++i) { - m_grabbers[i].angles = angles; - } + update_render_data(); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); - const BoundingBoxf3& selection_box = selection.get_bounding_box(); - - const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); + const float grabber_mean_size = (float) ((m_box.size().x() + m_box.size().y() + m_box.size().z()) / 3.0); //draw connections GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -370,35 +303,17 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) { double ratio = calc_ratio(data); if (ratio > 0.0) { - m_scale(axis) = m_starting.scale(axis) * ratio; - if (m_starting.ctrl_down) { - double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis); - if (m_hover_id == 2 * axis) - local_offset *= -1.0; - - Vec3d local_offset_vec; - switch (axis) - { - case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; } - case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break; } - case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break; } - default: break; - } - - m_offset = m_offsets_transform * local_offset_vec; - } - else - m_offset = Vec3d::Zero(); + Vec3d curr_scale = m_scale; + curr_scale(axis) = m_starting.scale(axis) * ratio; + m_scale = curr_scale; } } void GLGizmoScale3D::do_scale_uniform(const UpdateData & data) { const double ratio = calc_ratio(data); - if (ratio > 0.0) { + if (ratio > 0.0) m_scale = m_starting.scale * ratio; - m_offset = Vec3d::Zero(); - } } double GLGizmoScale3D::calc_ratio(const UpdateData& data) const @@ -436,5 +351,78 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const return ratio; } +void GLGizmoScale3D::update_render_data() +{ + + const Selection& selection = m_parent.get_selection(); + + bool single_instance = selection.is_single_full_instance(); + bool single_volume = selection.is_single_volume_or_modifier(); + + m_box.reset(); + m_transform = Transform3d::Identity(); + Vec3d angles = Vec3d::Zero(); + + if (single_instance) { + // calculate bounding box in instance local reference system + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + for (unsigned int idx : idxs) { + const GLVolume* vol = selection.get_volume(idx); + m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix())); + } + + // gets transform from first selected volume + const GLVolume* v = selection.get_first_volume(); + m_transform = v->get_instance_transformation().get_matrix(); + // gets angles from first selected volume + angles = v->get_instance_rotation(); + } + else if (single_volume) { + const GLVolume* v = selection.get_first_volume(); + m_box = v->bounding_box(); + m_transform = v->world_matrix(); + angles = Geometry::extract_euler_angles(m_transform); + } + else + m_box = selection.get_bounding_box(); + + const Vec3d& center = m_box.center(); + + // x axis + m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z()); + m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z()); + + // y axis + m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z()); + + // z axis do not show 4 + m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z()); + m_grabbers[4].enabled = false; + + m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z()); + + // uniform + m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z()); + m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z()); + m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z()); + + for (int i = 0; i < 6; ++i) { + m_grabbers[i].color = AXES_COLOR[i/2]; + m_grabbers[i].hover_color = AXES_HOVER_COLOR[i/2]; + } + + for (int i = 6; i < 10; ++i) { + m_grabbers[i].color = GRABBER_UNIFORM_COL; + m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL; + } + + // sets grabbers orientation + for (int i = 0; i < 10; ++i) { + m_grabbers[i].angles = angles; + } +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 589b074491..5d8565aa05 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -34,10 +34,7 @@ class GLGizmoScale3D : public GLGizmoBase BoundingBoxf3 m_box; Transform3d m_transform; - // Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes) - Transform3d m_offsets_transform; Vec3d m_scale{ Vec3d::Ones() }; - Vec3d m_offset{ Vec3d::Zero() }; double m_snap_step{ 0.05 }; StartingData m_starting; @@ -99,6 +96,7 @@ private: void do_scale_uniform(const UpdateData& data); double calc_ratio(const UpdateData& data) const; + void update_render_data(); }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f5d017eb00..20f65758a0 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2646,6 +2646,15 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) sidebar_layout.is_collapsed = !sidebar.IsShown(); } + // Keep tracking the current sidebar size, by storing it using `best_size`, which will be stored + // in the config and re-applied when the app is opened again. + this->sidebar->Bind(wxEVT_IDLE, [&sidebar, this](wxIdleEvent& e) { + if (sidebar.IsShown() && sidebar.IsDocked() && sidebar.rect.GetWidth() > 0) { + sidebar.BestSize(sidebar.rect.GetWidth(), sidebar.best_size.GetHeight()); + } + e.Skip(); + }); + // Hide sidebar initially, will re-show it after initialization when we got proper window size sidebar.Hide(); m_aui_mgr.Update(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e879000899..325a56d8c6 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2027,6 +2027,7 @@ void TabPrint::build() optgroup->append_single_option_line("infill_anchor"); optgroup->append_single_option_line("infill_anchor_max"); optgroup->append_single_option_line("internal_solid_infill_pattern"); + optgroup->append_single_option_line("gap_fill_target"); optgroup->append_single_option_line("filter_out_gap_fill"); optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); @@ -2037,6 +2038,7 @@ void TabPrint::build() optgroup->append_single_option_line("infill_combination"); optgroup->append_single_option_line("detect_narrow_internal_solid_infill"); optgroup->append_single_option_line("ensure_vertical_shell_thickness"); + optgroup->append_single_option_line("reduce_wall_solid_infill"); page = add_options_page(L("Speed"), "empty"); optgroup = page->new_optgroup(L("Initial layer speed"), L"param_speed_first", 15);