Merge branch 'vb_dev250_cooling' into dev_250

This commit is contained in:
Lukas Matena 2022-06-28 10:33:33 +02:00
commit 2c9658cc88
9 changed files with 128 additions and 58 deletions

View File

@ -153,11 +153,10 @@ double ExtrusionLoop::length() const
return len; return len;
} }
bool ExtrusionLoop::split_at_vertex(const Point &point) bool ExtrusionLoop::split_at_vertex(const Point &point, const double scaled_epsilon)
{ {
for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path) { for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path)
int idx = path->polyline.find_point(point); if (int idx = path->polyline.find_point(point, scaled_epsilon); idx != -1) {
if (idx != -1) {
if (this->paths.size() == 1) { if (this->paths.size() == 1) {
// just change the order of points // just change the order of points
path->polyline.points.insert(path->polyline.points.end(), path->polyline.points.begin() + 1, path->polyline.points.begin() + idx + 1); path->polyline.points.insert(path->polyline.points.end(), path->polyline.points.begin() + 1, path->polyline.points.begin() + idx + 1);
@ -169,70 +168,85 @@ bool ExtrusionLoop::split_at_vertex(const Point &point)
{ {
ExtrusionPath p = *path; ExtrusionPath p = *path;
p.polyline.points.erase(p.polyline.points.begin(), p.polyline.points.begin() + idx); p.polyline.points.erase(p.polyline.points.begin(), p.polyline.points.begin() + idx);
if (p.polyline.is_valid()) new_paths.push_back(p); if (p.polyline.is_valid())
new_paths.emplace_back(std::move(p));
} }
// then we add all paths until the end of current path list // then we add all paths until the end of current path list
new_paths.insert(new_paths.end(), path+1, this->paths.end()); // not including this path std::move(path + 1, this->paths.end(), std::back_inserter(new_paths)); // not including this path
// then we add all paths since the beginning of current list up to the previous one // then we add all paths since the beginning of current list up to the previous one
new_paths.insert(new_paths.end(), this->paths.begin(), path); // not including this path std::move(this->paths.begin(), path, std::back_inserter(new_paths)); // not including this path
// finally we add the first half of current path // finally we add the first half of current path
{ {
ExtrusionPath p = *path; ExtrusionPath &p = *path;
p.polyline.points.erase(p.polyline.points.begin() + idx + 1, p.polyline.points.end()); p.polyline.points.erase(p.polyline.points.begin() + idx + 1, p.polyline.points.end());
if (p.polyline.is_valid()) new_paths.push_back(p); if (p.polyline.is_valid())
new_paths.emplace_back(std::move(p));
} }
// we can now override the old path list with the new one and stop looping // we can now override the old path list with the new one and stop looping
std::swap(this->paths, new_paths); this->paths = std::move(new_paths);
} }
return true; return true;
} }
} // The point was not found.
return false; return false;
} }
std::pair<size_t, Point> ExtrusionLoop::get_closest_path_and_point(const Point& point, bool prefer_non_overhang) const ExtrusionLoop::ClosestPathPoint ExtrusionLoop::get_closest_path_and_point(const Point &point, bool prefer_non_overhang) const
{ {
// Find the closest path and closest point belonging to that path. Avoid overhangs, if asked for. // Find the closest path and closest point belonging to that path. Avoid overhangs, if asked for.
size_t path_idx = 0; ClosestPathPoint out { 0, 0 };
Point p; double min2 = std::numeric_limits<double>::max();
{ ClosestPathPoint best_non_overhang { 0, 0 };
double min = std::numeric_limits<double>::max(); double min2_non_overhang = std::numeric_limits<double>::max();
Point p_non_overhang;
size_t path_idx_non_overhang = 0;
double min_non_overhang = std::numeric_limits<double>::max();
for (const ExtrusionPath &path : this->paths) { for (const ExtrusionPath &path : this->paths) {
Point p_tmp = point.projection_onto(path.polyline); std::pair<int, Point> foot_pt_ = foot_pt(path.polyline.points, point);
double dist = (p_tmp - point).cast<double>().norm(); double d2 = (foot_pt_.second - point).cast<double>().squaredNorm();
if (dist < min) { if (d2 < min2) {
p = p_tmp; out.foot_pt = foot_pt_.second;
min = dist; out.path_idx = &path - &this->paths.front();
path_idx = &path - &this->paths.front(); out.segment_idx = foot_pt_.first;
min2 = d2;
} }
if (prefer_non_overhang && !is_bridge(path.role()) && dist < min_non_overhang) { if (prefer_non_overhang && !is_bridge(path.role()) && d2 < min2_non_overhang) {
p_non_overhang = p_tmp; best_non_overhang.foot_pt = foot_pt_.second;
min_non_overhang = dist; best_non_overhang.path_idx = &path - &this->paths.front();
path_idx_non_overhang = &path - &this->paths.front(); best_non_overhang.segment_idx = foot_pt_.first;
min2_non_overhang = d2;
} }
} }
if (prefer_non_overhang && min_non_overhang != std::numeric_limits<double>::max()) { if (prefer_non_overhang && min2_non_overhang != std::numeric_limits<double>::max())
// Only apply the non-overhang point if there is one. // Only apply the non-overhang point if there is one.
path_idx = path_idx_non_overhang; out = best_non_overhang;
p = p_non_overhang; return out;
}
}
return std::make_pair(path_idx, p);
} }
// Splitting an extrusion loop, possibly made of multiple segments, some of the segments may be bridging. // Splitting an extrusion loop, possibly made of multiple segments, some of the segments may be bridging.
void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang) void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang, const double scaled_epsilon)
{ {
if (this->paths.empty()) if (this->paths.empty())
return; return;
auto [path_idx, p] = get_closest_path_and_point(point, prefer_non_overhang); auto [path_idx, segment_idx, p] = get_closest_path_and_point(point, prefer_non_overhang);
// Snap p to start or end of segment_idx if closer than scaled_epsilon.
{
const Point *p1 = this->paths[path_idx].polyline.points.data() + segment_idx;
const Point *p2 = p1;
++ p2;
double d2_1 = (point - *p1).cast<double>().squaredNorm();
double d2_2 = (point - *p2).cast<double>().squaredNorm();
const double thr2 = scaled_epsilon * scaled_epsilon;
if (d2_1 < d2_2) {
if (d2_1 < thr2)
p = *p1;
} else {
if (d2_2 < thr2)
p = *p2;
}
}
// now split path_idx in two parts // now split path_idx in two parts
const ExtrusionPath &path = this->paths[path_idx]; const ExtrusionPath &path = this->paths[path_idx];
@ -241,14 +255,12 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang)
path.polyline.split_at(p, &p1.polyline, &p2.polyline); path.polyline.split_at(p, &p1.polyline, &p2.polyline);
if (this->paths.size() == 1) { if (this->paths.size() == 1) {
if (! p1.polyline.is_valid()) if (p2.polyline.is_valid()) {
std::swap(this->paths.front().polyline.points, p2.polyline.points); if (p1.polyline.is_valid())
else if (! p2.polyline.is_valid())
std::swap(this->paths.front().polyline.points, p1.polyline.points);
else {
p2.polyline.points.insert(p2.polyline.points.end(), p1.polyline.points.begin() + 1, p1.polyline.points.end()); p2.polyline.points.insert(p2.polyline.points.end(), p1.polyline.points.begin() + 1, p1.polyline.points.end());
std::swap(this->paths.front().polyline.points, p2.polyline.points); this->paths.front().polyline.points = std::move(p2.polyline.points);
} } else
this->paths.front().polyline.points = std::move(p1.polyline.points);
} else { } else {
// install the two paths // install the two paths
this->paths.erase(this->paths.begin() + path_idx); this->paths.erase(this->paths.begin() + path_idx);
@ -257,7 +269,7 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang)
} }
// split at the new vertex // split at the new vertex
this->split_at_vertex(p); this->split_at_vertex(p, 0.);
} }
void ExtrusionLoop::clip_end(double distance, ExtrusionPaths* paths) const void ExtrusionLoop::clip_end(double distance, ExtrusionPaths* paths) const

View File

@ -256,9 +256,14 @@ public:
const Point& last_point() const override { assert(this->first_point() == this->paths.back().polyline.points.back()); return this->first_point(); } const Point& last_point() const override { assert(this->first_point() == this->paths.back().polyline.points.back()); return this->first_point(); }
Polygon polygon() const; Polygon polygon() const;
double length() const override; double length() const override;
bool split_at_vertex(const Point &point); bool split_at_vertex(const Point &point, const double scaled_epsilon = scaled<double>(0.001));
void split_at(const Point &point, bool prefer_non_overhang); void split_at(const Point &point, bool prefer_non_overhang, const double scaled_epsilon = scaled<double>(0.001));
std::pair<size_t, Point> get_closest_path_and_point(const Point& point, bool prefer_non_overhang) const; struct ClosestPathPoint {
size_t path_idx;
size_t segment_idx;
Point foot_pt;
};
ClosestPathPoint get_closest_path_and_point(const Point& point, bool prefer_non_overhang) const;
void clip_end(double distance, ExtrusionPaths* paths) const; void clip_end(double distance, ExtrusionPaths* paths) const;
// Test, whether the point is extruded by a bridging flow. // 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. // This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead.

View File

@ -2638,7 +2638,9 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
assert(m_layer != nullptr); assert(m_layer != nullptr);
m_seam_placer.place_seam(m_layer, loop, m_config.external_perimeters_first, this->last_pos()); m_seam_placer.place_seam(m_layer, loop, m_config.external_perimeters_first, this->last_pos());
} else } else
loop.split_at(last_pos, false); // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns,
// thus empty path segments will not be produced by G-code export.
loop.split_at(last_pos, false, scaled<double>(0.0015));
// clip the path to avoid the extruder to get exactly on the first point of the loop; // clip the path to avoid the extruder to get exactly on the first point of the loop;
// if polyline was shorter than the clipping distance we'd get a null polyline, so // if polyline was shorter than the clipping distance we'd get a null polyline, so

View File

@ -1573,16 +1573,18 @@ void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool extern
+ (perimeter_point.position - layer_perimeters.points[index_of_next].position).head<2>().normalized()) + (perimeter_point.position - layer_perimeters.points[index_of_next].position).head<2>().normalized())
* 0.5; * 0.5;
auto [_, projected_point] = loop.get_closest_path_and_point(seam_point, true); ExtrusionLoop::ClosestPathPoint projected_point = loop.get_closest_path_and_point(seam_point, true);
//get closest projected point, determine depth of the seam point. //get closest projected point, determine depth of the seam point.
float depth = (float) unscale(Point(seam_point - projected_point)).norm(); float depth = (float) unscale(Point(seam_point - projected_point.foot_pt)).norm();
float angle_factor = cos(-perimeter_point.local_ccw_angle / 2.0f); // There are some nice geometric identities in determination of the correct depth of new seam point. float angle_factor = cos(-perimeter_point.local_ccw_angle / 2.0f); // There are some nice geometric identities in determination of the correct depth of new seam point.
//overshoot the target depth, in concave angles it will correctly snap to the corner; TODO: find out why such big overshoot is needed. //overshoot the target depth, in concave angles it will correctly snap to the corner; TODO: find out why such big overshoot is needed.
Vec2f final_pos = perimeter_point.position.head<2>() + (1.4142 * depth / angle_factor) * dir_to_middle; Vec2f final_pos = perimeter_point.position.head<2>() + (1.4142 * depth / angle_factor) * dir_to_middle;
seam_point = Point::new_scale(final_pos.x(), final_pos.y()); seam_point = Point::new_scale(final_pos.x(), final_pos.y());
} }
if (!loop.split_at_vertex(seam_point)) { // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns,
// thus empty path segments will not be produced by G-code export.
if (!loop.split_at_vertex(seam_point, scaled<double>(0.0015))) {
// The point is not in the original loop. // The point is not in the original loop.
// Insert it. // Insert it.
loop.split_at(seam_point, true); loop.split_at(seam_point, true);

View File

@ -63,6 +63,24 @@ int MultiPoint::find_point(const Point &point) const
return -1; // not found return -1; // not found
} }
int MultiPoint::find_point(const Point &point, double scaled_epsilon) const
{
if (scaled_epsilon == 0)
return this->find_point(point);
auto dist2_min = std::numeric_limits<double>::max();
auto eps2 = scaled_epsilon * scaled_epsilon;
int idx_min = -1;
for (const Point &pt : this->points) {
double d2 = (pt - point).cast<double>().squaredNorm();
if (d2 < dist2_min) {
idx_min = int(&pt - &this->points.front());
dist2_min = d2;
}
}
return dist2_min < eps2 ? idx_min : -1;
}
bool MultiPoint::has_boundary_point(const Point &point) const bool MultiPoint::has_boundary_point(const Point &point) const
{ {
double dist = (point.projection_onto(*this) - point).cast<double>().norm(); double dist = (point.projection_onto(*this) - point).cast<double>().norm();

View File

@ -43,7 +43,12 @@ public:
double length() const; double length() const;
bool is_valid() const { return this->points.size() >= 2; } bool is_valid() const { return this->points.size() >= 2; }
// Return index of a polygon point exactly equal to point.
// Return -1 if no such point exists.
int find_point(const Point &point) const; int find_point(const Point &point) const;
// Return index of the closest point to point closer than scaled_epsilon.
// Return -1 if no such point exists.
int find_point(const Point &point, const double scaled_epsilon) const;
bool has_boundary_point(const Point &point) const; bool has_boundary_point(const Point &point) const;
int closest_point_index(const Point &point) const { int closest_point_index(const Point &point) const {
int idx = -1; int idx = -1;

View File

@ -225,6 +225,29 @@ bool remove_degenerate(Polylines &polylines)
return modified; return modified;
} }
std::pair<int, Point> foot_pt(const Points &polyline, const Point &pt)
{
if (polyline.size() < 2)
return std::make_pair(-1, Point(0, 0));
auto d2_min = std::numeric_limits<double>::max();
Point foot_pt_min;
Point prev = polyline.front();
auto it = polyline.begin();
auto it_proj = polyline.begin();
for (++ it; it != polyline.end(); ++ it) {
Point foot_pt = pt.projection_onto(Line(prev, *it));
double d2 = (foot_pt - pt).cast<double>().squaredNorm();
if (d2 < d2_min) {
d2_min = d2;
foot_pt_min = foot_pt;
it_proj = it;
}
prev = *it;
}
return std::make_pair(int(it_proj - polyline.begin()) - 1, foot_pt_min);
}
ThickLines ThickPolyline::thicklines() const ThickLines ThickPolyline::thicklines() const
{ {
ThickLines lines; ThickLines lines;

View File

@ -162,6 +162,9 @@ const Point& leftmost_point(const Polylines &polylines);
bool remove_degenerate(Polylines &polylines); bool remove_degenerate(Polylines &polylines);
// Returns index of a segment of a polyline and foot point of pt on polyline.
std::pair<int, Point> foot_pt(const Points &polyline, const Point &pt);
class ThickPolyline : public Polyline { class ThickPolyline : public Polyline {
public: public:
ThickPolyline() : endpoints(std::make_pair(false, false)) {} ThickPolyline() : endpoints(std::make_pair(false, false)) {}

View File

@ -21,8 +21,8 @@
double length(); double length();
bool split_at_vertex(Point* point) bool split_at_vertex(Point* point)
%code{% RETVAL = THIS->split_at_vertex(*point); %}; %code{% RETVAL = THIS->split_at_vertex(*point); %};
void split_at(Point* point, int prefer_non_overhang = 0) void split_at(Point* point, int prefer_non_overhang = 0, double scaled_epsilon = 0.)
%code{% THIS->split_at(*point, prefer_non_overhang != 0); %}; %code{% THIS->split_at(*point, prefer_non_overhang != 0, scaled_epsilon); %};
ExtrusionPaths clip_end(double distance) ExtrusionPaths clip_end(double distance)
%code{% THIS->clip_end(distance, &RETVAL); %}; %code{% THIS->clip_end(distance, &RETVAL); %};
bool has_overhang_point(Point* point) bool has_overhang_point(Point* point)