fix(imex): block slicing when the prime tower overlaps a parallel-printing zone

IMEX placement validation only walked model instances. The prime tower is
not a ModelObject, so it could sit in a secondary zone or a carriage
collision strip and slice with no warning -- on mirror mode, a carriage
crash. Span (paired-gantry multicolor) is what made towers reachable in
parallel modes, so this is a gap in that feature, not inherited breakage.

The check now returns a cause instead of a bool so the message can name the
offender, and the tower and per-instance paths share one predicate,
imex_hull_violates_zones(), moved to libslic3r and covered by tests.
Overlap is area-based: a hull flush against a zone boundary is legal, only
a crossing violates. The tests pin that in both directions, since switching
to a touch-based test would silently block placements that work today.

The tower footprint comes from the same estimate the scene draws, so
validation matches what the user sees and drags. Three config reads there
are load-bearing in non-obvious ways and are commented at the point of use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-08-03 08:26:38 -04:00
co-authored by Claude Opus 5
parent 3315b88012
commit 3852f4be61
6 changed files with 222 additions and 41 deletions
+19 -4
View File
@@ -8982,13 +8982,28 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
q->post_process_string_object_exception(err);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": validate err=%1%, warnings=%2%")%err.string%warnings.size();
// IDEX/IQEX placement check: if objects overlap secondary zones, treat it as a
// IDEX/IQEX placement check: if anything overlaps a reserved area, treat it as a
// validation error so the standard pathway handles button state, notifications,
// and auto-slice blocking consistently.
// and auto-slice blocking consistently. The message names both kinds of reserved
// area because the check covers secondary zones AND the carriage clearance strips,
// and the strips sit INSIDE the primary zone — saying "secondary zone" alone sends
// the user looking in the wrong half of the bed.
if (err.string.empty()) {
PartPlate* imex_plate = partplate_list.get_curr_plate();
if (imex_plate && imex_plate->has_imex_placement_violations())
err.string = _u8L("Cannot slice: objects are in secondary zones reserved for IDEX/IQEX parallel printing.");
if (imex_plate) {
switch (imex_plate->imex_placement_violation()) {
case PartPlate::ImexPlacementViolation::Object:
err.string = _u8L("Cannot slice: an object overlaps an area reserved for IMEX parallel printing "
"(a secondary zone, or a carriage clearance strip inside the primary zone).");
break;
case PartPlate::ImexPlacementViolation::PrimeTower:
err.string = _u8L("Cannot slice: the prime tower overlaps an area reserved for IMEX parallel printing "
"(a secondary zone, or a carriage clearance strip inside the primary zone).");
break;
case PartPlate::ImexPlacementViolation::None:
break;
}
}
}
if (err.string.empty()) {