FIX: the slicing result is incorrect in multi-color case

jira: udesk: https://bblcs.s5.udesk.cn/entry/ticket/show/7173936
Change-Id: I183a45448b6cc5cff094c2d0567797e7220485f5
This commit is contained in:
zhimin.zeng 2024-09-19 14:06:06 +08:00 committed by Lane.Wei
parent a1f70ff27e
commit 63d59f0104
2 changed files with 189 additions and 125 deletions

View File

@ -169,26 +169,9 @@ public:
std::vector<std::pair<ContourEdge, ContourEdge>> intersecting_edges() const; std::vector<std::pair<ContourEdge, ContourEdge>> intersecting_edges() const;
bool has_intersecting_edges() const; bool has_intersecting_edges() const;
template<typename VISITOR> void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, VISITOR &visitor) const template<typename VISITOR>
void visit_intersect_line_impl(coord_t ix, coord_t iy, Point p1, coord_t ixb, coord_t iyb, Point p2, VISITOR &visitor) const
{ {
// End points of the line segment.
assert(m_bbox.contains(p1));
assert(m_bbox.contains(p2));
p1 -= m_bbox.min;
p2 -= m_bbox.min;
assert(p1.x() >= 0 && size_t(p1.x()) < m_cols * m_resolution);
assert(p1.y() >= 0 && size_t(p1.y()) < m_rows * m_resolution);
assert(p2.x() >= 0 && size_t(p2.x()) < m_cols * m_resolution);
assert(p2.y() >= 0 && size_t(p2.y()) < m_rows * m_resolution);
// Get the cells of the end points.
coord_t ix = p1(0) / m_resolution;
coord_t iy = p1(1) / m_resolution;
coord_t ixb = p2(0) / m_resolution;
coord_t iyb = p2(1) / m_resolution;
assert(ix >= 0 && size_t(ix) < m_cols);
assert(iy >= 0 && size_t(iy) < m_rows);
assert(ixb >= 0 && size_t(ixb) < m_cols);
assert(iyb >= 0 && size_t(iyb) < m_rows);
// Account for the end points. // Account for the end points.
if (!visitor(iy, ix) || (ix == ixb && iy == iyb)) if (!visitor(iy, ix) || (ix == ixb && iy == iyb))
// Both ends fall into the same cell. // Both ends fall into the same cell.
@ -208,16 +191,14 @@ public:
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix += 1; ix += 1;
assert(ix <= ixb); assert(ix <= ixb);
} } else if (ex == ey) {
else if (ex == ey) {
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
ix += 1; ix += 1;
iy += 1; iy += 1;
assert(ix <= ixb); assert(ix <= ixb);
assert(iy <= iyb); assert(iy <= iyb);
} } else {
else {
assert(ex > ey); assert(ex > ey);
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
@ -227,8 +208,7 @@ public:
if (!visitor(iy, ix)) if (!visitor(iy, ix))
return; return;
} while (ix != ixb || iy != iyb); } while (ix != ixb || iy != iyb);
} } else {
else {
// x positive, y non positive // x positive, y non positive
int64_t ey = int64_t(p1(1) - iy * m_resolution) * int64_t(dx); int64_t ey = int64_t(p1(1) - iy * m_resolution) * int64_t(dx);
do { do {
@ -238,8 +218,7 @@ public:
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix += 1; ix += 1;
assert(ix <= ixb); assert(ix <= ixb);
} } else {
else {
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
iy -= 1; iy -= 1;
@ -249,8 +228,7 @@ public:
return; return;
} while (ix != ixb || iy != iyb); } while (ix != ixb || iy != iyb);
} }
} } else {
else {
int64_t ex = int64_t(p1(0) - ix * m_resolution) * int64_t(dy); int64_t ex = int64_t(p1(0) - ix * m_resolution) * int64_t(dy);
if (p1(1) < p2(1)) { if (p1(1) < p2(1)) {
// x non positive, y positive // x non positive, y positive
@ -262,8 +240,7 @@ public:
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix -= 1; ix -= 1;
assert(ix >= ixb); assert(ix >= ixb);
} } else {
else {
assert(ex >= ey); assert(ex >= ey);
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
@ -273,8 +250,7 @@ public:
if (!visitor(iy, ix)) if (!visitor(iy, ix))
return; return;
} while (ix != ixb || iy != iyb); } while (ix != ixb || iy != iyb);
} } else {
else {
// x non positive, y non positive // x non positive, y non positive
int64_t ey = int64_t(p1(1) - iy * m_resolution) * int64_t(dx); int64_t ey = int64_t(p1(1) - iy * m_resolution) * int64_t(dx);
do { do {
@ -284,8 +260,7 @@ public:
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix -= 1; ix -= 1;
assert(ix >= ixb); assert(ix >= ixb);
} } else if (ex == ey) {
else if (ex == ey) {
// The lower edge of a grid cell belongs to the cell. // The lower edge of a grid cell belongs to the cell.
// Handle the case where the ray may cross the lower left corner of a cell in a general case, // Handle the case where the ray may cross the lower left corner of a cell in a general case,
// or a left or lower edge in a degenerate case (horizontal or vertical line). // or a left or lower edge in a degenerate case (horizontal or vertical line).
@ -299,8 +274,7 @@ public:
iy -= 1; iy -= 1;
assert(iy >= iyb); assert(iy >= iyb);
} }
} } else {
else {
assert(ex > ey); assert(ex > ey);
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
@ -314,6 +288,83 @@ public:
} }
} }
template<typename VISITOR> void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, VISITOR &visitor, bool need_consider_eps = false) const
{
// End points of the line segment.
assert(m_bbox.contains(p1));
assert(m_bbox.contains(p2));
p1 -= m_bbox.min;
p2 -= m_bbox.min;
assert(p1.x() >= 0 && size_t(p1.x()) < m_cols * m_resolution);
assert(p1.y() >= 0 && size_t(p1.y()) < m_rows * m_resolution);
assert(p2.x() >= 0 && size_t(p2.x()) < m_cols * m_resolution);
assert(p2.y() >= 0 && size_t(p2.y()) < m_rows * m_resolution);
// Get the cells of the end points.
coord_t ix = p1(0) / m_resolution;
coord_t iy = p1(1) / m_resolution;
coord_t ixb = p2(0) / m_resolution;
coord_t iyb = p2(1) / m_resolution;
assert(ix >= 0 && size_t(ix) < m_cols);
assert(iy >= 0 && size_t(iy) < m_rows);
assert(ixb >= 0 && size_t(ixb) < m_cols);
assert(iyb >= 0 && size_t(iyb) < m_rows);
std::vector<std::tuple<float, float, Slic3r::Point>> start_pos;
std::vector<std::tuple<float, float, Slic3r::Point>> end_pos;
start_pos.push_back(std::make_tuple(ix, iy, p1));
end_pos.push_back(std::make_tuple(ixb, iyb, p2));
if (need_consider_eps) {
auto calculate_upper = [&](coord_t value, double eps) {
return coord_t((value + eps) / m_resolution);
};
auto calculate_lower = [&](coord_t value, double eps) {
return coord_t((value - eps) / m_resolution);
};
const double eps = scale_(10 * EPSILON);
if (coord_t ix_u = calculate_upper(p1(0), eps);
ix_u != ix) {
start_pos.push_back(std::make_tuple(ix_u, iy, Slic3r::Point(coord_t(p1(0) + eps), p1(1))));
}
if (coord_t ix_l = calculate_lower(p1(0), eps);
ix_l != ix) {
start_pos.push_back(std::make_tuple(ix_l, iy, Slic3r::Point(coord_t(p1(0) - eps), p1(1))));
}
if (coord_t iy_u = calculate_upper(p1(1), eps);
iy_u != iy) {
start_pos.push_back(std::make_tuple(ix, iy_u, Slic3r::Point(p1(0), coord_t(p1(1) + eps))));
}
if (coord_t iy_l = calculate_lower(p1(1), eps);
iy_l != iy) {
start_pos.push_back(std::make_tuple(ix, iy_l, Slic3r::Point(p1(0), coord_t(p1(1) - eps))));
}
if (coord_t ixb_u = calculate_upper(p2(0), eps);
ixb_u != ixb) {
end_pos.push_back(std::make_tuple(ixb_u, iyb, Slic3r::Point(coord_t(p2(0) + eps), p2(1))));
}
if (coord_t ixb_l = calculate_lower(p2(0), eps);
ixb_l != ixb) {
end_pos.push_back(std::make_tuple(ixb_l, iyb, Slic3r::Point(coord_t(p2(0) - eps), p2(1))));
}
if (coord_t iyb_u = calculate_upper(p2(1), eps);
iyb_u != iyb) {
end_pos.push_back(std::make_tuple(ixb, iyb_u, Slic3r::Point(p2(0), coord_t(p2(1) + eps))));
}
if (coord_t iyb_l = calculate_lower(p2(1), eps);
iyb_l != iyb) {
end_pos.push_back(std::make_tuple(ixb, iyb_l, Slic3r::Point(p2(0), coord_t(p2(1) - eps))));
}
}
for (size_t start_idx = 0; start_idx < start_pos.size(); ++start_idx) {
for (size_t end_idx = 0; end_idx < end_pos.size(); ++end_idx) {
visit_intersect_line_impl(std::get<0>(start_pos[start_idx]), std::get<1>(start_pos[start_idx]), std::get<2>(start_pos[start_idx]),
std::get<0>(end_pos[end_idx]), std::get<1>(end_pos[end_idx]), std::get<2>(end_pos[end_idx]), visitor);
}
}
}
template<typename VISITOR> void visit_cells_intersecting_box(BoundingBox bbox, VISITOR &visitor) const template<typename VISITOR> void visit_cells_intersecting_box(BoundingBox bbox, VISITOR &visitor) const
{ {
// End points of the line segment. // End points of the line segment.

View File

@ -16,6 +16,7 @@
#include <mutex> #include <mutex>
#include <boost/thread/lock_guard.hpp> #include <boost/thread/lock_guard.hpp>
//#define MM_SEGMENTATION_DEBUG_PAINT_LINE
//#define MM_SEGMENTATION_DEBUG_GRAPH //#define MM_SEGMENTATION_DEBUG_GRAPH
//#define MM_SEGMENTATION_DEBUG_REGIONS //#define MM_SEGMENTATION_DEBUG_REGIONS
//#define MM_SEGMENTATION_DEBUG_INPUT //#define MM_SEGMENTATION_DEBUG_INPUT
@ -2161,16 +2162,24 @@ std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(con
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - projection of painted triangles - begin"; BOOST_LOG_TRIVIAL(debug) << "MM segmentation - projection of painted triangles - begin";
for (const ModelVolume *mv : print_object.model_object()->volumes) { for (const ModelVolume *mv : print_object.model_object()->volumes) {
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
tbb::parallel_for(tbb::blocked_range<size_t>(1, num_extruders + 1), [&mv, &print_object, &layers, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(1, num_extruders + 1), [&mv, &print_object, &layers, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t extruder_idx = range.begin(); extruder_idx < range.end(); ++extruder_idx) { for (size_t extruder_idx = range.begin(); extruder_idx < range.end(); ++extruder_idx) {
#else
for (size_t extruder_idx = 1; extruder_idx < num_extruders + 1; ++extruder_idx) {
#endif
throw_on_cancel_callback(); throw_on_cancel_callback();
const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx)); const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx));
if (!mv->is_model_part() || custom_facets.indices.empty()) if (!mv->is_model_part() || custom_facets.indices.empty())
continue; continue;
const Transform3f tr = print_object.trafo().cast<float>() * mv->get_matrix().cast<float>(); const Transform3f tr = print_object.trafo().cast<float>() * mv->get_matrix().cast<float>();
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
tbb::parallel_for(tbb::blocked_range<size_t>(0, custom_facets.indices.size()), [&tr, &custom_facets, &print_object, &layers, &edge_grids, &input_expolygons, &painted_lines, &painted_lines_mutex, &extruder_idx](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, custom_facets.indices.size()), [&tr, &custom_facets, &print_object, &layers, &edge_grids, &input_expolygons, &painted_lines, &painted_lines_mutex, &extruder_idx](const tbb::blocked_range<size_t> &range) {
for (size_t facet_idx = range.begin(); facet_idx < range.end(); ++facet_idx) { for (size_t facet_idx = range.begin(); facet_idx < range.end(); ++facet_idx) {
#else
for (size_t facet_idx = 0; facet_idx < custom_facets.indices.size(); ++facet_idx) {
#endif
float min_z = std::numeric_limits<float>::max(); float min_z = std::numeric_limits<float>::max();
float max_z = std::numeric_limits<float>::lowest(); float max_z = std::numeric_limits<float>::lowest();
@ -2243,12 +2252,16 @@ std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(con
PaintedLineVisitor visitor(edge_grids[layer_idx], painted_lines[layer_idx], painted_lines_mutex[mutex_idx], 16); PaintedLineVisitor visitor(edge_grids[layer_idx], painted_lines[layer_idx], painted_lines_mutex[mutex_idx], 16);
visitor.line_to_test = line_to_test; visitor.line_to_test = line_to_test;
visitor.color = int(extruder_idx); visitor.color = int(extruder_idx);
edge_grids[layer_idx].visit_cells_intersecting_line(line_to_test.a, line_to_test.b, visitor); edge_grids[layer_idx].visit_cells_intersecting_line(line_to_test.a, line_to_test.b, visitor, true);
} }
} }
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
}); // end of parallel_for }); // end of parallel_for
#endif
} }
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
}); // end of parallel_for }); // end of parallel_for
#endif
} }
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - projection of painted triangles - end"; BOOST_LOG_TRIVIAL(debug) << "MM segmentation - projection of painted triangles - end";
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - painted layers count: " BOOST_LOG_TRIVIAL(debug) << "MM segmentation - painted layers count: "