diff options
author | supermerill <merill@free.fr> | 2021-11-17 02:39:46 +0300 |
---|---|---|
committer | supermerill <merill@free.fr> | 2021-11-18 03:05:09 +0300 |
commit | 0d25f9b266ebe279a14e1a494bb60262f8ff9f2f (patch) | |
tree | cdf1dc8f70d37d3f59163cc3e2823a0a10df5eb1 | |
parent | 282db5bd4f623e7d49648b6b4a056e7250df65af (diff) |
bridge_overlap fix & redesign
* now has a min setting.
* the density can be chosen between the two values, with the highest density possible.
* remove the hardcoded 87.5% density modifier. Replaced by a max of 90% and a min of 80%
* try to place the bridge at the right position (only works if the shape is simple).
FIXME: bridge can be printed on top of the previous one (if began in the wrong direction, or it has a odd number and need to go back to the same side)
try to mitigate that.
-rw-r--r-- | resources/ui_layout/print.ui | 5 | ||||
-rw-r--r-- | src/libslic3r/Fill/Fill.cpp | 69 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillBase.cpp | 7 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillBase.hpp | 11 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillConcentric.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillConcentric.hpp | 2 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillLine.cpp | 4 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillLine.hpp | 2 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillRectilinear.cpp | 26 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillRectilinear.hpp | 2 | ||||
-rw-r--r-- | src/libslic3r/Fill/FillSmooth.cpp | 5 | ||||
-rw-r--r-- | src/libslic3r/Flow.cpp | 8 | ||||
-rw-r--r-- | src/libslic3r/Flow.hpp | 3 | ||||
-rw-r--r-- | src/libslic3r/Preset.cpp | 1 | ||||
-rw-r--r-- | src/libslic3r/PrintConfig.cpp | 30 | ||||
-rw-r--r-- | src/libslic3r/PrintConfig.hpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/ConfigManipulation.cpp | 1 | ||||
-rw-r--r-- | src/slic3r/GUI/Field.cpp | 180 | ||||
-rw-r--r-- | src/slic3r/GUI/Field.hpp | 4 |
19 files changed, 231 insertions, 133 deletions
diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index 2eb5ff0d6..b5f893b70 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -321,8 +321,11 @@ group:Overlap setting:label$External:external_perimeter_overlap setting:label$Gap Fill:gap_fill_overlap end_line + line:Bridge lines density + setting:bridge_overlap_min + setting:bridge_overlap + end_line setting:sidetext_width$7:infill_overlap - setting:bridge_overlap group:Flow line:Flow ratio setting:bridge_flow_ratio diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 9f0030fa3..aa1b38d76 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -23,9 +23,9 @@ struct SurfaceFillParams : FillParams // FillBase // in unscaled coordinates - coordf_t spacing = 0.; + double spacing = 0.; // infill / perimeter overlap, in unscaled coordinates - coordf_t overlap = 0.; + double overlap = 0.; // Angle as provided by the region config, in radians. float angle = 0.f; // Non-negative for a bridge. @@ -435,6 +435,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: store_fill(current_region_id); } current_region_id = surface_fill.region_id; + const LayerRegion* layerm = this->m_regions[surface_fill.region_id]; // Create the filler object. std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern)); @@ -446,6 +447,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: // calculate flow spacing for infill pattern generation bool using_internal_flow = ! surface_fill.surface.has_fill_solid() && ! surface_fill.params.flow.bridge; + //init spacing, it may also use & modify a bit the surface_fill.params, so most of these should be set before. + // note that the bridge overlap is applied here via the rectilinear init_spacing. f->init_spacing(surface_fill.params.spacing, surface_fill.params); double link_max_length = 0.; if (! surface_fill.params.flow.bridge) { @@ -463,7 +466,6 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: //give the overlap size to let the infill do his overlap //add overlap if at least one perimeter - const LayerRegion* layerm = this->m_regions[surface_fill.region_id]; const float perimeter_spacing = layerm->flow(frPerimeter).spacing(); // Used by the concentric infill pattern to clip the loops to create extrusion paths. @@ -485,10 +487,6 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: surface_fill.params.flow = Flow::new_from_spacing((float)f->get_spacing(), surface_fill.params.flow.nozzle_diameter, (float)surface_fill.params.flow.height, overlap, surface_fill.params.flow.bridge); } - //apply bridge_overlap if needed - if (surface_fill.params.flow.bridge && surface_fill.params.density > 0.99 && layerm->region()->config().bridge_overlap.get_abs_value(1) != 1) { - surface_fill.params.density *= float(layerm->region()->config().bridge_overlap.get_abs_value(1)); - } for (ExPolygon &expoly : surface_fill.expolygons) { //set overlap polygons @@ -509,6 +507,63 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: if (!expoly.contour.empty()) { surface_fill.surface.expolygon = std::move(expoly); + //adjust the bridge density + if (surface_fill.params.flow.bridge && surface_fill.params.density > 0.99 /*&& layerm->region()->config().bridge_overlap.get_abs_value(1) != 1*/) { + ////varies the overlap to have teh best coverage for the bridge + //surface_fill.params.density *= float(layerm->region()->config().bridge_overlap.get_abs_value(1)); + double min_spacing = 0.999 * surface_fill.params.spacing / surface_fill.params.config->bridge_overlap.get_abs_value(surface_fill.params.density); + double max_spacing = 1.001 * surface_fill.params.spacing / surface_fill.params.config->bridge_overlap_min.get_abs_value(surface_fill.params.density); + double factor = 1.00001; + if (min_spacing < max_spacing * 1.01) { + // create a bouding box of the rotated surface + coord_t bounding_box_size_x = 0; + Polygon poly = surface_fill.surface.expolygon.contour; + coord_t bounding_box_min_x = 0; + poly.rotate(PI / 2 - (surface_fill.params.bridge_angle < 0 ? surface_fill.params.angle : surface_fill.params.bridge_angle)); + ExPolygons expolys; + if (surface_fill.params.bridge_angle > 0 && !f->no_overlap_expolygons.empty()) { + //take only the no-overlap area + expolys = offset_ex(intersection_ex(ExPolygons{ ExPolygon{surface_fill.surface.expolygon.contour} }, f->no_overlap_expolygons), -scale_t(surface_fill.params.spacing) / 2 - 10); + } else { + expolys = offset_ex(ExPolygon{surface_fill.surface.expolygon.contour}, -scale_t(surface_fill.params.spacing) / 2 - 10); + } + BoundingBox bb; + bool first = true; + for (ExPolygon& expoly : expolys) { + expoly.holes.clear(); + expoly.rotate(PI / 2 - (surface_fill.params.bridge_angle < 0 ? surface_fill.params.angle : surface_fill.params.bridge_angle)); + if (first) { + bb = expoly.contour.bounding_box(); + first = false; + } else { + bb.merge(expoly.contour.points); + } + } + bounding_box_size_x = bb.size().x(); + bounding_box_min_x = bb.min.x(); + + //compute the dist + double new_spacing = unscaled(f->_adjust_solid_spacing(bounding_box_size_x, scale_t(min_spacing), 2)); + if (new_spacing <= max_spacing) { + surface_fill.params.density = factor * surface_fill.params.spacing / new_spacing; + } else { + double new_spacing2 = unscaled(f->_adjust_solid_spacing(bounding_box_size_x, scale_t(min_spacing * 1.999 - new_spacing), 2)); + if (new_spacing2 < min_spacing) { + if (min_spacing - new_spacing2 < new_spacing - max_spacing) { + surface_fill.params.density = surface_fill.params.config->bridge_overlap.get_abs_value(surface_fill.params.density); + } else { + surface_fill.params.density = surface_fill.params.config->bridge_overlap_min.get_abs_value(surface_fill.params.density); + } + } else { + //use the highest density + surface_fill.params.density = surface_fill.params.config->bridge_overlap.get_abs_value(surface_fill.params.density); + } + } + surface_fill.params.dont_adjust = true; + surface_fill.params.bridge_offset = std::abs(poly.bounding_box().min.x() - bounding_box_min_x); + } + } + //make fill while ((size_t)surface_fill.params.priority >= fills_by_priority.size()) fills_by_priority.push_back(new ExtrusionEntityCollection()); diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 08bcc9d9f..b2806c19d 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -84,7 +84,7 @@ Polylines Fill::fill_surface(const Surface *surface, const FillParams ¶ms) c // This function possibly increases the spacing, never decreases, // and for a narrow width the increase in spacing may become severe, // therefore the adjustment is limited to 20% increase. -coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance) +coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance, const double factor_max) { assert(width >= 0); assert(distance > 0); @@ -93,10 +93,9 @@ coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance) coord_t distance_new = (number_of_intervals == 0) ? distance : (coord_t)(((width - EPSILON) / number_of_intervals)); - const coordf_t factor = coordf_t(distance_new) / coordf_t(distance); + const double factor = coordf_t(distance_new) / coordf_t(distance); assert(factor > 1. - 1e-5); // How much could the extrusion width be increased? By 20%. - const coordf_t factor_max = 1.2; if (factor > factor_max) distance_new = coord_t(floor((coordf_t(distance) * factor_max + 0.5))); return distance_new; @@ -228,7 +227,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ coord_t Fill::_line_spacing_for_density(float density) const { - return scale_(this->get_spacing() / density); + return scale_t(this->get_spacing() / density); } //FIXME: add recent improvmeent from perimetergenerator: avoid thick gapfill diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index bfac2d55b..5c5773b10 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -44,6 +44,9 @@ struct FillParams // Fill density, fraction in <0, 1> float density { 0.f }; + // bridge offset from the centerline. + coord_t bridge_offset = -1; + // Fill extruding flow multiplier, fraction in <0, 1>. Used by "over bridge compensation" float flow_mult { 1.0f }; @@ -108,7 +111,7 @@ public: FillAdaptive::Octree* adapt_fill_octree = nullptr; protected: // in unscaled coordinates, please use init (after settings all others settings) as some algos want to modify the value - coordf_t spacing_priv; + double spacing_priv; public: virtual ~Fill() {} @@ -118,8 +121,8 @@ public: static Fill* new_from_type(const std::string &type); void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; } - virtual void init_spacing(coordf_t spacing, const FillParams ¶ms) { this->spacing_priv = spacing; } - coordf_t get_spacing() const { return spacing_priv; } + virtual void init_spacing(double spacing, const FillParams ¶ms) { this->spacing_priv = spacing; } + double get_spacing() const { return spacing_priv; } // Do not sort the fill lines to optimize the print head path? virtual bool no_sort() const { return false; } @@ -181,7 +184,7 @@ public: //for rectilinear static void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, const Polygons& polygons_src, Polylines& polylines_out, const double spacing, const FillParams& params); - static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance); + static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance, const double factor_max = 1.2); // Align a coordinate to a grid. The coordinate may be negative, // the aligned value will never be bigger than the original one. diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 86de14193..6da55e454 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -14,7 +14,7 @@ FillConcentric::init_spacing(coordf_t spacing, const FillParams ¶ms) { Fill::init_spacing(spacing, params); if (params.density > 0.9999f && !params.dont_adjust) { - this->spacing_priv = unscale<double>(this->_adjust_solid_spacing(bounding_box.size()(0), _line_spacing_for_density(params.density))); + this->spacing_priv = unscaled(this->_adjust_solid_spacing(bounding_box.size()(0), _line_spacing_for_density(params.density))); } } diff --git a/src/libslic3r/Fill/FillConcentric.hpp b/src/libslic3r/Fill/FillConcentric.hpp index b111ed7cf..8a6e97f9e 100644 --- a/src/libslic3r/Fill/FillConcentric.hpp +++ b/src/libslic3r/Fill/FillConcentric.hpp @@ -12,7 +12,7 @@ public: protected: Fill* clone() const override { return new FillConcentric(*this); }; - void init_spacing(coordf_t spacing, const FillParams ¶ms) override; + void init_spacing(double spacing, const FillParams ¶ms) override; void _fill_surface_single( const FillParams ¶ms, unsigned int thickness_layers, diff --git a/src/libslic3r/Fill/FillLine.cpp b/src/libslic3r/Fill/FillLine.cpp index eb2a17af5..356528e94 100644 --- a/src/libslic3r/Fill/FillLine.cpp +++ b/src/libslic3r/Fill/FillLine.cpp @@ -7,9 +7,9 @@ namespace Slic3r { -void FillLine::init_spacing(coordf_t spacing, const FillParams& params) { +void FillLine::init_spacing(double spacing, const FillParams& params) { - this->_min_spacing = scale_(spacing); + this->_min_spacing = scale_t(spacing); assert(params.density > 0.0001f && params.density <= 1.f); this->_line_spacing = coord_t(coordf_t(this->_min_spacing) / params.density); this->_diagonal_distance = this->_line_spacing * 2; diff --git a/src/libslic3r/Fill/FillLine.hpp b/src/libslic3r/Fill/FillLine.hpp index f14b9c4bb..771639d4f 100644 --- a/src/libslic3r/Fill/FillLine.hpp +++ b/src/libslic3r/Fill/FillLine.hpp @@ -15,7 +15,7 @@ public: Fill* clone() const override { return new FillLine(*this); }; ~FillLine() override = default; - void init_spacing(coordf_t spacing, const FillParams& params) override; + void init_spacing(double spacing, const FillParams& params) override; protected: void _fill_surface_single( const FillParams ¶ms, diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 3457f3b4e..ab5418b56 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -754,13 +754,13 @@ static inline float measure_outer_contour_slab( */ void -FillRectilinear::init_spacing(coordf_t spacing, const FillParams& params) +FillRectilinear::init_spacing(double spacing, const FillParams& params) { Fill::init_spacing(spacing, params); //remove this code path becaus it's only really useful for squares at 45° and it override a setting // define flow spacing according to requested density //if (params.full_infill() && !params.dont_adjust) { - // this->spacing = unscale<coordf_t>(this->_adjust_solid_spacing(bounding_box.size()(0), _line_spacing_for_density(params.density))); + // this->spacing = unscaled(this->_adjust_solid_spacing(bounding_box.size()(0), _line_spacing_for_density(params.density))); //} } @@ -774,9 +774,11 @@ enum DirectionMask std::vector<SegmentedIntersectionLine> FillRectilinear::_vert_lines_for_polygon(const ExPolygonWithOffset &poly_with_offset, const BoundingBox &bounding_box, const FillParams ¶ms, coord_t line_spacing) const { // n_vlines = ceil(bbox_width / line_spacing) - size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing; - coord_t x0 = bounding_box.min(0); - if (params.full_infill()) + size_t n_vlines = 1 + (bounding_box.max.x() - bounding_box.min.x() - 10) / line_spacing; + coord_t x0 = bounding_box.min.x(); + if (params.flow.bridge && params.bridge_offset >= 0) { + x0 += params.bridge_offset; + }else if (params.full_infill()) x0 += (line_spacing + coord_t(SCALED_EPSILON)) / 2; #ifdef SLIC3R_DEBUG @@ -2813,8 +2815,8 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa // Shrink the input polygon a bit first to not push the infill lines out of the perimeters. // const float INFILL_OVERLAP_OVER_SPACING = 0.3f; - const float INFILL_OVERLAP_OVER_SPACING = 0.45f; //merill: what is this value??? shouldn't it be like flow.width()? - assert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f); + //const float INFILL_OVERLAP_OVER_SPACING = 0.45f; //merill: what is this value??? + //assert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f); // Rotate polygons so that we can work with vertical lines here std::pair<float, Point> rotate_vector = this->_infill_direction(surface); @@ -2827,8 +2829,8 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa ExPolygonWithOffset poly_with_offset( surface->expolygon, - rotate_vector.first, - (scale_t(0 /*this->overlap*/ - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->get_spacing())), - (scale_t(0 /*this->overlap*/ - 0.5f * this->get_spacing()))); + (scale_t(0 /*this->overlap*/ - /*(0.5 - INFILL_OVERLAP_OVER_SPACING)*/ 0.05 * this->get_spacing())), // outer offset, have to be > to the inner one (less negative) + (scale_t(0 /*this->overlap*/ - 0.48f * this->get_spacing()))); // inner offset (don't put 0.5, as it will cut full-filled area when it's exactly at the right place) if (poly_with_offset.n_contours_inner == 0) { // Not a single infill line fits. //Prusa: maybe one shall trigger the gap fill here? @@ -2839,15 +2841,15 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa BoundingBox bounding_box = poly_with_offset.bounding_box_src(); // define flow spacing according to requested density - if (params.full_infill() && !params.dont_adjust || line_spacing == 0 ) { + if ((params.full_infill() && !params.dont_adjust) || line_spacing == 0 ) { //it's == this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing) because of the init_spacing line_spacing = scale_(this->get_spacing()); - } else { + } else if (!params.full_infill()) { // extend bounding box so that our pattern will be aligned with other layers // Transform the reference point to the rotated coordinate system. Point refpt = rotate_vector.second.rotated(- rotate_vector.first); // _align_to_grid will not work correctly with positive pattern_shift. - coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing; + coord_t pattern_shift_scaled = scale_t(pattern_shift) % line_spacing; refpt.x() -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled); bounding_box.merge(_align_to_grid( bounding_box.min, diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index 9e3cc056e..d15abf4e5 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -16,7 +16,7 @@ class FillRectilinear : public Fill public: Fill* clone() const override { return new FillRectilinear(*this); }; ~FillRectilinear() override = default; - virtual void init_spacing(coordf_t spacing, const FillParams& params) override; + virtual void init_spacing(double spacing, const FillParams& params) override; Polylines fill_surface(const Surface* surface, const FillParams& params) const override; protected: diff --git a/src/libslic3r/Fill/FillSmooth.cpp b/src/libslic3r/Fill/FillSmooth.cpp index 4f6276ee6..3fa43d673 100644 --- a/src/libslic3r/Fill/FillSmooth.cpp +++ b/src/libslic3r/Fill/FillSmooth.cpp @@ -61,11 +61,12 @@ namespace Slic3r { } void FillSmooth::fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill, - const FillParams ¶ms, const double volume) const { + const FillParams ¶ms_init, const double volume) const { + FillParams params = params_init; std::unique_ptr<Fill> f2 = std::unique_ptr<Fill>(Fill::new_from_type(fillPattern[idx])); f2->bounding_box = this->bounding_box; - f2->init_spacing(this->get_spacing(),params); + f2->init_spacing(this->get_spacing(), params); f2->layer_id = this->layer_id; f2->z = this->z; f2->angle = anglePass[idx] + this->angle; diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index 274c5af26..9f71af4b7 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -215,7 +215,7 @@ Flow Flow::new_from_spacing(float spacing, float nozzle_diameter, float height, // For normal extrusons, extrusion width is wider than the spacing due to the rounding and squishing of the extrusions. // For bridge extrusions, the extrusions are placed with a tiny BRIDGE_EXTRA_SPACING gaps between the threads. float width = float(bridge ? - (spacing - BRIDGE_EXTRA_SPACING_MULT * nozzle_diameter) : + (spacing /*- BRIDGE_EXTRA_SPACING_MULT (0.125) * nozzle_diameter*/) : #ifdef HAS_PERIMETER_LINE_OVERLAP (spacing + PERIMETER_LINE_OVERLAP_FACTOR * height * (1. - 0.25 * PI) * spacing_ratio); #else @@ -235,7 +235,7 @@ float Flow::spacing() const float min_flow_spacing = this->width - this->height * (1. - 0.25 * PI) * spacing_ratio; float res = this->width - PERIMETER_LINE_OVERLAP_FACTOR * (this->width - min_flow_spacing); #else - float res = float(this->bridge ? (this->width + BRIDGE_EXTRA_SPACING_MULT * nozzle_diameter) : (this->width - this->height * (1. - 0.25 * PI) * spacing_ratio)); + float res = float(this->bridge ? (this->width /*+ BRIDGE_EXTRA_SPACING_MULT * nozzle_diameter*/) : (this->width - this->height * (1. - 0.25 * PI) * spacing_ratio)); #endif // assert(res > 0.f); if (res <= 0.f) @@ -250,8 +250,8 @@ float Flow::spacing(const Flow &other) const { assert(this->height == other.height); assert(this->bridge == other.bridge); - float res = float(this->bridge ? - 0.5 * this->width + 0.5 * other.width + BRIDGE_EXTRA_SPACING_MULT * nozzle_diameter : + float res = float((this->bridge || other.bridge) ? + 0.5 * this->width + 0.5 * other.width : 0.5 * this->spacing() + 0.5 * other.spacing()); // assert(res > 0.f); if (res <= 0.f) diff --git a/src/libslic3r/Flow.hpp b/src/libslic3r/Flow.hpp index 06c4a158f..9d9be77ee 100644 --- a/src/libslic3r/Flow.hpp +++ b/src/libslic3r/Flow.hpp @@ -10,9 +10,6 @@ namespace Slic3r { class PrintObject; -// Extra spacing of bridge threads, in mult of nozzle_width/extrusion_width. 0.05 for 0.4 -#define BRIDGE_EXTRA_SPACING_MULT 0.125 - // Overlap factor of perimeter lines. Currently no overlap. #ifdef HAS_PERIMETER_LINE_OVERLAP #define PERIMETER_LINE_OVERLAP_FACTOR 1.0 diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index caee17188..d8be8af9e 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -591,6 +591,7 @@ const std::vector<std::string>& Preset::print_options() "clip_multipart_objects", "over_bridge_flow_ratio", "bridge_overlap", + "bridge_overlap_min", "first_layer_flow_ratio", "clip_multipart_objects", "enforce_full_fill_volume", "external_infill_margin", "bridged_infill_margin", // compensation diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 505200986..32c89872e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -404,16 +404,30 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercent(100)); + def = this->add("bridge_overlap_min", coPercent); + def->label = L("Min"); + def->full_label = L("Min bridge density"); + def->sidetext = L("%"); + def->category = OptionCategory::width; + def->tooltip = L("Minimum density for bridge lines. If Lower than bridge_overlap, then the overlap value can be lowered automatically down to this value." + " If the value is higher, this parameter has no effect." + "\nDefault to 87.5% to allow a little void between the lines."); + def->min = 50; + def->max = 200; + def->mode = comExpert; + def->set_default_value(new ConfigOptionPercent(80)); + def = this->add("bridge_overlap", coPercent); - def->label = L("Bridge overlap"); - def->full_label = L("Bridge overlap"); + def->label = L("Max"); + def->full_label = L("Max bridge density"); def->sidetext = L("%"); def->category = OptionCategory::width; - def->tooltip = L("Amount of overlap between lines of the bridge. If want more space between line (or less), you can modify it. Default to 100%. A value of 50% will create two times less lines."); + def->tooltip = L("Maximum density for bridge lines. If you want more space between line (or less), you can modify it." + " A value of 50% will create two times less lines, and a value of 200% will create two time more lines that overlap each other."); def->min = 50; def->max = 200; def->mode = comExpert; - def->set_default_value(new ConfigOptionPercent(100)); + def->set_default_value(new ConfigOptionPercent(90)); def = this->add("bridge_speed", coFloat); def->label = L("Bridges"); @@ -2406,15 +2420,16 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionBool(false)); def = this->add("infill_overlap", coFloatOrPercent); - def->label = L("Infill/perimeters overlap"); + def->label = L("Infill/perimeters encroachment"); def->category = OptionCategory::width; def->tooltip = L("This setting applies an additional overlap between infill and perimeters for better bonding. " "Theoretically this shouldn't be needed, but backlash might cause gaps. If expressed " - "as percentage (example: 15%) it is calculated over perimeter extrusion width."); + "as percentage (example: 15%) it is calculated over perimeter extrusion width." + "\nDon't put a value higher than 50% (of the perimeter width), as it will fuse with it and follow the perimeter."); def->sidetext = L("mm or %"); def->ratio_over = "perimeter_extrusion_width"; def->min = 0; - def->max_literal = { 1, true }; + def->max_literal = { 0.5, true }; def->mode = comExpert; def->set_default_value(new ConfigOptionFloatOrPercent(25, true)); @@ -5916,6 +5931,7 @@ std::unordered_set<std::string> prusa_export_to_remove_keys = { "avoid_crossing_not_first_layer", "bridge_internal_fan_speed", "bridge_overlap", +"bridge_overlap_min", "bridge_speed_internal", "bridged_infill_margin", "brim_ears_detection_length", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ce90d35f5..32537c609 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -782,6 +782,7 @@ public: ConfigOptionPercent bridge_flow_ratio; ConfigOptionPercent over_bridge_flow_ratio; ConfigOptionPercent bridge_overlap; + ConfigOptionPercent bridge_overlap_min; ConfigOptionEnum<InfillPattern> bottom_fill_pattern; ConfigOptionFloatOrPercent bridged_infill_margin; ConfigOptionFloat bridge_speed; @@ -900,6 +901,7 @@ protected: OPT_PTR(bridge_flow_ratio); OPT_PTR(over_bridge_flow_ratio); OPT_PTR(bridge_overlap); + OPT_PTR(bridge_overlap_min); OPT_PTR(bottom_fill_pattern); OPT_PTR(bridged_infill_margin); OPT_PTR(bridge_speed); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 3a75e57ae..1aff59ca0 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -216,6 +216,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con names.push_back("bridge_flow_ratio"); names.push_back("over_bridge_flow_ratio"); names.push_back("bridge_overlap"); + names.push_back("bridge_overlap_min"); names.push_back("fill_top_flow_ratio"); names.push_back("first_layer_flow_ratio"); for (int i = 0; i < names.size(); i++) { diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 793652f26..0bc236e43 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -413,104 +413,120 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true break; case coFloatsOrPercents: case coFloatOrPercent: { - if (!str.IsEmpty() && str.Last() != '%') - { - double val = 0.; - // Replace the first occurence of comma in decimal number. - str.Replace(",", ".", false); - - // remove space and "mm" substring, if any exists - str.Replace(" ", "", true); - str.Replace("m", "", true); - - if (m_opt.nullable && str == na_value()) { - val = ConfigOptionFloatsNullable::nil_value(); - str = "nan"; - } else if (!str.ToCDouble(&val)) { - if (!check_value) { - m_value.clear(); - break; + if (!str.IsEmpty()) { + if ("infill_overlap" == m_opt_id && m_last_validated_value != str) { + bool bad = false; + double val = 0.; + if (str.Last() != '%') { + if (str.ToCDouble(&val)) { + const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector<double>& nozzle_diameters = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values; + double nozzle_diameter = 0; + for (double diameter : nozzle_diameters) + nozzle_diameter = std::max(nozzle_diameter, diameter); + if (val > nozzle_diameter / 2) { + bad = true; + } + } + } else { + if (str.substr(0, str.size() - 1).ToCDouble(&val)) { + if (val >= 50) { + bad = true; + } + } } - show_error(m_parent, _(L("Invalid numeric input."))); - set_value(double_to_string(val, m_opt.precision), true); - } else { - - //at least check min, as we can want a 0 min - if (m_opt.min > val) - { + if (bad && check_value) { + const wxString msg_text = from_u8(_u8L("The infill / perimeter encroachment can't be higher than half of the perimeter width.\n" + "Are you sure to use this value?")); + wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); + auto ret = dialog.ShowModal(); + if (ret == wxID_NO) { + str = from_u8("49%"); + m_last_validated_value = str; + set_value(str, false); + str = m_last_validated_value; + } + m_last_validated_value = str; + } + } + else if (str.Last() != '%') { + double val = 0.; + // Replace the first occurence of comma in decimal number. + str.Replace(",", ".", false); + + // remove space and "mm" substring, if any exists + str.Replace(" ", "", true); + str.Replace("m", "", true); + + if (m_opt.nullable && str == na_value()) { + val = ConfigOptionFloatsNullable::nil_value(); + str = "nan"; + } else if (!str.ToCDouble(&val)) { if (!check_value) { m_value.clear(); break; } - show_error(m_parent, _(L("Input value is out of range"))); - if (m_opt.min > val) val = m_opt.min; + show_error(m_parent, _(L("Invalid numeric input."))); set_value(double_to_string(val, m_opt.precision), true); - } else if (m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)) { - bool not_ok = (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max); - if( !not_ok && m_opt.max_literal.value != 0 ) - if (m_opt.max_literal.percent) { - const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; - const std::vector<double>& nozzle_diameters = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values; - double nozzle_diameter = 0; - for (double diameter : nozzle_diameters) - nozzle_diameter = std::max(nozzle_diameter, diameter); - if (m_opt.max_literal.value > 0) - not_ok = val > nozzle_diameter * m_opt.max_literal.value; - else - not_ok = val < nozzle_diameter * (-m_opt.max_literal.value); - }else{ - if(m_opt.max_literal.value > 0) - not_ok = val > m_opt.max_literal.value; - else - not_ok = val < -m_opt.max_literal.value; - } - if (not_ok) { - - // if ( - // ( - // (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) - // || - // (m_opt.sidetext.rfind("mm ") != std::string::npos && val > m_opt.max_literal) - // ) - // && - // (m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value))) - //{ - // if (m_opt.opt_key.find("extrusion_width") != std::string::npos || m_opt.opt_key.find("extrusion_spacing") != std::string::npos) { - // const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; - // const std::vector<double>& nozzle_diameters = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values; - // double nozzle_diameter = 0; - // for (double diameter : nozzle_diameters) - // nozzle_diameter = std::max(nozzle_diameter, diameter); - // if (val < nozzle_diameter * 10) { - // m_value = std::string(str.ToUTF8().data()); - // break; - // } - // } - //TODO: chack for infill_overlap from diameter% => allow max_literal to be a % + } else { + //at least check min, as we can want a 0 min + if (m_opt.min > val) + { if (!check_value) { m_value.clear(); break; } + show_error(m_parent, _(L("Input value is out of range"))); + if (m_opt.min > val) val = m_opt.min; + set_value(double_to_string(val, m_opt.precision), true); + } else if (m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)) { + bool not_ok = (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max); + if (!not_ok && m_opt.max_literal.value != 0) { + if (m_opt.max_literal.percent) { + const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector<double>& nozzle_diameters = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values; + double nozzle_diameter = 0; + for (double diameter : nozzle_diameters) + nozzle_diameter = std::max(nozzle_diameter, diameter); + if (m_opt.max_literal.value > 0) + not_ok = val > nozzle_diameter * m_opt.max_literal.value; + else + not_ok = val < nozzle_diameter* (-m_opt.max_literal.value); + } else { + if (m_opt.max_literal.value > 0) + not_ok = val > m_opt.max_literal.value; + else + not_ok = val < -m_opt.max_literal.value; + } + } + if (not_ok && m_last_validated_value != str) { + if (!check_value) { + m_value.clear(); + break; + } - bool infill_anchors = m_opt.opt_key == "infill_anchor" || m_opt.opt_key == "infill_anchor_max"; - - const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm"; - const wxString stVal = double_to_string(val, m_opt.precision); - const wxString msg_text = from_u8((boost::format(_utf8(L("Do you mean %s%% instead of %s %s?\n" - "Select YES if you want to change this value to %s%%, \n" - "or NO if you are sure that %s %s is a correct value."))) % stVal % stVal % sidetext % stVal % stVal % sidetext).str()); - wxMessageDialog dialog(m_parent, msg_text, _(L("Parameter validation")) + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); - if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) { - set_value(from_u8((boost::format("%s%%") % stVal).str()), false/*true*/); - str += "%%"; - } else - set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "." + bool infill_anchors = m_opt.opt_key == "infill_anchor" || m_opt.opt_key == "infill_anchor_max"; + + const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm"; + const wxString stVal = double_to_string(val, m_opt.precision); + const wxString msg_text = from_u8((boost::format(_u8L("Do you mean %s%% instead of %s %s?\n" + "Select YES if you want to change this value to %s%%, \n" + "or NO if you are sure that %s %s is a correct value.")) % stVal % stVal % sidetext % stVal % stVal % sidetext).str()); + wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); + if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) { + str += "%"; + m_last_validated_value = str; + set_value(str, false/*true*/); + str = m_last_validated_value; + } else + set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "." + m_last_validated_value = str; + } } } } } - m_value = std::string(str.ToUTF8().data()); break; } diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 3c361f94b..e48473346 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -230,8 +230,10 @@ protected: // current value boost::any m_value; - // last maeningful value + // last meaningful value boost::any m_last_meaningful_value; + // last validated value + wxString m_last_validated_value; int m_em_unit; |