ENH: support circle speed compensation
Jira: none Change-Id: I05f31ff26463cdf6fd900f8f1ca6cf0e0b283925
This commit is contained in:
parent
e617e933b8
commit
7d44a8bdca
|
@ -14,6 +14,7 @@
|
|||
namespace Slic3r {
|
||||
static const double slope_path_ratio = 0.3;
|
||||
static const double slope_inner_outer_wall_gap = 0.4;
|
||||
static const int overhang_threshold = 1;
|
||||
|
||||
void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const
|
||||
{
|
||||
|
@ -418,6 +419,17 @@ bool ExtrusionLoop::has_overhang_point(const Point &point) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ExtrusionLoop::has_overhang_paths() const
|
||||
{
|
||||
for (const ExtrusionPath &path : this->paths) {
|
||||
if (is_bridge(path.role()))
|
||||
return true;
|
||||
if (path.overhang_degree >= overhang_threshold)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ExtrusionLoop::polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const
|
||||
{
|
||||
for (const ExtrusionPath &path : this->paths)
|
||||
|
|
|
@ -66,6 +66,11 @@ enum ExtrusionRole : uint8_t {
|
|||
erCount
|
||||
};
|
||||
|
||||
enum CustomizeFlag : uint8_t {
|
||||
cfNone,
|
||||
cfCircleCompensation // shaft hole tolerance compensation
|
||||
};
|
||||
|
||||
// Special flags describing loop
|
||||
enum ExtrusionLoopRole {
|
||||
elrDefault = 1 << 0,
|
||||
|
@ -119,6 +124,12 @@ inline bool is_bridge(ExtrusionRole role) {
|
|||
class ExtrusionEntity
|
||||
{
|
||||
public:
|
||||
ExtrusionEntity() = default;
|
||||
ExtrusionEntity(const ExtrusionEntity &rhs) { m_customize_flag = rhs.m_customize_flag; };
|
||||
ExtrusionEntity(ExtrusionEntity &&rhs) { m_customize_flag = rhs.m_customize_flag; };
|
||||
ExtrusionEntity &operator=(const ExtrusionEntity &rhs) { m_customize_flag = rhs.m_customize_flag; return *this; }
|
||||
ExtrusionEntity &operator=(ExtrusionEntity &&rhs) { m_customize_flag = rhs.m_customize_flag; return *this; }
|
||||
|
||||
virtual ExtrusionRole role() const = 0;
|
||||
virtual bool is_collection() const { return false; }
|
||||
virtual bool is_loop() const { return false; }
|
||||
|
@ -154,6 +165,12 @@ public:
|
|||
|
||||
static std::string role_to_string(ExtrusionRole role);
|
||||
static ExtrusionRole string_to_role(const std::string_view role);
|
||||
|
||||
virtual CustomizeFlag get_customize_flag() const { return m_customize_flag; };
|
||||
virtual void set_customize_flag(CustomizeFlag flag) { m_customize_flag = flag; };
|
||||
|
||||
protected:
|
||||
CustomizeFlag m_customize_flag{CustomizeFlag::cfNone};
|
||||
};
|
||||
|
||||
typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
|
||||
|
@ -178,7 +195,8 @@ public:
|
|||
ExtrusionPath(double overhang_degree, int curve_degree, ExtrusionRole role, double mm3_per_mm, float width, float height) : overhang_degree(overhang_degree), curve_degree(curve_degree), mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role) {}
|
||||
|
||||
ExtrusionPath(const ExtrusionPath &rhs)
|
||||
: polyline(rhs.polyline)
|
||||
: ExtrusionEntity(rhs)
|
||||
, polyline(rhs.polyline)
|
||||
, overhang_degree(rhs.overhang_degree)
|
||||
, curve_degree(rhs.curve_degree)
|
||||
, mm3_per_mm(rhs.mm3_per_mm)
|
||||
|
@ -190,7 +208,8 @@ public:
|
|||
, m_no_extrusion(rhs.m_no_extrusion)
|
||||
{}
|
||||
ExtrusionPath(ExtrusionPath &&rhs)
|
||||
: polyline(std::move(rhs.polyline))
|
||||
: ExtrusionEntity(rhs)
|
||||
, polyline(std::move(rhs.polyline))
|
||||
, overhang_degree(rhs.overhang_degree)
|
||||
, curve_degree(rhs.curve_degree)
|
||||
, mm3_per_mm(rhs.mm3_per_mm)
|
||||
|
@ -202,7 +221,8 @@ public:
|
|||
, m_no_extrusion(rhs.m_no_extrusion)
|
||||
{}
|
||||
ExtrusionPath(const Polyline &polyline, const ExtrusionPath &rhs)
|
||||
: polyline(polyline)
|
||||
: ExtrusionEntity(rhs)
|
||||
, polyline(polyline)
|
||||
, overhang_degree(rhs.overhang_degree)
|
||||
, curve_degree(rhs.curve_degree)
|
||||
, mm3_per_mm(rhs.mm3_per_mm)
|
||||
|
@ -214,7 +234,8 @@ public:
|
|||
, m_no_extrusion(rhs.m_no_extrusion)
|
||||
{}
|
||||
ExtrusionPath(Polyline &&polyline, const ExtrusionPath &rhs)
|
||||
: polyline(std::move(polyline))
|
||||
: ExtrusionEntity(rhs)
|
||||
, polyline(std::move(polyline))
|
||||
, overhang_degree(rhs.overhang_degree)
|
||||
, curve_degree(rhs.curve_degree)
|
||||
, mm3_per_mm(rhs.mm3_per_mm)
|
||||
|
@ -227,6 +248,7 @@ public:
|
|||
{}
|
||||
|
||||
ExtrusionPath& operator=(const ExtrusionPath& rhs) {
|
||||
ExtrusionEntity::operator=(rhs);
|
||||
m_can_reverse = rhs.m_can_reverse;
|
||||
m_role = rhs.m_role;
|
||||
m_no_extrusion = rhs.m_no_extrusion;
|
||||
|
@ -240,6 +262,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
ExtrusionPath& operator=(ExtrusionPath&& rhs) {
|
||||
ExtrusionEntity::operator=(rhs);
|
||||
m_can_reverse = rhs.m_can_reverse;
|
||||
m_role = rhs.m_role;
|
||||
m_no_extrusion = rhs.m_no_extrusion;
|
||||
|
@ -441,6 +464,7 @@ public:
|
|||
ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : m_loop_role(role) {}
|
||||
ExtrusionLoop(const ExtrusionPaths &paths, ExtrusionLoopRole role = elrDefault) : paths(paths), m_loop_role(role) {}
|
||||
ExtrusionLoop(ExtrusionPaths &&paths, ExtrusionLoopRole role = elrDefault) : paths(std::move(paths)), m_loop_role(role) {}
|
||||
ExtrusionLoop(ExtrusionPaths &&paths, ExtrusionLoopRole role, CustomizeFlag flag) : paths(std::move(paths)), m_loop_role(role) { m_customize_flag = flag; }
|
||||
ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
|
||||
{ this->paths.push_back(path); }
|
||||
ExtrusionLoop(const ExtrusionPath &&path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
|
||||
|
@ -472,6 +496,7 @@ public:
|
|||
// Test, whether the point is extruded by a bridging flow.
|
||||
// This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead.
|
||||
bool has_overhang_point(const Point &point) const;
|
||||
bool has_overhang_paths() const;
|
||||
ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); }
|
||||
ExtrusionLoopRole loop_role() const { return m_loop_role; }
|
||||
void set_loop_role(ExtrusionLoopRole role) { m_loop_role = role; }
|
||||
|
|
|
@ -4388,6 +4388,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
|||
const double clip_length = m_enable_loop_clipping && !enable_seam_slope ? seam_gap : 0;
|
||||
// get paths
|
||||
ExtrusionPaths paths;
|
||||
bool set_holes_and_compensation_speed = loop.get_customize_flag() && !loop.has_overhang_paths();
|
||||
loop.clip_end(clip_length, &paths);
|
||||
if (paths.empty()) return "";
|
||||
|
||||
|
@ -4449,7 +4450,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
|||
smooth_speed_discontinuity_area(new_loop.paths);
|
||||
// Then extrude it
|
||||
for (const auto &p : new_loop.get_all_paths()) {
|
||||
gcode += this->_extrude(*p, description, speed_for_path(*p));
|
||||
gcode += this->_extrude(*p, description, speed_for_path(*p), set_holes_and_compensation_speed);
|
||||
}
|
||||
set_last_scarf_seam_flag(true);
|
||||
|
||||
|
@ -4474,7 +4475,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
|||
smooth_speed_discontinuity_area(paths);
|
||||
|
||||
for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) {
|
||||
gcode += this->_extrude(*path, description, speed_for_path(*path));
|
||||
gcode += this->_extrude(*path, description, speed_for_path(*path), set_holes_and_compensation_speed);
|
||||
}
|
||||
set_last_scarf_seam_flag(false);
|
||||
}
|
||||
|
@ -5006,7 +5007,7 @@ void GCode::smooth_speed_discontinuity_area(ExtrusionPaths &paths) {
|
|||
paths = std::move(inter_paths);
|
||||
}
|
||||
|
||||
std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double speed, bool is_first_slope)
|
||||
std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double speed, bool set_holes_and_compensation_speed, bool is_first_slope)
|
||||
{
|
||||
std::string gcode;
|
||||
|
||||
|
@ -5099,7 +5100,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
if (speed == -1) {
|
||||
if (path.role() == erPerimeter) {
|
||||
speed = m_config.inner_wall_speed.get_at(cur_extruder_index());
|
||||
if (m_config.detect_overhang_wall && m_config.smooth_speed_discontinuity_area && path.smooth_speed != 0)
|
||||
//reset speed by auto compensation speed
|
||||
if(set_holes_and_compensation_speed) {
|
||||
speed = m_config.circle_compensation_speed;
|
||||
}else if (m_config.detect_overhang_wall && m_config.smooth_speed_discontinuity_area && path.smooth_speed != 0)
|
||||
speed = path.smooth_speed;
|
||||
else if (m_config.enable_overhang_speed.get_at(cur_extruder_index())) {
|
||||
double new_speed = 0;
|
||||
|
@ -5108,12 +5112,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
}
|
||||
} else if (path.role() == erExternalPerimeter) {
|
||||
speed = m_config.outer_wall_speed.get_at(cur_extruder_index());
|
||||
if (m_config.detect_overhang_wall && m_config.smooth_speed_discontinuity_area && path.smooth_speed != 0)
|
||||
// reset speed by auto compensation speed
|
||||
if (set_holes_and_compensation_speed) {
|
||||
speed = m_config.circle_compensation_speed;
|
||||
} else if (m_config.detect_overhang_wall && m_config.smooth_speed_discontinuity_area && path.smooth_speed != 0)
|
||||
speed = path.smooth_speed;
|
||||
else if (m_config.enable_overhang_speed.get_at(cur_extruder_index())) {
|
||||
double new_speed = 0;
|
||||
new_speed = get_overhang_degree_corr_speed(speed, path.overhang_degree);
|
||||
|
||||
new_speed = get_overhang_degree_corr_speed(speed, path.overhang_degree);
|
||||
speed = new_speed == 0.0 ? speed : new_speed;
|
||||
}
|
||||
} else if (path.role() == erOverhangPerimeter && path.overhang_degree == 5) {
|
||||
|
@ -5198,6 +5204,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
char buf[64];
|
||||
assert(is_decimal_separator_point());
|
||||
|
||||
|
||||
if (set_holes_and_compensation_speed)
|
||||
gcode += "; Slow Down Start\n";
|
||||
|
||||
if (path.role() != m_last_processor_extrusion_role) {
|
||||
m_last_processor_extrusion_role = path.role();
|
||||
sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str());
|
||||
|
@ -5349,6 +5359,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
}
|
||||
}
|
||||
|
||||
if (set_holes_and_compensation_speed) {
|
||||
gcode += "; Slow Down End\n";
|
||||
}
|
||||
|
||||
this->set_last_pos(path.last_point());
|
||||
return gcode;
|
||||
}
|
||||
|
|
|
@ -560,7 +560,7 @@ private:
|
|||
// BBS
|
||||
int get_bed_temperature(const int extruder_id, const bool is_first_layer, const BedType bed_type) const;
|
||||
|
||||
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1, bool is_first_slope = false);
|
||||
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1, bool set_holes_and_compensation_speed = false, bool is_first_slope = false);
|
||||
ExtrusionPaths set_speed_transition(ExtrusionPaths &paths);
|
||||
ExtrusionPaths split_and_mapping_speed(double &other_path_v, double &final_v, ExtrusionPath &this_path, double max_smooth_length, bool split_from_left = true);
|
||||
double get_path_speed(const ExtrusionPath &path);
|
||||
|
|
|
@ -128,7 +128,7 @@ std::vector<PerExtruderAdjustments> GCodeEditer::parse_layer_gcode(
|
|||
std::string cooling_node_label = "; COOLING_NODE: ";
|
||||
bool append_wall_ptr = false;
|
||||
bool append_inner_wall_ptr = false;
|
||||
|
||||
bool not_join_cooling = false;
|
||||
std::pair<int, int> node_pos;
|
||||
int line_idx = -1;
|
||||
for (; *line_start != 0; line_start = line_end)
|
||||
|
@ -199,7 +199,7 @@ std::vector<PerExtruderAdjustments> GCodeEditer::parse_layer_gcode(
|
|||
|
||||
if (wipe)
|
||||
line.type |= CoolingLine::TYPE_WIPE;
|
||||
if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && ! wipe) {
|
||||
if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && !wipe && !not_join_cooling) {
|
||||
line.type |= CoolingLine::TYPE_ADJUSTABLE;
|
||||
active_speed_modifier = adjustment->lines.size();
|
||||
}
|
||||
|
@ -279,6 +279,10 @@ std::vector<PerExtruderAdjustments> GCodeEditer::parse_layer_gcode(
|
|||
}
|
||||
}
|
||||
current_pos = std::move(new_pos);
|
||||
} else if (boost::starts_with(sline, "; Slow Down Start")) {
|
||||
not_join_cooling = true;
|
||||
} else if (boost::starts_with(sline, "; Slow Down End")) {
|
||||
not_join_cooling = false;
|
||||
} else if (boost::starts_with(sline, ";_EXTRUDE_END")) {
|
||||
line.type = CoolingLine::TYPE_EXTRUDE_END;
|
||||
active_speed_modifier = size_t(-1);
|
||||
|
|
|
@ -197,7 +197,13 @@ void Layer::make_perimeters()
|
|||
|
||||
if (layerms.size() == 1) { // optimization
|
||||
(*layerm)->fill_surfaces.surfaces.clear();
|
||||
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces, &(*layerm)->fill_no_overlap_expolygons, this->loop_nodes);
|
||||
if (this->object()->config().enable_circle_compensation) {
|
||||
SurfaceCollection copy_slices = (*layerm)->slices;
|
||||
(*layerm)->auto_circle_compensation(copy_slices);
|
||||
(*layerm)->make_perimeters(copy_slices, &(*layerm)->fill_surfaces, &(*layerm)->fill_no_overlap_expolygons, this->loop_nodes);
|
||||
} else
|
||||
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces, &(*layerm)->fill_no_overlap_expolygons, this->loop_nodes);
|
||||
|
||||
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
|
||||
} else {
|
||||
SurfaceCollection new_slices;
|
||||
|
@ -221,6 +227,8 @@ void Layer::make_perimeters()
|
|||
SurfaceCollection fill_surfaces;
|
||||
//BBS
|
||||
ExPolygons fill_no_overlap;
|
||||
if (this->object()->config().enable_circle_compensation)
|
||||
layerm_config->auto_circle_compensation(new_slices);
|
||||
layerm_config->make_perimeters(new_slices, &fill_surfaces, &fill_no_overlap, this->loop_nodes);
|
||||
|
||||
// assign fill_surfaces to each layer
|
||||
|
|
|
@ -80,6 +80,7 @@ public:
|
|||
void slices_to_fill_surfaces_clipped();
|
||||
void prepare_fill_surfaces();
|
||||
//BBS
|
||||
void auto_circle_compensation(SurfaceCollection &slices);
|
||||
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces, ExPolygons* fill_no_overlap, std::vector<LoopNode> &loop_nodes);
|
||||
void process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered);
|
||||
double infill_area_threshold() const;
|
||||
|
|
|
@ -64,12 +64,73 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
|
|||
}
|
||||
}
|
||||
|
||||
void LayerRegion::auto_circle_compensation(SurfaceCollection& slices)
|
||||
{
|
||||
const PrintObjectConfig &object_config = this->layer()->object()->config();
|
||||
double max_deviation = object_config.max_deviation * 1e6;
|
||||
double max_variance = object_config.max_variance * 1e6;
|
||||
double limited_speed = object_config.circle_compensation_speed;
|
||||
|
||||
double counter_speed_coef = object_config.counter_coef_1 / 1e6;
|
||||
double counter_diameter_coef = object_config.counter_coef_2 / 1e6;
|
||||
double counter_compensate_coef = object_config.counter_coef_3;
|
||||
|
||||
double hole_speed_coef = object_config.hole_coef_1 / 1e6;
|
||||
double hole_diameter_coef = object_config.hole_coef_2 / 1e6;
|
||||
double hole_compensate_coef = object_config.hole_coef_3;
|
||||
|
||||
double counter_limit_min_value = object_config.counter_limit_min;
|
||||
double counter_limit_max_value = object_config.counter_limit_max;
|
||||
double hole_limit_min_value = object_config.hole_limit_min;
|
||||
double hole_limit_max_value = object_config.hole_limit_max;
|
||||
|
||||
double diameter_limit_value = object_config.diameter_limit;
|
||||
|
||||
for (Surface &surface : slices.surfaces) {
|
||||
Point center;
|
||||
double diameter = 0;
|
||||
if (surface.expolygon.contour.is_approx_circle(max_deviation, max_variance, center, diameter)) {
|
||||
double offset_value = counter_speed_coef * limited_speed + counter_diameter_coef * diameter + counter_compensate_coef;
|
||||
if (offset_value < counter_limit_min_value) {
|
||||
offset_value = counter_limit_min_value;
|
||||
} else if (offset_value > counter_limit_max_value) {
|
||||
offset_value = counter_limit_max_value;
|
||||
}
|
||||
Polygons offseted_polys = offset(surface.expolygon.contour, offset_value);
|
||||
if (offseted_polys.size() == 1) {
|
||||
surface.expolygon.contour = offseted_polys[0];
|
||||
if (diameter < diameter_limit_value * 1e6)
|
||||
surface.counter_circle_compensation = true;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < surface.expolygon.holes.size(); ++i) {
|
||||
Polygon &hole = surface.expolygon.holes[i];
|
||||
if (hole.is_approx_circle(max_deviation, max_variance, center, diameter)) {
|
||||
double offset_value = hole_speed_coef * limited_speed + hole_diameter_coef * diameter + hole_compensate_coef;
|
||||
if (offset_value < hole_limit_min_value) {
|
||||
offset_value = hole_limit_min_value;
|
||||
} else if (offset_value > hole_limit_max_value) {
|
||||
offset_value = hole_limit_max_value;
|
||||
}
|
||||
// positive value means shrinking hole, which oppsite to contour
|
||||
offset_value = -offset_value;
|
||||
Polygons offseted_polys = offset(hole, offset_value);
|
||||
if (offseted_polys.size() == 1) {
|
||||
hole = offseted_polys[0];
|
||||
if (diameter < diameter_limit_value * 1e6)
|
||||
surface.holes_circle_compensation.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection *fill_surfaces, ExPolygons *fill_no_overlap, std::vector<LoopNode> &loop_nodes)
|
||||
{
|
||||
this->perimeters.clear();
|
||||
this->thin_fills.clear();
|
||||
|
||||
const PrintConfig &print_config = this->layer()->object()->print()->config();
|
||||
const PrintConfig & print_config = this->layer()->object()->print()->config();
|
||||
const PrintRegionConfig ®ion_config = this->region().config();
|
||||
const PrintObjectConfig& object_config = this->layer()->object()->config();
|
||||
// This needs to be in sync with PrintObject::_slice() slicing_mode_normal_below_layer!
|
||||
|
@ -87,7 +148,6 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
|||
&this->layer()->object()->config(),
|
||||
&print_config,
|
||||
spiral_mode,
|
||||
|
||||
// output:
|
||||
&this->perimeters,
|
||||
&this->thin_fills,
|
||||
|
@ -1049,4 +1109,3 @@ void LayerRegion::simplify_loop(ExtrusionLoop* loop)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -46,14 +46,16 @@ public:
|
|||
// BBS: is perimeter using smaller width
|
||||
bool is_smaller_width_perimeter;
|
||||
// Depth in the hierarchy. External perimeter has depth = 0. An external perimeter could be both a contour and a hole.
|
||||
unsigned short depth;
|
||||
unsigned short depth;
|
||||
// Should this contur be fuzzyfied on path generation?
|
||||
bool fuzzify;
|
||||
// Slow down speed for circle
|
||||
bool need_circle_compensation = false;
|
||||
// Children contour, may be both CCW and CW oriented (outer contours or holes).
|
||||
std::vector<PerimeterGeneratorLoop> children;
|
||||
|
||||
PerimeterGeneratorLoop(const Polygon &polygon, unsigned short depth, bool is_contour, bool fuzzify, bool is_small_width_perimeter = false) :
|
||||
polygon(polygon), is_contour(is_contour), is_smaller_width_perimeter(is_small_width_perimeter), depth(depth), fuzzify(fuzzify) {}
|
||||
PerimeterGeneratorLoop(const Polygon &polygon, unsigned short depth, bool is_contour, bool fuzzify, bool is_small_width_perimeter = false, bool need_circle_compensation_ = false) :
|
||||
polygon(polygon), is_contour(is_contour), is_smaller_width_perimeter(is_small_width_perimeter), depth(depth), fuzzify(fuzzify), need_circle_compensation(need_circle_compensation_) {}
|
||||
// External perimeter. It may be CCW or CW oriented (outer contour or hole contour).
|
||||
bool is_external() const { return this->depth == 0; }
|
||||
// An island, which may have holes, but it does not have another internal island.
|
||||
|
@ -452,6 +454,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
|||
for (const PerimeterGeneratorLoop &loop : loops) {
|
||||
bool is_external = loop.is_external();
|
||||
bool is_small_width = loop.is_smaller_width_perimeter;
|
||||
CustomizeFlag flag = loop.need_circle_compensation ? CustomizeFlag::cfCircleCompensation : CustomizeFlag::cfNone;
|
||||
|
||||
ExtrusionRole role;
|
||||
ExtrusionLoopRole loop_role;
|
||||
|
@ -631,7 +634,11 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
|||
paths.emplace_back(std::move(path));
|
||||
}
|
||||
|
||||
coll.append(ExtrusionLoop(std::move(paths), loop_role));
|
||||
for (ExtrusionPath& path : paths) {
|
||||
path.set_customize_flag(flag);
|
||||
}
|
||||
|
||||
coll.append(ExtrusionLoop(std::move(paths), loop_role, flag));
|
||||
}
|
||||
|
||||
// Append thin walls to the nearest-neighbor search (only for first iteration)
|
||||
|
@ -1185,7 +1192,26 @@ void PerimeterGenerator::process_classic()
|
|||
if (loop_number > 0 && ((this->object_config->top_one_wall_type != TopOneWallType::None && this->upper_slices == nullptr) || (this->object_config->only_one_wall_first_layer && layer_id == 0)))
|
||||
loop_number = 0;
|
||||
|
||||
bool counter_circle_compensation = surface.counter_circle_compensation;
|
||||
std::vector<Point> compensation_holes_centers;
|
||||
for (size_t i = 0; i < surface.holes_circle_compensation.size(); ++i) {
|
||||
Point center = surface.expolygon.holes[i].centroid();
|
||||
compensation_holes_centers.emplace_back(center);
|
||||
}
|
||||
|
||||
double eps = 1000;
|
||||
auto is_compensation_hole = [&compensation_holes_centers, &eps](const Polygon &hole) -> bool {
|
||||
auto iter = std::find_if(compensation_holes_centers.begin(), compensation_holes_centers.end(), [&hole, &eps](const Point &item) {
|
||||
double distance = std::sqrt(std::pow(hole.centroid().x() - item.x(), 2) + std::pow(hole.centroid().y() - item.y(), 2));
|
||||
return distance < eps;
|
||||
});
|
||||
|
||||
return iter != compensation_holes_centers.end();
|
||||
};
|
||||
|
||||
ExPolygons last = union_ex(surface.expolygon.simplify_p(surface_simplify_resolution));
|
||||
if (last.size() != 1)
|
||||
counter_circle_compensation = false;
|
||||
ExPolygons gaps;
|
||||
ExPolygons top_fills;
|
||||
ExPolygons fill_clip;
|
||||
|
@ -1304,12 +1330,11 @@ void PerimeterGenerator::process_classic()
|
|||
// 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(expolygon.contour, i, true, fuzzify_contours);
|
||||
|
||||
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, fuzzify_contours, false, counter_circle_compensation));
|
||||
if (!expolygon.holes.empty()) {
|
||||
holes[i].reserve(holes[i].size() + expolygon.holes.size());
|
||||
for (const Polygon& hole : expolygon.holes)
|
||||
holes[i].emplace_back(hole, i, false, fuzzify_holes);
|
||||
for (const Polygon &hole : expolygon.holes)
|
||||
holes[i].emplace_back(hole, i, false, fuzzify_holes, false, is_compensation_hole(hole));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1345,11 +1370,11 @@ void PerimeterGenerator::process_classic()
|
|||
}
|
||||
|
||||
for (const ExPolygon& expolygon : offsets_with_smaller_width) {
|
||||
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, fuzzify_contours, true));
|
||||
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, fuzzify_contours, true, counter_circle_compensation));
|
||||
if (!expolygon.holes.empty()) {
|
||||
holes[i].reserve(holes[i].size() + expolygon.holes.size());
|
||||
for (const Polygon& hole : expolygon.holes)
|
||||
holes[i].emplace_back(PerimeterGeneratorLoop(hole, i, false, fuzzify_contours, true));
|
||||
holes[i].emplace_back(PerimeterGeneratorLoop(hole, i, false, fuzzify_contours, true, is_compensation_hole(hole)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,39 @@ void Polygon::douglas_peucker(double tolerance)
|
|||
this->points = std::move(p);
|
||||
}
|
||||
|
||||
bool Polygon::is_approx_circle(double max_deviation, double max_variance, Point ¢er, double &diameter) const
|
||||
{
|
||||
if (this->points.size() < 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
center = centroid();
|
||||
std::vector<double> distances;
|
||||
for (const auto &point : this->points) {
|
||||
double distance = std::sqrt(std::pow(point.x() - center.x(), 2) + std::pow(point.y() - center.y(), 2));
|
||||
distances.push_back(distance);
|
||||
}
|
||||
|
||||
double max_dist = *std::max_element(distances.begin(), distances.end());
|
||||
double min_dist = *std::min_element(distances.begin(), distances.end());
|
||||
|
||||
if ((max_dist - min_dist) > max_deviation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double avg_dist = std::accumulate(distances.begin(), distances.end(), 0.0) / distances.size();
|
||||
double variance = 0;
|
||||
for (double d : distances) { variance += std::pow(d - avg_dist, 2); }
|
||||
variance /= distances.size();
|
||||
|
||||
if (variance > max_variance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
diameter = 2 * avg_dist;
|
||||
return true;
|
||||
}
|
||||
|
||||
Polygons Polygon::simplify(double tolerance) const
|
||||
{
|
||||
// Works on CCW polygons only, CW contour will be reoriented to CCW by Clipper's simplify_polygons()!
|
||||
|
|
|
@ -61,6 +61,10 @@ public:
|
|||
bool is_valid() const { return this->points.size() >= 3; }
|
||||
void douglas_peucker(double tolerance);
|
||||
|
||||
// Point ¢er : out, the center of circle
|
||||
// double &diameter: out, the diameter of circle
|
||||
bool is_approx_circle(double max_deviation, double max_variance, Point ¢er, double &diameter) const;
|
||||
|
||||
// Does an unoriented polygon contain a point?
|
||||
bool contains(const Point &point) const { return Slic3r::contains(*this, point, true); }
|
||||
// Approximate on boundary test.
|
||||
|
|
|
@ -880,6 +880,9 @@ static std::vector<std::string> s_Preset_print_options {
|
|||
"top_surface_line_width", "support_line_width", "infill_wall_overlap", "bridge_flow",
|
||||
"elefant_foot_compensation", "xy_contour_compensation", "xy_hole_compensation", "resolution", "enable_prime_tower",
|
||||
"prime_tower_width", "prime_tower_brim_width", "prime_tower_outer_first", "prime_volume",
|
||||
"enable_circle_compensation", "circle_compensation_speed", "max_deviation", "max_variance",
|
||||
"counter_coef_1", "counter_coef_2", "counter_coef_3", "hole_coef_1", "hole_coef_2", "hole_coef_3",
|
||||
"counter_limit_min", "counter_limit_max", "hole_limit_min", "hole_limit_max", "diameter_limit",
|
||||
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"flush_into_infill", "flush_into_objects", "flush_into_support","process_notes",
|
||||
// BBS
|
||||
|
|
|
@ -4164,8 +4164,100 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("enable_circle_compensation", coBool);
|
||||
def->label = L("Auto holes-contour compensation");
|
||||
def->tooltip = L("enable_circle_compensation");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("circle_compensation_speed", coFloat);
|
||||
def->label = L("Circle Compensation Speed");
|
||||
def->tooltip = L("circle_compensation_speed");
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionFloat(200));
|
||||
|
||||
def = this->add("max_deviation", coFloat);
|
||||
def->label = L("Deviation");
|
||||
def->tooltip = L("max_deviation");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionFloat(0.5));
|
||||
|
||||
def = this->add("max_variance", coFloat);
|
||||
def->label = L("Variance");
|
||||
def->tooltip = L("max_variance");
|
||||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionFloat(500));
|
||||
|
||||
def = this->add("counter_coef_1", coFloat);
|
||||
def->label = L("Counter Coef 1");
|
||||
def->tooltip = L("counter_coef_1");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("counter_coef_2", coFloat);
|
||||
def->label = L("Counter Coef 2");
|
||||
def->tooltip = L("counter_coef_2");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(25000));
|
||||
|
||||
def = this->add("counter_coef_3", coFloat);
|
||||
def->label = L("Counter Coef 3");
|
||||
def->tooltip = L("counter_coef_3");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(-110000));
|
||||
|
||||
def = this->add("hole_coef_1", coFloat);
|
||||
def->label = L("Hole Coef 1");
|
||||
def->tooltip = L("hole_coef_1");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("hole_coef_2", coFloat);
|
||||
def->label = L("Hole Coef 2");
|
||||
def->tooltip = L("hole_coef_2");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(-25000));
|
||||
|
||||
def = this->add("hole_coef_3", coFloat);
|
||||
def->label = L("Hole Coef 3");
|
||||
def->tooltip = L("hole_coef_3");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(280000));
|
||||
|
||||
def = this->add("counter_limit_min", coFloat);
|
||||
def->label = L("Counter limit min");
|
||||
def->tooltip = L("counter_limit_min");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(-40000));
|
||||
|
||||
def = this->add("counter_limit_max", coFloat);
|
||||
def->label = L("Counter limit max");
|
||||
def->tooltip = L("counter_limit_max");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(50000));
|
||||
|
||||
def = this->add("hole_limit_min", coFloat);
|
||||
def->label = L("Hole limit min");
|
||||
def->tooltip = L("hole_limit_min");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(80000));
|
||||
|
||||
def = this->add("hole_limit_max", coFloat);
|
||||
def->label = L("Hole limit max");
|
||||
def->tooltip = L("hole_limit_max");
|
||||
def->sidetext = L("/1e6");
|
||||
def->set_default_value(new ConfigOptionFloat(250000));
|
||||
|
||||
def = this->add("diameter_limit", coFloat);
|
||||
def->label = L("Diameter limit");
|
||||
def->tooltip = L("diameter_limit");
|
||||
def->sidetext = L("mm");
|
||||
def->set_default_value(new ConfigOptionFloat(50));
|
||||
|
||||
def = this->add("flush_volumes_vector", coFloats);
|
||||
// BBS: remove _L()
|
||||
// BBS: remove _L()w
|
||||
def->label = ("Purging volumes - load/unload volumes");
|
||||
//def->tooltip = L("This vector saves required volumes to change from/to each tool used on the "
|
||||
// "wipe tower. These values are used to simplify creation of the full purging "
|
||||
|
|
|
@ -822,6 +822,22 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||
((ConfigOptionFloat, support_object_first_layer_gap))
|
||||
((ConfigOptionFloat, xy_hole_compensation))
|
||||
((ConfigOptionFloat, xy_contour_compensation))
|
||||
//BBS auto hole contour compensation
|
||||
((ConfigOptionBool, enable_circle_compensation))
|
||||
((ConfigOptionFloat, circle_compensation_speed))
|
||||
((ConfigOptionFloat, max_deviation))
|
||||
((ConfigOptionFloat, max_variance))
|
||||
((ConfigOptionFloat, counter_coef_1))
|
||||
((ConfigOptionFloat, counter_coef_2))
|
||||
((ConfigOptionFloat, counter_coef_3))
|
||||
((ConfigOptionFloat, hole_coef_1))
|
||||
((ConfigOptionFloat, hole_coef_2))
|
||||
((ConfigOptionFloat, hole_coef_3))
|
||||
((ConfigOptionFloat, counter_limit_min))
|
||||
((ConfigOptionFloat, counter_limit_max))
|
||||
((ConfigOptionFloat, hole_limit_min))
|
||||
((ConfigOptionFloat, hole_limit_max))
|
||||
((ConfigOptionFloat, diameter_limit))
|
||||
((ConfigOptionBool, flush_into_objects))
|
||||
// BBS
|
||||
((ConfigOptionBool, flush_into_infill))
|
||||
|
|
|
@ -798,7 +798,22 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||
|| opt_key == "only_one_wall_first_layer"
|
||||
|| opt_key == "initial_layer_line_width"
|
||||
|| opt_key == "inner_wall_line_width"
|
||||
|| opt_key == "infill_wall_overlap") {
|
||||
|| opt_key == "infill_wall_overlap"
|
||||
|| opt_key == "enable_circle_compensation"
|
||||
|| opt_key == "circle_compensation_speed"
|
||||
|| opt_key == "max_deviation"
|
||||
|| opt_key == "max_variance"
|
||||
|| opt_key == "counter_coef_1"
|
||||
|| opt_key == "counter_coef_2"
|
||||
|| opt_key == "counter_coef_3"
|
||||
|| opt_key == "hole_coef_1"
|
||||
|| opt_key == "hole_coef_2"
|
||||
|| opt_key == "hole_coef_3"
|
||||
|| opt_key == "counter_limit_min"
|
||||
|| opt_key == "counter_limit_max"
|
||||
|| opt_key == "hole_limit_min"
|
||||
|| opt_key == "hole_limit_max"
|
||||
|| opt_key == "diameter_limit") {
|
||||
steps.emplace_back(posPerimeters);
|
||||
} else if (opt_key == "gap_infill_speed" || opt_key == "filter_out_gap_fill") {
|
||||
// Return true if gap-fill speed has changed from zero value to non-zero or from non-zero value to zero.
|
||||
|
|
|
@ -37,6 +37,8 @@ public:
|
|||
unsigned short thickness_layers; // in layers
|
||||
double bridge_angle; // in radians, ccw, 0 = East, only 0+ (negative means undefined)
|
||||
unsigned short extra_perimeters;
|
||||
bool counter_circle_compensation{false};
|
||||
std::vector<int> holes_circle_compensation; // hole index
|
||||
|
||||
Surface(SurfaceType _surface_type = stInternal)
|
||||
: surface_type(_surface_type),
|
||||
|
|
|
@ -266,6 +266,16 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||
is_msg_dlg_already_exist = false;
|
||||
}
|
||||
|
||||
//if enable auto hole and contour compensation, disable the manner
|
||||
if (config->opt_bool("enable_circle_compensation")) {
|
||||
DynamicPrintConfig new_conf = *config;
|
||||
is_msg_dlg_already_exist = true;
|
||||
new_conf.set_key_value("xy_contour_compensation", new ConfigOptionFloat(0));
|
||||
new_conf.set_key_value("xy_hole_compensation", new ConfigOptionFloat(0));
|
||||
apply(config, &new_conf);
|
||||
is_msg_dlg_already_exist = false;
|
||||
}
|
||||
|
||||
if (config->option<ConfigOptionFloat>("elefant_foot_compensation")->value > 1)
|
||||
{
|
||||
const wxString msg_text = _(L("Too large elephant foot compensation is unreasonable.\n"
|
||||
|
@ -715,6 +725,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
|
|||
toggle_line("interlocking_beam_layer_count", use_beam_interlocking);
|
||||
toggle_line("interlocking_depth", use_beam_interlocking);
|
||||
toggle_line("interlocking_boundary_avoidance", use_beam_interlocking);
|
||||
|
||||
bool enable_auto_hole_and_contour_compensation = config->opt_bool("enable_circle_compensation");
|
||||
for (auto el : {"max_deviation", "max_variance", "circle_compensation_speed", "counter_coef_1", "counter_coef_2", "counter_coef_3", "hole_coef_1", "hole_coef_2", "hole_coef_3", "counter_limit_min", "counter_limit_max", "hole_limit_min", "hole_limit_max", "diameter_limit"})
|
||||
toggle_line(el, enable_auto_hole_and_contour_compensation);
|
||||
toggle_field("xy_hole_compensation", !enable_auto_hole_and_contour_compensation);
|
||||
toggle_field("xy_contour_compensation", !enable_auto_hole_and_contour_compensation);
|
||||
}
|
||||
|
||||
void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)
|
||||
|
|
|
@ -2006,6 +2006,21 @@ void TabPrint::build()
|
|||
optgroup->append_single_option_line("xy_hole_compensation", "xy-hole-contour-compensation");
|
||||
optgroup->append_single_option_line("xy_contour_compensation", "xy-hole-contour-compensation");
|
||||
optgroup->append_single_option_line("elefant_foot_compensation", "parameter/elephant-foot");
|
||||
optgroup->append_single_option_line("enable_circle_compensation");
|
||||
optgroup->append_single_option_line("circle_compensation_speed");
|
||||
optgroup->append_single_option_line("max_deviation");
|
||||
optgroup->append_single_option_line("max_variance");
|
||||
optgroup->append_single_option_line("counter_coef_1");
|
||||
optgroup->append_single_option_line("counter_coef_2");
|
||||
optgroup->append_single_option_line("counter_coef_3");
|
||||
optgroup->append_single_option_line("hole_coef_1");
|
||||
optgroup->append_single_option_line("hole_coef_2");
|
||||
optgroup->append_single_option_line("hole_coef_3");
|
||||
optgroup->append_single_option_line("counter_limit_min");
|
||||
optgroup->append_single_option_line("counter_limit_max");
|
||||
optgroup->append_single_option_line("hole_limit_min");
|
||||
optgroup->append_single_option_line("hole_limit_max");
|
||||
optgroup->append_single_option_line("diameter_limit");
|
||||
optgroup->append_single_option_line("precise_z_height");
|
||||
|
||||
optgroup = page->new_optgroup(L("Ironing"), L"param_ironing");
|
||||
|
|
Loading…
Reference in New Issue