OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::ExclusionVolumeTravelAvoidance Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/ExclusionVolumeTravelAvoidance.hpp>

Collaboration diagram for Slic3r::ExclusionVolumeTravelAvoidance:

Classes

struct  Result
struct  RoutingSpace

Public Types

enum class  Status : unsigned char { Unchanged , Rerouted , EndpointInside , Failed }
enum class  Detail : unsigned char {
  None , UnknownExtruder , NoActiveObstacles , NoIntersection ,
  EndpointInside , SegmentOutsideBed , DetourFailed , FinalPathInvalid ,
  IterationLimit
}

Public Member Functions

void init (const PrintConfig &config, const Vec3d &plate_origin)
void clear ()
bool empty () const
Result route (const Polyline &travel, double start_z, double end_z, int extruder_id)

Private Member Functions

const ExPolygons * active_obstacles (RoutingSpace &space, double z_min, double z_max)

Private Attributes

std::vector< RoutingSpace > m_spaces
coord_t m_clearance { 0 }

Detailed Description


Class Documentation

◆ Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace

struct Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace
Collaboration diagram for Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace:
Class Members
map< vector< size_t >, ExPolygons > obstacle_cache
vector< BoundingBox > region_bboxes
vector< BedExcludeRegion > regions
ExPolygons valid_bed

Member Enumeration Documentation

◆ Detail

enum class Slic3r::ExclusionVolumeTravelAvoidance::Detail : unsigned char
strong
Enumerator
None 
UnknownExtruder 
NoActiveObstacles 
NoIntersection 
EndpointInside 
SegmentOutsideBed 
DetourFailed 
FinalPathInvalid 
IterationLimit 
28 {
29 None,
30 UnknownExtruder,
31 NoActiveObstacles,
33 EndpointInside,
34 SegmentOutsideBed,
35 DetourFailed,
36 FinalPathInvalid,
37 IterationLimit
38 };
@ NoIntersection
Definition PerformCSGMeshBooleans.hpp:20
@ None
Definition SketchEngine.hpp:180

◆ Status

enum class Slic3r::ExclusionVolumeTravelAvoidance::Status : unsigned char
strong
Enumerator
Unchanged 
Rerouted 
EndpointInside 
Failed 
20 {
22 Rerouted,
23 EndpointInside,
24 Failed
25 };
@ Unchanged
Definition TextureDisplacementPrepareJob.hpp:35

Member Function Documentation

◆ active_obstacles()

const ExPolygons * Slic3r::ExclusionVolumeTravelAvoidance::active_obstacles ( RoutingSpace & space,
double z_min,
double z_max )
private
502{
503 std::vector<size_t> active_region_ids;
504 active_region_ids.reserve(space.regions.size());
505 for (size_t region_id = 0; region_id < space.regions.size(); ++region_id) {
506 const BedExcludeRegion &region = space.regions[region_id];
507 if (bed_exclusion_z_ranges_overlap(z_min, z_max, region.z_min, region.z_max))
508 active_region_ids.emplace_back(region_id);
509 }
510 if (active_region_ids.empty())
511 return nullptr;
512
513 const auto cached = space.obstacle_cache.find(active_region_ids);
514 if (cached != space.obstacle_cache.end())
515 return cached->second.empty() ? nullptr : &cached->second;
516
517 std::vector<BedExcludeRegion> active_regions;
518 active_regions.reserve(active_region_ids.size());
519 for (const size_t region_id : active_region_ids)
520 active_regions.emplace_back(space.regions[region_id]);
521
523 active_regions, z_min, z_max, Point(0, 0), m_clearance);
524 const auto cache_result = space.obstacle_cache.emplace(
525 std::move(active_region_ids), std::move(obstacles));
526 return cache_result.first->second.empty() ? nullptr : &cache_result.first->second;
527}
coord_t m_clearance
Definition ExclusionVolumeTravelAvoidance.hpp:75
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
bool bed_exclusion_z_ranges_overlap(double first_min, double first_max, double second_min, double second_max)
Definition ExclusionVolumeGeometry.cpp:57
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:20
ExPolygons active_bed_exclusion_footprints(const std::vector< BedExcludeRegion > &regions, const double z_min, const double z_max, const Point &translation, const coord_t clearance)
Definition ExclusionVolumeGeometry.cpp:85

References Slic3r::active_bed_exclusion_footprints(), Slic3r::bed_exclusion_z_ranges_overlap(), m_clearance, Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::obstacle_cache, Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::regions, Slic3r::BedExcludeRegion::z_max, and Slic3r::BedExcludeRegion::z_min.

Referenced by route().

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

◆ clear()

void Slic3r::ExclusionVolumeTravelAvoidance::clear ( )
485{
486 m_spaces.clear();
487 m_clearance = static_cast<coord_t>(SCALED_EPSILON);
488}
std::vector< RoutingSpace > m_spaces
Definition ExclusionVolumeTravelAvoidance.hpp:74
#define SCALED_EPSILON
Definition libslic3r.h:109
int64_t coord_t
Definition libslic3r.h:48

References m_clearance, m_spaces, and SCALED_EPSILON.

Referenced by init().

Here is the caller graph for this function:

◆ empty()

bool Slic3r::ExclusionVolumeTravelAvoidance::empty ( ) const
491{
492 return std::all_of(m_spaces.begin(), m_spaces.end(), [](const RoutingSpace &space) {
493 return space.regions.empty();
494 });
495}
Definition ExclusionVolumeTravelAvoidance.hpp:62

References m_spaces.

◆ init()

void Slic3r::ExclusionVolumeTravelAvoidance::init ( const PrintConfig & config,
const Vec3d & plate_origin )
433{
434 clear();
435
436 double max_nozzle_diameter = 0.0;
437 for (double diameter : config.nozzle_diameter.values)
438 max_nozzle_diameter = std::max(max_nozzle_diameter, diameter);
439
440 // This is a numerical/perimeter-walk clearance, not a hidden toolhead
441 // footprint. The exact configured volume remains Stage 2's source of truth.
442 const coord_t minimum_clearance = static_cast<coord_t>(SCALED_EPSILON);
443 const coord_t configured_clearance =
444 static_cast<coord_t>(scale_(std::max(0.05, 0.1 * max_nozzle_diameter)));
445 m_clearance = std::max(minimum_clearance, configured_clearance);
446
447 std::vector<std::vector<BedExcludeRegion>> regions_by_extruder =
449 m_spaces.resize(regions_by_extruder.size());
450
451 const Polygon base_bed_shape(get_bed_shape(config));
452 const Vec2d plate_xy = plate_origin.head<2>();
453 for (size_t extruder_id = 0; extruder_id < regions_by_extruder.size(); ++extruder_id) {
454 RoutingSpace &space = m_spaces[extruder_id];
455 space.regions = std::move(regions_by_extruder[extruder_id]);
456 space.regions.erase(std::remove_if(space.regions.begin(), space.regions.end(),
457 [](const BedExcludeRegion &region) { return !region.is_collision_volume(); }), space.regions.end());
458
459 const Vec2d extruder_offset = extruder_id < config.extruder_offset.values.size() ?
460 config.extruder_offset.values[extruder_id] : Vec2d::Zero();
461 // Resolved regions are in nozzle/model space. The generator routes in
462 // emitted G-code space (model - active nozzle offset), before the writer
463 // subtracts the plate origin, so transform both obstacles and bed alike.
464 const Vec2d translation_mm = plate_xy - extruder_offset;
465 const Point translation = scaled<coord_t>(translation_mm);
466 for (BedExcludeRegion &region : space.regions) {
467 region.polygon.translate(translation);
468 BoundingBox bbox(region.polygon.points);
469 bbox.offset(m_clearance);
470 space.region_bboxes.emplace_back(std::move(bbox));
471 }
472
473 Polygon bed_shape = base_bed_shape;
474 bed_shape.translate(translation);
475 bed_shape.make_counter_clockwise();
476 if (bed_shape.points.size() >= 3) {
477 space.valid_bed = offset_ex(bed_shape, -float(m_clearance));
478 if (space.valid_bed.empty())
479 space.valid_bed = union_ex(Polygons { std::move(bed_shape) });
480 }
481 }
482}
void clear()
Definition ExclusionVolumeTravelAvoidance.cpp:484
void translate(double x, double y)
Definition MultiPoint.hpp:38
#define scale_(val)
Definition libslic3r.h:106
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:22
zaa_minimize_perimeter_height extruder_offset((ConfigOptionBools, reduce_fan_stop_start_freq))((ConfigOptionBools
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:605
std::vector< std::vector< BedExcludeRegion > > get_bed_excluded_regions_by_extruder(const DynamicPrintConfig &cfg)
Definition PrintConfig.cpp:14211
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type)
Definition ClipperUtils.cpp:1011
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
Points get_bed_shape(const DynamicPrintConfig &config, bool use_share)
Definition PrintConfig.cpp:13837
Slic3r::Polygon Polygon
Definition Emboss.cpp:101

References clear(), Slic3r::extruder_offset(), Slic3r::get_bed_excluded_regions_by_extruder(), Slic3r::get_bed_shape(), m_clearance, m_spaces, Slic3r::Polygon::make_counter_clockwise(), Slic3r::BoundingBoxBase< PointType, APointsType >::offset(), Slic3r::offset_ex(), Slic3r::MultiPoint::points, Slic3r::BedExcludeRegion::polygon, Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::region_bboxes, Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::regions, scale_, Slic3r::scaled(), SCALED_EPSILON, Slic3r::MultiPoint::translate(), Slic3r::union_ex(), and Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::valid_bed.

Here is the call graph for this function:

◆ route()

ExclusionVolumeTravelAvoidance::Result Slic3r::ExclusionVolumeTravelAvoidance::route ( const Polyline & travel,
double start_z,
double end_z,
int extruder_id )
534{
535 Result result;
536 result.path = travel;
537 if (travel.points.size() < 2)
538 return result;
539 if (extruder_id < 0 || size_t(extruder_id) >= m_spaces.size()) {
540 result.status = Status::Failed;
541 result.detail = Detail::UnknownExtruder;
542 return result;
543 }
544
545 RoutingSpace &space = m_spaces[size_t(extruder_id)];
546 if (space.regions.empty()) {
547 result.detail = Detail::NoActiveObstacles;
548 return result;
549 }
550
551 const double z_min = std::min(start_z, end_z);
552 const double z_max = std::max(start_z, end_z);
553
554 // Most travels are nowhere near an exclusion. Reject them using the cheap
555 // precomputed boxes before unioning and inflating obstacle polygons.
556 const BoundingBox travel_bbox(travel.points);
557 bool has_active_z = false;
558 bool may_intersect = false;
559 for (size_t region_id = 0; region_id < space.regions.size(); ++region_id) {
560 const BedExcludeRegion &region = space.regions[region_id];
561 if (!bed_exclusion_z_ranges_overlap(z_min, z_max, region.z_min, region.z_max))
562 continue;
563 has_active_z = true;
564 if (region_id < space.region_bboxes.size() && space.region_bboxes[region_id].overlap(travel_bbox)) {
565 may_intersect = true;
566 break;
567 }
568 }
569 if (!has_active_z) {
570 result.detail = Detail::NoActiveObstacles;
571 return result;
572 }
573 if (!may_intersect) {
574 result.detail = Detail::NoIntersection;
575 return result;
576 }
577
578 const ExPolygons *active = active_obstacles(space, z_min, z_max);
579 if (active == nullptr || active->empty()) {
580 result.detail = Detail::NoActiveObstacles;
581 return result;
582 }
583 result.active_obstacles = active->size();
584
585 const Point &start = travel.points.front();
586 const Point &end = travel.points.back();
587 const bool start_outside_bed = !space.valid_bed.empty() &&
588 !point_in_expolygons(space.valid_bed, start, true);
589 const bool end_outside_bed = !space.valid_bed.empty() &&
590 !point_in_expolygons(space.valid_bed, end, true);
591 const ExPolygons *start_obstacles = active_obstacles(space, start_z, start_z);
592 const ExPolygons *end_obstacles = active_obstacles(space, end_z, end_z);
593 if ((start_obstacles != nullptr && point_in_expolygons_interior(*start_obstacles, start)) ||
594 (end_obstacles != nullptr && point_in_expolygons_interior(*end_obstacles, end))) {
595 result.status = Status::EndpointInside;
596 result.detail = Detail::EndpointInside;
597 return result;
598 }
599
600 bool needs_reroute = false;
601 for (size_t idx = 1; idx < travel.points.size(); ++idx) {
602 if (segment_enters_expolygons_interior(travel.points[idx - 1], travel.points[idx], *active)) {
603 needs_reroute = true;
604 break;
605 }
606 }
607 if (!needs_reroute) {
608 result.detail = Detail::NoIntersection;
609 return result;
610 }
611
612 Polyline path = travel;
613 bool rerouted = false;
614 for (size_t iteration = 0; iteration < MAX_REROUTE_ITERATIONS; ++iteration) {
615 result.iterations = iteration + 1;
616 bool changed = false;
617 for (size_t segment_idx = 0; segment_idx + 1 < path.points.size(); ++segment_idx) {
618 const Point &a = path.points[segment_idx];
619 const Point &b = path.points[segment_idx + 1];
620 const bool allow_a_outside = start_outside_bed && segment_idx == 0;
621 const bool allow_b_outside = end_outside_bed && segment_idx + 2 == path.points.size();
622 const Polyline segment({a, b});
624 segment, space.valid_bed, allow_a_outside, allow_b_outside)) {
625 result.status = Status::Failed;
626 result.detail = Detail::SegmentOutsideBed;
627 return result;
628 }
629
630 const std::optional<size_t> obstacle_idx = first_intersected_obstacle(a, b, *active);
631 if (!obstacle_idx)
632 continue;
633
634 const std::optional<Polyline> detour = detour_around_obstacle(
635 a, b, (*active)[*obstacle_idx], *active, space.valid_bed,
636 allow_a_outside, allow_b_outside);
637 if (!detour) {
638 result.status = Status::Failed;
639 result.detail = Detail::DetourFailed;
640 return result;
641 }
642 if (replacement_matches_original_segment(*detour, a, b))
643 continue;
644
645 replace_segment(path, segment_idx, *detour);
646 changed = true;
647 rerouted = true;
648 break;
649 }
650
651 if (!changed) {
652 path = simplify_path(path, *active, space.valid_bed);
654 path, space.valid_bed, start_outside_bed, end_outside_bed) ||
655 polyline_intersects_obstacles(path, *active)) {
656 result.status = Status::Failed;
657 result.detail = Detail::FinalPathInvalid;
658 return result;
659 }
660 result.path = std::move(path);
661 result.status = rerouted ? Status::Rerouted : Status::Unchanged;
662 result.detail = rerouted ? Detail::None : Detail::NoIntersection;
663 return result;
664 }
665 }
666
667 result.status = Status::Failed;
668 result.detail = Detail::IterationLimit;
669 return result;
670}
@ NoActiveObstacles
Definition ExclusionVolumeTravelAvoidance.hpp:31
@ EndpointInside
Definition ExclusionVolumeTravelAvoidance.hpp:33
@ UnknownExtruder
Definition ExclusionVolumeTravelAvoidance.hpp:30
@ None
Definition ExclusionVolumeTravelAvoidance.hpp:29
@ DetourFailed
Definition ExclusionVolumeTravelAvoidance.hpp:35
@ FinalPathInvalid
Definition ExclusionVolumeTravelAvoidance.hpp:36
@ NoIntersection
Definition ExclusionVolumeTravelAvoidance.hpp:32
@ SegmentOutsideBed
Definition ExclusionVolumeTravelAvoidance.hpp:34
@ IterationLimit
Definition ExclusionVolumeTravelAvoidance.hpp:37
const ExPolygons * active_obstacles(RoutingSpace &space, double z_min, double z_max)
Definition ExclusionVolumeTravelAvoidance.cpp:498
@ EndpointInside
Definition ExclusionVolumeTravelAvoidance.hpp:23
@ Unchanged
Definition ExclusionVolumeTravelAvoidance.hpp:21
@ Rerouted
Definition ExclusionVolumeTravelAvoidance.hpp:22
@ Failed
Definition ExclusionVolumeTravelAvoidance.hpp:24
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
void segment(CGALMesh &src, std::vector< CGALMesh > &dst, double smoothing_alpha=0.5, int segment_number=5)
Definition MeshBoolean.cpp:480
bool point_in_expolygons(const ExPolygons &expolygons, const Point &point, bool border_result)
Definition ExclusionVolumeTravelAvoidance.cpp:112
bool polyline_intersects_obstacles(const Polyline &polyline, const ExPolygons &obstacles)
Definition ExclusionVolumeTravelAvoidance.cpp:326
std::optional< size_t > first_intersected_obstacle(const Point &a, const Point &b, const ExPolygons &obstacles)
Definition ExclusionVolumeTravelAvoidance.cpp:334
bool replacement_matches_original_segment(const Polyline &replacement, const Point &a, const Point &b)
Definition ExclusionVolumeTravelAvoidance.cpp:241
constexpr size_t MAX_REROUTE_ITERATIONS
Definition ExclusionVolumeTravelAvoidance.cpp:25
Polyline simplify_path(const Polyline &path, const ExPolygons &obstacles, const ExPolygons &valid_bed)
Definition ExclusionVolumeTravelAvoidance.cpp:408
bool segment_enters_expolygons_interior(const Point &a, const Point &b, const ExPolygons &expolygons)
Definition ExclusionVolumeTravelAvoidance.cpp:163
bool point_in_expolygons_interior(const ExPolygons &expolygons, const Point &point)
Definition ExclusionVolumeTravelAvoidance.cpp:136
bool routed_polyline_inside_bed(const Polyline &polyline, const ExPolygons &valid_bed, const bool allow_start_outside, const bool allow_end_outside)
Definition ExclusionVolumeTravelAvoidance.cpp:297
std::optional< Polyline > detour_around_obstacle(const Point &a, const Point &b, const ExPolygon &obstacle, const ExPolygons &obstacles, const ExPolygons &valid_bed, const bool allow_start_outside, const bool allow_end_outside)
Definition ExclusionVolumeTravelAvoidance.cpp:351
void replace_segment(Polyline &path, size_t segment_idx, const Polyline &replacement)
Definition ExclusionVolumeTravelAvoidance.cpp:395
Definition ExclusionVolumeTravelAvoidance.hpp:41
Polyline path
Definition ExclusionVolumeTravelAvoidance.hpp:44

References active_obstacles(), Slic3r::ExclusionVolumeTravelAvoidance::Result::active_obstacles, Slic3r::bed_exclusion_z_ranges_overlap(), Slic3r::ExclusionVolumeTravelAvoidance::Result::detail, DetourFailed, EndpointInside, Failed, FinalPathInvalid, IterationLimit, Slic3r::ExclusionVolumeTravelAvoidance::Result::iterations, m_spaces, NoActiveObstacles, NoIntersection, None, Slic3r::ExclusionVolumeTravelAvoidance::Result::path, Slic3r::MultiPoint::points, Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::region_bboxes, Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::regions, Rerouted, SegmentOutsideBed, Slic3r::ExclusionVolumeTravelAvoidance::Result::status, Unchanged, UnknownExtruder, Slic3r::ExclusionVolumeTravelAvoidance::RoutingSpace::valid_bed, Slic3r::BedExcludeRegion::z_max, and Slic3r::BedExcludeRegion::z_min.

Here is the call graph for this function:

Member Data Documentation

◆ m_clearance

coord_t Slic3r::ExclusionVolumeTravelAvoidance::m_clearance { 0 }
private
75{ 0 };

Referenced by active_obstacles(), clear(), and init().

◆ m_spaces

std::vector<RoutingSpace> Slic3r::ExclusionVolumeTravelAvoidance::m_spaces
private

Referenced by clear(), empty(), init(), and route().


The documentation for this class was generated from the following files: