mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-14 19:31:48 +08:00
Fix firmware min_length
* fix m_last_too_small fusion test * now use a modified douglas_peucker to take into account the segment length instead of the tolerance only * some tooltip & default value change for resolution.
This commit is contained in:
parent
d0b0bee995
commit
1d405304b9
@ -3289,10 +3289,11 @@ void GCode::use(const ExtrusionEntityCollection &collection) {
|
|||||||
std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed) {
|
std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed) {
|
||||||
|
|
||||||
ExtrusionPath simplifed_path = path;
|
ExtrusionPath simplifed_path = path;
|
||||||
if (this->config().min_length.value != 0 && !m_last_too_small.empty()) {
|
const double scaled_min_length = scale_(this->config().min_length.value);
|
||||||
|
if (scaled_min_length > 0 && !m_last_too_small.empty()) {
|
||||||
//descr += " trys fusion " + std::to_string(unscaled(m_last_too_small.last_point().x())) + " , " + std::to_string(unscaled(path.first_point().x()));
|
//descr += " trys fusion " + std::to_string(unscaled(m_last_too_small.last_point().x())) + " , " + std::to_string(unscaled(path.first_point().x()));
|
||||||
//ensure that it's a continous thing
|
//ensure that it's a continous thing
|
||||||
if (m_last_too_small.first_point().distance_to_square(path.first_point()) < scale_(this->config().min_length) /*&& m_last_too_small.first_point().distance_to_square(path.first_point()) > EPSILON*/) {
|
if (m_last_too_small.last_point().distance_to_square(path.first_point()) < scaled_min_length*scaled_min_length /*&& m_last_too_small.first_point().distance_to_square(path.first_point()) > EPSILON*/) {
|
||||||
//descr += " ! fusion " + std::to_string(simplifed_path.polyline.points.size());
|
//descr += " ! fusion " + std::to_string(simplifed_path.polyline.points.size());
|
||||||
simplifed_path.height = (m_last_too_small.height * m_last_too_small.length() + simplifed_path.height * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length());
|
simplifed_path.height = (m_last_too_small.height * m_last_too_small.length() + simplifed_path.height * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length());
|
||||||
simplifed_path.mm3_per_mm = (m_last_too_small.mm3_per_mm * m_last_too_small.length() + simplifed_path.mm3_per_mm * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length());
|
simplifed_path.mm3_per_mm = (m_last_too_small.mm3_per_mm * m_last_too_small.length() + simplifed_path.mm3_per_mm * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length());
|
||||||
@ -3302,24 +3303,20 @@ std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &de
|
|||||||
}
|
}
|
||||||
m_last_too_small.polyline.points.clear();
|
m_last_too_small.polyline.points.clear();
|
||||||
}
|
}
|
||||||
if (this->config().min_length.value > 0) {
|
if (scaled_min_length > 0) {
|
||||||
simplifed_path.simplify(scale_(this->config().min_length));
|
// it's an alternative to simplifed_path.simplify(scale_(this->config().min_length)); with more enphasis ont he segment length that on the feature detail.
|
||||||
|
// because tolerance = min_length /10, douglas_peucker will erase more points if angles are shallower than 6° and then the '_plus' will kick in to keep a bit more.
|
||||||
|
// if angles are all bigger than 6°, then the douglas_peucker will do all the work.
|
||||||
|
simplifed_path.polyline.points = MultiPoint::_douglas_peucker_plus(simplifed_path.polyline.points, scaled_min_length / 10, scaled_min_length);
|
||||||
}
|
}
|
||||||
//else simplifed_path.simplify(SCALED_RESOLUTION); //should already be simplified
|
//else simplifed_path.simplify(SCALED_RESOLUTION); //should already be simplified
|
||||||
if (this->config().min_length.value != 0 && simplifed_path.length() < scale_(this->config().min_length)) {
|
if (scaled_min_length > 0 && simplifed_path.length() < scaled_min_length) {
|
||||||
m_last_too_small = simplifed_path;
|
m_last_too_small = simplifed_path;
|
||||||
return "";
|
return "";
|
||||||
//"; "+ descr+" .... too small for extrude: "+std::to_string(simplifed_path.length())+" < "+ std::to_string(scale_(this->config().min_length))
|
|
||||||
//+ " ; " + std::to_string(unscaled(path.first_point().x())) + " : " + std::to_string(unscaled(path.last_point().x()))
|
|
||||||
//+" =;=> " + std::to_string(unscaled(simplifed_path.first_point().x())) + " : " + std::to_string(unscaled(simplifed_path.last_point().x()))
|
|
||||||
//+ "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string gcode = this->_extrude(simplifed_path, description, speed);
|
std::string gcode = this->_extrude(simplifed_path, description, speed);
|
||||||
|
|
||||||
//gcode += " ; " + std::to_string(unscaled(path.first_point().x())) + " : " + std::to_string(unscaled(path.last_point().x()));
|
|
||||||
//gcode += " =;=> " + std::to_string(unscaled(simplifed_path.first_point().x())) + " : " + std::to_string(unscaled(simplifed_path.last_point().x()));
|
|
||||||
|
|
||||||
if (m_wipe.enable) {
|
if (m_wipe.enable) {
|
||||||
m_wipe.path = std::move(simplifed_path.polyline);
|
m_wipe.path = std::move(simplifed_path.polyline);
|
||||||
m_wipe.path.reverse();
|
m_wipe.path.reverse();
|
||||||
|
@ -249,6 +249,163 @@ std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, c
|
|||||||
return result_pts;
|
return result_pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// douglas_peucker will keep only points that are more than 'tolerance' out of the current polygon.
|
||||||
|
/// But when we want to ensure we don't have a segment less than min_length, it's not very usable.
|
||||||
|
/// This one is more effective: it will keep all points like the douglas_peucker, and also all points
|
||||||
|
/// in-between that satisfies the min_length, ordered by their tolerance.
|
||||||
|
/// Note: to have a all 360 points of a circle, then you need 'tolerance <= min_length * (1-cos(1°)) ~= min_length * 0.000155'
|
||||||
|
/// Note: douglas_peucker is bad for simplifying circles, as it will create uneven segments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pts"></param>
|
||||||
|
/// <param name="tolerance"></param>
|
||||||
|
/// <param name="min_length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
std::vector<Point> MultiPoint::_douglas_peucker_plus(const std::vector<Point>& pts, const double tolerance, const double min_length)
|
||||||
|
{
|
||||||
|
std::vector<Point> result_pts;
|
||||||
|
std::vector<size_t> result_idx;
|
||||||
|
double tolerance_sq = tolerance * tolerance;
|
||||||
|
if (!pts.empty()) {
|
||||||
|
const Point* anchor = &pts.front();
|
||||||
|
size_t anchor_idx = 0;
|
||||||
|
const Point* floater = &pts.back();
|
||||||
|
size_t floater_idx = pts.size() - 1;
|
||||||
|
result_pts.reserve(pts.size());
|
||||||
|
result_pts.emplace_back(*anchor);
|
||||||
|
result_idx.reserve(pts.size());
|
||||||
|
result_idx.emplace_back(anchor_idx);
|
||||||
|
if (anchor_idx != floater_idx) {
|
||||||
|
assert(pts.size() > 1);
|
||||||
|
std::vector<size_t> dpStack;
|
||||||
|
dpStack.reserve(pts.size());
|
||||||
|
dpStack.emplace_back(floater_idx);
|
||||||
|
for (;;) {
|
||||||
|
double max_dist_sq = 0.0;
|
||||||
|
size_t furthest_idx = anchor_idx;
|
||||||
|
// find point furthest from line seg created by (anchor, floater) and note it
|
||||||
|
for (size_t i = anchor_idx + 1; i < floater_idx; ++i) {
|
||||||
|
double dist_sq = Line::distance_to_squared(pts[i], *anchor, *floater);
|
||||||
|
if (dist_sq > max_dist_sq) {
|
||||||
|
max_dist_sq = dist_sq;
|
||||||
|
furthest_idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove point if less than tolerance
|
||||||
|
if (max_dist_sq <= tolerance_sq) {
|
||||||
|
result_pts.emplace_back(*floater);
|
||||||
|
result_idx.emplace_back(floater_idx);
|
||||||
|
anchor_idx = floater_idx;
|
||||||
|
anchor = floater;
|
||||||
|
assert(dpStack.back() == floater_idx);
|
||||||
|
dpStack.pop_back();
|
||||||
|
if (dpStack.empty())
|
||||||
|
break;
|
||||||
|
floater_idx = dpStack.back();
|
||||||
|
} else {
|
||||||
|
floater_idx = furthest_idx;
|
||||||
|
dpStack.emplace_back(floater_idx);
|
||||||
|
}
|
||||||
|
floater = &pts[floater_idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(result_pts.front() == pts.front());
|
||||||
|
assert(result_pts.back() == pts.back());
|
||||||
|
|
||||||
|
//TODO use linked list if needed.
|
||||||
|
// add other points that are at not less than min_length dist of the other points.
|
||||||
|
std::vector<double> distances;
|
||||||
|
for (size_t segment_idx = 0; segment_idx < result_idx.size()-1; segment_idx++) {
|
||||||
|
distances.clear();
|
||||||
|
size_t start_idx = result_idx[segment_idx];
|
||||||
|
size_t end_idx = result_idx[segment_idx + 1];
|
||||||
|
if (end_idx - start_idx == 1) continue;
|
||||||
|
//create the list of distances
|
||||||
|
double sum = 0;
|
||||||
|
for (size_t i = start_idx; i < end_idx; i++) {
|
||||||
|
double dist = pts[i].distance_to(pts[i + 1]);
|
||||||
|
distances.push_back(dist);
|
||||||
|
sum += dist;
|
||||||
|
}
|
||||||
|
if (sum < min_length * 2) continue;
|
||||||
|
//if there are too many points and dist, then choose a more difficult sections of ~min_length * 2-4, where we will at least one
|
||||||
|
if (sum > min_length * 4) {
|
||||||
|
//check what is the last index possible
|
||||||
|
double current_sum = 0;
|
||||||
|
size_t last_possible_idx = end_idx;
|
||||||
|
while (current_sum < min_length * 2) {
|
||||||
|
last_possible_idx--;
|
||||||
|
current_sum += distances[last_possible_idx - start_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//find the new end point
|
||||||
|
current_sum = 0;
|
||||||
|
size_t current_idx = start_idx;
|
||||||
|
while (current_sum < min_length * 4 && current_idx < last_possible_idx){
|
||||||
|
current_sum += distances[current_idx - start_idx];
|
||||||
|
current_idx ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// last check, to see if the points are well distributed enough.
|
||||||
|
if (current_sum > min_length * 2 && current_idx > start_idx + 1) {
|
||||||
|
//set new end
|
||||||
|
sum = current_sum;
|
||||||
|
end_idx = current_idx;
|
||||||
|
result_idx.insert(result_idx.begin() + segment_idx + 1, end_idx);
|
||||||
|
result_pts.insert(result_pts.begin() + segment_idx + 1, pts[end_idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Point* start_point = &result_pts[segment_idx];
|
||||||
|
Point* end_point = &result_pts[segment_idx + 1];
|
||||||
|
|
||||||
|
//use at least a point, even if it's not in the middle and sum ~= min_length * 2
|
||||||
|
double max_dist_sq = 0.0;
|
||||||
|
size_t furthest_idx = start_idx + 1;
|
||||||
|
// find point furthest from line seg created by (anchor, floater) and note it
|
||||||
|
for (size_t i = start_idx + 1; i < end_idx; ++i) {
|
||||||
|
double dist_sq = Line::distance_to_squared(pts[i], *start_point, *end_point);
|
||||||
|
if (dist_sq > max_dist_sq) {
|
||||||
|
max_dist_sq = dist_sq;
|
||||||
|
furthest_idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add this point and skip it
|
||||||
|
result_idx.insert(result_idx.begin() + segment_idx + 1, furthest_idx);
|
||||||
|
result_pts.insert(result_pts.begin() + segment_idx + 1, pts[furthest_idx]);
|
||||||
|
segment_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
static int iRun = 0;
|
||||||
|
BoundingBox bbox(pts);
|
||||||
|
BoundingBox bbox2(result_pts);
|
||||||
|
bbox.merge(bbox2);
|
||||||
|
//SVG svg(debug_out_path("douglas_peucker_%d.svg", iRun ++).c_str(), bbox);
|
||||||
|
|
||||||
|
std::stringstream stri;
|
||||||
|
stri << "douglas_peucker_" << (iRun++) << ".svg";
|
||||||
|
SVG svg(stri.str());
|
||||||
|
if (pts.front() == pts.back())
|
||||||
|
svg.draw(Polygon(pts), "black");
|
||||||
|
else
|
||||||
|
svg.draw(Polyline(pts), "black");
|
||||||
|
if (result_pts.front() == result_pts.back())
|
||||||
|
svg.draw(Polygon(result_pts), "green");
|
||||||
|
else
|
||||||
|
svg.draw(Polyline(result_pts), "green", scale_(0.1));
|
||||||
|
svg.Close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return result_pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Visivalingam simplification algorithm https://github.com/slic3r/Slic3r/pull/3825
|
// Visivalingam simplification algorithm https://github.com/slic3r/Slic3r/pull/3825
|
||||||
// thanks to @fuchstraumer
|
// thanks to @fuchstraumer
|
||||||
/*
|
/*
|
||||||
|
@ -82,8 +82,9 @@ public:
|
|||||||
bool intersections(const Line &line, Points *intersections) const;
|
bool intersections(const Line &line, Points *intersections) const;
|
||||||
// Projection of a point onto the lines defined by the points.
|
// Projection of a point onto the lines defined by the points.
|
||||||
virtual Point point_projection(const Point &point) const;
|
virtual Point point_projection(const Point &point) const;
|
||||||
|
|
||||||
static Points _douglas_peucker(const Points &points, const double tolerance);
|
static Points _douglas_peucker(const Points& points, const double tolerance);
|
||||||
|
static Points _douglas_peucker_plus(const Points& points, const double tolerance, const double min_length);
|
||||||
static Points visivalingam(const Points& pts, const double& tolerance);
|
static Points visivalingam(const Points& pts, const double& tolerance);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -125,12 +125,13 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||||||
"gcode_precision_e",
|
"gcode_precision_e",
|
||||||
"infill_acceleration",
|
"infill_acceleration",
|
||||||
"layer_gcode",
|
"layer_gcode",
|
||||||
"min_fan_speed",
|
|
||||||
"max_fan_speed",
|
"max_fan_speed",
|
||||||
"max_print_height",
|
"max_print_height",
|
||||||
"min_print_speed",
|
|
||||||
"max_print_speed",
|
"max_print_speed",
|
||||||
"max_volumetric_speed",
|
"max_volumetric_speed",
|
||||||
|
"min_fan_speed",
|
||||||
|
"min_length",
|
||||||
|
"min_print_speed",
|
||||||
"milling_toolchange_end_gcode",
|
"milling_toolchange_end_gcode",
|
||||||
"milling_toolchange_start_gcode",
|
"milling_toolchange_start_gcode",
|
||||||
"milling_offset",
|
"milling_offset",
|
||||||
|
@ -2909,14 +2909,14 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->category = OptionCategory::slicing;
|
def->category = OptionCategory::slicing;
|
||||||
def->tooltip = L("Minimum detail resolution, used to simplify the input file for speeding up "
|
def->tooltip = L("Minimum detail resolution, used to simplify the input file for speeding up "
|
||||||
"the slicing job and reducing memory usage. High-resolution models often carry "
|
"the slicing job and reducing memory usage. High-resolution models often carry "
|
||||||
"more detail than printers can render. Set to zero to disable any simplification "
|
"more details than printers can render. Set to zero to disable any simplification "
|
||||||
"and use full resolution from input. "
|
"and use full resolution from input. "
|
||||||
"\nNote: " SLIC3R_APP_NAME " has an internal resolution of 0.000001mm."
|
"\nNote: " SLIC3R_APP_NAME " has an internal working resolution of 0.0001mm."
|
||||||
"\nInfill & Thin areas are simplified up to 0.0125mm.");
|
"\nInfill & Thin areas are simplified up to 0.0125mm.");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->mode = comExpert;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionFloat(0.0125));
|
def->set_default_value(new ConfigOptionFloat(0.002));
|
||||||
|
|
||||||
def = this->add("retract_before_travel", coFloats);
|
def = this->add("retract_before_travel", coFloats);
|
||||||
def->label = L("Minimum travel after retraction");
|
def->label = L("Minimum travel after retraction");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user