mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-11 14:48:59 +08:00
SPE-2486: Refactor function apply_mm_segmentation() to prepare support for fuzzy skin painting.
This commit is contained in:
parent
519f5eea8e
commit
2c06c81159
@ -39,7 +39,6 @@
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "tcbspan/span.hpp"
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
@ -580,34 +579,36 @@ void PrintObject::slice()
|
||||
template<typename ThrowOnCancel>
|
||||
void apply_mm_segmentation(PrintObject &print_object, ThrowOnCancel throw_on_cancel)
|
||||
{
|
||||
// Returns MMU segmentation based on painting in MMU segmentation gizmo
|
||||
// Returns MM segmentation based on painting in MM segmentation gizmo
|
||||
std::vector<std::vector<ExPolygons>> segmentation = multi_material_segmentation_by_painting(print_object, throw_on_cancel);
|
||||
assert(segmentation.size() == print_object.layer_count());
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, segmentation.size(), std::max(segmentation.size() / 128, size_t(1))),
|
||||
[&print_object, &segmentation, throw_on_cancel](const tbb::blocked_range<size_t> &range) {
|
||||
const auto &layer_ranges = print_object.shared_regions()->layer_ranges;
|
||||
double z = print_object.get_layer(range.begin())->slice_z;
|
||||
double z = print_object.get_layer(int(range.begin()))->slice_z;
|
||||
auto it_layer_range = layer_range_first(layer_ranges, z);
|
||||
const size_t num_extruders = print_object.print()->config().nozzle_diameter.size();
|
||||
|
||||
struct ByExtruder {
|
||||
ExPolygons expolygons;
|
||||
BoundingBox bbox;
|
||||
};
|
||||
|
||||
std::vector<ByExtruder> by_extruder;
|
||||
struct ByRegion {
|
||||
ExPolygons expolygons;
|
||||
bool needs_merge { false };
|
||||
};
|
||||
std::vector<ByRegion> by_region;
|
||||
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||
for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) {
|
||||
throw_on_cancel();
|
||||
Layer *layer = print_object.get_layer(layer_id);
|
||||
it_layer_range = layer_range_next(layer_ranges, it_layer_range, layer->slice_z);
|
||||
Layer &layer = *print_object.get_layer(int(layer_id));
|
||||
it_layer_range = layer_range_next(layer_ranges, it_layer_range, layer.slice_z);
|
||||
const PrintObjectRegions::LayerRangeRegions &layer_range = *it_layer_range;
|
||||
// Gather per extruder expolygons.
|
||||
by_extruder.assign(num_extruders, ByExtruder());
|
||||
by_region.assign(layer->region_count(), ByRegion());
|
||||
by_region.assign(layer.region_count(), ByRegion());
|
||||
bool layer_split = false;
|
||||
for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) {
|
||||
ByExtruder ®ion = by_extruder[extruder_id];
|
||||
@ -617,87 +618,114 @@ void apply_mm_segmentation(PrintObject &print_object, ThrowOnCancel throw_on_can
|
||||
layer_split = true;
|
||||
}
|
||||
}
|
||||
if (! layer_split)
|
||||
|
||||
if (!layer_split)
|
||||
continue;
|
||||
|
||||
// Split LayerRegions by by_extruder regions.
|
||||
// layer_range.painted_regions are sorted by extruder ID and parent PrintObject region ID.
|
||||
auto it_painted_region = layer_range.painted_regions.begin();
|
||||
for (int region_id = 0; region_id < int(layer->region_count()); ++ region_id)
|
||||
if (LayerRegion &layerm = *layer->get_region(region_id); ! layerm.slices().empty()) {
|
||||
assert(layerm.region().print_object_region_id() == region_id);
|
||||
const BoundingBox bbox = get_extents(layerm.slices().surfaces);
|
||||
assert(it_painted_region < layer_range.painted_regions.end());
|
||||
// Find the first it_painted_region which overrides this region.
|
||||
for (; layer_range.volume_regions[it_painted_region->parent].region->print_object_region_id() < region_id; ++ it_painted_region)
|
||||
assert(it_painted_region != layer_range.painted_regions.end());
|
||||
assert(it_painted_region != layer_range.painted_regions.end());
|
||||
assert(layer_range.volume_regions[it_painted_region->parent].region == &layerm.region());
|
||||
// 1-based extruder ID
|
||||
bool self_trimmed = false;
|
||||
int self_extruder_id = -1;
|
||||
for (int extruder_id = 1; extruder_id <= int(by_extruder.size()); ++ extruder_id)
|
||||
if (ByExtruder &segmented = by_extruder[extruder_id - 1]; segmented.bbox.defined && bbox.overlap(segmented.bbox)) {
|
||||
// Find the target region.
|
||||
for (; int(it_painted_region->extruder_id) < extruder_id; ++ it_painted_region)
|
||||
assert(it_painted_region != layer_range.painted_regions.end());
|
||||
assert(layer_range.volume_regions[it_painted_region->parent].region == &layerm.region() && int(it_painted_region->extruder_id) == extruder_id);
|
||||
//FIXME Don't trim by self, it is not reliable.
|
||||
if (&layerm.region() == it_painted_region->region) {
|
||||
self_extruder_id = extruder_id;
|
||||
continue;
|
||||
}
|
||||
// Steal from this region.
|
||||
int target_region_id = it_painted_region->region->print_object_region_id();
|
||||
ExPolygons stolen = intersection_ex(layerm.slices().surfaces, segmented.expolygons);
|
||||
if (! stolen.empty()) {
|
||||
ByRegion &dst = by_region[target_region_id];
|
||||
if (dst.expolygons.empty()) {
|
||||
dst.expolygons = std::move(stolen);
|
||||
} else {
|
||||
append(dst.expolygons, std::move(stolen));
|
||||
dst.needs_merge = true;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (&layerm.region() == it_painted_region->region)
|
||||
// Slices of this LayerRegion were trimmed by a MMU region of the same PrintRegion.
|
||||
self_trimmed = true;
|
||||
#endif
|
||||
}
|
||||
if (! self_trimmed) {
|
||||
// Trim slices of this LayerRegion with all the MMU regions.
|
||||
Polygons mine = to_polygons(std::move(layerm.slices().surfaces));
|
||||
for (auto &segmented : by_extruder)
|
||||
if (&segmented - by_extruder.data() + 1 != self_extruder_id && segmented.bbox.defined && bbox.overlap(segmented.bbox)) {
|
||||
mine = diff(mine, segmented.expolygons);
|
||||
if (mine.empty())
|
||||
break;
|
||||
}
|
||||
// Filter out unprintable polygons produced by subtraction multi-material painted regions from layerm.region().
|
||||
// ExPolygon returned from multi-material segmentation does not precisely match ExPolygons in layerm.region()
|
||||
// (because of preprocessing of the input regions in multi-material segmentation). Therefore, subtraction from
|
||||
// layerm.region() could produce a huge number of small unprintable regions for the model's base extruder.
|
||||
// This could, on some models, produce bulges with the model's base color (#7109).
|
||||
if (! mine.empty())
|
||||
mine = opening(union_ex(mine), float(scale_(5 * EPSILON)), float(scale_(5 * EPSILON)));
|
||||
if (! mine.empty()) {
|
||||
ByRegion &dst = by_region[layerm.region().print_object_region_id()];
|
||||
if (dst.expolygons.empty()) {
|
||||
dst.expolygons = union_ex(mine);
|
||||
} else {
|
||||
append(dst.expolygons, union_ex(mine));
|
||||
dst.needs_merge = true;
|
||||
}
|
||||
auto it_painted_region_begin = layer_range.painted_regions.cbegin();
|
||||
for (int parent_layer_region_idx = 0; parent_layer_region_idx < layer.region_count(); ++parent_layer_region_idx) {
|
||||
if (it_painted_region_begin == layer_range.painted_regions.cend())
|
||||
continue;
|
||||
|
||||
const LayerRegion &parent_layer_region = *layer.get_region(parent_layer_region_idx);
|
||||
const PrintRegion &parent_print_region = parent_layer_region.region();
|
||||
assert(parent_print_region.print_object_region_id() == parent_layer_region_idx);
|
||||
if (parent_layer_region.slices().empty())
|
||||
continue;
|
||||
|
||||
// Find the first PaintedRegion, which overrides the parent PrintRegion.
|
||||
auto it_first_painted_region = std::find_if(it_painted_region_begin, layer_range.painted_regions.cend(), [&layer_range, &parent_print_region](const auto &painted_region) {
|
||||
return layer_range.volume_regions[painted_region.parent].region->print_object_region_id() == parent_print_region.print_object_region_id();
|
||||
});
|
||||
|
||||
if (it_first_painted_region == layer_range.painted_regions.cend())
|
||||
continue; // This LayerRegion isn't overrides by any PaintedRegion.
|
||||
|
||||
assert(&parent_print_region == layer_range.volume_regions[it_first_painted_region->parent].region);
|
||||
|
||||
// Find the first PaintedRegion with different parent PrintRegion.
|
||||
auto it_last_painted_region = std::find_if(it_first_painted_region, layer_range.painted_regions.cend(), [&it_first_painted_region](const auto &painted_region) {
|
||||
return painted_region.parent != it_first_painted_region->parent;
|
||||
});
|
||||
|
||||
// Update the beginning PaintedRegion iterator for the next iteration.
|
||||
it_painted_region_begin = it_last_painted_region;
|
||||
|
||||
const BoundingBox parent_layer_region_bbox = get_extents(parent_layer_region.slices().surfaces);
|
||||
bool self_trimmed = false;
|
||||
int self_extruder_id = -1; // 1-based extruder ID
|
||||
for (auto it_painted_region = it_first_painted_region; it_painted_region != it_last_painted_region; ++it_painted_region) {
|
||||
const int extruder_id = int(it_painted_region->extruder_id); // 1-based extruder ID
|
||||
assert(extruder_id > 0 && (extruder_id - 1) < int(by_extruder.size()));
|
||||
assert(layer_range.volume_regions[it_painted_region->parent].region == &parent_print_region);
|
||||
|
||||
const ByExtruder &segmented = by_extruder[extruder_id - 1];
|
||||
if (!segmented.bbox.defined || !parent_layer_region_bbox.overlap(segmented.bbox))
|
||||
continue;
|
||||
|
||||
// FIXME: Don't trim by self, it is not reliable.
|
||||
if (it_painted_region->region == &parent_print_region) {
|
||||
self_extruder_id = extruder_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Steal from this region.
|
||||
int target_region_id = it_painted_region->region->print_object_region_id();
|
||||
ExPolygons stolen = intersection_ex(parent_layer_region.slices().surfaces, segmented.expolygons);
|
||||
if (!stolen.empty()) {
|
||||
ByRegion &dst = by_region[target_region_id];
|
||||
if (dst.expolygons.empty()) {
|
||||
dst.expolygons = std::move(stolen);
|
||||
} else {
|
||||
append(dst.expolygons, std::move(stolen));
|
||||
dst.needs_merge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!self_trimmed) {
|
||||
// Trim slices of this LayerRegion with all the MM regions.
|
||||
Polygons mine = to_polygons(parent_layer_region.slices().surfaces);
|
||||
for (auto &segmented : by_extruder) {
|
||||
if (&segmented - by_extruder.data() + 1 != self_extruder_id && segmented.bbox.defined && parent_layer_region_bbox.overlap(segmented.bbox)) {
|
||||
mine = diff(mine, segmented.expolygons);
|
||||
if (mine.empty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out unprintable polygons produced by subtraction multi-material painted regions from layerm.region().
|
||||
// ExPolygon returned from multi-material segmentation does not precisely match ExPolygons in layerm.region()
|
||||
// (because of preprocessing of the input regions in multi-material segmentation). Therefore, subtraction from
|
||||
// layerm.region() could produce a huge number of small unprintable regions for the model's base extruder.
|
||||
// This could, on some models, produce bulges with the model's base color (#7109).
|
||||
if (!mine.empty()) {
|
||||
mine = opening(union_ex(mine), scaled<float>(5. * EPSILON), scaled<float>(5. * EPSILON));
|
||||
}
|
||||
|
||||
if (!mine.empty()) {
|
||||
ByRegion &dst = by_region[parent_print_region.print_object_region_id()];
|
||||
if (dst.expolygons.empty()) {
|
||||
dst.expolygons = union_ex(mine);
|
||||
} else {
|
||||
append(dst.expolygons, union_ex(mine));
|
||||
dst.needs_merge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-create Surfaces of LayerRegions.
|
||||
for (size_t region_id = 0; region_id < layer->region_count(); ++ region_id) {
|
||||
for (int region_id = 0; region_id < layer.region_count(); ++region_id) {
|
||||
ByRegion &src = by_region[region_id];
|
||||
if (src.needs_merge)
|
||||
if (src.needs_merge) {
|
||||
// Multiple regions were merged into one.
|
||||
src.expolygons = closing_ex(src.expolygons, float(scale_(10 * EPSILON)));
|
||||
layer->get_region(region_id)->m_slices.set(std::move(src.expolygons), stInternal);
|
||||
src.expolygons = closing_ex(src.expolygons, scaled<float>(10. * EPSILON));
|
||||
}
|
||||
|
||||
layer.get_region(region_id)->m_slices.set(std::move(src.expolygons), stInternal);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -752,7 +780,7 @@ void PrintObject::slice_volumes()
|
||||
m_layers.back()->upper_layer = nullptr;
|
||||
m_print->throw_if_canceled();
|
||||
|
||||
// Is any ModelVolume MMU painted?
|
||||
// Is any ModelVolume multi-material painted?
|
||||
if (m_print->config().nozzle_diameter.size() > 1 && this->model_object()->is_mm_painted()) {
|
||||
// If XY Size compensation is also enabled, notify the user that XY Size compensation
|
||||
// would not be used because the object is multi-material painted.
|
||||
|
Loading…
x
Reference in New Issue
Block a user