Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate
This commit is contained in:
commit
a5822800b9
@ -117,18 +117,18 @@ inline std::tuple<int, int> coordinate_aligned_ray_hit_count(size_t
|
||||
}
|
||||
|
||||
template<typename LineType, typename TreeType, typename VectorType>
|
||||
inline std::vector<VectorType> get_intersections_with_line(size_t node_idx,
|
||||
const TreeType &tree,
|
||||
const std::vector<LineType> &lines,
|
||||
const LineType &line,
|
||||
const typename TreeType::BoundingBox &line_bb)
|
||||
inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(size_t node_idx,
|
||||
const TreeType &tree,
|
||||
const std::vector<LineType> &lines,
|
||||
const LineType &line,
|
||||
const typename TreeType::BoundingBox &line_bb)
|
||||
{
|
||||
const auto &node = tree.node(node_idx);
|
||||
assert(node.is_valid());
|
||||
if (node.is_leaf()) {
|
||||
VectorType intersection_pt;
|
||||
if (line_alg::intersection(line, lines[node.idx], &intersection_pt)) {
|
||||
return {intersection_pt};
|
||||
return {std::pair<VectorType, size_t>(intersection_pt, node.idx)};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
@ -140,17 +140,17 @@ inline std::vector<VectorType> get_intersections_with_line(size_t
|
||||
assert(node_left.is_valid());
|
||||
assert(node_right.is_valid());
|
||||
|
||||
std::vector<VectorType> result;
|
||||
std::vector<std::pair<VectorType, size_t>> result;
|
||||
|
||||
if (node_left.bbox.intersects(line_bb)) {
|
||||
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines,
|
||||
line, line_bb);
|
||||
std::vector<std::pair<VectorType, size_t>> intersections =
|
||||
get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines, line, line_bb);
|
||||
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||
}
|
||||
|
||||
if (node_right.bbox.intersects(line_bb)) {
|
||||
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines,
|
||||
line, line_bb);
|
||||
std::vector<std::pair<VectorType, size_t>> intersections =
|
||||
get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines, line, line_bb);
|
||||
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||
}
|
||||
|
||||
@ -263,9 +263,13 @@ inline int point_outside_closed_contours(const std::vector<LineType> &lines, con
|
||||
}
|
||||
|
||||
template<bool sorted, typename VectorType, typename LineType, typename TreeType>
|
||||
inline std::vector<VectorType> get_intersections_with_line(const std::vector<LineType> &lines, const TreeType &tree, const LineType &line)
|
||||
inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(const std::vector<LineType> &lines,
|
||||
const TreeType &tree,
|
||||
const LineType &line)
|
||||
{
|
||||
if (tree.empty()) { return {}; }
|
||||
if (tree.empty()) {
|
||||
return {};
|
||||
}
|
||||
auto line_bb = typename TreeType::BoundingBox(line.a, line.a);
|
||||
line_bb.extend(line.b);
|
||||
|
||||
@ -274,15 +278,16 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
|
||||
using Floating =
|
||||
typename std::conditional<std::is_floating_point<typename LineType::Scalar>::value, typename LineType::Scalar, double>::type;
|
||||
|
||||
std::vector<std::pair<Floating, VectorType>> points_with_sq_distance{};
|
||||
for (const VectorType &p : intersections) {
|
||||
points_with_sq_distance.emplace_back((p - line.a).template cast<Floating>().squaredNorm(), p);
|
||||
std::vector<std::pair<Floating, std::pair<VectorType, size_t>>> points_with_sq_distance{};
|
||||
for (const auto &p : intersections) {
|
||||
points_with_sq_distance.emplace_back((p.first - line.a).template cast<Floating>().squaredNorm(), p);
|
||||
}
|
||||
std::sort(points_with_sq_distance.begin(), points_with_sq_distance.end(),
|
||||
[](const std::pair<Floating, VectorType> &left, std::pair<Floating, VectorType> &right) {
|
||||
return left.first < right.first;
|
||||
});
|
||||
for (size_t i = 0; i < points_with_sq_distance.size(); i++) { intersections[i] = points_with_sq_distance[i].second; }
|
||||
[](const std::pair<Floating, std::pair<VectorType, size_t>> &left,
|
||||
std::pair<Floating, std::pair<VectorType, size_t>> &right) { return left.first < right.first; });
|
||||
for (size_t i = 0; i < points_with_sq_distance.size(); i++) {
|
||||
intersections[i] = points_with_sq_distance[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
return intersections;
|
||||
@ -290,10 +295,11 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
|
||||
|
||||
template<typename LineType> class LinesDistancer
|
||||
{
|
||||
private:
|
||||
std::vector<LineType> lines;
|
||||
public:
|
||||
using Scalar = typename LineType::Scalar;
|
||||
using Floating = typename std::conditional<std::is_floating_point<Scalar>::value, Scalar, double>::type;
|
||||
private:
|
||||
std::vector<LineType> lines;
|
||||
AABBTreeIndirect::Tree<2, Scalar> tree;
|
||||
|
||||
public:
|
||||
@ -313,23 +319,29 @@ public:
|
||||
int outside(const Vec<2, Scalar> &point) const { return point_outside_closed_contours(lines, tree, point); }
|
||||
|
||||
// negative sign means inside
|
||||
std::tuple<Floating, size_t, Vec<2, Floating>> signed_distance_from_lines_extra(const Vec<2, Scalar> &point) const
|
||||
template<bool SIGNED_DISTANCE>
|
||||
std::tuple<Floating, size_t, Vec<2, Floating>> distance_from_lines_extra(const Vec<2, Scalar> &point) const
|
||||
{
|
||||
size_t nearest_line_index_out = size_t(-1);
|
||||
Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero();
|
||||
Vec<2, Floating> p = point.template cast<Floating>();
|
||||
auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out);
|
||||
|
||||
if (distance < 0) { return {std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out}; }
|
||||
if (distance < 0) {
|
||||
return {std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out};
|
||||
}
|
||||
distance = sqrt(distance);
|
||||
distance *= outside(point);
|
||||
|
||||
if (SIGNED_DISTANCE) {
|
||||
distance *= outside(point);
|
||||
}
|
||||
|
||||
return {distance, nearest_line_index_out, nearest_point_out};
|
||||
}
|
||||
|
||||
Floating signed_distance_from_lines(const Vec<2, typename LineType::Scalar> &point) const
|
||||
template<bool SIGNED_DISTANCE> Floating distance_from_lines(const Vec<2, typename LineType::Scalar> &point) const
|
||||
{
|
||||
auto [dist, idx, np] = signed_distance_from_lines_extra(point);
|
||||
auto [dist, idx, np] = distance_from_lines_extra<SIGNED_DISTANCE>(point);
|
||||
return dist;
|
||||
}
|
||||
|
||||
@ -338,7 +350,7 @@ public:
|
||||
return all_lines_in_radius(this->lines, this->tree, point, radius * radius);
|
||||
}
|
||||
|
||||
template<bool sorted> std::vector<Vec<2, Scalar>> intersections_with_line(const LineType &line) const
|
||||
template<bool sorted> std::vector<std::pair<Vec<2, Scalar>, size_t>> intersections_with_line(const LineType &line) const
|
||||
{
|
||||
return get_intersections_with_line<sorted, Vec<2, Scalar>>(lines, tree, line);
|
||||
}
|
||||
|
@ -2161,11 +2161,11 @@ LayerResult GCode::process_layer(
|
||||
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) :
|
||||
Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done);
|
||||
|
||||
if (this->config().avoid_curled_filament_during_travels) {
|
||||
m_avoid_curled_filaments.clear();
|
||||
if (this->config().avoid_crossing_curled_overhangs) {
|
||||
m_avoid_crossing_curled_overhangs.clear();
|
||||
for (const ObjectLayerToPrint &layer_to_print : layers) {
|
||||
m_avoid_curled_filaments.add_obstacles(layer_to_print.object_layer, Point(scaled(this->origin())));
|
||||
m_avoid_curled_filaments.add_obstacles(layer_to_print.support_layer, Point(scaled(this->origin())));
|
||||
m_avoid_crossing_curled_overhangs.add_obstacles(layer_to_print.object_layer, Point(scaled(this->origin())));
|
||||
m_avoid_crossing_curled_overhangs.add_obstacles(layer_to_print.support_layer, Point(scaled(this->origin())));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2916,7 +2916,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
bool variable_speed = false;
|
||||
std::vector<ProcessedPoint> new_points{};
|
||||
if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && is_perimeter(path.role())) {
|
||||
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_steepness_levels,
|
||||
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_overlap_levels,
|
||||
m_config.dynamic_overhang_speeds,
|
||||
m_config.get_abs_value("external_perimeter_speed"), speed);
|
||||
variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.speed != speed; });
|
||||
@ -3040,13 +3040,13 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||
this->origin in order to get G-code coordinates. */
|
||||
Polyline travel { this->last_pos(), point };
|
||||
|
||||
if (this->config().avoid_curled_filament_during_travels) {
|
||||
if (this->config().avoid_crossing_curled_overhangs) {
|
||||
if (m_config.avoid_crossing_perimeters) {
|
||||
BOOST_LOG_TRIVIAL(warning)
|
||||
<< "Option >avoid curled filament during travels< is not compatible with avoid crossing perimeters and it will be ignored!";
|
||||
<< "Option >avoid crossing curled overhangs< is not compatible with avoid crossing perimeters and it will be ignored!";
|
||||
} else {
|
||||
Point scaled_origin = Point(scaled(this->origin()));
|
||||
travel = m_avoid_curled_filaments.find_path(this->last_pos() + scaled_origin, point + scaled_origin);
|
||||
travel = m_avoid_crossing_curled_overhangs.find_path(this->last_pos() + scaled_origin, point + scaled_origin);
|
||||
travel.translate(-scaled_origin);
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ private:
|
||||
OozePrevention m_ooze_prevention;
|
||||
Wipe m_wipe;
|
||||
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
||||
JPSPathFinder m_avoid_curled_filaments;
|
||||
JPSPathFinder m_avoid_crossing_curled_overhangs;
|
||||
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters;
|
||||
bool m_enable_loop_clipping;
|
||||
// If enabled, the G-code generator will put following comments at the ends
|
||||
|
@ -39,9 +39,9 @@ public:
|
||||
void add_point(float distance, float angle)
|
||||
{
|
||||
total_distance += distance;
|
||||
total_curvature += std::abs(angle);
|
||||
total_curvature += angle;
|
||||
distances.push_back(distance);
|
||||
angles.push_back(std::abs(angle));
|
||||
angles.push_back(angle);
|
||||
|
||||
while (distances.size() > 1 && total_distance > window_size) {
|
||||
total_distance -= distances.front();
|
||||
@ -53,8 +53,6 @@ public:
|
||||
|
||||
float get_curvature() const
|
||||
{
|
||||
if (total_distance < EPSILON) { return 0.0; }
|
||||
|
||||
return total_curvature / window_size;
|
||||
}
|
||||
|
||||
@ -69,24 +67,33 @@ public:
|
||||
|
||||
class CurvatureEstimator
|
||||
{
|
||||
static const size_t sliders_count = 2;
|
||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.5}, {3.0}};
|
||||
static const size_t sliders_count = 3;
|
||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.0},{4.0}, {10.0}};
|
||||
|
||||
public:
|
||||
void add_point(float distance, float angle)
|
||||
{
|
||||
if (distance < EPSILON) return;
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.add_point(distance, angle); }
|
||||
if (distance < EPSILON)
|
||||
return;
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||
slider.add_point(distance, angle);
|
||||
}
|
||||
}
|
||||
float get_curvature()
|
||||
{
|
||||
float max_curvature = std::numeric_limits<float>::min();
|
||||
for (const SlidingWindowCurvatureAccumulator &slider : sliders) { max_curvature = std::max(max_curvature, slider.get_curvature()); }
|
||||
float max_curvature = 0.0f;
|
||||
for (const SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||
if (abs(slider.get_curvature()) > abs(max_curvature)) {
|
||||
max_curvature = slider.get_curvature();
|
||||
}
|
||||
}
|
||||
return max_curvature;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.reset(); }
|
||||
for (SlidingWindowCurvatureAccumulator &slider : sliders) {
|
||||
slider.reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -102,45 +109,68 @@ struct ExtendedPoint
|
||||
float curvature;
|
||||
};
|
||||
|
||||
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_ONLY, bool CONCAVITY_RESETS_CURVATURE, typename P, typename L>
|
||||
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &extrusion_points,
|
||||
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename P, typename L>
|
||||
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &input_points,
|
||||
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
|
||||
float flow_width)
|
||||
float flow_width,
|
||||
float max_line_length = -1.0f)
|
||||
{
|
||||
if (extrusion_points.empty()) return {};
|
||||
float boundary_offset = PREV_LAYER_BOUNDARY_ONLY ? 0.5 * flow_width : 0.0f;
|
||||
using AABBScalar = typename AABBTreeLines::LinesDistancer<L>::Scalar;
|
||||
if (input_points.empty())
|
||||
return {};
|
||||
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
|
||||
CurvatureEstimator cestim;
|
||||
float min_malformation_dist = 0.55 * flow_width;
|
||||
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
|
||||
|
||||
std::vector<P> extrusion_points;
|
||||
{
|
||||
if (max_line_length <= 0) {
|
||||
extrusion_points = input_points;
|
||||
} else {
|
||||
extrusion_points.reserve(input_points.size() * 2);
|
||||
for (size_t i = 0; i + 1 < input_points.size(); i++) {
|
||||
const P &curr = input_points[i];
|
||||
const P &next = input_points[i + 1];
|
||||
extrusion_points.push_back(curr);
|
||||
auto len = maybe_unscale(next - curr).squaredNorm();
|
||||
double t = sqrt((max_line_length * max_line_length) / len);
|
||||
size_t new_point_count = 1.0 / (t + EPSILON);
|
||||
for (size_t j = 1; j < new_point_count + 1; j++) {
|
||||
extrusion_points.push_back(curr * (1.0 - j * t) + next * (j * t));
|
||||
}
|
||||
}
|
||||
extrusion_points.push_back(input_points.back());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ExtendedPoint> points;
|
||||
points.reserve(extrusion_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
|
||||
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
|
||||
|
||||
{
|
||||
ExtendedPoint start_point{maybe_unscale(extrusion_points.front())};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(start_point.position);
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
|
||||
start_point.distance = distance + boundary_offset;
|
||||
start_point.nearest_prev_layer_line = nearest_line;
|
||||
points.push_back(start_point);
|
||||
}
|
||||
for (size_t i = 1; i < extrusion_points.size(); i++) {
|
||||
ExtendedPoint next_point{maybe_unscale(extrusion_points[i])};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(next_point.position);
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
|
||||
next_point.distance = distance + boundary_offset;
|
||||
next_point.nearest_prev_layer_line = nearest_line;
|
||||
|
||||
if (ADD_INTERSECTIONS &&
|
||||
((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) {
|
||||
const ExtendedPoint &prev_point = points.back();
|
||||
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position, next_point.position});
|
||||
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position.cast<AABBScalar>(), next_point.position.cast<AABBScalar>()});
|
||||
for (const auto &intersection : intersections) {
|
||||
points.emplace_back(intersection, boundary_offset);
|
||||
points.emplace_back(intersection.first.template cast<double>(), boundary_offset, intersection.second);
|
||||
}
|
||||
}
|
||||
points.push_back(next_point);
|
||||
}
|
||||
|
||||
if (PREV_LAYER_BOUNDARY_ONLY && ADD_INTERSECTIONS) {
|
||||
if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) {
|
||||
std::vector<ExtendedPoint> new_points;
|
||||
new_points.reserve(points.size() * 2);
|
||||
new_points.push_back(points.front());
|
||||
@ -159,12 +189,12 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
|
||||
|
||||
if (t0 < 1.0) {
|
||||
auto p0 = curr.position + t0 * (next.position - curr.position);
|
||||
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.signed_distance_from_lines_extra(p0);
|
||||
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p0.cast<AABBScalar>());
|
||||
new_points.push_back(ExtendedPoint{p0, float(p0_dist + boundary_offset), p0_near_l});
|
||||
}
|
||||
if (t1 > 0.0) {
|
||||
auto p1 = curr.position + t1 * (next.position - curr.position);
|
||||
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.signed_distance_from_lines_extra(p1);
|
||||
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p1.cast<AABBScalar>());
|
||||
new_points.push_back(ExtendedPoint{p1, float(p1_dist + boundary_offset), p1_near_l});
|
||||
}
|
||||
}
|
||||
@ -194,10 +224,8 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
|
||||
float distance = (prev.position - a.position).norm();
|
||||
float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position);
|
||||
cestim.add_point(distance, alfa);
|
||||
if (CONCAVITY_RESETS_CURVATURE && alfa < 0.0) { cestim.reset(); }
|
||||
}
|
||||
|
||||
if (a.distance < min_malformation_dist) { cestim.reset(); }
|
||||
a.curvature = cestim.get_curvature();
|
||||
}
|
||||
|
||||
@ -241,10 +269,23 @@ public:
|
||||
speed_sections.push_back({distance, speed});
|
||||
}
|
||||
std::sort(speed_sections.begin(), speed_sections.end(),
|
||||
[](const std::pair<float, float> &a, const std::pair<float, float> &b) { return a.first < b.first; });
|
||||
[](const std::pair<float, float> &a, const std::pair<float, float> &b) {
|
||||
if (a.first == b.first) {
|
||||
return a.second > b.second;
|
||||
}
|
||||
return a.first < b.first; });
|
||||
|
||||
std::pair<float, float> last_section{INFINITY, 0};
|
||||
for (auto §ion : speed_sections) {
|
||||
if (section.first == last_section.first) {
|
||||
section.second = last_section.second;
|
||||
} else {
|
||||
last_section = section;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ExtendedPoint> extended_points =
|
||||
estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
||||
estimate_points_properties<true, true, true, true>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
||||
|
||||
std::vector<ProcessedPoint> processed_points;
|
||||
processed_points.reserve(extended_points.size());
|
||||
|
@ -1071,7 +1071,7 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
|
||||
for (SeamCandidate &perimeter_point : layers[layer_idx].points) {
|
||||
Vec2f point = Vec2f { perimeter_point.position.head<2>() };
|
||||
if (prev_layer_distancer.get() != nullptr) {
|
||||
perimeter_point.overhang = prev_layer_distancer->signed_distance_from_lines(point.cast<double>())
|
||||
perimeter_point.overhang = prev_layer_distancer->distance_from_lines<true>(point.cast<double>())
|
||||
+ 0.6f * perimeter_point.perimeter.flow_width
|
||||
- tan(SeamPlacer::overhang_angle_threshold)
|
||||
* po->layers()[layer_idx]->height;
|
||||
@ -1080,7 +1080,7 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
|
||||
}
|
||||
|
||||
if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam)
|
||||
perimeter_point.embedded_distance = current_layer_distancer->signed_distance_from_lines(point.cast<double>())
|
||||
perimeter_point.embedded_distance = current_layer_distancer->distance_from_lines<true>(point.cast<double>())
|
||||
+ 0.6f * perimeter_point.perimeter.flow_width;
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ public:
|
||||
coordf_t height; // layer height in unscaled coordinates
|
||||
coordf_t bottom_z() const { return this->print_z - this->height; }
|
||||
|
||||
//Lines estimated to be seriously malformed, info from the IssueSearch algorithm. These lines should probably be avoided during fast travels.
|
||||
//Extrusions estimated to be seriously malformed, estimated during "Estimating curled extrusions" step. These lines should be avoided during fast travels.
|
||||
Lines malformed_lines;
|
||||
|
||||
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry
|
||||
|
@ -664,11 +664,11 @@ bool paths_touch(const ExtrusionPath &path_one, const ExtrusionPath &path_two, d
|
||||
AABBTreeLines::LinesDistancer<Line> lines_two{path_two.as_polyline().lines()};
|
||||
|
||||
for (size_t pt_idx = 0; pt_idx < path_one.polyline.size(); pt_idx++) {
|
||||
if (std::abs(lines_two.signed_distance_from_lines(path_one.polyline.points[pt_idx])) < limit_distance) { return true; }
|
||||
if (lines_two.distance_from_lines<false>(path_one.polyline.points[pt_idx]) < limit_distance) { return true; }
|
||||
}
|
||||
|
||||
for (size_t pt_idx = 0; pt_idx < path_two.polyline.size(); pt_idx++) {
|
||||
if (std::abs(lines_one.signed_distance_from_lines(path_two.polyline.points[pt_idx])) < limit_distance) { return true; }
|
||||
if (lines_one.distance_from_lines<false>(path_two.polyline.points[pt_idx]) < limit_distance) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -831,23 +831,21 @@ std::tuple<std::vector<ExtrusionPaths>, Polygons> generate_extra_perimeters_over
|
||||
|
||||
std::vector<Polygons> anchor_areas_w_delta_anchor_size{};
|
||||
for (double delta : deltas) {
|
||||
// for each delta, store anchors without the delta region around overhangs
|
||||
anchor_areas_w_delta_anchor_size.push_back(diff(anchors, expand(overhangs, delta, EXTRA_PERIMETER_OFFSET_PARAMETERS)));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < anchor_areas_w_delta_anchor_size.size() - 1; i++) {
|
||||
Polygons clipped = diff(anchor_areas_w_delta_anchor_size[i], expand(anchor_areas_w_delta_anchor_size[i + 1],
|
||||
// Then, clip off each anchor area by the next area expanded back to original size, so that this smaller anchor region is only where larger wouldnt fit
|
||||
anchor_areas_w_delta_anchor_size[i] = diff(anchor_areas_w_delta_anchor_size[i], expand(anchor_areas_w_delta_anchor_size[i + 1],
|
||||
deltas[i + 1], EXTRA_PERIMETER_OFFSET_PARAMETERS));
|
||||
anchor_areas_w_delta_anchor_size[i] = intersection(anchor_areas_w_delta_anchor_size[i],
|
||||
expand(clipped, deltas[i+1] + 0.1*overhang_flow.scaled_spacing(),
|
||||
EXTRA_PERIMETER_OFFSET_PARAMETERS));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < anchor_areas_w_delta_anchor_size.size(); i++) {
|
||||
inset_anchors = union_(inset_anchors, anchor_areas_w_delta_anchor_size[i]);
|
||||
}
|
||||
|
||||
inset_anchors = opening(inset_anchors, 0.8 * deltas[0], EXTRA_PERIMETER_OFFSET_PARAMETERS);
|
||||
inset_anchors = closing(inset_anchors, 0.8 * deltas[0], EXTRA_PERIMETER_OFFSET_PARAMETERS);
|
||||
inset_anchors = expand(inset_anchors, 0.1*overhang_flow.scaled_width());
|
||||
|
||||
#ifdef EXTRA_PERIM_DEBUG_FILES
|
||||
{
|
||||
@ -901,12 +899,6 @@ std::tuple<std::vector<ExtrusionPaths>, Polygons> generate_extra_perimeters_over
|
||||
|
||||
Polygon anchoring_convex_hull = Geometry::convex_hull(anchoring);
|
||||
double unbridgeable_area = area(diff(real_overhang, {anchoring_convex_hull}));
|
||||
// penalize also holes
|
||||
for (const Polygon &poly : perimeter_polygon) {
|
||||
if (poly.is_clockwise()) { // hole, penalize bridges.
|
||||
unbridgeable_area += std::abs(area(poly));
|
||||
}
|
||||
}
|
||||
|
||||
auto [dir, unsupp_dist] = detect_bridging_direction(real_overhang, anchors);
|
||||
|
||||
@ -920,16 +912,19 @@ std::tuple<std::vector<ExtrusionPaths>, Polygons> generate_extra_perimeters_over
|
||||
for (const Line &line : to_lines(anchoring_convex_hull)) svg.draw(line, "green", scale_(0.15));
|
||||
for (const Line &line : to_lines(anchoring)) svg.draw(line, "yellow", scale_(0.10));
|
||||
for (const Line &line : to_lines(diff_ex(perimeter_polygon, {anchoring_convex_hull}))) svg.draw(line, "black", scale_(0.10));
|
||||
for (const Line &line : to_lines(diff_pl(to_polylines(diff(real_overhang, anchors)), expand(anchors, float(SCALED_EPSILON)))))
|
||||
svg.draw(line, "blue", scale_(0.30));
|
||||
svg.Close();
|
||||
}
|
||||
#endif
|
||||
if (unbridgeable_area < 0.2 * area(real_overhang) && unsupp_dist < total_length(real_overhang) * 0.125) {
|
||||
|
||||
if (unbridgeable_area < 0.2 * area(real_overhang) && unsupp_dist < total_length(real_overhang) * 0.2) {
|
||||
inset_overhang_area_left_unfilled.insert(inset_overhang_area_left_unfilled.end(),overhang_to_cover.begin(),overhang_to_cover.end());
|
||||
perimeter_polygon.clear();
|
||||
} else {
|
||||
// fill the overhang with perimeters
|
||||
int continuation_loops = 2;
|
||||
while (continuation_loops > 0) {
|
||||
while (continuation_loops >= 0) {
|
||||
auto prev = perimeter_polygon;
|
||||
// prepare next perimeter lines
|
||||
Polylines perimeter = intersection_pl(to_polylines(perimeter_polygon), shrinked_overhang_to_cover);
|
||||
|
@ -420,7 +420,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
|
||||
static std::vector<std::string> s_Preset_print_options {
|
||||
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode",
|
||||
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
|
||||
"extra_perimeters", "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "avoid_curled_filament_during_travels", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||
"extra_perimeters", "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||
"seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
||||
"infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
|
||||
@ -429,7 +429,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
|
||||
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
|
||||
"enable_dynamic_overhang_speeds", "dynamic_overhang_speeds", "overhang_steepness_levels",
|
||||
"enable_dynamic_overhang_speeds", "dynamic_overhang_speeds", "overhang_overlap_levels",
|
||||
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
||||
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
||||
|
@ -222,7 +222,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
osteps.emplace_back(posInfill);
|
||||
osteps.emplace_back(posSupportMaterial);
|
||||
steps.emplace_back(psSkirtBrim);
|
||||
} else if (opt_key == "avoid_curled_filament_during_travels") {
|
||||
} else if (opt_key == "avoid_crossing_curled_overhangs") {
|
||||
osteps.emplace_back(posEstimateCurledExtrusions);
|
||||
} else {
|
||||
// for legacy, if we can't handle this option let's invalidate all steps
|
||||
|
@ -222,7 +222,6 @@ public:
|
||||
all_regions.clear();
|
||||
layer_ranges.clear();
|
||||
cached_volume_ids.clear();
|
||||
generated_support_points.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -13,7 +13,7 @@
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
void PrintTryCancel::operator()()
|
||||
void PrintTryCancel::operator()() const
|
||||
{
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
|
@ -340,7 +340,7 @@ class PrintTryCancel
|
||||
{
|
||||
public:
|
||||
// calls print.throw_if_canceled().
|
||||
void operator()();
|
||||
void operator()() const;
|
||||
private:
|
||||
friend PrintBase;
|
||||
PrintTryCancel() = delete;
|
||||
|
@ -400,10 +400,10 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
// Maximum extruder temperature, bumped to 1500 to support printing of glass.
|
||||
const int max_temp = 1500;
|
||||
def = this->add("avoid_curled_filament_during_travels", coBool);
|
||||
def->label = L("Avoid curled filament during travels");
|
||||
def->tooltip = L("Plan travel moves such that the extruder avoids areas where filament may be curled up. "
|
||||
"This is mostly happening on steeper rounded overhangs and may cause crash or borken print. "
|
||||
def = this->add("avoid_crossing_curled_overhangs", coBool);
|
||||
def->label = L("Avoid crossing curled overhangs (Experimental)");
|
||||
def->tooltip = L("Plan travel moves such that the extruder avoids areas where the filament may be curled up. "
|
||||
"This is mostly happening on steeper rounded overhangs and may cause a crash with the nozzle. "
|
||||
"This feature slows down both the print and the G-code generation.");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
@ -536,11 +536,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("overhang_steepness_levels", coPercents);
|
||||
def->full_label = L("Steepness levels of overhangs");
|
||||
def = this->add("overhang_overlap_levels", coPercents);
|
||||
def->full_label = L("Overhang overlap levels");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("Controls overhang steepness, expressed as percentage of overlap of the extrusion with the previous layer. "
|
||||
"Each overhang level then corresponds with the overhang speed below.");
|
||||
def->tooltip = L("Controls overhang levels, expressed as a percentage of overlap of the extrusion with the previous layer - "
|
||||
"100% represents full overlap - no overhang is present, while 0% represents full overhang (floating extrusion). "
|
||||
"Each overhang level then corresponds with the overhang speed below. Speeds for overhang levels in between are "
|
||||
"calculated via linear interpolation."
|
||||
"If you set multiple different speeds for the same overhang level, only the largest speed is used. "
|
||||
);
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
@ -550,7 +554,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("dynamic_overhang_speeds", coFloatsOrPercents);
|
||||
def->full_label = L("Dynamic speed on overhangs");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("This setting controls the speed on the overhang with steepness value above. "
|
||||
def->tooltip = L("This setting controls the speed on the overhang with the overlap value set above. "
|
||||
"The speed of the extrusion is calculated as a linear interpolation of the speeds for higher and lower overlap. "
|
||||
"If set as percentage, the speed is calculated over the external perimeter speed."
|
||||
);
|
||||
def->sidetext = L("mm/s or %");
|
||||
|
@ -565,7 +565,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width))
|
||||
((ConfigOptionFloatOrPercent, external_perimeter_speed))
|
||||
((ConfigOptionBool, enable_dynamic_overhang_speeds))
|
||||
((ConfigOptionPercents, overhang_steepness_levels))
|
||||
((ConfigOptionPercents, overhang_overlap_levels))
|
||||
((ConfigOptionFloatsOrPercents, dynamic_overhang_speeds))
|
||||
((ConfigOptionBool, external_perimeters_first))
|
||||
((ConfigOptionBool, extra_perimeters))
|
||||
@ -732,7 +732,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
PrintConfig,
|
||||
(MachineEnvelopeConfig, GCodeConfig),
|
||||
|
||||
((ConfigOptionBool, avoid_curled_filament_during_travels))
|
||||
((ConfigOptionBool, avoid_crossing_curled_overhangs))
|
||||
((ConfigOptionBool, avoid_crossing_perimeters))
|
||||
((ConfigOptionFloatOrPercent, avoid_crossing_perimeters_max_detour))
|
||||
((ConfigOptionPoints, bed_shape))
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "I18N.hpp"
|
||||
#include "Layer.hpp"
|
||||
#include "MutablePolygon.hpp"
|
||||
#include "PrintBase.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "TreeSupport.hpp"
|
||||
#include "Surface.hpp"
|
||||
@ -420,8 +421,9 @@ void PrintObject::generate_support_spots()
|
||||
BOOST_LOG_TRIVIAL(debug) << "Searching support spots - start";
|
||||
m_print->set_status(75, L("Searching support spots"));
|
||||
if (!this->shared_regions()->generated_support_points.has_value()) {
|
||||
PrintTryCancel cancel_func = m_print->make_try_cancel();
|
||||
SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values};
|
||||
SupportSpotsGenerator::SupportPoints supp_points = SupportSpotsGenerator::full_search(this, params);
|
||||
SupportSpotsGenerator::SupportPoints supp_points = SupportSpotsGenerator::full_search(this, cancel_func, params);
|
||||
this->m_shared_regions->generated_support_points = {this->trafo_centered(), supp_points};
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
@ -454,7 +456,7 @@ void PrintObject::generate_support_material()
|
||||
void PrintObject::estimate_curled_extrusions()
|
||||
{
|
||||
if (this->set_started(posEstimateCurledExtrusions)) {
|
||||
if (this->print()->config().avoid_curled_filament_during_travels) {
|
||||
if (this->print()->config().avoid_crossing_curled_overhangs) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - start";
|
||||
m_print->set_status(88, L("Estimating curled extrusions"));
|
||||
|
||||
@ -463,7 +465,6 @@ void PrintObject::estimate_curled_extrusions()
|
||||
SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values};
|
||||
SupportSpotsGenerator::estimate_supports_malformations(this->support_layers(), support_flow_width, params);
|
||||
SupportSpotsGenerator::estimate_malformations(this->layers(), params);
|
||||
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - end";
|
||||
}
|
||||
@ -749,7 +750,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
|| opt_key == "support_material_interface_speed"
|
||||
|| opt_key == "bridge_speed"
|
||||
|| opt_key == "enable_dynamic_overhang_speeds"
|
||||
|| opt_key == "overhang_steepness_levels"
|
||||
|| opt_key == "overhang_overlap_levels"
|
||||
|| opt_key == "dynamic_overhang_speeds"
|
||||
|| opt_key == "external_perimeter_speed"
|
||||
|| opt_key == "infill_speed"
|
||||
@ -787,10 +788,10 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
|
||||
} else if (step == posPrepareInfill) {
|
||||
invalidated |= this->invalidate_steps({ posInfill, posIroning });
|
||||
} else if (step == posInfill) {
|
||||
invalidated |= this->invalidate_steps({ posIroning });
|
||||
invalidated |= this->invalidate_steps({ posIroning, posSupportSpotsSearch });
|
||||
invalidated |= m_print->invalidate_steps({ psSkirtBrim });
|
||||
} else if (step == posSlice) {
|
||||
invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportMaterial, posEstimateCurledExtrusions });
|
||||
invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportSpotsSearch, posSupportMaterial, posEstimateCurledExtrusions });
|
||||
invalidated |= m_print->invalidate_steps({ psSkirtBrim });
|
||||
m_slicing_params.valid = false;
|
||||
} else if (step == posSupportMaterial) {
|
||||
|
@ -3,23 +3,28 @@
|
||||
#include "ExPolygon.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "ExtrusionEntityCollection.hpp"
|
||||
#include "GCode/ExtrusionProcessor.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "PrintBase.hpp"
|
||||
#include "Tesselate.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include "tbb/parallel_for.h"
|
||||
#include "tbb/blocked_range.h"
|
||||
#include "tbb/blocked_range2d.h"
|
||||
#include "tbb/parallel_reduce.h"
|
||||
#include <algorithm>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "AABBTreeLines.hpp"
|
||||
@ -41,12 +46,14 @@ namespace Slic3r {
|
||||
class ExtrusionLine
|
||||
{
|
||||
public:
|
||||
ExtrusionLine() : a(Vec2f::Zero()), b(Vec2f::Zero()), len(0.0f), origin_entity(nullptr) {}
|
||||
ExtrusionLine(const Vec2f &a, const Vec2f &b, const ExtrusionEntity *origin_entity)
|
||||
: a(a), b(b), len((a - b).norm()), origin_entity(origin_entity)
|
||||
ExtrusionLine() : a(Vec2f::Zero()), b(Vec2f::Zero()), len(0.0), origin_entity(nullptr) {}
|
||||
ExtrusionLine(const Vec2f &a, const Vec2f &b, float len, const ExtrusionEntity *origin_entity)
|
||||
: a(a), b(b), len(len), origin_entity(origin_entity)
|
||||
{}
|
||||
|
||||
float length() { return (a - b).norm(); }
|
||||
ExtrusionLine(const Vec2f &a, const Vec2f &b)
|
||||
: a(a), b(b), len((a-b).norm()), origin_entity(nullptr)
|
||||
{}
|
||||
|
||||
bool is_external_perimeter() const
|
||||
{
|
||||
@ -60,7 +67,8 @@ public:
|
||||
const ExtrusionEntity *origin_entity;
|
||||
|
||||
bool support_point_generated = false;
|
||||
float malformation = 0.0f;
|
||||
float form_quality = 1.0f;
|
||||
float curled_up_height = 0.0f;
|
||||
|
||||
static const constexpr int Dim = 2;
|
||||
using Scalar = Vec2f::Scalar;
|
||||
@ -174,38 +182,12 @@ float get_flow_width(const LayerRegion *region, ExtrusionRole role)
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulator of current extrusion path properties
|
||||
// It remembers unsuported distance and maximum accumulated curvature over that distance.
|
||||
// Used to determine local stability issues (too long bridges, extrusion curves into air)
|
||||
struct ExtrusionPropertiesAccumulator
|
||||
{
|
||||
float distance = 0; // accumulated distance
|
||||
float curvature = 0; // accumulated signed ccw angles
|
||||
float max_curvature = 0; // max absolute accumulated value
|
||||
|
||||
void add_distance(float dist) { distance += dist; }
|
||||
|
||||
void add_angle(float ccw_angle)
|
||||
{
|
||||
curvature += ccw_angle;
|
||||
max_curvature = std::max(max_curvature, std::abs(curvature));
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
distance = 0;
|
||||
curvature = 0;
|
||||
max_curvature = 0;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<ExtrusionLine> to_short_lines(const ExtrusionEntity *e, float length_limit)
|
||||
{
|
||||
assert(!e->is_collection());
|
||||
Polyline pl = e->as_polyline();
|
||||
std::vector<ExtrusionLine> lines;
|
||||
lines.reserve(pl.points.size() * 1.5f);
|
||||
lines.emplace_back(unscaled(pl.points[0]).cast<float>(), unscaled(pl.points[0]).cast<float>(), e);
|
||||
for (int point_idx = 0; point_idx < int(pl.points.size()) - 1; ++point_idx) {
|
||||
Vec2f start = unscaled(pl.points[point_idx]).cast<float>();
|
||||
Vec2f next = unscaled(pl.points[point_idx + 1]).cast<float>();
|
||||
@ -217,87 +199,102 @@ std::vector<ExtrusionLine> to_short_lines(const ExtrusionEntity *e, float length
|
||||
for (int i = 0; i < lines_count; ++i) {
|
||||
Vec2f a(start + v * (i * step_size));
|
||||
Vec2f b(start + v * ((i + 1) * step_size));
|
||||
lines.emplace_back(a, b, e);
|
||||
lines.emplace_back(a, b, (a-b).norm(), e);
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntity *entity,
|
||||
const LayerRegion *layer_region,
|
||||
const LD &prev_layer_lines,
|
||||
const Params ¶ms)
|
||||
float estimate_curled_up_height(
|
||||
const ExtendedPoint &point, float layer_height, float flow_width, float prev_line_curled_height, Params params)
|
||||
{
|
||||
float curled_up_height = 0.0f;
|
||||
if (fabs(point.distance) < 1.5 * flow_width) {
|
||||
curled_up_height = 0.85 * prev_line_curled_height;
|
||||
}
|
||||
if (point.distance > params.malformation_distance_factors.first * flow_width &&
|
||||
point.distance < params.malformation_distance_factors.second * flow_width && point.curvature > -0.1f) {
|
||||
float dist_factor = std::max(point.distance - params.malformation_distance_factors.first * flow_width, 0.01f) /
|
||||
((params.malformation_distance_factors.second - params.malformation_distance_factors.first) * flow_width);
|
||||
|
||||
curled_up_height = layer_height * 2.0f * sqrt(sqrt(dist_factor)) * std::clamp(6.0f * point.curvature, 1.0f, 6.0f);
|
||||
curled_up_height = std::min(curled_up_height, params.max_curled_height_factor * layer_height);
|
||||
}
|
||||
|
||||
return curled_up_height;
|
||||
}
|
||||
|
||||
std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntity *entity,
|
||||
const LayerRegion *layer_region,
|
||||
const LD &prev_layer_lines,
|
||||
const AABBTreeLines::LinesDistancer<Linef> &prev_layer_boundary,
|
||||
const Params ¶ms)
|
||||
{
|
||||
if (entity->is_collection()) {
|
||||
std::vector<ExtrusionLine> checked_lines_out;
|
||||
checked_lines_out.reserve(prev_layer_lines.get_lines().size() / 3);
|
||||
for (const auto *e : static_cast<const ExtrusionEntityCollection *>(entity)->entities) {
|
||||
auto tmp = check_extrusion_entity_stability(e, layer_region, prev_layer_lines, params);
|
||||
auto tmp = check_extrusion_entity_stability(e, layer_region, prev_layer_lines, prev_layer_boundary, params);
|
||||
checked_lines_out.insert(checked_lines_out.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
return checked_lines_out;
|
||||
} else { // single extrusion path, with possible varying parameters
|
||||
if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) { return {}; }
|
||||
|
||||
std::vector<ExtrusionLine> lines = to_short_lines(entity, params.bridge_distance);
|
||||
|
||||
ExtrusionPropertiesAccumulator bridging_acc{};
|
||||
ExtrusionPropertiesAccumulator malformation_acc{};
|
||||
bridging_acc.add_distance(params.bridge_distance + 1.0f);
|
||||
const float flow_width = get_flow_width(layer_region, entity->role());
|
||||
float min_malformation_dist = flow_width - params.malformation_overlap_factor.first * flow_width;
|
||||
float max_malformation_dist = flow_width - params.malformation_overlap_factor.second * flow_width;
|
||||
|
||||
for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) {
|
||||
ExtrusionLine ¤t_line = lines[line_idx];
|
||||
if (line_idx + 1 == lines.size() && current_line.b != lines.begin()->a) {
|
||||
bridging_acc.add_distance(params.bridge_distance + 1.0f);
|
||||
}
|
||||
float curr_angle = 0;
|
||||
if (line_idx + 1 < lines.size()) {
|
||||
const Vec2f v1 = current_line.b - current_line.a;
|
||||
const Vec2f v2 = lines[line_idx + 1].b - lines[line_idx + 1].a;
|
||||
curr_angle = angle(v1, v2);
|
||||
}
|
||||
bridging_acc.add_angle(curr_angle);
|
||||
// malformation in concave angles does not happen
|
||||
malformation_acc.add_angle(std::max(0.0f, curr_angle));
|
||||
if (curr_angle < -20.0 * PI / 180.0) { malformation_acc.reset(); }
|
||||
|
||||
auto [dist_from_prev_layer, nearest_line_idx, nearest_point] = prev_layer_lines.signed_distance_from_lines_extra(current_line.b);
|
||||
if (dist_from_prev_layer < flow_width) {
|
||||
bridging_acc.reset();
|
||||
} else {
|
||||
bridging_acc.add_distance(current_line.len);
|
||||
// if unsupported distance is larger than bridge distance linearly decreased by curvature, enforce supports.
|
||||
bool in_layer_dist_condition = bridging_acc.distance >
|
||||
params.bridge_distance / (1.0f + (bridging_acc.max_curvature *
|
||||
params.bridge_distance_decrease_by_curvature_factor / PI));
|
||||
bool between_layers_condition = dist_from_prev_layer > max_malformation_dist;
|
||||
if (in_layer_dist_condition && between_layers_condition) {
|
||||
current_line.support_point_generated = true;
|
||||
bridging_acc.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// malformation propagation from below
|
||||
if (fabs(dist_from_prev_layer) < 2.0f * flow_width) {
|
||||
const ExtrusionLine &nearest_line = prev_layer_lines.get_line(nearest_line_idx);
|
||||
current_line.malformation += 0.85 * nearest_line.malformation;
|
||||
}
|
||||
// current line maformation
|
||||
if (dist_from_prev_layer > min_malformation_dist && dist_from_prev_layer < max_malformation_dist) {
|
||||
float factor = std::abs(dist_from_prev_layer - (max_malformation_dist + min_malformation_dist) * 0.5) /
|
||||
(max_malformation_dist - min_malformation_dist);
|
||||
malformation_acc.add_distance(current_line.len);
|
||||
current_line.malformation += layer_region->layer()->height * factor * (2.0f + 3.0f * (malformation_acc.max_curvature / PI));
|
||||
current_line.malformation = std::min(current_line.malformation,
|
||||
float(layer_region->layer()->height * params.max_malformation_factor));
|
||||
} else {
|
||||
malformation_acc.reset();
|
||||
}
|
||||
if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) {
|
||||
return {};
|
||||
}
|
||||
return lines;
|
||||
|
||||
const float flow_width = get_flow_width(layer_region, entity->role());
|
||||
|
||||
std::vector<ExtendedPoint> annotated_points = estimate_points_properties<true, true, false, false>(entity->as_polyline().points,
|
||||
prev_layer_lines, flow_width,
|
||||
params.bridge_distance);
|
||||
|
||||
std::vector<ExtrusionLine> lines_out;
|
||||
lines_out.reserve(annotated_points.size());
|
||||
float bridged_distance = annotated_points.front().position != annotated_points.back().position ? (params.bridge_distance + 1.0f) :
|
||||
0.0f;
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
ExtendedPoint &curr_point = annotated_points[i];
|
||||
float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f;
|
||||
ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast<float>() : curr_point.position.cast<float>(),
|
||||
curr_point.position.cast<float>(), line_len, entity};
|
||||
|
||||
const ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ?
|
||||
prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) :
|
||||
ExtrusionLine{};
|
||||
|
||||
float sign = (prev_layer_boundary.distance_from_lines<true>(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
|
||||
curr_point.distance *= sign;
|
||||
|
||||
float max_bridge_len = params.bridge_distance /
|
||||
((1.0f + std::abs(curr_point.curvature)) * (1.0f + std::abs(curr_point.curvature)));
|
||||
|
||||
if (curr_point.distance > 2.0f * flow_width) {
|
||||
line_out.form_quality = 0.8f;
|
||||
bridged_distance += line_len;
|
||||
if (bridged_distance > max_bridge_len) {
|
||||
line_out.support_point_generated = true;
|
||||
bridged_distance = 0.0f;
|
||||
}
|
||||
} else if (curr_point.distance > flow_width * (1.0 + std::clamp(curr_point.curvature, -0.30f, 0.20f))) {
|
||||
bridged_distance += line_len;
|
||||
line_out.form_quality = nearest_prev_layer_line.form_quality - 0.3f;
|
||||
if (line_out.form_quality < 0 && bridged_distance > max_bridge_len) {
|
||||
line_out.support_point_generated = true;
|
||||
line_out.form_quality = 0.5f;
|
||||
bridged_distance = 0.0f;
|
||||
}
|
||||
} else {
|
||||
bridged_distance = 0.0f;
|
||||
}
|
||||
|
||||
line_out.curled_up_height = estimate_curled_up_height(curr_point, layer_region->layer()->height, flow_width,
|
||||
nearest_prev_layer_line.curled_up_height, params);
|
||||
|
||||
lines_out.push_back(line_out);
|
||||
}
|
||||
|
||||
return lines_out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,7 +471,7 @@ public:
|
||||
float movement_force = params.max_acceleration * mass;
|
||||
|
||||
float extruder_conflict_force = params.standard_extruder_conflict_force +
|
||||
std::min(extruded_line.malformation, 1.0f) * params.malformations_additive_conflict_extruder_force;
|
||||
std::min(extruded_line.curled_up_height, 1.0f) * params.malformations_additive_conflict_extruder_force;
|
||||
|
||||
// section for bed calculations
|
||||
{
|
||||
@ -512,7 +509,8 @@ public:
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: bed_movement_arm: " << bed_movement_arm;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: bed_movement_torque: " << bed_movement_torque;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: bed_conflict_torque_arm: " << bed_conflict_torque_arm;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: extruded_line.malformation: " << extruded_line.malformation;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: extruded_line.curled_up_height: " << extruded_line.curled_up_height;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: extruded_line.form_quality: " << extruded_line.form_quality;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: extruder_conflict_force: " << extruder_conflict_force;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: bed_extruder_conflict_torque: " << bed_extruder_conflict_torque;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: total_torque: " << bed_total_torque << " layer_z: " << layer_z;
|
||||
@ -546,7 +544,7 @@ public:
|
||||
float conn_total_torque = conn_movement_torque + conn_extruder_conflict_torque + conn_weight_torque - conn_yield_torque;
|
||||
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
BOOST_LOG_TRIVIAL(debug) << "bed_centroid: " << conn_centroid.x() << " " << conn_centroid.y() << " " << conn_centroid.z();
|
||||
BOOST_LOG_TRIVIAL(debug) << "conn_centroid: " << conn_centroid.x() << " " << conn_centroid.y() << " " << conn_centroid.z();
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: conn_yield_torque: " << conn_yield_torque;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: conn_weight_arm: " << conn_weight_arm;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SSG: conn_weight_torque: " << conn_weight_torque;
|
||||
@ -580,7 +578,7 @@ std::tuple<ObjectPart, float> build_object_part_from_slice(const LayerSlice &sli
|
||||
new_object_part.volume += volume;
|
||||
new_object_part.volume_centroid_accumulator += to_3d(Vec2f((line.a + line.b) / 2.0f), slice_z) * volume;
|
||||
|
||||
if (l->id() == 0) { // first layer
|
||||
if (l->bottom_z() < EPSILON) { // layer attached on bed
|
||||
float sticking_area = line.len * flow_width;
|
||||
new_object_part.sticking_area += sticking_area;
|
||||
Vec2f middle = Vec2f((line.a + line.b) / 2.0f);
|
||||
@ -664,7 +662,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
SupportPoints check_stability(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms)
|
||||
{
|
||||
SupportPoints supp_points{};
|
||||
SupportGridFilter supports_presence_grid(po, params.min_distance_between_support_points);
|
||||
@ -677,6 +675,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
std::unordered_map<size_t, SliceConnection> next_slice_idx_to_weakest_connection;
|
||||
|
||||
for (size_t layer_idx = 0; layer_idx < po->layer_count(); ++layer_idx) {
|
||||
cancel_func();
|
||||
const Layer *layer = po->get_layer(layer_idx);
|
||||
float bottom_z = layer->bottom_z();
|
||||
auto create_support_point_position = [bottom_z](const Vec2f &layer_pos) { return Vec3f{layer_pos.x(), layer_pos.y(), bottom_z}; };
|
||||
@ -756,6 +755,15 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
||||
ObjectPart &part = active_object_parts.access(prev_slice_idx_to_object_part_mapping[slice_idx]);
|
||||
SliceConnection &weakest_conn = prev_slice_idx_to_weakest_connection[slice_idx];
|
||||
|
||||
std::vector<Linef> boundary_lines;
|
||||
for (const auto &link : slice.overlaps_below) {
|
||||
auto ls = to_unscaled_linesf({layer->lower_layer->lslices[link.slice_idx]});
|
||||
boundary_lines.insert(boundary_lines.end(), ls.begin(), ls.end());
|
||||
}
|
||||
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary{std::move(boundary_lines)};
|
||||
|
||||
|
||||
std::vector<ExtrusionLine> current_slice_ext_perims_lines{};
|
||||
current_slice_ext_perims_lines.reserve(prev_layer_ext_perim_lines.get_lines().size() / layer->lslices_ex.size());
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
@ -765,14 +773,17 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
// and the support presence grid and add the point to the issues.
|
||||
auto reckon_new_support_point = [&part, &weakest_conn, &supp_points, &supports_presence_grid, ¶ms,
|
||||
&layer_idx](const Vec3f &support_point, float force, const Vec2f &dir) {
|
||||
if (supports_presence_grid.position_taken(support_point) || layer_idx <= 1) { return; }
|
||||
if ((supports_presence_grid.position_taken(support_point) && force > 0) || layer_idx <= 1) {
|
||||
return;
|
||||
}
|
||||
float area = params.support_points_interface_radius * params.support_points_interface_radius * float(PI);
|
||||
part.add_support_point(support_point, area);
|
||||
|
||||
float radius = params.support_points_interface_radius;
|
||||
supp_points.emplace_back(support_point, force, radius, dir);
|
||||
supports_presence_grid.take_position(support_point);
|
||||
|
||||
if (force > 0) {
|
||||
supports_presence_grid.take_position(support_point);
|
||||
}
|
||||
if (weakest_conn.area > EPSILON) { // Do not add it to the weakest connection if it is not valid - does not exist
|
||||
weakest_conn.area += area;
|
||||
weakest_conn.centroid_accumulator += support_point * area;
|
||||
@ -791,7 +802,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
const ExtrusionEntity *entity = fill_region->fills().entities[fill_idx];
|
||||
if (entity->role() == erBridgeInfill) {
|
||||
for (const ExtrusionLine &bridge :
|
||||
check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines, params)) {
|
||||
check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines,prev_layer_boundary, params)) {
|
||||
if (bridge.support_point_generated) {
|
||||
reckon_new_support_point(create_support_point_position(bridge.b), -EPSILON, Vec2f::Zero());
|
||||
}
|
||||
@ -804,7 +815,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
for (const auto &perimeter_idx : island.perimeters) {
|
||||
const ExtrusionEntity *entity = perimeter_region->perimeters().entities[perimeter_idx];
|
||||
std::vector<ExtrusionLine> perims = check_extrusion_entity_stability(entity, perimeter_region,
|
||||
prev_layer_ext_perim_lines, params);
|
||||
prev_layer_ext_perim_lines,prev_layer_boundary, params);
|
||||
for (const ExtrusionLine &perim : perims) {
|
||||
if (perim.support_point_generated) {
|
||||
reckon_new_support_point(create_support_point_position(perim.b), -EPSILON, Vec2f::Zero());
|
||||
@ -818,13 +829,13 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
|
||||
|
||||
for (const ExtrusionLine &line : current_slice_ext_perims_lines) {
|
||||
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.malformation < 0.3f) || line.len == 0) {
|
||||
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < 0.3f) || line.len < EPSILON) {
|
||||
unchecked_dist += line.len;
|
||||
} else {
|
||||
unchecked_dist = line.len;
|
||||
Vec2f pivot_site_search_point = Vec2f(line.b + (line.b - line.a).normalized() * 300.0f);
|
||||
auto [dist, nidx,
|
||||
nearest_point] = current_slice_lines_distancer.signed_distance_from_lines_extra(pivot_site_search_point);
|
||||
nearest_point] = current_slice_lines_distancer.distance_from_lines_extra<false>(pivot_site_search_point);
|
||||
Vec3f support_point = create_support_point_position(nearest_point);
|
||||
auto force = part.is_stable_while_extruding(weakest_conn, line, support_point, bottom_z, params);
|
||||
if (force > 0) { reckon_new_support_point(support_point, force, (line.b - line.a).normalized()); }
|
||||
@ -839,7 +850,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
void debug_export(Issues issues, std::string file_name)
|
||||
void debug_export(SupportPoints support_points, std::string file_name)
|
||||
{
|
||||
Slic3r::CNumericLocalesSetter locales_setter;
|
||||
{
|
||||
@ -849,13 +860,13 @@ void debug_export(Issues issues, std::string file_name)
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < issues.support_points.size(); ++i) {
|
||||
if (issues.support_points[i].force <= 0) {
|
||||
fprintf(fp, "v %f %f %f %f %f %f\n", issues.support_points[i].position(0), issues.support_points[i].position(1),
|
||||
issues.support_points[i].position(2), 0.0, 1.0, 0.0);
|
||||
for (size_t i = 0; i < support_points.size(); ++i) {
|
||||
if (support_points[i].force <= 0) {
|
||||
fprintf(fp, "v %f %f %f %f %f %f\n", support_points[i].position(0), support_points[i].position(1),
|
||||
support_points[i].position(2), 0.0, 1.0, 0.0);
|
||||
} else {
|
||||
fprintf(fp, "v %f %f %f %f %f %f\n", issues.support_points[i].position(0), issues.support_points[i].position(1),
|
||||
issues.support_points[i].position(2), 1.0, 0.0, 0.0);
|
||||
fprintf(fp, "v %f %f %f %f %f %f\n", support_points[i].position(0), support_points[i].position(1),
|
||||
support_points[i].position(2), 1.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -867,113 +878,84 @@ void debug_export(Issues issues, std::string file_name)
|
||||
// std::vector<size_t> quick_search(const PrintObject *po, const Params ¶ms) {
|
||||
// return {};
|
||||
// }
|
||||
SupportPoints full_search(const PrintObject *po, const Params ¶ms)
|
||||
SupportPoints full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms)
|
||||
{
|
||||
SupportPoints supp_points = check_stability(po, params);
|
||||
SupportPoints supp_points = check_stability(po, cancel_func, params);
|
||||
#ifdef DEBUG_FILES
|
||||
debug_export(issues, "issues");
|
||||
debug_export(supp_points, "issues");
|
||||
#endif
|
||||
|
||||
return supp_points;
|
||||
}
|
||||
|
||||
|
||||
struct LayerCurlingEstimator
|
||||
{
|
||||
LD prev_layer_lines;
|
||||
Params params;
|
||||
std::function<float(const ExtrusionLine &)> flow_width_getter;
|
||||
|
||||
LayerCurlingEstimator(std::function<float(const ExtrusionLine &)> flow_width_getter, const Params ¶ms)
|
||||
: flow_width_getter(flow_width_getter), params(params)
|
||||
{}
|
||||
|
||||
void estimate_curling(std::vector<ExtrusionLine> &extrusion_lines, Layer *l)
|
||||
{
|
||||
ExtrusionPropertiesAccumulator malformation_acc{};
|
||||
for (size_t line_idx = 0; line_idx < extrusion_lines.size(); ++line_idx) {
|
||||
ExtrusionLine ¤t_line = extrusion_lines[line_idx];
|
||||
|
||||
float flow_width = flow_width_getter(current_line);
|
||||
|
||||
float min_malformation_dist = flow_width - params.malformation_overlap_factor.first * flow_width;
|
||||
float max_malformation_dist = flow_width - params.malformation_overlap_factor.second * flow_width;
|
||||
|
||||
float curr_angle = 0;
|
||||
if (line_idx + 1 < extrusion_lines.size()) {
|
||||
const Vec2f v1 = current_line.b - current_line.a;
|
||||
const Vec2f v2 = extrusion_lines[line_idx + 1].b - extrusion_lines[line_idx + 1].a;
|
||||
curr_angle = angle(v1, v2);
|
||||
}
|
||||
// malformation in concave angles does not happen
|
||||
malformation_acc.add_angle(std::max(0.0f, curr_angle));
|
||||
if (curr_angle < -20.0 * PI / 180.0) { malformation_acc.reset(); }
|
||||
|
||||
auto [dist_from_prev_layer, nearest_line_idx, nearest_point] = prev_layer_lines.signed_distance_from_lines_extra(current_line.b);
|
||||
|
||||
if (fabs(dist_from_prev_layer) < 2.0f * flow_width) {
|
||||
const ExtrusionLine &nearest_line = prev_layer_lines.get_line(nearest_line_idx);
|
||||
current_line.malformation += 0.9 * nearest_line.malformation;
|
||||
}
|
||||
if (dist_from_prev_layer > min_malformation_dist && dist_from_prev_layer < max_malformation_dist) {
|
||||
float factor = 0.5f + 0.5f * std::abs(dist_from_prev_layer - (max_malformation_dist + min_malformation_dist) * 0.5) /
|
||||
(max_malformation_dist - min_malformation_dist);
|
||||
malformation_acc.add_distance(current_line.len);
|
||||
current_line.malformation += l->height * factor * (1.5f + 3.0f * (malformation_acc.max_curvature / PI));
|
||||
current_line.malformation = std::min(current_line.malformation, float(l->height * params.max_malformation_factor));
|
||||
} else {
|
||||
malformation_acc.reset();
|
||||
}
|
||||
}
|
||||
|
||||
for (const ExtrusionLine &line : extrusion_lines) {
|
||||
if (line.malformation > 0.3f) { l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)}); }
|
||||
}
|
||||
prev_layer_lines = LD(extrusion_lines);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void estimate_supports_malformations(SupportLayerPtrs &layers, float supports_flow_width, const Params ¶ms)
|
||||
void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width, const Params ¶ms)
|
||||
{
|
||||
#ifdef DEBUG_FILES
|
||||
FILE *debug_file = boost::nowide::fopen(debug_out_path("supports_malformations.obj").c_str(), "w");
|
||||
FILE *full_file = boost::nowide::fopen(debug_out_path("supports_full.obj").c_str(), "w");
|
||||
#endif
|
||||
auto flow_width_getter = [=](const ExtrusionLine& l) {
|
||||
return supports_flow_width;
|
||||
};
|
||||
|
||||
LayerCurlingEstimator lce{flow_width_getter, params};
|
||||
AABBTreeLines::LinesDistancer<ExtrusionLine> prev_layer_lines{};
|
||||
|
||||
for (SupportLayer *l : layers) {
|
||||
std::vector<ExtrusionLine> extrusion_lines;
|
||||
std::vector<ExtrusionLine> current_layer_lines;
|
||||
|
||||
for (const ExtrusionEntity *extrusion : l->support_fills.flatten().entities) {
|
||||
Polyline pl = extrusion->as_polyline();
|
||||
Polygon pol(pl.points);
|
||||
Polygon pol(pl.points);
|
||||
pol.make_counter_clockwise();
|
||||
pl = pol.split_at_first_point();
|
||||
for (int point_idx = 0; point_idx < int(pl.points.size() - 1); ++point_idx) {
|
||||
Vec2f start = unscaled(pl.points[point_idx]).cast<float>();
|
||||
Vec2f next = unscaled(pl.points[point_idx + 1]).cast<float>();
|
||||
ExtrusionLine line{start, next, extrusion};
|
||||
extrusion_lines.push_back(line);
|
||||
|
||||
auto annotated_points = estimate_points_properties<true, true, false, false>(pol.points, prev_layer_lines, flow_width);
|
||||
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
ExtendedPoint &curr_point = annotated_points[i];
|
||||
float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f;
|
||||
ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast<float>() : curr_point.position.cast<float>(),
|
||||
curr_point.position.cast<float>(), line_len, extrusion};
|
||||
|
||||
const ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ?
|
||||
prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) :
|
||||
ExtrusionLine{};
|
||||
|
||||
Vec2f v1 = (nearest_prev_layer_line.b - nearest_prev_layer_line.a);
|
||||
Vec2f v2 = (curr_point.position.cast<float>() - nearest_prev_layer_line.a);
|
||||
auto d = (v1.x() * v2.y()) - (v1.y() * v2.x());
|
||||
if (d > 0) {
|
||||
curr_point.distance *= -1.0f;
|
||||
}
|
||||
|
||||
line_out.curled_up_height = estimate_curled_up_height(curr_point, l->height, flow_width,
|
||||
nearest_prev_layer_line.curled_up_height, params);
|
||||
|
||||
current_layer_lines.push_back(line_out);
|
||||
}
|
||||
}
|
||||
|
||||
lce.estimate_curling(extrusion_lines, l);
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
if (line.curled_up_height > 0.3f) {
|
||||
l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)});
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
for (const ExtrusionLine &line : extrusion_lines) {
|
||||
if (line.malformation > 0.3f) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_malformation_factor, line.malformation);
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
if (line.curled_up_height > 0.3f) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
|
||||
fprintf(debug_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
|
||||
}
|
||||
}
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
|
||||
fprintf(full_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
prev_layer_lines = LD{current_layer_lines};
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
fclose(debug_file);
|
||||
fclose(full_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -981,52 +963,71 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms)
|
||||
{
|
||||
#ifdef DEBUG_FILES
|
||||
FILE *debug_file = boost::nowide::fopen(debug_out_path("object_malformations.obj").c_str(), "w");
|
||||
FILE *full_file = boost::nowide::fopen(debug_out_path("object_full.obj").c_str(), "w");
|
||||
#endif
|
||||
auto flow_width_getter = [](const ExtrusionLine &l) { return 0.0; };
|
||||
LayerCurlingEstimator lce{flow_width_getter, params};
|
||||
|
||||
LD prev_layer_lines{};
|
||||
|
||||
for (Layer *l : layers) {
|
||||
if (l->regions().empty()) {
|
||||
continue;
|
||||
}
|
||||
struct Visitor {
|
||||
Visitor(const Params ¶ms) : params(params) {}
|
||||
void recursive_do(const ExtrusionEntityCollection &collection, const LayerRegion *region) {
|
||||
for (const ExtrusionEntity* entity : collection.entities)
|
||||
if (entity->is_collection())
|
||||
this->recursive_do(*static_cast<const ExtrusionEntityCollection*>(entity), region);
|
||||
else {
|
||||
append(extrusion_lines, to_short_lines(entity, params.bridge_distance));
|
||||
extrusions_widths.emplace(entity, get_flow_width(region, entity->role()));
|
||||
}
|
||||
std::vector<Linef> boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector<Linef>();
|
||||
AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary{std::move(boundary_lines)};
|
||||
std::vector<ExtrusionLine> current_layer_lines;
|
||||
for (const LayerRegion *layer_region : l->regions()) {
|
||||
for (const ExtrusionEntity *extrusion : layer_region->perimeters().flatten().entities) {
|
||||
Points extrusion_pts;
|
||||
extrusion->collect_points(extrusion_pts);
|
||||
float flow_width = get_flow_width(layer_region, extrusion->role());
|
||||
auto annotated_points = estimate_points_properties<true, false, false, false>(extrusion_pts, prev_layer_lines, flow_width,
|
||||
params.bridge_distance);
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
ExtendedPoint &curr_point = annotated_points[i];
|
||||
float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f;
|
||||
ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast<float>() : curr_point.position.cast<float>(),
|
||||
curr_point.position.cast<float>(), line_len, extrusion};
|
||||
|
||||
const ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ?
|
||||
prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) :
|
||||
ExtrusionLine{};
|
||||
|
||||
float sign = (prev_layer_boundary.distance_from_lines<true>(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f :
|
||||
1.0f;
|
||||
curr_point.distance *= sign;
|
||||
|
||||
line_out.curled_up_height = estimate_curled_up_height(curr_point, layer_region->layer()->height, flow_width,
|
||||
nearest_prev_layer_line.curled_up_height, params);
|
||||
|
||||
current_layer_lines.push_back(line_out);
|
||||
}
|
||||
}
|
||||
const Params ¶ms;
|
||||
std::unordered_map<const ExtrusionEntity*, float> extrusions_widths;
|
||||
std::vector<ExtrusionLine> extrusion_lines;
|
||||
} visitor(params);
|
||||
}
|
||||
|
||||
for (const LayerRegion *region : l->regions())
|
||||
visitor.recursive_do(region->perimeters(), region);
|
||||
|
||||
lce.flow_width_getter = [&](const ExtrusionLine &l) { return visitor.extrusions_widths[l.origin_entity]; };
|
||||
|
||||
lce.estimate_curling(visitor.extrusion_lines, l);
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
if (line.curled_up_height > 0.3f) {
|
||||
l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)});
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
for (const ExtrusionLine &line : extrusion_lines) {
|
||||
if (line.malformation > 0.3f) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_malformation_factor, line.malformation);
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
if (line.curled_up_height > 0.3f) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
|
||||
fprintf(debug_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
|
||||
}
|
||||
}
|
||||
for (const ExtrusionLine &line : current_layer_lines) {
|
||||
Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
|
||||
fprintf(full_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
prev_layer_lines = LD{current_layer_lines};
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FILES
|
||||
fclose(debug_file);
|
||||
fclose(full_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
} //SupportableIssues End
|
||||
}
|
||||
|
||||
} // namespace SupportSpotsGenerator
|
||||
} // namespace Slic3r
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Layer.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "PrintBase.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <vector>
|
||||
|
||||
@ -22,19 +23,20 @@ struct Params {
|
||||
filament_type = std::string("PLA");
|
||||
} else {
|
||||
filament_type = filament_types[0];
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< "SupportSpotsGenerator: applying filament type: " << filament_type;
|
||||
}
|
||||
}
|
||||
|
||||
// the algorithm should use the following units for all computations: distance [mm], mass [g], time [s], force [g*mm/s^2]
|
||||
const float bridge_distance = 12.0f; //mm
|
||||
const float bridge_distance_decrease_by_curvature_factor = 5.0f; // allowed bridge distance = bridge_distance / (1 + this factor * (curvature / PI) )
|
||||
const std::pair<float,float> malformation_overlap_factor = std::pair<float, float> { 0.50, -0.1 };
|
||||
const float max_malformation_factor = 10.0f;
|
||||
const std::pair<float,float> malformation_distance_factors = std::pair<float, float> { 0.4, 1.2 };
|
||||
const float max_curled_height_factor = 10.0f;
|
||||
|
||||
const float min_distance_between_support_points = 3.0f; //mm
|
||||
const float support_points_interface_radius = 1.5f; // mm
|
||||
const float connections_min_considerable_area = 1.5f; //mm^2
|
||||
const float min_distance_to_allow_local_supports = 2.0f; //mm
|
||||
const float min_distance_to_allow_local_supports = 1.0f; //mm
|
||||
|
||||
std::string filament_type;
|
||||
const float gravity_constant = 9806.65f; // mm/s^2; gravity acceleration on Earth's surface, algorithm assumes that printer is in upwards position.
|
||||
@ -42,7 +44,7 @@ struct Params {
|
||||
const double filament_density = 1.25e-3f; // g/mm^3 ; Common filaments are very lightweight, so precise number is not that important
|
||||
const double material_yield_strength = 33.0f * 1e6f; // (g*mm/s^2)/mm^2; 33 MPa is yield strength of ABS, which has the lowest yield strength from common materials.
|
||||
const float standard_extruder_conflict_force = 20.0f * gravity_constant; // force that can occasionally push the model due to various factors (filament leaks, small curling, ... );
|
||||
const float malformations_additive_conflict_extruder_force = 300.0f * gravity_constant; // for areas with possible high layered curled filaments
|
||||
const float malformations_additive_conflict_extruder_force = 100.0f * gravity_constant; // for areas with possible high layered curled filaments
|
||||
|
||||
// MPa * 1e^6 = (g*mm/s^2)/mm^2 = g/(mm*s^2); yield strength of the bed surface
|
||||
double get_bed_adhesion_yield_strength() const {
|
||||
@ -76,7 +78,7 @@ struct Malformations {
|
||||
};
|
||||
|
||||
// std::vector<size_t> quick_search(const PrintObject *po, const Params ¶ms);
|
||||
SupportPoints full_search(const PrintObject *po, const Params ¶ms);
|
||||
SupportPoints full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms);
|
||||
|
||||
void estimate_supports_malformations(std::vector<SupportLayer*> &layers, float supports_flow_width, const Params ¶ms);
|
||||
void estimate_malformations(std::vector<Layer*> &layers, const Params ¶ms);
|
||||
|
@ -221,11 +221,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||
bool have_perimeters = config->opt_int("perimeters") > 0;
|
||||
for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||
"seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds", "overhang_steepness_levels", "dynamic_overhang_speeds" })
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds", "overhang_overlap_levels", "dynamic_overhang_speeds" })
|
||||
toggle_field(el, have_perimeters);
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
toggle_field("overhang_steepness_levels#" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||
toggle_field("overhang_overlap_levels#" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||
toggle_field("dynamic_overhang_speeds#" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||
}
|
||||
|
||||
@ -321,8 +321,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||
"wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" })
|
||||
toggle_field(el, have_wipe_tower);
|
||||
|
||||
toggle_field("avoid_curled_filament_during_travels", !config->opt_bool("avoid_crossing_perimeters"));
|
||||
toggle_field("avoid_crossing_perimeters", !config->opt_bool("avoid_curled_filament_during_travels"));
|
||||
toggle_field("avoid_crossing_curled_overhangs", !config->opt_bool("avoid_crossing_perimeters"));
|
||||
toggle_field("avoid_crossing_perimeters", !config->opt_bool("avoid_crossing_curled_overhangs"));
|
||||
|
||||
bool have_avoid_crossing_perimeters = config->opt_bool("avoid_crossing_perimeters");
|
||||
toggle_field("avoid_crossing_perimeters_max_detour", have_avoid_crossing_perimeters);
|
||||
|
@ -497,18 +497,24 @@ void GLGizmoFdmSupports::update_from_model_object()
|
||||
|
||||
bool GLGizmoFdmSupports::has_backend_supports()
|
||||
{
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
if (! mo) {
|
||||
const ModelObject *mo = m_c->selection_info()->model_object();
|
||||
if (!mo) {
|
||||
waiting_for_autogenerated_supports = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// find PrintObject with this ID
|
||||
for (const PrintObject* po : m_parent.fff_print()->objects()) {
|
||||
bool done = false;
|
||||
for (const PrintObject *po : m_parent.fff_print()->objects()) {
|
||||
if (po->model_object()->id() == mo->id())
|
||||
return po->is_step_done(posSupportSpotsSearch);
|
||||
done = po->is_step_done(posSupportSpotsSearch);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (!done && !wxGetApp().plater()->is_background_process_update_scheduled()) {
|
||||
waiting_for_autogenerated_supports = false;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::reslice_FDM_supports(bool postpone_error_messages) const {
|
||||
|
@ -1425,7 +1425,7 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("extra_perimeters", category_path + "extra-perimeters-if-needed");
|
||||
optgroup->append_single_option_line("extra_perimeters_on_overhangs", category_path + "extra-perimeters-on-overhangs");
|
||||
optgroup->append_single_option_line("ensure_vertical_shell_thickness", category_path + "ensure-vertical-shell-thickness");
|
||||
optgroup->append_single_option_line("avoid_curled_filament_during_travels", category_path + "avoid-curled-filament-during-travels");
|
||||
optgroup->append_single_option_line("avoid_crossing_curled_overhangs", category_path + "avoid-crossing-curled-overhangs");
|
||||
optgroup->append_single_option_line("avoid_crossing_perimeters", category_path + "avoid-crossing-perimeters");
|
||||
optgroup->append_single_option_line("avoid_crossing_perimeters_max_detour", category_path + "avoid_crossing_perimeters_max_detour");
|
||||
optgroup->append_single_option_line("thin_walls", category_path + "detect-thin-walls");
|
||||
@ -1548,7 +1548,7 @@ void TabPrint::build()
|
||||
optgroup->append_line(line);
|
||||
};
|
||||
optgroup->append_single_option_line("enable_dynamic_overhang_speeds");
|
||||
append_option_line(optgroup,"overhang_steepness_levels");
|
||||
append_option_line(optgroup,"overhang_overlap_levels");
|
||||
append_option_line(optgroup,"dynamic_overhang_speeds");
|
||||
|
||||
optgroup = page->new_optgroup(L("Speed for non-print moves"));
|
||||
|
Loading…
Reference in New Issue
Block a user