mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-28 11:21:30 +00:00
Fix inner-outer-inner wall ordering falling back to outer-inner on narrow walls with Arachne (#15924)
* Fix wall ordering edge case * IOI performance tuning - greedy stop when a first touch is identified.
This commit is contained in:
@@ -2256,13 +2256,45 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim
|
||||
|
||||
// ORCA:
|
||||
// Inner Outer Inner wall ordering mode perimeter order optimisation functions
|
||||
|
||||
// Whether two Arachne lines touch: somewhere the gap between their centrelines is no more than the
|
||||
// touching distance there. Each junction of one line is measured against the segments of the other,
|
||||
// both ways, and the search stops at the first spot that touches.
|
||||
// Arachne varies line width to fill the region (e.g. the odd centre line of a narrow wall is wider
|
||||
// than nominal), so the touching distance is half the combined width at the closest points, not the
|
||||
// nominal spacing. Widths are taken locally so a line widened in one place (a wedge tip, a wall
|
||||
// transition) does not count as touching where it passes close to other perimeters. min_threshold keeps
|
||||
// the nominal spacing threshold as the lower bound.
|
||||
static bool arachne_lines_touch(const Arachne::ExtrusionLine &a, const Arachne::ExtrusionLine &b, double min_threshold)
|
||||
{
|
||||
auto one_way = [min_threshold](const Arachne::ExtrusionLine &from, const Arachne::ExtrusionLine &to) {
|
||||
for (const Arachne::ExtrusionJunction &j : from.junctions) {
|
||||
const Vec2d p = j.p.cast<double>();
|
||||
for (size_t k = 0; k + 1 < to.junctions.size(); ++k) {
|
||||
const Arachne::ExtrusionJunction &j0 = to.junctions[k];
|
||||
const Arachne::ExtrusionJunction &j1 = to.junctions[k + 1];
|
||||
const Vec2d s0 = j0.p.cast<double>();
|
||||
const Vec2d seg = j1.p.cast<double>() - s0;
|
||||
const double l2 = seg.squaredNorm();
|
||||
const double t = l2 > 0. ? std::clamp((p - s0).dot(seg) / l2, 0., 1.) : 0.;
|
||||
const double w = double(j0.w) + t * double(j1.w - j0.w); // width of `to` at the closest point
|
||||
const double touch_distance = std::max(min_threshold, 0.5 * (double(j.w) + w));
|
||||
if ((s0 + t * seg - p).norm() <= touch_distance)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return one_way(a, b) || one_way(b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds all perimeters touching a given set of reference lines, given as indexes.
|
||||
*
|
||||
* @param entities The list of PerimeterGeneratorArachneExtrusion entities.
|
||||
* @param referenceIndices A set of indices representing the reference points.
|
||||
* @param threshold_external The distance threshold to consider for proximity for a reference perimeter with inset index 0
|
||||
* @param threshold_internal The distance threshold to consider for proximity for a reference perimeter with inset index 1+
|
||||
* @param threshold_external The minimum touching distance for a reference perimeter with inset index 0
|
||||
* @param threshold_internal The minimum touching distance for a reference perimeter with inset index 1+
|
||||
* @param considered_inset_idx What perimeter inset index are we searching for (eg. if we are searching for first internal perimeters proximate to the current reference perimeter, this value should be set to 1 etc).
|
||||
* @return std::vector<int> A vector of indices representing the touching perimeters.
|
||||
*/
|
||||
@@ -2271,7 +2303,6 @@ std::vector<int> findAllTouchingPerimeters(const std::vector<PerimeterGeneratorA
|
||||
|
||||
for (const int refIdx : referenceIndices) {
|
||||
const auto& referenceEntity = entities[refIdx];
|
||||
Points referencePoints = Arachne::to_points(*referenceEntity.extrusion);
|
||||
for (size_t i = 0; i < entities.size(); ++i) {
|
||||
// Skip already considered references and the reference entity
|
||||
if (referenceIndices.count(i) > 0) continue;
|
||||
@@ -2282,15 +2313,9 @@ std::vector<int> findAllTouchingPerimeters(const std::vector<PerimeterGeneratorA
|
||||
continue; // skip if they dont match
|
||||
}
|
||||
|
||||
Points points = Arachne::to_points(*entity.extrusion);
|
||||
double distance = MultiPoint::minimumDistanceBetweenLinesDefinedByPoints(referencePoints, points);
|
||||
// Add to touchingIndices if within threshold distance
|
||||
size_t threshold=0;
|
||||
if(referenceEntity.extrusion->inset_idx == 0)
|
||||
threshold = threshold_external;
|
||||
else
|
||||
threshold = threshold_internal;
|
||||
if (distance <= threshold) {
|
||||
// Add to touchingIndices if the lines touch.
|
||||
const double threshold = double(referenceEntity.extrusion->inset_idx == 0 ? threshold_external : threshold_internal);
|
||||
if (arachne_lines_touch(*referenceEntity.extrusion, *entity.extrusion, threshold)) {
|
||||
touchingIndices.insert(i);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user