Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::SupportSpotsGenerator Namespace Reference

Classes

class  ActiveObjectParts
 
struct  Malformations
 
class  ObjectPart
 
struct  Params
 
struct  PartialObject
 
struct  SliceConnection
 
struct  SupportGridFilter
 
struct  SupportPoint
 

Typedefs

using LD = AABBTreeLines::LinesDistancer< ExtrusionLine >
 
using PrecomputedSliceConnections = std::vector< std::vector< SliceConnection > >
 
using SupportPoints = std::vector< SupportPoint >
 
using PartialObjects = std::vector< PartialObject >
 

Enumerations

enum class  SupportPointCause {
  LongBridge , FloatingBridgeAnchor , FloatingExtrusion , SeparationFromBed ,
  UnstableFloatingPart , WeakObjectPart
}
 

Functions

SliceConnection estimate_slice_connection (size_t slice_idx, const Layer *layer)
 
PrecomputedSliceConnections precompute_slices_connections (const PrintObject *po)
 
float get_flow_width (const LayerRegion *region, ExtrusionRole role)
 
std::vector< ExtrusionLineto_short_lines (const ExtrusionEntity *e, float length_limit)
 
float estimate_curled_up_height (float distance, float curvature, float layer_height, float flow_width, float prev_line_curled_height, Params params)
 
std::vector< ExtrusionLinecheck_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)
 
std::tuple< ObjectPart, float > build_object_part_from_slice (const size_t &slice_idx, const Layer *layer, const Params &params)
 
std::tuple< SupportPoints, PartialObjectscheck_stability (const PrintObject *po, const PrecomputedSliceConnections &precomputed_slices_connections, const PrintTryCancel &cancel_func, const Params &params)
 
std::tuple< SupportPoints, PartialObjectsfull_search (const PrintObject *po, const PrintTryCancel &cancel_func, const Params &params)
 
void estimate_supports_malformations (SupportLayerPtrs &layers, float flow_width, const Params &params)
 
void estimate_malformations (LayerPtrs &layers, const Params &params)
 
std::vector< std::pair< SupportPointCause, bool > > gather_issues (const SupportPoints &support_points, PartialObjects &partial_objects)
 
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)
 

Class Documentation

◆ Slic3r::SupportSpotsGenerator::Malformations

struct Slic3r::SupportSpotsGenerator::Malformations
+ Collaboration diagram for Slic3r::SupportSpotsGenerator::Malformations:
Class Members
vector< Lines > layers

Typedef Documentation

◆ LD

◆ PartialObjects

◆ PrecomputedSliceConnections

◆ SupportPoints

Enumeration Type Documentation

◆ SupportPointCause

Enumerator
LongBridge 
FloatingBridgeAnchor 
FloatingExtrusion 
SeparationFromBed 
UnstableFloatingPart 
WeakObjectPart 
81 {
82 LongBridge, // point generated on bridge and straight perimeter extrusion longer than the allowed length
83 FloatingBridgeAnchor, // point generated on unsupported bridge endpoint
84 FloatingExtrusion, // point generated on extrusion that does not hold on its own
85 SeparationFromBed, // point generated for object parts that are connected to the bed, but the area is too small and there is a risk of separation (brim may help)
86 UnstableFloatingPart, // point generated for object parts not connected to the bed, holded only by the other support points (brim will not help here)
87 WeakObjectPart // point generated when some part of the object is too weak to hold the upper part and may break (imagine hourglass)
88 };

Function Documentation

◆ build_object_part_from_slice()

std::tuple< ObjectPart, float > Slic3r::SupportSpotsGenerator::build_object_part_from_slice ( const size_t &  slice_idx,
const Layer layer,
const Params params 
)
635{
636 ObjectPart new_object_part;
637 float area_covered_by_extrusions = 0;
638 const LayerSlice& slice = layer->lslices_ex.at(slice_idx);
639
640 auto add_extrusions_to_object = [&new_object_part, &area_covered_by_extrusions, &params](const ExtrusionEntity *e,
641 const LayerRegion *region) {
642 float flow_width = get_flow_width(region, e->role());
643 const Layer *l = region->layer();
644 float slice_z = l->slice_z;
645 float height = l->height;
646 std::vector<ExtrusionLine> lines = to_short_lines(e, 5.0);
647 for (const ExtrusionLine &line : lines) {
648 float volume = line.len * height * flow_width * PI / 4.0f;
649 area_covered_by_extrusions += line.len * flow_width;
650 new_object_part.volume += volume;
651 new_object_part.volume_centroid_accumulator += to_3d(Vec2f((line.a + line.b) / 2.0f), slice_z) * volume;
652
653 if (int(l->id()) == params.raft_layers_count) { // layer attached on bed/raft
654 new_object_part.connected_to_bed = true;
655 float sticking_area = line.len * flow_width;
656 new_object_part.sticking_area += sticking_area;
657 Vec2f middle = Vec2f((line.a + line.b) / 2.0f);
658 new_object_part.sticking_centroid_accumulator += sticking_area * to_3d(middle, slice_z);
659 // Bottom infill lines can be quite long, and algined, so the middle approximaton used above does not work
660 Vec2f dir = (line.b - line.a).normalized();
661 float segment_length = flow_width; // segments of size flow_width
662 for (float segment_middle_dist = std::min(line.len, segment_length * 0.5f); segment_middle_dist < line.len;
663 segment_middle_dist += segment_length) {
664 Vec2f segment_middle = line.a + segment_middle_dist * dir;
665 new_object_part.sticking_second_moment_of_area_accumulator += segment_length * flow_width *
666 segment_middle.cwiseProduct(segment_middle);
667 new_object_part.sticking_second_moment_of_area_covariance_accumulator += segment_length * flow_width *
668 segment_middle.x() * segment_middle.y();
669 }
670 }
671 }
672 };
673
674 for (const auto &island : slice.islands) {
675 const LayerRegion *perimeter_region = layer->get_region(island.perimeters.region());
676 for (size_t perimeter_idx : island.perimeters) {
677 for (const ExtrusionEntity *perimeter :
678 static_cast<const ExtrusionEntityCollection *>(perimeter_region->perimeters().entities[perimeter_idx])->entities) {
679 add_extrusions_to_object(perimeter, perimeter_region);
680 }
681 }
682 for (const LayerExtrusionRange &fill_range : island.fills) {
683 const LayerRegion *fill_region = layer->get_region(fill_range.region());
684 for (size_t fill_idx : fill_range) {
685 for (const ExtrusionEntity *fill :
686 static_cast<const ExtrusionEntityCollection *>(fill_region->fills().entities[fill_idx])->entities) {
687 add_extrusions_to_object(fill, fill_region);
688 }
689 }
690 }
691 for (size_t thin_fill_idx : island.thin_fills) {
692 add_extrusions_to_object(perimeter_region->thin_fills().entities[thin_fill_idx], perimeter_region);
693 }
694 }
695
696 // BRIM HANDLING
697 if (int(layer->id()) == params.raft_layers_count && params.raft_layers_count == 0 && params.brim_type != BrimType::btNoBrim &&
698 params.brim_width > 0.0) {
699 // TODO: The algorithm here should take into account that multiple slices may have coliding Brim areas and the final brim area is
700 // smaller,
701 // thus has lower adhesion. For now this effect will be neglected.
702 ExPolygon slice_poly = layer->lslices[slice_idx];
703 ExPolygons brim;
704 if (params.brim_type == BrimType::btOuterAndInner || params.brim_type == BrimType::btOuterOnly) {
705 Polygon brim_hole = slice_poly.contour;
706 brim_hole.reverse();
707 Polygons c = expand(slice_poly.contour, scale_(params.brim_width)); // For very small polygons, the expand may result in empty vector, even thought the input is correct.
708 if (!c.empty()) {
709 brim.push_back(ExPolygon{c.front(), brim_hole});
710 }
711 }
712 if (params.brim_type == BrimType::btOuterAndInner || params.brim_type == BrimType::btInnerOnly) {
713 Polygons brim_contours = slice_poly.holes;
714 polygons_reverse(brim_contours);
715 for (const Polygon &brim_contour : brim_contours) {
716 Polygons brim_holes = shrink({brim_contour}, scale_(params.brim_width));
717 polygons_reverse(brim_holes);
718 ExPolygon inner_brim{brim_contour};
719 inner_brim.holes = brim_holes;
720 brim.push_back(inner_brim);
721 }
722 }
723
724 for (const Polygon &poly : to_polygons(brim)) {
725 Vec2f p0 = unscaled(poly.first_point()).cast<float>();
726 for (size_t i = 2; i < poly.points.size(); i++) {
727 Vec2f p1 = unscaled(poly.points[i - 1]).cast<float>();
728 Vec2f p2 = unscaled(poly.points[i]).cast<float>();
729
730 float sign = cross2(p1 - p0, p2 - p1) > 0 ? 1.0f : -1.0f;
731
732 auto [area, first_moment_of_area, second_moment_area,
733 second_moment_of_area_covariance] = compute_moments_of_area_of_triangle(p0, p1, p2);
734 new_object_part.sticking_area += sign * area;
735 new_object_part.sticking_centroid_accumulator += sign * Vec3f(first_moment_of_area.x(), first_moment_of_area.y(),
736 layer->print_z * area);
737 new_object_part.sticking_second_moment_of_area_accumulator += sign * second_moment_area;
738 new_object_part.sticking_second_moment_of_area_covariance_accumulator += sign * second_moment_of_area_covariance;
739 }
740 }
741 }
742
743 return {new_object_part, area_covered_by_extrusions};
744}
EIGEN_DEVICE_FUNC const SignReturnType sign() const
Definition ArrayCwiseUnaryOps.h:184
Definition ExtrusionEntity.hpp:21
Definition SupportSpotsGenerator.cpp:56
Definition Layer.hpp:312
ExPolygons lslices
Definition Layer.hpp:339
coordf_t slice_z
Definition Layer.hpp:323
coordf_t height
Definition Layer.hpp:325
size_t id() const
Definition Layer.hpp:315
coordf_t print_z
Definition Layer.hpp:324
LayerSlices lslices_ex
Definition Layer.hpp:341
const LayerRegion * get_region(int idx) const
Definition Layer.hpp:344
Definition Layer.hpp:95
void reverse()
Definition MultiPoint.hpp:34
Definition SupportSpotsGenerator.cpp:446
Vec2f sticking_second_moment_of_area_accumulator
Definition SupportSpotsGenerator.cpp:452
Vec3f sticking_centroid_accumulator
Definition SupportSpotsGenerator.cpp:451
Vec3f volume_centroid_accumulator
Definition SupportSpotsGenerator.cpp:449
float volume
Definition SupportSpotsGenerator.cpp:448
float sticking_area
Definition SupportSpotsGenerator.cpp:450
bool connected_to_bed
Definition SupportSpotsGenerator.cpp:454
float sticking_second_moment_of_area_covariance_accumulator
Definition SupportSpotsGenerator.cpp:453
#define const
Definition getopt.c:38
static constexpr double PI
Definition libslic3r.h:58
#define scale_(val)
Definition libslic3r.h:69
float get_flow_width(const LayerRegion *region, ExtrusionRole role)
Definition SupportSpotsGenerator.cpp:240
std::vector< ExtrusionLine > to_short_lines(const ExtrusionEntity *e, float length_limit)
Definition SupportSpotsGenerator.cpp:253
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
std::tuple< float, Vec2f, Vec2f, float > compute_moments_of_area_of_triangle(const Vec2f &a, const Vec2f &b, const Vec2f &c)
Definition PrincipalComponents2D.cpp:13
Derived::Scalar cross2(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:93
Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:363
Eigen::Matrix< typename Derived::Scalar, 3, 1, Eigen::DontAlign > to_3d(const Eigen::MatrixBase< Derived > &pt, const typename Derived::Scalar z)
Definition Point.hpp:127
void polygons_reverse(Polygons &polys)
Definition Polygon.hpp:163
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:49
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
Slic3r::Polygons shrink(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:372
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:281
constexpr Eigen::Matrix< Tout, 2, EigenArgs... > unscaled(const Slic3r::ClipperLib::IntPoint &v) noexcept
Definition Arrange.cpp:55
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:48
IGL_INLINE void slice(const Eigen::SparseMatrix< TX > &X, const Eigen::Matrix< int, Eigen::Dynamic, 1 > &R, const Eigen::Matrix< int, Eigen::Dynamic, 1 > &C, Eigen::SparseMatrix< TY > &Y)
Definition slice.cpp:15
Unit area(const Cntr &poly, const PathTag &)
Definition geometry_traits.hpp:971
Slic3r::Polygon Polygon
Definition Emboss.cpp:34
Definition Layer.hpp:282
const float brim_width
Definition SupportSpotsGenerator.hpp:43
BrimType brim_type
Definition SupportSpotsGenerator.hpp:42
const int raft_layers_count
Definition SupportSpotsGenerator.hpp:39

References Slic3r::area(), Slic3r::SupportSpotsGenerator::Params::brim_type, Slic3r::SupportSpotsGenerator::Params::brim_width, Slic3r::btInnerOnly, Slic3r::btNoBrim, Slic3r::btOuterAndInner, Slic3r::btOuterOnly, build_object_part_from_slice(), Slic3r::compute_moments_of_area_of_triangle(), Slic3r::SupportSpotsGenerator::ObjectPart::connected_to_bed, Slic3r::ExPolygon::contour, Slic3r::cross2(), Slic3r::ExtrusionEntityCollection::entities, Slic3r::expand(), Slic3r::LayerRegion::fills(), get_flow_width(), Slic3r::Layer::get_region(), Slic3r::Layer::height, Slic3r::ExPolygon::holes, Slic3r::Layer::id(), Slic3r::Layer::lslices, Slic3r::Layer::lslices_ex, Slic3r::LayerRegion::perimeters(), PI, Slic3r::polygons_reverse(), Slic3r::Layer::print_z, Slic3r::SupportSpotsGenerator::Params::raft_layers_count, Slic3r::MultiPoint::reverse(), scale_, Slic3r::segment_length(), Slic3r::shrink(), sign(), Slic3r::Layer::slice_z, Slic3r::SupportSpotsGenerator::ObjectPart::sticking_area, Slic3r::SupportSpotsGenerator::ObjectPart::sticking_centroid_accumulator, Slic3r::SupportSpotsGenerator::ObjectPart::sticking_second_moment_of_area_accumulator, Slic3r::SupportSpotsGenerator::ObjectPart::sticking_second_moment_of_area_covariance_accumulator, Slic3r::LayerRegion::thin_fills(), Slic3r::to_3d(), Slic3r::to_polygons(), to_short_lines(), Slic3r::unscaled(), Slic3r::SupportSpotsGenerator::ObjectPart::volume, and Slic3r::SupportSpotsGenerator::ObjectPart::volume_centroid_accumulator.

Referenced by build_object_part_from_slice(), and check_stability().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_extrusion_entity_stability()

std::vector< ExtrusionLine > Slic3r::SupportSpotsGenerator::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 
)
320{
321 assert(!entity->is_collection());
322 if (entity->role().is_bridge() && !entity->role().is_perimeter()) {
323 // pure bridges are handled separately, beacuse we need to align the forward and backward direction support points
324 if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) {
325 return {};
326 }
327 const float flow_width = get_flow_width(layer_region, entity->role());
328 std::vector<ExtendedPoint> annotated_points = estimate_points_properties<true, true, true, true>(entity->as_polyline().points,
329 prev_layer_boundary, flow_width,
330 params.bridge_distance);
331
332 std::vector<ExtrusionLine> lines_out;
333 lines_out.reserve(annotated_points.size());
334 float bridged_distance = 0.0f;
335
336 std::optional<Vec2d> bridging_dir{};
337
338 for (size_t i = 0; i < annotated_points.size(); ++i) {
339 ExtendedPoint &curr_point = annotated_points[i];
340 const ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i];
341
342 SupportPointCause potential_cause = std::abs(curr_point.curvature) > 0.1 ? SupportPointCause::FloatingBridgeAnchor :
343 SupportPointCause::LongBridge;
344 float line_len = (prev_point.position - curr_point.position).norm();
345 Vec2d line_dir = line_len > EPSILON ? Vec2d((curr_point.position - prev_point.position) / double(line_len)) : Vec2d::Zero();
346
347 ExtrusionLine line_out{prev_point.position.cast<float>(), curr_point.position.cast<float>(), line_len, entity};
348
349 float max_bridge_len = std::max(params.support_points_interface_radius * 2.0f,
350 params.bridge_distance /
351 ((1.0f + std::abs(curr_point.curvature)) * (1.0f + std::abs(curr_point.curvature)) *
352 (1.0f + std::abs(curr_point.curvature))));
353
354 if (!bridging_dir.has_value() && curr_point.distance > flow_width && line_len > params.bridge_distance * 0.6) {
355 bridging_dir = line_dir;
356 }
357
358 if (curr_point.distance > flow_width && potential_cause == SupportPointCause::LongBridge && bridging_dir.has_value() &&
359 bridging_dir->dot(line_dir) < 0.8) { // skip backward direction of bridge - supported by forward points enough
360 bridged_distance += line_len;
361 } else if (curr_point.distance > flow_width) {
362 bridged_distance += line_len;
363 if (bridged_distance > max_bridge_len) {
364 bridged_distance = 0.0f;
365 line_out.support_point_generated = potential_cause;
366 }
367 } else {
368 bridged_distance = 0.0f;
369 }
370
371 lines_out.push_back(line_out);
372 }
373 return lines_out;
374
375 } else { // single extrusion path, with possible varying parameters
376 if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) {
377 return {};
378 }
379
380 const float flow_width = get_flow_width(layer_region, entity->role());
381 // Compute only unsigned distance - prev_layer_lines can contain unconnected paths, thus the sign of the distance is unreliable
382 std::vector<ExtendedPoint> annotated_points = estimate_points_properties<true, true, false, false>(entity->as_polyline().points,
383 prev_layer_lines, flow_width,
384 params.bridge_distance);
385
386 std::vector<ExtrusionLine> lines_out;
387 lines_out.reserve(annotated_points.size());
388 float bridged_distance = annotated_points.front().position != annotated_points.back().position ? (params.bridge_distance + 1.0f) :
389 0.0f;
390 for (size_t i = 0; i < annotated_points.size(); ++i) {
391 ExtendedPoint &curr_point = annotated_points[i];
392 const ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i];
393 float line_len = (prev_point.position - curr_point.position).norm();
394 ExtrusionLine line_out{prev_point.position.cast<float>(), curr_point.position.cast<float>(), line_len, entity};
395
396 Vec2f middle = 0.5 * (line_out.a + line_out.b);
397 auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra<false>(middle);
398 ExtrusionLine bottom_line = prev_layer_lines.get_lines().empty() ? ExtrusionLine{} : prev_layer_lines.get_line(bottom_line_idx);
399
400 // correctify the distance sign using slice polygons
401 float sign = (prev_layer_boundary.distance_from_lines<true>(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
402 curr_point.distance *= sign;
403
404 SupportPointCause potential_cause = SupportPointCause::FloatingExtrusion;
405 // Bridges are now separated. While long overhang perimeter is technically bridge, it would confuse the users
406 // if (bridged_distance + line_len > params.bridge_distance * 0.8 && std::abs(curr_point.curvature) < 0.1) {
407 // potential_cause = SupportPointCause::FloatingExtrusion;
408 // }
409
410 float max_bridge_len = std::max(params.support_points_interface_radius * 2.0f,
411 params.bridge_distance /
412 ((1.0f + std::abs(curr_point.curvature)) * (1.0f + std::abs(curr_point.curvature)) *
413 (1.0f + std::abs(curr_point.curvature))));
414
415 if (curr_point.distance > 1.2f * flow_width) {
416 line_out.form_quality = 0.8f;
417 bridged_distance += line_len;
418 if (bridged_distance > max_bridge_len) {
419 line_out.support_point_generated = potential_cause;
420 bridged_distance = 0.0f;
421 }
422 } else if (curr_point.distance > flow_width * 0.8f) {
423 bridged_distance += line_len;
424 line_out.form_quality = bottom_line.form_quality - 0.3f;
425 if (line_out.form_quality < 0 && bridged_distance > max_bridge_len) {
426 line_out.support_point_generated = potential_cause;
427 line_out.form_quality = 0.5f;
428 bridged_distance = 0.0f;
429 }
430 } else {
431 bridged_distance = 0.0f;
432 }
433
434 line_out.curled_up_height = estimate_curled_up_height(middle_distance, 0.5 * (prev_point.curvature + curr_point.curvature),
435 layer_region->layer()->height, flow_width, bottom_line.curled_up_height,
436 params);
437
438 lines_out.push_back(line_out);
439 }
440
441 return lines_out;
442 }
443}
const std::vector< LineType > & get_lines() const
Definition AABBTreeLines.hpp:360
const LineType & get_line(size_t line_idx) const
Definition AABBTreeLines.hpp:358
Floating distance_from_lines(const Vec< 2, Scalar > &point) const
Definition AABBTreeLines.hpp:342
std::tuple< Floating, size_t, Vec< 2, Floating > > distance_from_lines_extra(const Vec< 2, Scalar > &point) const
Definition AABBTreeLines.hpp:323
virtual double length() const =0
virtual Polyline as_polyline() const =0
virtual ExtrusionRole role() const =0
virtual bool is_collection() const
Definition ExtrusionEntity.hpp:24
Layer * layer()
Definition Layer.hpp:97
Points points
Definition MultiPoint.hpp:18
static constexpr double EPSILON
Definition libslic3r.h:51
SupportPointCause
Definition SupportSpotsGenerator.hpp:81
float estimate_curled_up_height(float distance, float curvature, float layer_height, float flow_width, float prev_line_curled_height, Params params)
Definition SupportSpotsGenerator.cpp:276
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:51
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297
bool is_perimeter() const
Definition ExtrusionRole.hpp:81
bool is_bridge() const
Definition ExtrusionRole.hpp:86
const float min_distance_to_allow_local_supports
Definition SupportSpotsGenerator.hpp:51
const float support_points_interface_radius
Definition SupportSpotsGenerator.hpp:50
const float bridge_distance
Definition SupportSpotsGenerator.hpp:36

References Slic3r::ExtrusionEntity::as_polyline(), Slic3r::SupportSpotsGenerator::Params::bridge_distance, check_extrusion_entity_stability(), Slic3r::ExtrusionLine::curled_up_height, Slic3r::ExtendedPoint::curvature, Slic3r::ExtendedPoint::distance, Slic3r::AABBTreeLines::LinesDistancer< LineType >::distance_from_lines(), Slic3r::AABBTreeLines::LinesDistancer< LineType >::distance_from_lines_extra(), EPSILON, estimate_curled_up_height(), Slic3r::ExtrusionLine::form_quality, get_flow_width(), Slic3r::AABBTreeLines::LinesDistancer< LineType >::get_line(), Slic3r::AABBTreeLines::LinesDistancer< LineType >::get_lines(), Slic3r::Layer::height, Slic3r::ExtrusionRole::is_bridge(), Slic3r::ExtrusionEntity::is_collection(), Slic3r::ExtrusionRole::is_perimeter(), Slic3r::LayerRegion::layer(), Slic3r::ExtrusionEntity::length(), Slic3r::SupportSpotsGenerator::Params::min_distance_to_allow_local_supports, Slic3r::MultiPoint::points, Slic3r::ExtendedPoint::position, Slic3r::ExtrusionEntity::role(), scale_, sign(), and Slic3r::SupportSpotsGenerator::Params::support_points_interface_radius.

Referenced by check_extrusion_entity_stability().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_stability()

std::tuple< SupportPoints, PartialObjects > Slic3r::SupportSpotsGenerator::check_stability ( const PrintObject po,
const PrecomputedSliceConnections precomputed_slices_connections,
const PrintTryCancel cancel_func,
const Params params 
)
789{
790 SupportPoints supp_points{};
791 SupportGridFilter supports_presence_grid(po, params.min_distance_between_support_points);
792 ActiveObjectParts active_object_parts{};
793 PartialObjects partial_objects{};
794 LD prev_layer_ext_perim_lines;
795
796 std::unordered_map<size_t, size_t> prev_slice_idx_to_object_part_mapping;
797 std::unordered_map<size_t, size_t> next_slice_idx_to_object_part_mapping;
798 std::unordered_map<size_t, SliceConnection> prev_slice_idx_to_weakest_connection;
799 std::unordered_map<size_t, SliceConnection> next_slice_idx_to_weakest_connection;
800
801 auto remember_partial_object = [&active_object_parts, &partial_objects](size_t object_part_id) {
802 auto object_part = active_object_parts.access(object_part_id);
803 if (object_part.volume > EPSILON) {
804 partial_objects.emplace_back(object_part.volume_centroid_accumulator / object_part.volume, object_part.volume,
805 object_part.connected_to_bed);
806 }
807 };
808
809 for (size_t layer_idx = 0; layer_idx < po->layer_count(); ++layer_idx) {
810 cancel_func();
811 const Layer *layer = po->get_layer(layer_idx);
812 float bottom_z = layer->bottom_z();
813 auto create_support_point_position = [bottom_z](const Vec2f &layer_pos) { return Vec3f{layer_pos.x(), layer_pos.y(), bottom_z}; };
814
815 for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
816 const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
817 auto [new_part, covered_area] = build_object_part_from_slice(slice_idx, layer, params);
818 const SliceConnection &connection_to_below = precomputed_slices_connections[layer_idx][slice_idx];
819
820#ifdef DETAILED_DEBUG_LOGS
821 std::cout << "SLICE IDX: " << slice_idx << std::endl;
822 for (const auto &link : slice.overlaps_below) {
823 std::cout << "connected to slice below: " << link.slice_idx << " by area : " << link.area << std::endl;
824 }
825 connection_to_below.print_info("CONNECTION TO BELOW");
826#endif
827
828 if (connection_to_below.area < EPSILON) { // new object part emerging
829 size_t part_id = active_object_parts.insert(new_part);
830 next_slice_idx_to_object_part_mapping.emplace(slice_idx, part_id);
831 next_slice_idx_to_weakest_connection.emplace(slice_idx, connection_to_below);
832 } else {
833 size_t final_part_id{};
834 SliceConnection transfered_weakest_connection{};
835 // MERGE parts
836 {
837 std::unordered_set<size_t> parts_ids;
838 for (const auto &link : slice.overlaps_below) {
839 size_t part_id = active_object_parts.get_flat_id(prev_slice_idx_to_object_part_mapping.at(link.slice_idx));
840 parts_ids.insert(part_id);
841 transfered_weakest_connection.add(prev_slice_idx_to_weakest_connection.at(link.slice_idx));
842 }
843
844 final_part_id = *parts_ids.begin();
845 for (size_t part_id : parts_ids) {
846 if (final_part_id != part_id) {
847 remember_partial_object(part_id);
848 active_object_parts.merge(part_id, final_part_id);
849 }
850 }
851 }
852 auto estimate_conn_strength = [bottom_z](const SliceConnection &conn) {
853 if (conn.area < EPSILON) { // connection is empty, does not exists. Return max strength so that it is not picked as the
854 // weakest connection.
855 return INFINITY;
856 }
857 Vec3f centroid = conn.centroid_accumulator / conn.area;
858 Vec2f variance = (conn.second_moment_of_area_accumulator / conn.area -
859 centroid.head<2>().cwiseProduct(centroid.head<2>()));
860 float xy_variance = variance.x() + variance.y();
861 float arm_len_estimate = std::max(1.0f, bottom_z - (conn.centroid_accumulator.z() / conn.area));
862 return conn.area * sqrt(xy_variance) / arm_len_estimate;
863 };
864
865#ifdef DETAILED_DEBUG_LOGS
866 connection_to_below.print_info("new_weakest_connection");
867 transfered_weakest_connection.print_info("transfered_weakest_connection");
868#endif
869
870 if (estimate_conn_strength(transfered_weakest_connection) > estimate_conn_strength(connection_to_below)) {
871 transfered_weakest_connection = connection_to_below;
872 }
873 next_slice_idx_to_weakest_connection.emplace(slice_idx, transfered_weakest_connection);
874 next_slice_idx_to_object_part_mapping.emplace(slice_idx, final_part_id);
875 ObjectPart &part = active_object_parts.access(final_part_id);
876 part.add(new_part);
877 }
878 }
879
880 prev_slice_idx_to_object_part_mapping = next_slice_idx_to_object_part_mapping;
881 next_slice_idx_to_object_part_mapping.clear();
882 prev_slice_idx_to_weakest_connection = next_slice_idx_to_weakest_connection;
883 next_slice_idx_to_weakest_connection.clear();
884
885 auto get_flat_entities = [](const ExtrusionEntity *e) {
886 std::vector<const ExtrusionEntity *> entities;
887 std::vector<const ExtrusionEntity *> queue{e};
888 while (!queue.empty()) {
889 const ExtrusionEntity *next = queue.back();
890 queue.pop_back();
891 if (next->is_collection()) {
892 for (const ExtrusionEntity *e : static_cast<const ExtrusionEntityCollection *>(next)->entities) {
893 queue.push_back(e);
894 }
895 } else {
896 entities.push_back(next);
897 }
898 }
899 return entities;
900 };
901
902 struct EnitityToCheck
903 {
904 const ExtrusionEntity *e;
905 const LayerRegion *region;
906 size_t slice_idx;
907 };
908 std::vector<EnitityToCheck> entities_to_check;
909 for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
910 const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
911 for (const auto &island : slice.islands) {
912 for (const LayerExtrusionRange &fill_range : island.fills) {
913 const LayerRegion *fill_region = layer->get_region(fill_range.region());
914 for (size_t fill_idx : fill_range) {
915 for (const ExtrusionEntity *e : get_flat_entities(fill_region->fills().entities[fill_idx])) {
916 if (e->role() == ExtrusionRole::BridgeInfill) {
917 entities_to_check.push_back({e, fill_region, slice_idx});
918 }
919 }
920 }
921 }
922
923 const LayerRegion *perimeter_region = layer->get_region(island.perimeters.region());
924 for (size_t perimeter_idx : island.perimeters) {
925 for (const ExtrusionEntity *e : get_flat_entities(perimeter_region->perimeters().entities[perimeter_idx])) {
926 entities_to_check.push_back({e, perimeter_region, slice_idx});
927 }
928 }
929 }
930 }
931
932 AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary = layer->lower_layer != nullptr ?
933 AABBTreeLines::LinesDistancer<Linef>{
934 to_unscaled_linesf(layer->lower_layer->lslices)} :
935 AABBTreeLines::LinesDistancer<Linef>{};
936
937 std::vector<tbb::concurrent_vector<ExtrusionLine>> unstable_lines_per_slice(layer->lslices_ex.size());
938 std::vector<tbb::concurrent_vector<ExtrusionLine>> ext_perim_lines_per_slice(layer->lslices_ex.size());
939
940 tbb::parallel_for(tbb::blocked_range<size_t>(0, entities_to_check.size()),
941 [&entities_to_check, &prev_layer_ext_perim_lines, &prev_layer_boundary, &unstable_lines_per_slice,
942 &ext_perim_lines_per_slice, &params](tbb::blocked_range<size_t> r) {
943 for (size_t entity_idx = r.begin(); entity_idx < r.end(); ++entity_idx) {
944 const auto &e_to_check = entities_to_check[entity_idx];
945 for (const auto &line :
946 check_extrusion_entity_stability(e_to_check.e, e_to_check.region, prev_layer_ext_perim_lines,
947 prev_layer_boundary, params)) {
948 if (line.support_point_generated.has_value()) {
949 unstable_lines_per_slice[e_to_check.slice_idx].push_back(line);
950 }
951 if (line.is_external_perimeter()) {
952 ext_perim_lines_per_slice[e_to_check.slice_idx].push_back(line);
953 }
954 }
955 }
956 });
957
958 std::vector<ExtrusionLine> current_layer_ext_perims_lines{};
959 current_layer_ext_perims_lines.reserve(prev_layer_ext_perim_lines.get_lines().size());
960 // All object parts updated, and for each slice we have coresponding weakest connection.
961 // We can now check each slice and its corresponding weakest connection and object part for stability.
962 for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) {
963 ObjectPart &part = active_object_parts.access(prev_slice_idx_to_object_part_mapping[slice_idx]);
964 SliceConnection &weakest_conn = prev_slice_idx_to_weakest_connection[slice_idx];
965
966#ifdef DETAILED_DEBUG_LOGS
967 weakest_conn.print_info("weakest connection info: ");
968#endif
969 // Function that is used when new support point is generated. It will update the ObjectPart stability, weakest conneciton info,
970 // and the support presence grid and add the point to the issues.
971 auto reckon_new_support_point = [&part, &weakest_conn, &supp_points, &supports_presence_grid, &params,
972 &layer_idx](SupportPointCause cause, const Vec3f &support_point, float force,
973 const Vec2f &dir) {
974 // if position is taken and point is for global stability (force > 0) or we are too close to the bed, do not add
975 // This allows local support points (e.g. bridging) to be generated densely
976 if ((supports_presence_grid.position_taken(support_point) && force > 0) || layer_idx <= 1) {
977 return;
978 }
979
980 float area = params.support_points_interface_radius * params.support_points_interface_radius * float(PI);
981 // add the stability effect of the point only if the spot is not taken, so that the densely created local support points do
982 // not add unrealistic amount of stability to the object (due to overlaping of local support points)
983 if (!(supports_presence_grid.position_taken(support_point))) {
984 part.add_support_point(support_point, area);
985 }
986
987 float radius = params.support_points_interface_radius;
988 supp_points.emplace_back(cause, support_point, force, radius, dir);
989 supports_presence_grid.take_position(support_point);
990
991 // The support point also increases the stability of the weakest connection of the object, which should be reflected
992 if (weakest_conn.area > EPSILON) { // Do not add it to the weakest connection if it is not valid - does not exist
993 weakest_conn.area += area;
994 weakest_conn.centroid_accumulator += support_point * area;
995 weakest_conn.second_moment_of_area_accumulator += area * support_point.head<2>().cwiseProduct(support_point.head<2>());
996 weakest_conn.second_moment_of_area_covariance_accumulator += area * support_point.x() * support_point.y();
997 }
998 };
999
1000 for (const auto &l : unstable_lines_per_slice[slice_idx]) {
1001 assert(l.support_point_generated.has_value());
1002 reckon_new_support_point(*l.support_point_generated, create_support_point_position(l.b), float(-EPSILON), Vec2f::Zero());
1003 }
1004
1005 LD current_slice_lines_distancer({ext_perim_lines_per_slice[slice_idx].begin(), ext_perim_lines_per_slice[slice_idx].end()});
1006 float unchecked_dist = params.min_distance_between_support_points + 1.0f;
1007
1008 for (const ExtrusionLine &line : current_slice_lines_distancer.get_lines()) {
1009 if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < params.curling_tolerance_limit) ||
1010 line.len < EPSILON) {
1011 unchecked_dist += line.len;
1012 } else {
1013 unchecked_dist = line.len;
1014 Vec2f pivot_site_search_point = Vec2f(line.b + (line.b - line.a).normalized() * 300.0f);
1015 auto [dist, nidx,
1016 nearest_point] = current_slice_lines_distancer.distance_from_lines_extra<false>(pivot_site_search_point);
1017 Vec3f support_point = create_support_point_position(nearest_point);
1018 auto [force, cause] = part.is_stable_while_extruding(weakest_conn, line, support_point, bottom_z, params);
1019 if (force > 0) {
1020 reckon_new_support_point(cause, support_point, force, (line.b - line.a).normalized());
1021 }
1022 }
1023 }
1024 current_layer_ext_perims_lines.insert(current_layer_ext_perims_lines.end(), current_slice_lines_distancer.get_lines().begin(),
1025 current_slice_lines_distancer.get_lines().end());
1026 } // slice iterations
1027 prev_layer_ext_perim_lines = LD(current_layer_ext_perims_lines);
1028 } // layer iterations
1029
1030 for (const auto& active_obj_pair : prev_slice_idx_to_object_part_mapping) {
1031 remember_partial_object(active_obj_pair.second);
1032 }
1033
1034 return {supp_points, partial_objects};
1035}
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
Definition ArrayCwiseUnaryOps.h:152
coordf_t bottom_z() const
Definition Layer.hpp:326
size_t layer_count() const
Definition Print.hpp:278
const Layer * get_layer(int idx) const
Definition Print.hpp:280
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:280
AABBTreeLines::LinesDistancer< ExtrusionLine > LD
Definition SupportSpotsGenerator.cpp:91
std::tuple< ObjectPart, float > build_object_part_from_slice(const size_t &slice_idx, const Layer *layer, const Params &params)
Definition SupportSpotsGenerator.cpp:634
std::vector< SupportPoint > SupportPoints
Definition SupportSpotsGenerator.hpp:129
std::pair< Point, bool > nearest_point(const Points &points, const Point &pt)
Definition Point.hpp:266
Linesf to_unscaled_linesf(const ExPolygons &src)
Definition ExPolygon.hpp:175
IGL_INLINE void centroid(const Eigen::MatrixBase< DerivedV > &V, const Eigen::MatrixBase< DerivedF > &F, Eigen::PlainObjectBase< Derivedc > &c, Derivedvol &vol)
Definition centroid.cpp:16
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620
const float min_distance_between_support_points
Definition SupportSpotsGenerator.hpp:49

References Slic3r::SupportSpotsGenerator::ObjectPart::add(), Slic3r::SupportSpotsGenerator::SliceConnection::add(), Slic3r::SupportSpotsGenerator::ObjectPart::add_support_point(), Slic3r::area(), Slic3r::SupportSpotsGenerator::SliceConnection::area, Slic3r::Layer::bottom_z(), Slic3r::ExtrusionRole::BridgeInfill, build_object_part_from_slice(), Slic3r::SupportSpotsGenerator::SliceConnection::centroid_accumulator, check_stability(), Slic3r::ExtrusionEntityCollection::entities, EPSILON, Slic3r::LayerRegion::fills(), Slic3r::PrintObject::get_layer(), Slic3r::AABBTreeLines::LinesDistancer< LineType >::get_lines(), Slic3r::Layer::get_region(), Slic3r::ExtrusionEntity::is_collection(), Slic3r::SupportSpotsGenerator::ObjectPart::is_stable_while_extruding(), Slic3r::PrintObject::layer_count(), Slic3r::Layer::lower_layer, Slic3r::Layer::lslices, Slic3r::Layer::lslices_ex, Slic3r::SupportSpotsGenerator::Params::min_distance_between_support_points, Slic3r::nearest_point(), Slic3r::LayerRegion::perimeters(), PI, Slic3r::SupportSpotsGenerator::SliceConnection::print_info(), Slic3r::SupportSpotsGenerator::SliceConnection::second_moment_of_area_accumulator, Slic3r::SupportSpotsGenerator::SliceConnection::second_moment_of_area_covariance_accumulator, sqrt(), and Slic3r::to_unscaled_linesf().

Referenced by check_stability(), and full_search().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ estimate_curled_up_height()

float Slic3r::SupportSpotsGenerator::estimate_curled_up_height ( float  distance,
float  curvature,
float  layer_height,
float  flow_width,
float  prev_line_curled_height,
Params  params 
)
278{
279 float curled_up_height = 0;
280 if (fabs(distance) < 3.0 * flow_width) {
281 curled_up_height = std::max(prev_line_curled_height - layer_height * 0.75f, 0.0f);
282 }
283
284 if (distance > params.malformation_distance_factors.first * flow_width &&
285 distance < params.malformation_distance_factors.second * flow_width) {
286 // imagine the extrusion profile. The part that has been glued (melted) with the previous layer will be called anchored section
287 // and the rest will be called curling section
288 // float anchored_section = flow_width - point.distance;
289 float curling_section = distance;
290
291 // after extruding, the curling (floating) part of the extrusion starts to shrink back to the rounded shape of the nozzle
292 // The anchored part not, because the melted material holds to the previous layer well.
293 // We can assume for simplicity perfect equalization of layer height and raising part width, from which:
294 float swelling_radius = (layer_height + curling_section) / 2.0f;
295 curled_up_height += std::max(0.f, (swelling_radius - layer_height) / 2.0f);
296
297 // On convex turns, there is larger tension on the floating edge of the extrusion then on the middle section.
298 // The tension is caused by the shrinking tendency of the filament, and on outer edge of convex trun, the expansion is greater and
299 // thus shrinking force is greater. This tension will cause the curling section to curle up
300 if (curvature > 0.01) {
301 float radius = (1.0 / curvature);
302 float curling_t = sqrt(radius / 100);
303 float b = curling_t * flow_width;
304 float a = curling_section;
305 float c = sqrt(std::max(0.0f, a * a - b * b));
306
307 curled_up_height += c;
308 }
309 curled_up_height = std::min(curled_up_height, params.max_curled_height_factor * layer_height);
310 }
311
312 return curled_up_height;
313}
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat
const std::pair< float, float > malformation_distance_factors
Definition SupportSpotsGenerator.hpp:45
const float max_curled_height_factor
Definition SupportSpotsGenerator.hpp:46

References estimate_curled_up_height(), Slic3r::layer_height(), Slic3r::SupportSpotsGenerator::Params::malformation_distance_factors, Slic3r::SupportSpotsGenerator::Params::max_curled_height_factor, and sqrt().

Referenced by check_extrusion_entity_stability(), estimate_curled_up_height(), estimate_malformations(), and estimate_supports_malformations().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ estimate_malformations() [1/2]

void Slic3r::SupportSpotsGenerator::estimate_malformations ( LayerPtrs layers,
const Params params 
)
1161{
1162#ifdef DEBUG_FILES
1163 FILE *debug_file = boost::nowide::fopen(debug_out_path("object_malformations.obj").c_str(), "w");
1164 FILE *full_file = boost::nowide::fopen(debug_out_path("object_full.obj").c_str(), "w");
1165#endif
1166
1167 LD prev_layer_lines{};
1168
1169 for (Layer *l : layers) {
1170 l->curled_lines.clear();
1171 std::vector<Linef> boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector<Linef>();
1172 AABBTreeLines::LinesDistancer<Linef> prev_layer_boundary{std::move(boundary_lines)};
1173 std::vector<ExtrusionLine> current_layer_lines;
1174 for (const LayerRegion *layer_region : l->regions()) {
1175 for (const ExtrusionEntity *extrusion : layer_region->perimeters().flatten().entities) {
1176 if (!extrusion->role().is_external_perimeter())
1177 continue;
1178
1179 Points extrusion_pts;
1180 extrusion->collect_points(extrusion_pts);
1181 float flow_width = get_flow_width(layer_region, extrusion->role());
1182 auto annotated_points = estimate_points_properties<true, true, false, false>(extrusion_pts, prev_layer_lines, flow_width,
1183 params.bridge_distance);
1184 for (size_t i = 0; i < annotated_points.size(); ++i) {
1185 const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
1186 const ExtendedPoint &b = annotated_points[i];
1187 ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
1188 extrusion};
1189
1190 Vec2f middle = 0.5 * (line_out.a + line_out.b);
1191 auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra<false>(middle);
1192 ExtrusionLine bottom_line = prev_layer_lines.get_lines().empty() ? ExtrusionLine{} :
1193 prev_layer_lines.get_line(bottom_line_idx);
1194
1195 // correctify the distance sign using slice polygons
1196 float sign = (prev_layer_boundary.distance_from_lines<true>(middle.cast<double>()) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f;
1197
1198 line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign, 0.5 * (a.curvature + b.curvature),
1199 l->height, flow_width, bottom_line.curled_up_height, params);
1200
1201 current_layer_lines.push_back(line_out);
1202 }
1203 }
1204 }
1205
1206 for (const ExtrusionLine &line : current_layer_lines) {
1207 if (line.curled_up_height > params.curling_tolerance_limit) {
1208 l->curled_lines.push_back(CurledLine{Point::new_scale(line.a), Point::new_scale(line.b), line.curled_up_height});
1209 }
1210 }
1211
1212#ifdef DEBUG_FILES
1213 for (const ExtrusionLine &line : current_layer_lines) {
1214 if (line.curled_up_height > params.curling_tolerance_limit) {
1215 Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
1216 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]);
1217 }
1218 }
1219 for (const ExtrusionLine &line : current_layer_lines) {
1220 Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
1221 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]);
1222 }
1223#endif
1224
1225 prev_layer_lines = LD{current_layer_lines};
1226 }
1227
1228#ifdef DEBUG_FILES
1229 fclose(debug_file);
1230 fclose(full_file);
1231#endif
1232}
Definition AABBTreeLines.hpp:297
Definition Line.hpp:243
Vec3f value_to_rgbf(float minimum, float maximum, float value)
Definition Color.hpp:169
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
STL namespace.
const float curling_tolerance_limit
Definition SupportSpotsGenerator.hpp:47

References Slic3r::SupportSpotsGenerator::Params::bridge_distance, Slic3r::ExtrusionLine::curled_up_height, Slic3r::SupportSpotsGenerator::Params::curling_tolerance_limit, Slic3r::debug_out_path(), EPSILON, estimate_curled_up_height(), estimate_malformations(), get_flow_width(), Slic3r::SupportSpotsGenerator::Params::max_curled_height_factor, sign(), Slic3r::to_unscaled_linesf(), and Slic3r::value_to_rgbf().

Referenced by estimate_malformations().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ estimate_malformations() [2/2]

void Slic3r::SupportSpotsGenerator::estimate_malformations ( std::vector< Layer * > &  layers,
const Params params 
)

◆ estimate_slice_connection()

SliceConnection Slic3r::SupportSpotsGenerator::estimate_slice_connection ( size_t  slice_idx,
const Layer layer 
)
178{
179 SliceConnection connection;
180
181 const LayerSlice &slice = layer->lslices_ex[slice_idx];
182 Polygons slice_polys = to_polygons(layer->lslices[slice_idx]);
183 BoundingBox slice_bb = get_extents(slice_polys);
184 const Layer *lower_layer = layer->lower_layer;
185
186 ExPolygons below{};
187 for (const auto &link : slice.overlaps_below) { below.push_back(lower_layer->lslices[link.slice_idx]); }
188 Polygons below_polys = to_polygons(below);
189
190 BoundingBox below_bb = get_extents(below_polys);
191
192 Polygons overlap = intersection(ClipperUtils::clip_clipper_polygons_with_subject_bbox(slice_polys, below_bb),
193 ClipperUtils::clip_clipper_polygons_with_subject_bbox(below_polys, slice_bb));
194
195 for (const Polygon &poly : overlap) {
196 Vec2f p0 = unscaled(poly.first_point()).cast<float>();
197 for (size_t i = 2; i < poly.points.size(); i++) {
198 Vec2f p1 = unscaled(poly.points[i - 1]).cast<float>();
199 Vec2f p2 = unscaled(poly.points[i]).cast<float>();
200
201 float sign = cross2(p1 - p0, p2 - p1) > 0 ? 1.0f : -1.0f;
202
203 auto [area, first_moment_of_area, second_moment_area,
204 second_moment_of_area_covariance] = compute_moments_of_area_of_triangle(p0, p1, p2);
205 connection.area += sign * area;
206 connection.centroid_accumulator += sign * Vec3f(first_moment_of_area.x(), first_moment_of_area.y(), layer->print_z * area);
207 connection.second_moment_of_area_accumulator += sign * second_moment_area;
208 connection.second_moment_of_area_covariance_accumulator += sign * second_moment_of_area_covariance;
209 }
210 }
211
212 return connection;
213};
Definition BoundingBox.hpp:181
Layer * lower_layer
Definition Layer.hpp:321
BoundingBox get_extents(const ExPolygon &expolygon)
Definition ExPolygon.cpp:352
Definition SupportSpotsGenerator.cpp:150
Vec2f second_moment_of_area_accumulator
Definition SupportSpotsGenerator.cpp:153
Vec3f centroid_accumulator
Definition SupportSpotsGenerator.cpp:152
float area
Definition SupportSpotsGenerator.cpp:151
float second_moment_of_area_covariance_accumulator
Definition SupportSpotsGenerator.cpp:154

References Slic3r::area(), Slic3r::SupportSpotsGenerator::SliceConnection::area, Slic3r::SupportSpotsGenerator::SliceConnection::centroid_accumulator, Slic3r::ClipperUtils::clip_clipper_polygons_with_subject_bbox(), Slic3r::compute_moments_of_area_of_triangle(), Slic3r::cross2(), Slic3r::get_extents(), Slic3r::intersection(), Slic3r::Layer::lower_layer, Slic3r::Layer::lslices, Slic3r::Layer::lslices_ex, Slic3r::Layer::print_z, Slic3r::SupportSpotsGenerator::SliceConnection::second_moment_of_area_accumulator, Slic3r::SupportSpotsGenerator::SliceConnection::second_moment_of_area_covariance_accumulator, sign(), Slic3r::to_polygons(), and Slic3r::unscaled().

+ Here is the call graph for this function:

◆ estimate_supports_malformations() [1/2]

void Slic3r::SupportSpotsGenerator::estimate_supports_malformations ( std::vector< SupportLayer * > &  layers,
float  supports_flow_width,
const Params params 
)

◆ estimate_supports_malformations() [2/2]

void Slic3r::SupportSpotsGenerator::estimate_supports_malformations ( SupportLayerPtrs layers,
float  flow_width,
const Params params 
)
1090{
1091#ifdef DEBUG_FILES
1092 FILE *debug_file = boost::nowide::fopen(debug_out_path("supports_malformations.obj").c_str(), "w");
1093 FILE *full_file = boost::nowide::fopen(debug_out_path("supports_full.obj").c_str(), "w");
1094#endif
1095
1097
1098 for (SupportLayer *l : layers) {
1099 l->curled_lines.clear();
1100 std::vector<ExtrusionLine> current_layer_lines;
1101
1102 for (const ExtrusionEntity *extrusion : l->support_fills.flatten().entities) {
1103 Polyline pl = extrusion->as_polyline();
1104 Polygon pol(pl.points);
1105 pol.make_counter_clockwise();
1106
1107 auto annotated_points = estimate_points_properties<true, true, false, false>(pol.points, prev_layer_lines, flow_width);
1108
1109 for (size_t i = 0; i < annotated_points.size(); ++i) {
1110 const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
1111 const ExtendedPoint &b = annotated_points[i];
1112 ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
1113 extrusion};
1114
1115 Vec2f middle = 0.5 * (line_out.a + line_out.b);
1116 auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra<false>(middle);
1117 ExtrusionLine bottom_line = prev_layer_lines.get_lines().empty() ? ExtrusionLine{} :
1118 prev_layer_lines.get_line(bottom_line_idx);
1119
1120 Vec2f v1 = (bottom_line.b - bottom_line.a);
1121 Vec2f v2 = (a.position.cast<float>() - bottom_line.a);
1122 auto d = (v1.x() * v2.y()) - (v1.y() * v2.x());
1123 float sign = (d > 0) ? -1.0f : 1.0f;
1124
1125 line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign, 0.5 * (a.curvature + b.curvature), l->height,
1126 flow_width, bottom_line.curled_up_height, params);
1127
1128 current_layer_lines.push_back(line_out);
1129 }
1130 }
1131
1132 for (const ExtrusionLine &line : current_layer_lines) {
1133 if (line.curled_up_height > params.curling_tolerance_limit) {
1134 l->curled_lines.push_back(CurledLine{Point::new_scale(line.a), Point::new_scale(line.b), line.curled_up_height});
1135 }
1136 }
1137
1138#ifdef DEBUG_FILES
1139 for (const ExtrusionLine &line : current_layer_lines) {
1140 if (line.curled_up_height > params.curling_tolerance_limit) {
1141 Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
1142 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]);
1143 }
1144 }
1145 for (const ExtrusionLine &line : current_layer_lines) {
1146 Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height);
1147 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]);
1148 }
1149#endif
1150
1151 prev_layer_lines = LD{current_layer_lines};
1152 }
1153
1154#ifdef DEBUG_FILES
1155 fclose(debug_file);
1156 fclose(full_file);
1157#endif
1158}
Definition Polygon.hpp:24
Definition Polyline.hpp:17
Definition Layer.hpp:428
Definition ExtrusionProcessor.hpp:32

References Slic3r::ExtrusionLine::a, Slic3r::ExtrusionLine::b, Slic3r::ExtrusionLine::curled_up_height, Slic3r::SupportSpotsGenerator::Params::curling_tolerance_limit, Slic3r::debug_out_path(), EPSILON, estimate_curled_up_height(), estimate_supports_malformations(), Slic3r::Polygon::make_counter_clockwise(), Slic3r::SupportSpotsGenerator::Params::max_curled_height_factor, Slic3r::MultiPoint::points, sign(), and Slic3r::value_to_rgbf().

Referenced by estimate_supports_malformations().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ full_search()

std::tuple< SupportPoints, PartialObjects > Slic3r::SupportSpotsGenerator::full_search ( const PrintObject po,
const PrintTryCancel cancel_func,
const Params params 
)
1078{
1079 auto precomputed_slices_connections = precompute_slices_connections(po);
1080 auto results = check_stability(po, precomputed_slices_connections, cancel_func, params);
1081#ifdef DEBUG_FILES
1082 auto [supp_points, objects] = results;
1083 debug_export(supp_points, objects, "issues");
1084#endif
1085
1086 return results;
1087}
PrecomputedSliceConnections precompute_slices_connections(const PrintObject *po)
Definition SupportSpotsGenerator.cpp:216
std::tuple< SupportPoints, PartialObjects > check_stability(const PrintObject *po, const PrecomputedSliceConnections &precomputed_slices_connections, const PrintTryCancel &cancel_func, const Params &params)
Definition SupportSpotsGenerator.cpp:785

References check_stability(), full_search(), and precompute_slices_connections().

Referenced by full_search().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ gather_issues()

std::vector< std::pair< SupportPointCause, bool > > Slic3r::SupportSpotsGenerator::gather_issues ( const SupportPoints support_points,
PartialObjects partial_objects 
)
1235{
1236 std::vector<std::pair<SupportPointCause, bool>> result;
1237 // The partial object are most likely sorted from smaller to larger as the print continues, so this should save some sorting time
1238 std::reverse(partial_objects.begin(), partial_objects.end());
1239 std::sort(partial_objects.begin(), partial_objects.end(),
1240 [](const PartialObject &left, const PartialObject &right) { return left.volume > right.volume; });
1241
1242 // Object may have zero extrusions and thus no partial objects. (e.g. very tiny object)
1243 float max_volume_part = partial_objects.empty() ? 0.0f : partial_objects.front().volume;
1244 for (const PartialObject &p : partial_objects) {
1245 if (p.volume > max_volume_part / 200.0f && !p.connected_to_bed) {
1246 result.emplace_back(SupportPointCause::UnstableFloatingPart, true);
1247 break;
1248 }
1249 }
1250
1251 // should be detected in previous step
1252 // if (!unstable_floating_part_added) {
1253 // for (const SupportPoint &sp : support_points) {
1254 // if (sp.cause == SupportPointCause::UnstableFloatingPart) {
1255 // result.emplace_back(SupportPointCause::UnstableFloatingPart, true);
1256 // break;
1257 // }
1258 // }
1259 // }
1260
1261 std::vector<SupportPoint> ext_supp_points{};
1262 ext_supp_points.reserve(support_points.size());
1263 for (const SupportPoint &sp : support_points) {
1264 switch (sp.cause) {
1265 case SupportPointCause::FloatingBridgeAnchor:
1266 case SupportPointCause::FloatingExtrusion: ext_supp_points.push_back(sp); break;
1267 default: break;
1268 }
1269 }
1270
1271 auto coord_fn = [&ext_supp_points](size_t idx, size_t dim) { return ext_supp_points[idx].position[dim]; };
1272 KDTreeIndirect<3, float, decltype(coord_fn)> ext_points_tree{coord_fn, ext_supp_points.size()};
1273 for (const SupportPoint &sp : ext_supp_points) {
1274 auto cluster = find_nearby_points(ext_points_tree, sp.position, 3.0);
1275 int score = 0;
1276 bool floating_bridge = false;
1277 for (size_t idx : cluster) {
1278 score += ext_supp_points[idx].cause == SupportPointCause::FloatingBridgeAnchor ? 3 : 1;
1279 floating_bridge = floating_bridge || ext_supp_points[idx].cause == SupportPointCause::FloatingBridgeAnchor;
1280 }
1281 if (score > 5) {
1282 if (floating_bridge) {
1283 result.emplace_back(SupportPointCause::FloatingBridgeAnchor, true);
1284 } else {
1285 result.emplace_back(SupportPointCause::FloatingExtrusion, true);
1286 }
1287 break;
1288 }
1289 }
1290
1291 for (const SupportPoint &sp : support_points) {
1292 if (sp.cause == SupportPointCause::SeparationFromBed) {
1293 result.emplace_back(SupportPointCause::SeparationFromBed, true);
1294 break;
1295 }
1296 }
1297
1298 for (const SupportPoint &sp : support_points) {
1299 if (sp.cause == SupportPointCause::WeakObjectPart) {
1300 result.emplace_back(SupportPointCause::WeakObjectPart, true);
1301 break;
1302 }
1303 }
1304
1305 if (ext_supp_points.size() > max_volume_part / 200.0f) {
1306 result.emplace_back(SupportPointCause::FloatingExtrusion, false);
1307 }
1308
1309 for (const SupportPoint &sp : support_points) {
1310 if (sp.cause == SupportPointCause::LongBridge) {
1311 result.emplace_back(SupportPointCause::LongBridge, false);
1312 break;
1313 }
1314 }
1315
1316 return result;
1317}
ClusteredPoints cluster(Index3D &sindex, unsigned max_points, std::function< std::vector< PointIndexEl >(const Index3D &, const PointIndexEl &)> qfn)
Definition Clustering.cpp:19
std::vector< size_t > find_nearby_points(const KDTreeIndirectType &kdtree, const PointType &center, const typename KDTreeIndirectType::CoordType &max_distance, FilterFn filter)
Definition KDTreeIndirect.hpp:281
Definition SupportSpotsGenerator.hpp:136

References Slic3r::find_nearby_points(), and gather_issues().

Referenced by Slic3r::Print::alert_when_supports_needed(), and gather_issues().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_flow_width()

float Slic3r::SupportSpotsGenerator::get_flow_width ( const LayerRegion region,
ExtrusionRole  role 
)
241{
242 if (role == ExtrusionRole::BridgeInfill) return region->flow(FlowRole::frExternalPerimeter).width();
243 if (role == ExtrusionRole::ExternalPerimeter) return region->flow(FlowRole::frExternalPerimeter).width();
244 if (role == ExtrusionRole::GapFill) return region->flow(FlowRole::frInfill).width();
245 if (role == ExtrusionRole::Perimeter) return region->flow(FlowRole::frPerimeter).width();
246 if (role == ExtrusionRole::SolidInfill) return region->flow(FlowRole::frSolidInfill).width();
247 if (role == ExtrusionRole::InternalInfill) return region->flow(FlowRole::frInfill).width();
248 if (role == ExtrusionRole::TopSolidInfill) return region->flow(FlowRole::frTopSolidInfill).width();
249 // default
250 return region->flow(FlowRole::frPerimeter).width();
251}
float width() const
Definition Flow.hpp:60
Flow flow(FlowRole role) const
Definition LayerRegion.cpp:22

References Slic3r::ExtrusionRole::BridgeInfill, Slic3r::ExtrusionRole::ExternalPerimeter, Slic3r::LayerRegion::flow(), Slic3r::frExternalPerimeter, Slic3r::frInfill, Slic3r::frPerimeter, Slic3r::frSolidInfill, Slic3r::frTopSolidInfill, Slic3r::ExtrusionRole::GapFill, get_flow_width(), Slic3r::ExtrusionRole::InternalInfill, Slic3r::ExtrusionRole::Perimeter, Slic3r::ExtrusionRole::SolidInfill, Slic3r::ExtrusionRole::TopSolidInfill, and Slic3r::Flow::width().

Referenced by build_object_part_from_slice(), check_extrusion_entity_stability(), estimate_malformations(), and get_flow_width().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ precompute_slices_connections()

PrecomputedSliceConnections Slic3r::SupportSpotsGenerator::precompute_slices_connections ( const PrintObject po)
217{
219 for (size_t lidx = 0; lidx < po->layer_count(); lidx++) {
220 result.emplace_back(std::vector<SliceConnection>{});
221 for (size_t slice_idx = 0; slice_idx < po->get_layer(lidx)->lslices_ex.size(); slice_idx++) {
222 result[lidx].push_back(SliceConnection{});
223 }
224 }
225
226 tbb::parallel_for(tbb::blocked_range<size_t>(0, po->layers().size()), [po, &result](tbb::blocked_range<size_t> r) {
227 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
228 const Layer *l = po->get_layer(lidx);
229 tbb::parallel_for(tbb::blocked_range<size_t>(0, l->lslices_ex.size()), [lidx, l, &result](tbb::blocked_range<size_t> r2) {
230 for (size_t slice_idx = r2.begin(); slice_idx < r2.end(); slice_idx++) {
231 result[lidx][slice_idx] = estimate_slice_connection(slice_idx, l);
232 }
233 });
234 }
235 });
236
237 return result;
238};
auto layers() const
Definition Print.hpp:247
std::vector< std::vector< SliceConnection > > PrecomputedSliceConnections
Definition SupportSpotsGenerator.cpp:215

References Slic3r::PrintObject::get_layer(), Slic3r::PrintObject::layer_count(), and Slic3r::PrintObject::layers().

Referenced by full_search().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ to_short_lines()

std::vector< ExtrusionLine > Slic3r::SupportSpotsGenerator::to_short_lines ( const ExtrusionEntity e,
float  length_limit 
)
254{
255 assert(!e->is_collection());
256 Polyline pl = e->as_polyline();
257 std::vector<ExtrusionLine> lines;
258 lines.reserve(pl.points.size() * 1.5f);
259 for (int point_idx = 0; point_idx < int(pl.points.size()) - 1; ++point_idx) {
260 Vec2f start = unscaled(pl.points[point_idx]).cast<float>();
261 Vec2f next = unscaled(pl.points[point_idx + 1]).cast<float>();
262 Vec2f v = next - start; // vector from next to current
263 float dist_to_next = v.norm();
264 v.normalize();
265 int lines_count = int(std::ceil(dist_to_next / length_limit));
266 float step_size = dist_to_next / lines_count;
267 for (int i = 0; i < lines_count; ++i) {
268 Vec2f a(start + v * (i * step_size));
269 Vec2f b(start + v * ((i + 1) * step_size));
270 lines.emplace_back(a, b, (a-b).norm(), e);
271 }
272 }
273 return lines;
274}

References Slic3r::ExtrusionEntity::as_polyline(), Slic3r::ExtrusionEntity::is_collection(), Slic3r::MultiPoint::points, to_short_lines(), and Slic3r::unscaled().

Referenced by build_object_part_from_slice(), and to_short_lines().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: