From 1cacc6d02d88bd991690f5482e0e17fcaf7d316d Mon Sep 17 00:00:00 2001 From: Clifford Garwood Date: Mon, 6 Apr 2026 01:02:44 -0400 Subject: [PATCH] fix: exclude iXex collision strips from auto-arrange placement Auto-arrange now injects the carriage collision zones as hard excluded regions (is_virt_object) when an iXex parallel mode is active, using the same BoundingBoxf3 data already stored for rendering and violation checks. Objects will no longer be placed in the mirror-edge danger strips. Co-Authored-By: Claude Sonnet 4.6 --- src/slic3r/GUI/Jobs/ArrangeJob.cpp | 20 +++++++++++++++++++- src/slic3r/GUI/PartPlate.hpp | 3 +++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index dded97556a..16e5531a74 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -540,7 +540,8 @@ void ArrangeJob::process(Ctl &ctl) Points bedpts = get_shrink_bedpts(m_plater->config(),params); - // When an iXex parallel mode is active, constrain auto-arrange to the primary zone only. + // When an iXex parallel mode is active, constrain auto-arrange to the primary zone only + // and treat carriage collision strips as hard excluded regions. if (PartPlate* curr_plate = partplate_list.get_curr_plate()) { if (auto pz = curr_plate->ixex_primary_zone()) { BoundingBox scaled_pz = scaled(*pz); @@ -550,6 +551,23 @@ void ArrangeJob::process(Ctl &ctl) { scaled_pz.max.x(), scaled_pz.max.y() }, { scaled_pz.min.x(), scaled_pz.max.y() }, }; + for (const BoundingBoxf3& cz : curr_plate->ixex_collision_zones()) { + Polygon poly({ + { scaled(cz.min.x()), scaled(cz.min.y()) }, + { scaled(cz.max.x()), scaled(cz.min.y()) }, + { scaled(cz.max.x()), scaled(cz.max.y()) }, + { scaled(cz.min.x()), scaled(cz.max.y()) }, + }); + arrangement::ArrangePolygon ap; + ap.poly.contour = poly; + ap.translation = Vec2crd(0, 0); + ap.rotation = 0.0; + ap.is_virt_object = true; + ap.bed_idx = current_plate_index; + ap.height = 1; + ap.name = "IXexCollisionZone"; + params.excluded_regions.emplace_back(std::move(ap)); + } } } diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 23d63da7e0..4954e6f3b5 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -449,6 +449,9 @@ public: // Returns the primary-zone bounding box in mm when an iXex parallel mode is active. // Empty (nullopt) when iXex is off or the mode is "primary" (full-bed). std::optional ixex_primary_zone() { ensure_ixex_zones(); return m_ixex_primary_zone_box; } + // Returns carriage collision strips (mm) for the current iXex mode. + // Always call ixex_primary_zone() first to ensure the cache is warm. + const std::vector& ixex_collision_zones() const { return m_ixex_collision_zones; } void update_slice_ready_status(bool ready_slice) { m_ready_for_slice = ready_slice;