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;
|
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;
|
for (const ExtrusionPath &path : this->paths) {
|
||||||
size_t path_idx_non_overhang = 0;
|
std::pair<int, Point> foot_pt_ = foot_pt(path.polyline.points, point);
|
||||||
double min_non_overhang = std::numeric_limits<double>::max();
|
double d2 = (foot_pt_.second - point).cast<double>().squaredNorm();
|
||||||
for (const ExtrusionPath& path : this->paths) {
|
if (d2 < min2) {
|
||||||
Point p_tmp = point.projection_onto(path.polyline);
|
out.foot_pt = foot_pt_.second;
|
||||||
double dist = (p_tmp - point).cast<double>().norm();
|
out.path_idx = &path - &this->paths.front();
|
||||||
if (dist < min) {
|
out.segment_idx = foot_pt_.first;
|
||||||
p = p_tmp;
|
min2 = d2;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (prefer_non_overhang && min_non_overhang != std::numeric_limits<double>::max()) {
|
if (prefer_non_overhang && !is_bridge(path.role()) && d2 < min2_non_overhang) {
|
||||||
// Only apply the non-overhang point if there is one.
|
best_non_overhang.foot_pt = foot_pt_.second;
|
||||||
path_idx = path_idx_non_overhang;
|
best_non_overhang.path_idx = &path - &this->paths.front();
|
||||||
p = p_non_overhang;
|
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.
|
// 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())
|
p2.polyline.points.insert(p2.polyline.points.end(), p1.polyline.points.begin() + 1, p1.polyline.points.end());
|
||||||
std::swap(this->paths.front().polyline.points, p1.polyline.points);
|
this->paths.front().polyline.points = std::move(p2.polyline.points);
|
||||||
else {
|
} else
|
||||||
p2.polyline.points.insert(p2.polyline.points.end(), p1.polyline.points.begin() + 1, p1.polyline.points.end());
|
this->paths.front().polyline.points = std::move(p1.polyline.points);
|
||||||
std::swap(this->paths.front().polyline.points, p2.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
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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)) {}
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user