Skip to content

Commit

Permalink
fix avoid crossing peri, fix gapfill, and some others
Browse files Browse the repository at this point in the history
  • Loading branch information
supermerill committed Dec 22, 2021
2 parents ab4d1ca + 9198f9e commit e56be3c
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 75 deletions.
2 changes: 1 addition & 1 deletion resources/profiles
Submodule profiles updated 2 files
+1 −0 Anycubic.idx
+23 −2 Anycubic.ini
1 change: 1 addition & 0 deletions resources/ui_layout/extruder.ui
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ group:Retraction wipe
setting:idx:wipe
setting:idx:wipe_speed
setting:idx:retract_before_wipe
setting:idx:wipe_only_crossing
setting:idx:wipe_extra_perimeter
setting:idx:seam_gap
group:Retraction when tool is disabled (advanced settings for multi-extruder setups)
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ class ConfigOption {
enum FlagsConfigOption : uint32_t {
FCO_PHONY = 1,
FCO_EXTRUDER_ARRAY = 1 << 1,
FCO_PLACEHOLDER_TEMP = 1 << 2,
};

ConfigOption() : flags(uint32_t(0)) {}
Expand Down
117 changes: 99 additions & 18 deletions src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3339,12 +3339,16 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
Point current_point = paths.front().first_point();
Point next_point = paths.front().polyline.points[1]; // second point

gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n";
//extra wipe before the little move.
if (EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter, 0) > 0) {
coordf_t wipe_dist = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter,0));
ExtrusionPaths paths_wipe;
m_wipe.reset_path();
for (int i = 0; i < paths.size(); i++) {
ExtrusionPath& path = paths[i];
if (wipe_dist > 0) {
//first, we use the polyline for wipe_extra_perimeter
if (path.length() < wipe_dist) {
wipe_dist -= path.length();
paths_wipe.push_back(path);
Expand All @@ -3363,15 +3367,22 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
} else {
next_point = paths[0].first_point();
}
break;
m_wipe.path.append(path.polyline);
m_wipe.path.clip_start(wipe_dist);
wipe_dist -= path.length();
}
} else {
//then, it's stored for the wipe on retract
m_wipe.path.append(path.polyline);
}
}
//move
for (ExtrusionPath& path : paths_wipe) {
for (Point& pt : path.polyline.points) {
prev_point = current_point;
current_point = pt;
gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, config().gcode_comments ? "; extra wipe" : "");
this->set_last_pos(pt);
}
}
}
Expand Down Expand Up @@ -3399,14 +3410,73 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
Vec2d current_pos = current_point.cast<double>();
Vec2d next_pos = next_point.cast<double>();
Vec2d vec_dist = next_pos - current_pos;
double nd = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0));
const coordf_t nd = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0));
double l2 = vec_dist.squaredNorm();
// Shift by no more than a nozzle diameter.
//FIXME Hiding the seams will not work nicely for very densely discretized contours!
Point pt = ((nd * nd >= l2) ? next_pos : (current_pos + vec_dist * (nd / sqrt(l2)))).cast<coord_t>();
pt.rotate(angle, current_point);
// generate the travel move
gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, "move inwards before travel");
this->set_last_pos(pt);
gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";

// also shift the wipe on retract
if (m_wipe.enable) {
current_pos = pt.cast<double>();
//go to the inside (use clipper for easy shift)
Polygon original_polygon = original_loop.polygon();
Polygons polys = offset(original_polygon, (original_polygon.is_clockwise()?1:-1) * nd / 2);
//find nearest point
size_t best_poly_idx = 0;
size_t best_pt_idx = 0;
coordf_t best_sqr_dist = nd*nd*2;
for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) {
Polygon& poly = polys[poly_idx];
if (poly.is_clockwise() ^ original_polygon.is_clockwise())
poly.reverse();
for (size_t pt_idx = 0; pt_idx < poly.points.size(); pt_idx++) {
if (poly.points[pt_idx].distance_to_square(pt) < best_sqr_dist) {
best_sqr_dist = poly.points[pt_idx].distance_to_square(pt);
best_poly_idx = poly_idx;
best_pt_idx = pt_idx;
}
}
}
if (best_sqr_dist == nd * nd * 2) {
//try to find an edge
for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) {
Polygon& poly = polys[poly_idx];
if (poly.is_clockwise() ^ original_polygon.is_clockwise())
poly.reverse();
poly.points.push_back(poly.points.front());
for (size_t pt_idx = 0; pt_idx < poly.points.size()-1; pt_idx++) {
if (Line{ poly.points[pt_idx], poly.points[pt_idx + 1] }.distance_to_squared(pt) < best_sqr_dist) {
poly.points.insert(poly.points.begin() + pt_idx + 1, pt);
best_sqr_dist = 0;
best_poly_idx = poly_idx;
best_pt_idx = pt_idx + 1;
poly.points.erase(poly.points.end() - 1);
break;
}
}
}
}
if (best_sqr_dist == nd * nd * 2) {
//can't find a path, use the old one
//BOOST_LOG_TRIVIAL(warning) << "Warn: can't find a proper path for wipe on retract. Layer " << m_layer_index << ", pos " << this->point_to_gcode(pt).x() << " : " << this->point_to_gcode(pt).y() << " !";
} else {
m_wipe.reset_path();
//get the points from here
Polygon& poly = polys[best_poly_idx];
for (size_t pt_idx = best_pt_idx; pt_idx < poly.points.size(); pt_idx++) {
m_wipe.path.append(poly.points[pt_idx]);
}
for (size_t pt_idx = 0; pt_idx < best_pt_idx; pt_idx++) {
m_wipe.path.append(poly.points[pt_idx]);
}
}
}
}

return gcode;
Expand Down Expand Up @@ -4179,40 +4249,49 @@ Polyline GCode::travel_to(std::string &gcode, const Point &point, ExtrusionRole
this->origin in order to get G-code coordinates. */
Polyline travel { this->last_pos(), point };

// check / compute avoid_crossing_perimeters
bool will_cross_perimeter = this->can_cross_perimeter(travel);
// check whether wipe could be disabled without causing visible stringing
bool could_be_wipe_disabled = false;

//can use the avoid crossing algo?
bool can_avoid_cross_peri = m_config.avoid_crossing_perimeters
&& !m_avoid_crossing_perimeters.disabled_once()
&& m_avoid_crossing_perimeters.is_init()
&& !(m_config.avoid_crossing_not_first_layer && this->on_first_layer());

// check / compute avoid_crossing_perimeters
bool will_cross_perimeter = this->can_cross_perimeter(travel, can_avoid_cross_peri);

// if a retraction would be needed (with a low min_dist threshold), try to use avoid_crossing_perimeters to plan a
// multi-hop travel path inside the configuration space
if (will_cross_perimeter && this->needs_retraction(travel, role, scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)) * 3)
&& m_config.avoid_crossing_perimeters
&& ! m_avoid_crossing_perimeters.disabled_once()
&& m_avoid_crossing_perimeters.is_init()
&& !(m_config.avoid_crossing_not_first_layer && this->on_first_layer())) {
&& can_avoid_cross_peri) {
travel = m_avoid_crossing_perimeters.travel_to(*this, point, &could_be_wipe_disabled);
}
if(can_avoid_cross_peri)
will_cross_perimeter = this->can_cross_perimeter(travel, false);

// check whether a straight travel move would need retraction
bool needs_retraction = this->needs_retraction(travel, role);
if (m_config.only_retract_when_crossing_perimeters)
needs_retraction = needs_retraction && will_cross_perimeter;

// Re-allow avoid_crossing_perimeters for the next travel moves
m_avoid_crossing_perimeters.reset_once_modifiers();

// generate G-code for the travel move
if (needs_retraction) {
if (m_config.avoid_crossing_perimeters && could_be_wipe_disabled)
if (m_config.avoid_crossing_perimeters && could_be_wipe_disabled && EXTRUDER_CONFIG_WITH_DEFAULT(wipe_only_crossing, true))
m_wipe.reset_path();

Point last_post_before_retract = this->last_pos();
gcode += this->retract();
// When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters.
// Because of it, it is necessary to call avoid crossing perimeters for the path between previous last_post and last_post after calling retraction()
if (last_post_before_retract != this->last_pos() && m_config.avoid_crossing_perimeters) {
Polyline retract_travel = m_avoid_crossing_perimeters.travel_to(*this, last_post_before_retract);
append(retract_travel.points, travel.points);
travel = std::move(retract_travel);
if (last_post_before_retract != this->last_pos() && can_avoid_cross_peri) {
// Is the distance is short enough to just shortcut it?
if (last_post_before_retract.distance_to(this->last_pos()) > scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)) * 2) {
// Because of it, it is necessary to redo the thing
travel = m_avoid_crossing_perimeters.travel_to(*this, point);
}
}
} else {
// Reset the wipe path when traveling, so one would not wipe along an old path.
Expand Down Expand Up @@ -4320,7 +4399,7 @@ bool GCode::needs_retraction(const Polyline& travel, ExtrusionRole role /*=erNon
return true;
}

bool GCode::can_cross_perimeter(const Polyline& travel)
bool GCode::can_cross_perimeter(const Polyline& travel, bool offset)
{
if(m_layer != nullptr)
if ( (m_config.only_retract_when_crossing_perimeters && m_config.fill_density.value > 0) || m_config.avoid_crossing_perimeters)
Expand All @@ -4339,13 +4418,13 @@ bool GCode::can_cross_perimeter(const Polyline& travel)
//if (inside) {
//contained inside at least one bb
//construct m_layer_slices_offseted if needed
if (m_layer_slices_offseted.layer != m_layer) {
if (m_layer_slices_offseted.layer != m_layer && offset) {
m_layer_slices_offseted.layer = m_layer;
m_layer_slices_offseted.diameter = scale_t(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4));
m_layer_slices_offseted.slices = offset_ex(m_layer->lslices, - m_layer_slices_offseted.diameter * 1.5);
m_layer_slices_offseted.slices = offset_ex(m_layer->lslices, -m_layer_slices_offseted.diameter * 1.5f);
}
// test if a expoly contains the entire travel
for (const ExPolygon &poly : m_layer_slices_offseted.slices)
for (const ExPolygon &poly : offset ? m_layer_slices_offseted.slices : m_layer->lslices)
if (poly.contains(travel)) {
return false;
}
Expand Down Expand Up @@ -4378,6 +4457,8 @@ std::string GCode::retract(bool toolchange)
methods even if we performed wipe, since this will ensure the entire retraction
length is honored in case wipe path was too short. */
gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract();

//check if need to lift
bool need_lift = !m_writer.tool_is_extruder() || toolchange
|| (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && m_config.print_retract_lift.value != 0 && this->m_layer_index == 0)
|| this->m_writer.get_extra_lift() > 0;
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/GCode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ class GCode : ExtrusionVisitorConst {

Polyline travel_to(std::string& gcode, const Point &point, ExtrusionRole role);
void write_travel_to(std::string& gcode, const Polyline& travel, std::string comment);
bool can_cross_perimeter(const Polyline& travel);
bool can_cross_perimeter(const Polyline& travel, bool offset);
bool needs_retraction(const Polyline& travel, ExtrusionRole role = erNone, coordf_t max_min_dist = 0);
std::string retract(bool toolchange = false);
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
Expand Down
32 changes: 29 additions & 3 deletions src/libslic3r/MedialAxis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,8 +1330,12 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
&& polyline.width.back() > best_candidate->width[1]) {
polyline.width.back() = std::min(polyline.width[polyline.width.size() - 2], best_candidate->width[1]);
}
polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + 1, best_candidate->points.end());
polyline.width.insert(polyline.width.end(), best_candidate->width.begin() + 1, best_candidate->width.end());
//be far enough
int far_idx = 1;
while (far_idx < best_candidate->points.size() && polyline.last_point().coincides_with_epsilon(best_candidate->points[far_idx]))
far_idx++;
polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + far_idx, best_candidate->points.end());
polyline.width.insert(polyline.width.end(), best_candidate->width.begin() + far_idx, best_candidate->width.end());
polyline.endpoints.second = best_candidate->endpoints.second;
assert(polyline.width.size() == polyline.points.size());
if (best_idx < i) i--;
Expand Down Expand Up @@ -1799,6 +1803,24 @@ MedialAxis::build(ThickPolylines &polylines_out)
// pp.erase(pp.begin() + tp_idx);
// --tp_idx;
//}
//voronoi problem: can put two consecutive points at the same position. Delete one.
for (size_t i = 1; i < tp.points.size()-1; i++) {
if (tp.points[i-1].distance_to_square(tp.points[i]) < SCALED_EPSILON) {
tp.points.erase(tp.points.begin() + i);
tp.width.erase(tp.width.begin() + i);
i--;
}
}
//delete the inner one
if (tp.points.size()>2 && tp.points[tp.points.size() - 2].distance_to_square(tp.points.back()) < SCALED_EPSILON) {
tp.points.erase(tp.points.end() - 2);
tp.width.erase(tp.width.end() - 2);
}
//delete null-length polylines
if (tp.length() < SCALED_EPSILON && tp.first_point().coincides_with_epsilon(tp.last_point())) {
pp.erase(pp.begin() + tp_idx);
--tp_idx;
}
}
//std::cout << "polyline_from_voronoi\n";
//{
Expand Down Expand Up @@ -2078,8 +2100,11 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
continue;
}
} else if (i > 0 && resolution_internal > line_len + prev_line_len) {
ThickLine& prev_line = lines[i - 1];
//merge lines?
//if it's a loop, merge only if the distance is high enough
if (p.first_point() == p.last_point() && p.length() < (line_len + prev_line_len) * 6)
continue;
ThickLine& prev_line = lines[i - 1];
coordf_t width = prev_line_len * (prev_line.a_width + prev_line.b_width) / 2;
width += line_len * (line.a_width + line.b_width) / 2;
prev_line.b = line.b;
Expand Down Expand Up @@ -2149,6 +2174,7 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
path.height = flow.height;
}
}
assert(path.polyline.points.size() > 2 || path.first_point() != path.last_point());
}
if (path.polyline.is_valid())
paths.emplace_back(std::move(path));
Expand Down
Loading

0 comments on commit e56be3c

Please sign in to comment.