From eef800b5c4215abc9226cebae5733227190d9fd8 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 22 Jan 2021 15:32:36 +0100 Subject: [PATCH 1/6] FIXME on ExPolygon::overlaps(), which should be commutative. --- src/libslic3r/ExPolygon.cpp | 4 ++-- src/libslic3r/SLA/SupportPointGenerator.hpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 02cc126a38..f698a35589 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -132,8 +132,7 @@ ExPolygon::has_boundary_point(const Point &point) const return false; } -bool -ExPolygon::overlaps(const ExPolygon &other) const +bool ExPolygon::overlaps(const ExPolygon &other) const { #if 0 BoundingBox bbox = get_extents(other); @@ -150,6 +149,7 @@ ExPolygon::overlaps(const ExPolygon &other) const #endif if (! pl_out.empty()) return true; + //FIXME ExPolygon::overlaps() shall be commutative, it is not! return ! other.contour.points.empty() && this->contains_b(other.contour.points.front()); } diff --git a/src/libslic3r/SLA/SupportPointGenerator.hpp b/src/libslic3r/SLA/SupportPointGenerator.hpp index ebb8cc373f..d7588e3ba3 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.hpp +++ b/src/libslic3r/SLA/SupportPointGenerator.hpp @@ -84,6 +84,7 @@ public: float overhangs_area = 0.f; bool overlaps(const Structure &rhs) const { + //FIXME ExPolygon::overlaps() shall be commutative, it is not! return this->bbox.overlap(rhs.bbox) && (this->polygon->overlaps(*rhs.polygon) || rhs.polygon->overlaps(*this->polygon)); } float overlap_area(const Structure &rhs) const { From 79b7ccbb798049c943073c67bb21fe467d409c9c Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 22 Jan 2021 21:44:15 +0100 Subject: [PATCH 2/6] OSX specific, related to the wxWidgets 3.1.4: Fixed wrong UI-scaling (wxWidgets 3.1.4 can binding of wxEVT_DPI_CHANGED now, so it was called msw_rescale() for most of the controls redundantly) + Fixed update of the DoubleSlider after changing of the system color --- src/slic3r/GUI/DoubleSlider.cpp | 20 ++++++++++++++++++++ src/slic3r/GUI/DoubleSlider.hpp | 1 + src/slic3r/GUI/GUI_Preview.cpp | 6 ++++++ src/slic3r/GUI/GUI_Preview.hpp | 1 + src/slic3r/GUI/GUI_Utils.hpp | 2 ++ src/slic3r/GUI/OG_CustomCtrl.cpp | 4 +++- src/slic3r/GUI/Plater.cpp | 1 + 7 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 8a2257274e..7ee5579e7c 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -160,6 +160,26 @@ void Control::msw_rescale() GetParent()->Layout(); } +void Control::sys_color_changed() +{ + m_bmp_add_tick_on .msw_rescale(); + m_bmp_add_tick_off.msw_rescale(); + m_bmp_del_tick_on .msw_rescale(); + m_bmp_del_tick_off.msw_rescale(); + m_tick_icon_dim = m_bmp_add_tick_on.GetBmpWidth(); + + m_bmp_one_layer_lock_on .msw_rescale(); + m_bmp_one_layer_lock_off .msw_rescale(); + m_bmp_one_layer_unlock_on .msw_rescale(); + m_bmp_one_layer_unlock_off.msw_rescale(); + m_lock_icon_dim = m_bmp_one_layer_lock_on.GetBmpWidth(); + + m_bmp_revert.msw_rescale(); + m_revert_icon_dim = m_bmp_revert.GetBmpWidth(); + m_bmp_cog.msw_rescale(); + m_cog_icon_dim = m_bmp_cog.GetBmpWidth(); +} + int Control::GetActiveValue() const { return m_selection == ssLower ? diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index 56baef6cf2..0d90367c0a 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -192,6 +192,7 @@ public: ~Control() {} void msw_rescale(); + void sys_color_changed(); int GetMinValue() const { return m_min_value; } int GetMaxValue() const { return m_max_value; } diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 36c1960d3f..71b1aa9ba2 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -410,6 +410,12 @@ void Preview::msw_rescale() refresh_print(); } +void Preview::sys_color_changed() +{ + if (m_layers_slider != nullptr) + m_layers_slider->sys_color_changed(); +} + void Preview::jump_layers_slider(wxKeyEvent& evt) { if (m_layers_slider) m_layers_slider->OnChar(evt); diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 0060bfcffb..372d44fa31 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -150,6 +150,7 @@ public: void refresh_print(); void msw_rescale(); + void sys_color_changed(); void jump_layers_slider(wxKeyEvent& evt); void move_layers_slider(wxKeyEvent& evt); void edit_layers_slider(wxKeyEvent& evt); diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 3235d6e9ea..dbb200f83b 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -108,6 +108,7 @@ public: // recalc_font(); +#ifndef __WXOSX__ #if wxVERSION_EQUAL_OR_GREATER_THAN(3,1,3) this->Bind(wxEVT_DPI_CHANGED, [this](wxDPIChangedEvent& evt) { m_scale_factor = (float)evt.GetNewDPI().x / (float)DPI_DEFAULT; @@ -128,6 +129,7 @@ public: rescale(evt.rect); }); #endif // wxVERSION_EQUAL_OR_GREATER_THAN +#endif // no __WXOSX__ this->Bind(wxEVT_MOVE_START, [this](wxMoveEvent& event) { diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index 07b96755da..1e581e70ba 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -360,6 +360,9 @@ void OG_CustomCtrl::correct_widgets_position(wxSizer* widget, const Line& line, void OG_CustomCtrl::msw_rescale() { +#ifdef __WXOSX__ + return; +#endif m_font = wxGetApp().normal_font(); m_em_unit = em_unit(m_parent); m_v_gap = lround(1.0 * m_em_unit); @@ -381,7 +384,6 @@ void OG_CustomCtrl::msw_rescale() void OG_CustomCtrl::sys_color_changed() { - msw_rescale(); } OG_CustomCtrl::CtrlLine::CtrlLine( wxCoord height, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 41e9c8ff5c..f7f56f5701 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6209,6 +6209,7 @@ void Plater::msw_rescale() void Plater::sys_color_changed() { + p->preview->sys_color_changed(); p->sidebar->sys_color_changed(); // msw_rescale_menu updates just icons, so use it From ab3468a42057f75079f71345deb669c6ac22277d Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 22 Jan 2021 21:48:10 +0100 Subject: [PATCH 3/6] Added missed icons for the DarkMode --- resources/icons/white/edit_gcode.svg | 15 +++++++++++++++ resources/icons/white/error_tick.svg | 12 ++++++++++++ resources/icons/white/pause_print.svg | 18 ++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 resources/icons/white/edit_gcode.svg create mode 100644 resources/icons/white/error_tick.svg create mode 100644 resources/icons/white/pause_print.svg diff --git a/resources/icons/white/edit_gcode.svg b/resources/icons/white/edit_gcode.svg new file mode 100644 index 0000000000..85836c0b49 --- /dev/null +++ b/resources/icons/white/edit_gcode.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/resources/icons/white/error_tick.svg b/resources/icons/white/error_tick.svg new file mode 100644 index 0000000000..f3de981f03 --- /dev/null +++ b/resources/icons/white/error_tick.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/resources/icons/white/pause_print.svg b/resources/icons/white/pause_print.svg new file mode 100644 index 0000000000..73f747fffd --- /dev/null +++ b/resources/icons/white/pause_print.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + From d9448c9f2ad1e3ed869906ae5aac91596790308f Mon Sep 17 00:00:00 2001 From: YuSanka Date: Sun, 24 Jan 2021 14:54:44 +0100 Subject: [PATCH 4/6] Follow-up to https://github.com/prusa3d/PrusaSlicer/commit/ab3468a42057f75079f71345deb669c6ac22277d : Added missed icon for the DarkMode --- resources/icons/white/colorchange_add_m.svg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 resources/icons/white/colorchange_add_m.svg diff --git a/resources/icons/white/colorchange_add_m.svg b/resources/icons/white/colorchange_add_m.svg new file mode 100644 index 0000000000..2266560daa --- /dev/null +++ b/resources/icons/white/colorchange_add_m.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + From 4620402ab44af3547ddc2f9ebbeb579261df0cef Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 22 Jan 2021 17:51:26 +0100 Subject: [PATCH 5/6] WIP: Initial Fuzzy Skin implementaiton #2010 Based on pull request Experimental fuzzy skin mode #4611 by @etet100 and on CuraEngine implementation of perimeter fuzzyfication void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) --- src/libslic3r/PerimeterGenerator.cpp | 175 ++++++++++++++++++++++++++- src/libslic3r/Preset.cpp | 1 + src/libslic3r/PrintConfig.cpp | 62 ++++++++++ src/libslic3r/PrintConfig.hpp | 54 +++++++++ src/libslic3r/PrintObject.cpp | 4 + src/slic3r/GUI/Field.cpp | 4 + src/slic3r/GUI/GUI.cpp | 4 + src/slic3r/GUI/OptionsGroup.cpp | 6 + src/slic3r/GUI/Tab.cpp | 14 ++- 9 files changed, 320 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index ba12a1edbb..ff9e439ba8 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -5,6 +5,7 @@ #include #include +#include namespace Slic3r { @@ -230,8 +231,128 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime return out; } +enum class FuzzyShape { + Triangle, + Sawtooth, + Random +}; + +static void fuzzy_polygon(Polygon &poly, FuzzyShape shape, double fuzzy_skin_thickness, double fuzzy_skin_point_dist) +{ +#if 0 + Point last = poly.points.at(poly.points.size() - 1); + Point last_processed = last; + + double max_length = scale_(2); + double min_length = scale_(1); + + if (poly.length() < scale_(5)) + return; + + deepness *= 3; + + bool triangle_or_sawtooth = shape == FuzzyShape::Sawtooth; + double length_sum = 0; + Points::iterator it = poly.points.begin(); + while (it != poly.points.end()) { + Point &pt = *it; + + Line line(last, pt); + double length = line.length(); + + // split long line + if (length > max_length) { + auto parts = int(ceil(length / max_length)); + if (parts == 2) { + Point point_to_insert(line.midpoint()); + it = poly.points.insert(it, point_to_insert); + } + else { + Vector part_vector = line.vector() / parts; + + Points points_to_insert; + Point point_to_insert(last); + while (--parts) { + point_to_insert += part_vector; + Point point_to_insert_2(point_to_insert); + points_to_insert.push_back(point_to_insert_2); + } + + it = poly.points.insert(it, points_to_insert.begin(), points_to_insert.end()); + } + continue; + } + + length_sum += length; + + // join short lines + if (length_sum < min_length) { + last = pt; + it = poly.points.erase(it); + continue; + } + + line = Line(last_processed, pt); + last = pt; + last_processed = pt; + + if (shape == FuzzyShape::Random) { + triangle_or_sawtooth = !(rand() % 2); + } + + Point point_to_insert(triangle_or_sawtooth ? pt : line.midpoint()); + + int scale = (rand() % deepness) + 1; + + Vec2d normal = line.normal().cast(); + normal /= line.length() / scale_(1.) / ((double)scale / 20.); + + it = poly.points.insert(it, point_to_insert + normal.cast()) + 2; + + length_sum = 0; + } + +#else + const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value + const double range_random_point_dist = fuzzy_skin_point_dist / 2.; + double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point + Point* p0 = &poly.points.back(); + Points out; + out.reserve(poly.points.size()); + for (Point &p1 : poly.points) + { // 'a' is the (next) new point between p0 and p1 + Vec2d p0p1 = (p1 - *p0).cast(); + double p0p1_size = p0p1.norm(); + // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size + double dist_last_point = dist_left_over + p0p1_size * 2.; + for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; + p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX)) + { + double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; + out.emplace_back(*p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast()); + dist_last_point = p0pa_dist; + } + dist_left_over = p0p1_size - dist_last_point; + p0 = &p1; + } + while (out.size() < 3) { + size_t point_idx = poly.size() - 2; + out.emplace_back(poly[point_idx]); + if (point_idx == 0) + break; + -- point_idx; + } + if (out.size() >= 3) + poly.points = std::move(out); +#endif +} + void PerimeterGenerator::process() { + // nasty hack! initialize random generator + auto time_us = std::chrono::duration_cast(std::chrono::time_point_cast(std::chrono::high_resolution_clock::now()).time_since_epoch()).count(); + srand(this->layer_id * time_us); + // other perimeters m_mm3_per_mm = this->perimeter_flow.mm3_per_mm(); coord_t perimeter_width = this->perimeter_flow.scaled_width(); @@ -272,6 +393,32 @@ void PerimeterGenerator::process() m_lower_slices_polygons = offset(*this->lower_slices, float(scale_(+nozzle_diameter/2))); } + // fuzzy skin configuration + double fuzzy_skin_thickness; + double fuzzy_skin_point_dist; + FuzzyShape fuzzy_skin_shape; + if (this->object_config->fuzzy_skin_perimeter_mode != FuzzySkinPerimeterMode::None) { + switch (this->object_config->fuzzy_skin_shape) { + case FuzzySkinShape::Triangle1: + case FuzzySkinShape::Triangle2: + case FuzzySkinShape::Triangle3: + fuzzy_skin_shape = FuzzyShape::Triangle; + break; + case FuzzySkinShape::Sawtooth1: + case FuzzySkinShape::Sawtooth2: + case FuzzySkinShape::Sawtooth3: + fuzzy_skin_shape = FuzzyShape::Sawtooth; + break; + case FuzzySkinShape::Random1: + case FuzzySkinShape::Random2: + case FuzzySkinShape::Random3: + fuzzy_skin_shape = FuzzyShape::Random; + break; + } + fuzzy_skin_thickness = scale_(this->object_config->fuzzy_skin_thickness); + fuzzy_skin_point_dist = scale_(this->object_config->fuzzy_skin_point_dist); + } + // we need to process each island separately because we might have different // extra perimeters for each one for (const Surface &surface : this->slices->surfaces) { @@ -352,13 +499,35 @@ void PerimeterGenerator::process() // If i > loop_number, we were looking just for gaps. break; } - for (const ExPolygon &expolygon : offsets) { + for (ExPolygon &expolygon : offsets) { // Outer contour may overlap with an inner contour, // inner contour may overlap with another inner contour, // outer contour may overlap with itself. //FIXME evaluate the overlaps, annotate each point with an overlap depth, - // compensate for the depth of intersection. - contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true)); + + bool skip_polygon = false; + + if (this->object_config->fuzzy_skin_perimeter_mode != FuzzySkinPerimeterMode::None) { + if (i == 0 && (this->object_config->fuzzy_skin_perimeter_mode != FuzzySkinPerimeterMode::ExternalSkipFirst || this->layer_id > 0)) { + if ( + this->object_config->fuzzy_skin_perimeter_mode == FuzzySkinPerimeterMode::External || + this->object_config->fuzzy_skin_perimeter_mode == FuzzySkinPerimeterMode::ExternalSkipFirst + ) { + ExPolygon expolygon_fuzzy(expolygon); + fuzzy_polygon(expolygon_fuzzy.contour, fuzzy_skin_shape, fuzzy_skin_thickness, fuzzy_skin_point_dist); + // compensate for the depth of intersection. + contours[i].emplace_back(PerimeterGeneratorLoop(expolygon_fuzzy.contour, i, true)); + skip_polygon = true; + } else + fuzzy_polygon(expolygon.contour, fuzzy_skin_shape, fuzzy_skin_thickness, fuzzy_skin_point_dist); + } + } + + if (!skip_polygon) { + // compensate for the depth of intersection. + contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true)); + } + if (! expolygon.holes.empty()) { holes[i].reserve(holes[i].size() + expolygon.holes.size()); for (const Polygon &hole : expolygon.holes) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index c24033df20..f75f653ef3 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -411,6 +411,7 @@ const std::vector& Preset::print_options() "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", "ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing", "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour", + "fuzzy_skin_perimeter_mode", "fuzzy_skin_shape", "fuzzy_skin_thickness", "fuzzy_skin_point_dist", #ifdef HAS_PRESSURE_EQUALIZER "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative", #endif /* HAS_PRESSURE_EQUALIZER */ diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index da2b655689..9247e69da3 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1007,6 +1007,68 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionInts { 0 }); + def = this->add("fuzzy_skin_perimeter_mode", coEnum); + def->label = L("Fuzzy skin perimeter mode"); + def->category = L("Fuzzy Skin"); + def->tooltip = L("Fuzzy skin perimeter mode."); + + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("none"); + def->enum_values.push_back("external_only"); + def->enum_values.push_back("external_only_skip_first_layer"); + def->enum_values.push_back("all"); + def->enum_labels.push_back(L("None")); + def->enum_labels.push_back(L("External")); + def->enum_labels.push_back(L("External (skip first layer)")); + def->enum_labels.push_back(L("All perimeters")); + def->mode = comSimple; + def->set_default_value(new ConfigOptionEnum(FuzzySkinPerimeterMode::None)); + + def = this->add("fuzzy_skin_shape", coEnum); + def->label = L("Fuzzy skin shape"); + def->category = L("Fuzzy Skin"); + def->tooltip = L("Fuzzy skin shape."); + + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("triangle1"); + def->enum_values.push_back("triangle2"); + def->enum_values.push_back("triangle3"); + def->enum_values.push_back("sawtooth1"); + def->enum_values.push_back("sawtooth2"); + def->enum_values.push_back("sawtooth3"); + def->enum_values.push_back("random1"); + def->enum_values.push_back("random2"); + def->enum_values.push_back("random3"); + def->enum_labels.push_back(L("Triangle (1)")); + def->enum_labels.push_back(L("Triangle (2)")); + def->enum_labels.push_back(L("Triangle (3)")); + def->enum_labels.push_back(L("Sawtooth (1)")); + def->enum_labels.push_back(L("Sawtooth (2)")); + def->enum_labels.push_back(L("Sawtooth (3)")); + def->enum_labels.push_back(L("Random (1)")); + def->enum_labels.push_back(L("Random (2)")); + def->enum_labels.push_back(L("Random (3)")); + def->mode = comSimple; + def->set_default_value(new ConfigOptionEnum(FuzzySkinShape::Triangle1)); + + def = this->add("fuzzy_skin_thickness", coFloat); + def->label = L("Fuzzy skin thickness"); + def->category = L("Fuzzy Skin"); + def->tooltip = L(""); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.3)); + + def = this->add("fuzzy_skin_point_dist", coFloat); + def->label = L("Fuzzy skin point distance"); + def->category = L("Fuzzy Skin"); + def->tooltip = L(""); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.8)); + def = this->add("gap_fill_speed", coFloat); def->label = L("Gap fill"); def->category = L("Speed"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index fa09cfb172..40929c34b0 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -43,6 +43,25 @@ enum AuthorizationType { atKeyPassword, atUserPassword }; +enum class FuzzySkinPerimeterMode { + None, + External, + ExternalSkipFirst, + All +}; + +enum class FuzzySkinShape { + Triangle1, + Triangle2, + Triangle3, + Sawtooth1, + Sawtooth2, + Sawtooth3, + Random1, + Random2, + Random3 +}; + enum InfillPattern : int { ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipCount, @@ -140,6 +159,33 @@ template<> inline const t_config_enum_values& ConfigOptionEnum inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { + static t_config_enum_values keys_map; + if (keys_map.empty()) { + keys_map["none"] = int(FuzzySkinPerimeterMode::None); + keys_map["external_only"] = int(FuzzySkinPerimeterMode::External); + keys_map["external_only_skip_first_layer"] = int(FuzzySkinPerimeterMode::ExternalSkipFirst); + keys_map["all"] = int(FuzzySkinPerimeterMode::All); + } + return keys_map; +} + +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { + static t_config_enum_values keys_map; + if (keys_map.empty()) { + keys_map["triangle1"] = int(FuzzySkinShape::Triangle1); + keys_map["triangle2"] = int(FuzzySkinShape::Triangle2); + keys_map["triangle3"] = int(FuzzySkinShape::Triangle3); + keys_map["sawtooth1"] = int(FuzzySkinShape::Sawtooth1); + keys_map["sawtooth2"] = int(FuzzySkinShape::Sawtooth2); + keys_map["sawtooth3"] = int(FuzzySkinShape::Sawtooth3); + keys_map["random1"] = int(FuzzySkinShape::Random1); + keys_map["random2"] = int(FuzzySkinShape::Random2); + keys_map["random3"] = int(FuzzySkinShape::Random3); + } + return keys_map; +} + template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { @@ -432,6 +478,10 @@ public: ConfigOptionFloat elefant_foot_compensation; ConfigOptionFloatOrPercent extrusion_width; ConfigOptionFloatOrPercent first_layer_height; + ConfigOptionEnum fuzzy_skin_perimeter_mode; + ConfigOptionEnum fuzzy_skin_shape; + ConfigOptionFloat fuzzy_skin_thickness; + ConfigOptionFloat fuzzy_skin_point_dist; ConfigOptionBool infill_only_where_needed; // Force the generation of solid shells between adjacent materials/volumes. ConfigOptionBool interface_shells; @@ -477,6 +527,10 @@ protected: OPT_PTR(elefant_foot_compensation); OPT_PTR(extrusion_width); OPT_PTR(first_layer_height); + OPT_PTR(fuzzy_skin_perimeter_mode); + OPT_PTR(fuzzy_skin_shape); + OPT_PTR(fuzzy_skin_thickness); + OPT_PTR(fuzzy_skin_point_dist); OPT_PTR(infill_only_where_needed); OPT_PTR(interface_shells); OPT_PTR(layer_height); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 99b4130f4c..dcf94fe9ab 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -521,6 +521,10 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector(ret_enum); + else if (m_opt_id.compare("fuzzy_skin_perimeter_mode") == 0) + m_value = static_cast(ret_enum); + else if (m_opt_id.compare("fuzzy_skin_shape") == 0) + m_value = static_cast(ret_enum); else if (m_opt_id.compare("gcode_flavor") == 0) m_value = static_cast(ret_enum); else if (m_opt_id.compare("machine_limits_usage") == 0) diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index dea2260122..6b664c0edb 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -182,6 +182,10 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("ironing_type") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + else if (opt_key.compare("fuzzy_skin_perimeter_mode") == 0) + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + else if (opt_key.compare("fuzzy_skin_shape") == 0) + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("gcode_flavor") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("machine_limits_usage") == 0) diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 10774abe3a..ced780adb6 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -870,6 +870,12 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config else if (opt_key == "ironing_type") { ret = static_cast(config.option>(opt_key)->value); } + else if (opt_key == "fuzzy_skin_perimeter_mode") { + ret = static_cast(config.option>(opt_key)->value); + } + else if (opt_key == "fuzzy_skin_shape") { + ret = static_cast(config.option>(opt_key)->value); + } else if (opt_key == "gcode_flavor") { ret = static_cast(config.option>(opt_key)->value); } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index aec2f87542..974b709f7c 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1434,6 +1434,18 @@ void TabPrint::build() optgroup->append_single_option_line("seam_position", category_path + "seam-position"); optgroup->append_single_option_line("external_perimeters_first", category_path + "external-perimeters-first"); + optgroup = page->new_optgroup(L("Fuzzy skin (experimental)")); + Option option = optgroup->get_option("fuzzy_skin_perimeter_mode"); + option.opt.width = 30; + optgroup->append_single_option_line(option); +#if 0 + option = optgroup->get_option("fuzzy_skin_shape"); + option.opt.width = 30; + optgroup->append_single_option_line(option); +#endif + optgroup->append_single_option_line(optgroup->get_option("fuzzy_skin_thickness")); + optgroup->append_single_option_line(optgroup->get_option("fuzzy_skin_point_dist")); + page = add_options_page(L("Infill"), "infill"); category_path = "infill_42#"; optgroup = page->new_optgroup(L("Infill")); @@ -1597,7 +1609,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Output file")); optgroup->append_single_option_line("gcode_comments"); optgroup->append_single_option_line("gcode_label_objects"); - Option option = optgroup->get_option("output_filename_format"); + option = optgroup->get_option("output_filename_format"); option.opt.full_width = true; optgroup->append_single_option_line(option); From 500c667d7abadab88aa6c127d6cae934c7ddfb1b Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 26 Jan 2021 09:29:24 +0100 Subject: [PATCH 6/6] Extended miniz with https://github.com/richgel999/miniz/pull/147 to support writing a file from a callback without knowing the file size up front. See comments in src/miniz/README-Prusa.txt for potential pitfalls. --- src/miniz/README-Prusa.txt | 27 ++++++++++++++++++++ src/miniz/miniz.c | 52 +++++++++++++++++++++++--------------- src/miniz/miniz.h | 2 +- 3 files changed, 59 insertions(+), 22 deletions(-) create mode 100644 src/miniz/README-Prusa.txt diff --git a/src/miniz/README-Prusa.txt b/src/miniz/README-Prusa.txt new file mode 100644 index 0000000000..7ed99c5347 --- /dev/null +++ b/src/miniz/README-Prusa.txt @@ -0,0 +1,27 @@ +This library is based on miniz 2.1.0 - amalgamated version. + +---------------------------------------------------------------- + +Merged with https://github.com/richgel999/miniz/pull/147 +to support writing a zipped file using a callback without +knowing the size of the file up front. + +Vojtech made the following comments to the pull request above: + +The pull request looks good to me in general. We need such a functionality at https://github.com/prusa3d/PrusaSlicer so we are going to merge it into our project. Namely, we are exporting potentially huge model files, which are XML encoded, thus the compression ration is quite high and keeping the XML encoded model file in memory is not really practical. + +I am a bit uneasy about two things though: + +mz_zip_writer_create_zip64_extra_data() call at the start of the file block stores uncompressed and compressed size. Naturally the uncompressed size will be over estimated, while the compressed size will be zero (as it was before). I suppose it does not make any difference, as usually the decompressors do not read this block, but they rely on the copy of this block in the central directory at the end of the ZIP file. I used https://en.wikipedia.org/wiki/ZIP_(file_format) as a source and there is no definition of the ZIP64 extra data block, though the "Data descriptor" section says: +If the bit at offset 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written. The fields in the local header are filled with zero, and the CRC-32 and size are appended in a 12-byte structure (optionally preceded by a 4-byte signature) immediately after the compressed data: + +Thus I suppose it is all right if the file size at the start of the file block is not correct. + +There are weird conditions in the original code as if (uncomp_size <= 3), if (uncomp_size == 0). I am not quite sure what will happen if one called your modified mz_zip_writer_add_read_buf_callback() with maximum size >= 4, but the callback provided less than 4 bytes. This is not a problem in our application, but in general it could be an issue. + +Is it an issue if the maximum size mandates a 64bit format, while the callback provides less than 4GB of data? I suppose there will only be a tiny bit of performance and file size penalty, but the code will work and the exported ZIP file will be valid. + +Are you using your modification in a production code? How well is your modification tested? + +---------------------------------------------------------------- + diff --git a/src/miniz/miniz.c b/src/miniz/miniz.c index 9ded4c75ab..66afb94c21 100644 --- a/src/miniz/miniz.c +++ b/src/miniz/miniz.c @@ -6370,13 +6370,13 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n return MZ_TRUE; } -mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, +mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; - mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; mz_uint8 *pExtra_data = NULL; @@ -6398,7 +6398,7 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA pState = pZip->m_pState; - if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) + if ((!pState->m_zip64) && (max_size > MZ_UINT32_MAX)) { /* Source file is too large for non-zip64 */ /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ @@ -6455,7 +6455,7 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA } #endif - if (uncomp_size <= 3) + if (max_size <= 3) level = 0; if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) @@ -6471,7 +6471,7 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - if (uncomp_size && level) + if (max_size && level) { method = MZ_DEFLATED; } @@ -6479,11 +6479,11 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA MZ_CLEAR_OBJ(local_dir_header); if (pState->m_zip64) { - if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + if (max_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; - extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, - (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date)) @@ -6534,9 +6534,8 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA cur_archive_file_ofs += user_extra_data_len; } - if (uncomp_size) + if (max_size) { - mz_uint64 uncomp_remaining = uncomp_size; void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); if (!pRead_buf) { @@ -6545,19 +6544,27 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA if (!level) { - while (uncomp_remaining) + while (1) { - mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); - if ((read_callback(callback_opaque, file_ofs, pRead_buf, n) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) + size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); + if (n == 0) + break; + + if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } - file_ofs += n; + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + file_ofs += n; uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); - uncomp_remaining -= n; cur_archive_file_ofs += n; } + uncomp_size = file_ofs; comp_size = uncomp_size; } else @@ -6584,24 +6591,26 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA for (;;) { - size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); tdefl_status status; tdefl_flush flush = TDEFL_NO_FLUSH; - if (read_callback(callback_opaque, file_ofs, pRead_buf, in_buf_size)!= in_buf_size) + size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); + if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); break; } - file_ofs += in_buf_size; - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); - uncomp_remaining -= in_buf_size; + file_ofs += n; + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) flush = TDEFL_FULL_FLUSH; - status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); + if (n == 0) + flush = TDEFL_FINISH; + + status = tdefl_compress_buffer(pComp, pRead_buf, n, flush); if (status == TDEFL_STATUS_DONE) { result = MZ_TRUE; @@ -6622,6 +6631,7 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pA return MZ_FALSE; } + uncomp_size = file_ofs; comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; } diff --git a/src/miniz/miniz.h b/src/miniz/miniz.h index 7db62811e5..63e5267872 100644 --- a/src/miniz/miniz.h +++ b/src/miniz/miniz.h @@ -1282,7 +1282,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n /* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */ /* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/ -mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, +mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len);