Merge branch 'vb_dev250_cooling' into dev_250
This commit is contained in:
commit
2c9658cc88
@ -153,11 +153,10 @@ double ExtrusionLoop::length() const
|
||||
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) {
|
||||
int idx = path->polyline.find_point(point);
|
||||
if (idx != -1) {
|
||||
for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path)
|
||||
if (int idx = path->polyline.find_point(point, scaled_epsilon); idx != -1) {
|
||||
if (this->paths.size() == 1) {
|
||||
// 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);
|
||||
@ -169,70 +168,85 @@ bool ExtrusionLoop::split_at_vertex(const Point &point)
|
||||
{
|
||||
ExtrusionPath p = *path;
|
||||
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
|
||||
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
|
||||
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
|
||||
{
|
||||
ExtrusionPath p = *path;
|
||||
ExtrusionPath &p = *path;
|
||||
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
|
||||
std::swap(this->paths, new_paths);
|
||||
this->paths = std::move(new_paths);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// The point was not found.
|
||||
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.
|
||||
size_t path_idx = 0;
|
||||
Point p;
|
||||
{
|
||||
double min = 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) {
|
||||
Point p_tmp = point.projection_onto(path.polyline);
|
||||
double dist = (p_tmp - point).cast<double>().norm();
|
||||
if (dist < min) {
|
||||
p = p_tmp;
|
||||
min = dist;
|
||||
path_idx = &path - &this->paths.front();
|
||||
}
|
||||
if (prefer_non_overhang && !is_bridge(path.role()) && dist < min_non_overhang) {
|
||||
p_non_overhang = p_tmp;
|
||||
min_non_overhang = dist;
|
||||
path_idx_non_overhang = &path - &this->paths.front();
|
||||
}
|
||||
ClosestPathPoint out { 0, 0 };
|
||||
double min2 = std::numeric_limits<double>::max();
|
||||
ClosestPathPoint best_non_overhang { 0, 0 };
|
||||
double min2_non_overhang = std::numeric_limits<double>::max();
|
||||
for (const ExtrusionPath &path : this->paths) {
|
||||
std::pair<int, Point> foot_pt_ = foot_pt(path.polyline.points, point);
|
||||
double d2 = (foot_pt_.second - point).cast<double>().squaredNorm();
|
||||
if (d2 < min2) {
|
||||
out.foot_pt = foot_pt_.second;
|
||||
out.path_idx = &path - &this->paths.front();
|
||||
out.segment_idx = foot_pt_.first;
|
||||
min2 = d2;
|
||||
}
|
||||
if (prefer_non_overhang && min_non_overhang != std::numeric_limits<double>::max()) {
|
||||
// Only apply the non-overhang point if there is one.
|
||||
path_idx = path_idx_non_overhang;
|
||||
p = p_non_overhang;
|
||||
if (prefer_non_overhang && !is_bridge(path.role()) && d2 < min2_non_overhang) {
|
||||
best_non_overhang.foot_pt = foot_pt_.second;
|
||||
best_non_overhang.path_idx = &path - &this->paths.front();
|
||||
best_non_overhang.segment_idx = foot_pt_.first;
|
||||
min2_non_overhang = d2;
|
||||
}
|
||||
}
|
||||
return std::make_pair(path_idx, p);
|
||||
if (prefer_non_overhang && min2_non_overhang != std::numeric_limits<double>::max())
|
||||
// Only apply the non-overhang point if there is one.
|
||||
out = best_non_overhang;
|
||||
return out;
|
||||
}
|
||||
|
||||
// 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())
|
||||
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
|
||||
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);
|
||||
|
||||
if (this->paths.size() == 1) {
|
||||
if (! p1.polyline.is_valid())
|
||||
std::swap(this->paths.front().polyline.points, p2.polyline.points);
|
||||
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());
|
||||
std::swap(this->paths.front().polyline.points, p2.polyline.points);
|
||||
}
|
||||
if (p2.polyline.is_valid()) {
|
||||
if (p1.polyline.is_valid())
|
||||
p2.polyline.points.insert(p2.polyline.points.end(), p1.polyline.points.begin() + 1, p1.polyline.points.end());
|
||||
this->paths.front().polyline.points = std::move(p2.polyline.points);
|
||||
} else
|
||||
this->paths.front().polyline.points = std::move(p1.polyline.points);
|
||||
} else {
|
||||
// install the two paths
|
||||
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
|
||||
this->split_at_vertex(p);
|
||||
this->split_at_vertex(p, 0.);
|
||||
}
|
||||
|
||||
void ExtrusionLoop::clip_end(double distance, ExtrusionPaths* paths) const
|
||||
|
@ -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(); }
|
||||
Polygon polygon() const;
|
||||
double length() const override;
|
||||
bool split_at_vertex(const Point &point);
|
||||
void split_at(const Point &point, bool prefer_non_overhang);
|
||||
std::pair<size_t, Point> get_closest_path_and_point(const Point& point, bool prefer_non_overhang) const;
|
||||
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, const double scaled_epsilon = scaled<double>(0.001));
|
||||
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;
|
||||
// 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.
|
||||
|
@ -2638,7 +2638,9 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
assert(m_layer != nullptr);
|
||||
m_seam_placer.place_seam(m_layer, loop, m_config.external_perimeters_first, this->last_pos());
|
||||
} 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;
|
||||
// if polyline was shorter than the clipping distance we'd get a null polyline, so
|
||||
|
@ -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())
|
||||
* 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.
|
||||
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.
|
||||
//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;
|
||||
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.
|
||||
// Insert it.
|
||||
loop.split_at(seam_point, true);
|
||||
|
@ -63,6 +63,24 @@ int MultiPoint::find_point(const Point &point) const
|
||||
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
|
||||
{
|
||||
double dist = (point.projection_onto(*this) - point).cast<double>().norm();
|
||||
|
@ -43,7 +43,12 @@ public:
|
||||
double length() const;
|
||||
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;
|
||||
// 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;
|
||||
int closest_point_index(const Point &point) const {
|
||||
int idx = -1;
|
||||
|
@ -225,6 +225,29 @@ bool remove_degenerate(Polylines &polylines)
|
||||
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 lines;
|
||||
|
@ -162,6 +162,9 @@ const Point& leftmost_point(const 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 {
|
||||
public:
|
||||
ThickPolyline() : endpoints(std::make_pair(false, false)) {}
|
||||
|
@ -21,8 +21,8 @@
|
||||
double length();
|
||||
bool split_at_vertex(Point* point)
|
||||
%code{% RETVAL = THIS->split_at_vertex(*point); %};
|
||||
void split_at(Point* point, int prefer_non_overhang = 0)
|
||||
%code{% THIS->split_at(*point, 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, scaled_epsilon); %};
|
||||
ExtrusionPaths clip_end(double distance)
|
||||
%code{% THIS->clip_end(distance, &RETVAL); %};
|
||||
bool has_overhang_point(Point* point)
|
||||
|
Loading…
Reference in New Issue
Block a user