This commit is contained in:
Filip Sykala - NTB T15p 2023-01-11 17:19:24 +01:00
commit a5822800b9
20 changed files with 411 additions and 349 deletions

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 &section : 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());

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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",

View File

@ -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

View File

@ -222,7 +222,6 @@ public:
all_regions.clear();
layer_ranges.clear();
cached_volume_ids.clear();
generated_support_points.reset();
}
private:

View File

@ -13,7 +13,7 @@
namespace Slic3r
{
void PrintTryCancel::operator()()
void PrintTryCancel::operator()() const
{
m_print->throw_if_canceled();
}

View File

@ -340,7 +340,7 @@ class PrintTryCancel
{
public:
// calls print.throw_if_canceled().
void operator()();
void operator()() const;
private:
friend PrintBase;
PrintTryCancel() = delete;

View File

@ -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 %");

View File

@ -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))

View File

@ -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) {

View File

@ -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 &params)
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 &params)
{
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 &current_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 &params)
SupportPoints check_stability(const PrintObject *po, const PrintTryCancel& cancel_func, const Params &params)
{
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 &params)
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 &params)
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 &params)
// 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, &params,
&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 &params)
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 &params)
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 &params)
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 &params)
}
#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 &params) {
// return {};
// }
SupportPoints full_search(const PrintObject *po, const Params &params)
SupportPoints full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params &params)
{
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 &params)
: 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 &current_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 &params)
void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width, const Params &params)
{
#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 &params)
{
#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 &params) : 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 &params;
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

View File

@ -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 &params);
SupportPoints full_search(const PrintObject *po, const Params &params);
SupportPoints full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params &params);
void estimate_supports_malformations(std::vector<SupportLayer*> &layers, float supports_flow_width, const Params &params);
void estimate_malformations(std::vector<Layer*> &layers, const Params &params);

View File

@ -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);

View File

@ -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 {

View File

@ -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"));