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.
This commit is contained in:
supermerill 2021-11-17 00:39:46 +01:00
parent 282db5bd4f
commit 0d25f9b266
19 changed files with 231 additions and 133 deletions

View File

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

View File

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

View File

@ -84,7 +84,7 @@ Polylines Fill::fill_surface(const Surface *surface, const FillParams &params) 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 &para
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

View File

@ -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 &params) { this->spacing_priv = spacing; }
coordf_t get_spacing() const { return spacing_priv; }
virtual void init_spacing(double spacing, const FillParams &params) { 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.

View File

@ -14,7 +14,7 @@ FillConcentric::init_spacing(coordf_t spacing, const FillParams &params)
{
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)));
}
}

View File

@ -12,7 +12,7 @@ public:
protected:
Fill* clone() const override { return new FillConcentric(*this); };
void init_spacing(coordf_t spacing, const FillParams &params) override;
void init_spacing(double spacing, const FillParams &params) override;
void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,

View File

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

View File

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

View File

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

View File

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

View File

@ -61,11 +61,12 @@ namespace Slic3r {
}
void FillSmooth::fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill,
const FillParams &params, const double volume) const {
const FillParams &params_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;

View File

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

View File

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

View File

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

View File

@ -404,16 +404,30 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionPercent(100));
def = this->add("bridge_overlap", coPercent);
def->label = L("Bridge overlap");
def->full_label = L("Bridge overlap");
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("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("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(100));
def->set_default_value(new ConfigOptionPercent(80));
def = this->add("bridge_overlap", coPercent);
def->label = L("Max");
def->full_label = L("Max bridge density");
def->sidetext = L("%");
def->category = OptionCategory::width;
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(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",

View File

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

View File

@ -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++) {

View File

@ -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;
}
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 (!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;
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 (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 (val > nozzle_diameter / 2) {
bad = true;
}
if (not_ok) {
}
} else {
if (str.substr(0, str.size() - 1).ToCDouble(&val)) {
if (val >= 50) {
bad = true;
}
}
}
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);
// 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 %
// 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("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 (!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";
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 "."
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;
}

View File

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