Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_imgui_slider

This commit is contained in:
enricoturri1966 2021-11-08 13:44:13 +01:00
commit 67533da405
24 changed files with 523 additions and 255 deletions

View file

@ -135,7 +135,7 @@ ArchiveData extract_sla_archive(const std::string &zipfname,
ExPolygons rings_to_expolygons(const std::vector<marchsq::Ring> &rings,
double px_w, double px_h)
{
ExPolygons polys; polys.reserve(rings.size());
auto polys = reserve_vector<ExPolygon>(rings.size());
for (const marchsq::Ring &ring : rings) {
Polygon poly; Points &pts = poly.points;
@ -147,7 +147,7 @@ ExPolygons rings_to_expolygons(const std::vector<marchsq::Ring> &rings,
polys.emplace_back(poly);
}
// reverse the raster transformations
// TODO: Is a union necessary?
return union_ex(polys);
}
@ -270,11 +270,11 @@ std::vector<ExPolygons> extract_slices_from_sla_archive(
png::ReadBuf rb{arch.images[i].buf.data(), arch.images[i].buf.size()};
if (!png::decode_png(rb, img)) return;
auto rings = marchsq::execute(img, 128, rstp.win);
uint8_t isoval = 128;
auto rings = marchsq::execute(img, isoval, rstp.win);
ExPolygons expolys = rings_to_expolygons(rings, rstp.px_w, rstp.px_h);
// Invert the raster transformations indicated in
// the profile metadata
// Invert the raster transformations indicated in the profile metadata
invert_raster_trafo(expolys, rstp.trafo, rstp.width, rstp.height);
slices[i] = std::move(expolys);
@ -310,7 +310,24 @@ ConfigSubstitutions import_sla_archive(
std::string exclude_entries{"thumbnail"};
ArchiveData arch = extract_sla_archive(zipfname, exclude_entries);
DynamicPrintConfig profile_in, profile_use;
ConfigSubstitutions config_substitutions = profile_in.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
ConfigSubstitutions config_substitutions =
profile_in.load(arch.profile,
ForwardCompatibilitySubstitutionRule::Enable);
if (profile_in.empty()) { // missing profile... do guess work
// try to recover the layer height from the config.ini which was
// present in all versions of sl1 files.
if (auto lh_opt = arch.config.find("layerHeight");
lh_opt != arch.config.not_found())
{
auto lh_str = lh_opt->second.data();
try {
double lh = std::stod(lh_str); // TODO replace with std::from_chars
profile_out.set("layer_height", lh);
profile_out.set("initial_layer_height", lh);
} catch(...) {}
}
}
// If the archive contains an empty profile, use the one that was passed as output argument
// then replace it with the readed profile to report that it was empty.

View file

@ -1263,10 +1263,10 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr
instances[instance]->get_mirror()
);
z -= instances[instance]->get_offset()(2);
z -= instances[instance]->get_offset().z();
// Lower part per-instance bounding boxes
std::vector<BoundingBoxf3> lower_bboxes { instances.size() };
// Displacement (in instance coordinates) to be applied to place the upper parts
Vec3d local_displace = Vec3d::Zero();
for (ModelVolume *volume : volumes) {
const auto volume_matrix = volume->get_matrix();
@ -1286,8 +1286,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr
if (attributes.has(ModelObjectCutAttribute::KeepLower))
lower->add_volume(*volume);
}
else if (! volume->mesh().empty()) {
else if (! volume->mesh().empty()) {
// Transform the mesh by the combined transformation matrix.
// Flip the triangles in case the composite transformation is left handed.
TriangleMesh mesh(volume->mesh());
@ -1327,13 +1326,10 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr
assert(vol->config.id() != volume->config.id());
vol->set_material(volume->material_id(), *volume->material());
// Compute the lower part instances' bounding boxes to figure out where to place
// the upper part
if (attributes.has(ModelObjectCutAttribute::KeepUpper)) {
for (size_t i = 0; i < instances.size(); i++) {
lower_bboxes[i].merge(instances[i]->transform_mesh_bounding_box(lower_mesh, true));
}
}
// Compute the displacement (in instance coordinates) to be applied to place the upper parts
// The upper part displacement is set to half of the lower part bounding box
// this is done in hope at least a part of the upper part will always be visible and draggable
local_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0));
}
}
}
@ -1341,17 +1337,18 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr
ModelObjectPtrs res;
if (attributes.has(ModelObjectCutAttribute::KeepUpper) && upper->volumes.size() > 0) {
upper->invalidate_bounding_box();
upper->center_around_origin();
if (!upper->origin_translation.isApprox(Vec3d::Zero()) && instances[instance]->get_offset().isApprox(Vec3d::Zero())) {
upper->center_around_origin();
upper->translate_instances(-upper->origin_translation);
upper->origin_translation = Vec3d::Zero();
}
// Reset instance transformation except offset and Z-rotation
for (size_t i = 0; i < instances.size(); i++) {
for (size_t i = 0; i < instances.size(); ++i) {
auto &instance = upper->instances[i];
const Vec3d offset = instance->get_offset();
const double rot_z = instance->get_rotation()(2);
// The upper part displacement is set to half of the lower part bounding box
// this is done in hope at least a part of the upper part will always be visible and draggable
const Vec3d displace = lower_bboxes[i].size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0));
const double rot_z = instance->get_rotation().z();
const Vec3d displace = Geometry::assemble_transform(Vec3d::Zero(), instance->get_rotation()) * local_displace;
instance->set_transformation(Geometry::Transformation());
instance->set_offset(offset + displace);
@ -1361,14 +1358,16 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr
res.push_back(upper);
}
if (attributes.has(ModelObjectCutAttribute::KeepLower) && lower->volumes.size() > 0) {
lower->invalidate_bounding_box();
lower->center_around_origin();
if (!lower->origin_translation.isApprox(Vec3d::Zero()) && instances[instance]->get_offset().isApprox(Vec3d::Zero())) {
lower->center_around_origin();
lower->translate_instances(-lower->origin_translation);
lower->origin_translation = Vec3d::Zero();
}
// Reset instance transformation except offset and Z-rotation
for (auto *instance : lower->instances) {
const Vec3d offset = instance->get_offset();
const double rot_z = instance->get_rotation()(2);
const double rot_z = instance->get_rotation().z();
instance->set_transformation(Geometry::Transformation());
instance->set_offset(offset);
instance->set_rotation(Vec3d(attributes.has(ModelObjectCutAttribute::FlipLower) ? Geometry::deg2rad(180.0) : 0.0, 0.0, rot_z));

View file

@ -1113,7 +1113,7 @@ static inline Polygon to_polygon(const std::vector<Linef> &lines)
// It iterates through all nodes on the border between two different colors, and from this point,
// start selection always left most edges for every node to construct CCW polygons.
// Assumes that graph is planar (without self-intersection edges)
static std::vector<std::pair<Polygon, size_t>> extract_colored_segments(const MMU_Graph &graph)
static std::vector<ExPolygons> extract_colored_segments(const MMU_Graph &graph, const size_t num_extruders)
{
std::vector<bool> used_arcs(graph.arcs.size(), false);
// When there is no next arc, then is returned original_arc or edge with is marked as used
@ -1153,7 +1153,7 @@ static std::vector<std::pair<Polygon, size_t>> extract_colored_segments(const MM
return std::all_of(node.arc_idxs.cbegin(), node.arc_idxs.cend(), [&used_arcs](const size_t &arc_idx) -> bool { return used_arcs[arc_idx]; });
};
std::vector<std::pair<Polygon, size_t>> polygons_segments;
std::vector<ExPolygons> expolygons_segments(num_extruders + 1);
for (size_t node_idx = 0; node_idx < graph.all_border_points; ++node_idx) {
const MMU_Graph::Node &node = graph.nodes[node_idx];
@ -1183,12 +1183,11 @@ static std::vector<std::pair<Polygon, size_t>> extract_colored_segments(const MM
p_arc = &next;
} while (graph.nodes[p_arc->to_idx].point != start_p || !all_arc_used(graph.nodes[p_arc->to_idx]));
Polygon poly = to_polygon(face_lines);
if (poly.is_counter_clockwise() && poly.is_valid())
polygons_segments.emplace_back(poly, arc.color);
if (Polygon poly = to_polygon(face_lines); poly.is_counter_clockwise() && poly.is_valid())
expolygons_segments[arc.color].emplace_back(std::move(poly));
}
}
return polygons_segments;
return expolygons_segments;
}
// Used in remove_multiple_edges_in_vertices()
@ -1269,21 +1268,20 @@ static void remove_multiple_edges_in_vertices(MMU_Graph &graph, const std::vecto
}
}
static void cut_segmented_layers(const std::vector<ExPolygons> &input_expolygons,
std::vector<std::vector<std::pair<ExPolygon, size_t>>> &segmented_regions,
const float cut_width,
const std::function<void()> &throw_on_cancel_callback)
static void cut_segmented_layers(const std::vector<ExPolygons> &input_expolygons,
std::vector<std::vector<ExPolygons>> &segmented_regions,
const float cut_width,
const std::function<void()> &throw_on_cancel_callback)
{
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),[&segmented_regions, &input_expolygons, &cut_width, &throw_on_cancel_callback](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback();
std::vector<std::pair<ExPolygon, size_t>> segmented_regions_cuts;
for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) {
ExPolygons cut_colored_expoly = diff_ex(colored_expoly.first, offset_ex(input_expolygons[layer_idx], cut_width));
for (ExPolygon &expoly : cut_colored_expoly)
segmented_regions_cuts.emplace_back(std::move(expoly), colored_expoly.second);
}
const size_t num_extruders_plus_one = segmented_regions[layer_idx].size();
std::vector<ExPolygons> segmented_regions_cuts(num_extruders_plus_one); // Indexed by extruder_id
for (size_t extruder_idx = 0; extruder_idx < num_extruders_plus_one; ++extruder_idx)
if (const ExPolygons &ex_polygons = segmented_regions[layer_idx][extruder_idx]; !ex_polygons.empty())
segmented_regions_cuts[extruder_idx] = diff_ex(ex_polygons, offset_ex(input_expolygons[layer_idx], cut_width));
segmented_regions[layer_idx] = std::move(segmented_regions_cuts);
}
}); // end of parallel_for
@ -1323,7 +1321,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
// Project upwards pointing painted triangles over top surfaces,
// project downards pointing painted triangles over bottom surfaces.
std::vector<std::vector<Polygons>> top_raw(num_extruders), bottom_raw(num_extruders);
std::vector<float> zs = zs_from_layers(print_object.layers());
std::vector<float> zs = zs_from_layers(layers);
Transform3d object_trafo = print_object.trafo_centered();
#ifdef MMU_SEGMENTATION_DEBUG_TOP_BOTTOM
@ -1532,31 +1530,42 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
return triangles_by_color_merged;
}
static std::vector<std::vector<std::pair<ExPolygon, size_t>>> merge_segmented_layers(
const std::vector<std::vector<std::pair<ExPolygon, size_t>>> &segmented_regions,
std::vector<std::vector<ExPolygons>> &&top_and_bottom_layers,
const std::function<void()> &throw_on_cancel_callback)
static std::vector<std::vector<ExPolygons>> merge_segmented_layers(
const std::vector<std::vector<ExPolygons>> &segmented_regions,
std::vector<std::vector<ExPolygons>> &&top_and_bottom_layers,
const size_t num_extruders,
const std::function<void()> &throw_on_cancel_callback)
{
std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions_merged(segmented_regions.size());
const size_t num_layers = segmented_regions.size();
std::vector<std::vector<ExPolygons>> segmented_regions_merged(num_layers);
segmented_regions_merged.assign(num_layers, std::vector<ExPolygons>(num_extruders));
assert(num_extruders + 1 == top_and_bottom_layers.size());
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()), [&segmented_regions, &top_and_bottom_layers, &segmented_regions_merged, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&segmented_regions, &top_and_bottom_layers, &segmented_regions_merged, &num_extruders, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) {
assert(segmented_regions[layer_idx].size() == num_extruders + 1);
// Zero is skipped because it is the default color of the volume
for (size_t extruder_id = 1; extruder_id < num_extruders + 1; ++extruder_id) {
throw_on_cancel_callback();
// Zero is the default color of the volume.
if(colored_expoly.second == 0)
continue;
ExPolygons cut_colored_expoly = {colored_expoly.first};
for (const std::vector<ExPolygons> &top_and_bottom_layer : top_and_bottom_layers)
cut_colored_expoly = diff_ex(cut_colored_expoly, top_and_bottom_layer[layer_idx]);
for (ExPolygon &ex_poly : cut_colored_expoly)
segmented_regions_merged[layer_idx].emplace_back(std::move(ex_poly), colored_expoly.second - 1);
}
if (!segmented_regions[layer_idx][extruder_id].empty()) {
ExPolygons segmented_regions_trimmed = segmented_regions[layer_idx][extruder_id];
for (const std::vector<ExPolygons> &top_and_bottom_by_extruder : top_and_bottom_layers)
if (!top_and_bottom_by_extruder[layer_idx].empty() && !segmented_regions_trimmed.empty())
segmented_regions_trimmed = diff_ex(segmented_regions_trimmed, top_and_bottom_by_extruder[layer_idx]);
for (size_t color_idx = 1; color_idx < top_and_bottom_layers.size(); ++color_idx)
for (ExPolygon &expoly : top_and_bottom_layers[color_idx][layer_idx])
segmented_regions_merged[layer_idx].emplace_back(std::move(expoly), color_idx - 1);
segmented_regions_merged[layer_idx][extruder_id - 1] = std::move(segmented_regions_trimmed);
}
if (!top_and_bottom_layers[extruder_id][layer_idx].empty()) {
bool was_top_and_bottom_empty = segmented_regions_merged[layer_idx][extruder_id - 1].empty();
append(segmented_regions_merged[layer_idx][extruder_id - 1], top_and_bottom_layers[extruder_id][layer_idx]);
// Remove dimples (#7235) appearing after merging side segmentation of the model with tops and bottoms painted layers.
if (!was_top_and_bottom_empty)
segmented_regions_merged[layer_idx][extruder_id - 1] = offset2_ex(union_ex(segmented_regions_merged[layer_idx][extruder_id - 1]), float(SCALED_EPSILON), -float(SCALED_EPSILON));
}
}
}
}); // end of parallel_for
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - end";
@ -1565,7 +1574,7 @@ static std::vector<std::vector<std::pair<ExPolygon, size_t>>> merge_segmented_la
}
#ifdef MMU_SEGMENTATION_DEBUG_REGIONS
static void export_regions_to_svg(const std::string &path, const std::vector<std::pair<ExPolygon, size_t>> &regions, const ExPolygons &lslices)
static void export_regions_to_svg(const std::string &path, const std::vector<ExPolygons> &regions, const ExPolygons &lslices)
{
const std::vector<std::string> colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "yellow"};
coordf_t stroke_width = scale_(0.05);
@ -1574,12 +1583,12 @@ static void export_regions_to_svg(const std::string &path, const std::vector<std
::Slic3r::SVG svg(path.c_str(), bbox);
svg.draw_outline(lslices, "green", "lime", stroke_width);
for (const std::pair<ExPolygon, size_t> &region : regions) {
int region_color = int(region.second);
if (region_color >= 0 && region_color < int(colors.size()))
svg.draw(region.first, colors[region_color]);
for (const ExPolygons &by_extruder : regions) {
size_t extrude_idx = &by_extruder - &regions.front();
if (extrude_idx >= 0 && extrude_idx < int(colors.size()))
svg.draw(by_extruder, colors[extrude_idx], stroke_width);
else
svg.draw(region.first, "black");
svg.draw(by_extruder, "black", stroke_width);
}
}
#endif // MMU_SEGMENTATION_DEBUG_REGIONS
@ -1667,20 +1676,23 @@ static bool has_layer_only_one_color(const std::vector<std::vector<ColoredLine>>
return true;
}
std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback)
std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback)
{
std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions(print_object.layers().size());
std::vector<std::vector<PaintedLine>> painted_lines(print_object.layers().size());
std::array<std::mutex, 64> painted_lines_mutex;
std::vector<EdgeGrid::Grid> edge_grids(print_object.layers().size());
const ConstLayerPtrsAdaptor layers = print_object.layers();
std::vector<ExPolygons> input_expolygons(layers.size());
const size_t num_extruders = print_object.print()->config().nozzle_diameter.size();
const size_t num_layers = print_object.layers().size();
std::vector<std::vector<ExPolygons>> segmented_regions(num_layers);
segmented_regions.assign(num_layers, std::vector<ExPolygons>(num_extruders + 1));
std::vector<std::vector<PaintedLine>> painted_lines(num_layers);
std::array<std::mutex, 64> painted_lines_mutex;
std::vector<EdgeGrid::Grid> edge_grids(num_layers);
const ConstLayerPtrsAdaptor layers = print_object.layers();
std::vector<ExPolygons> input_expolygons(num_layers);
throw_on_cancel_callback();
// Merge all regions and remove small holes
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, layers.size()), [&layers, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&layers, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback();
ExPolygons ex_polygons;
@ -1711,7 +1723,7 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
}); // end of parallel_for
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - end";
for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) {
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
throw_on_cancel_callback();
BoundingBox bbox(get_extents(layers[layer_idx]->regions()));
bbox.merge(get_extents(input_expolygons[layer_idx]));
@ -1723,8 +1735,7 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - begin";
for (const ModelVolume *mv : print_object.model_object()->volumes) {
const size_t num_extruders = print_object.print()->config().nozzle_diameter.size() + 1;
tbb::parallel_for(tbb::blocked_range<size_t>(1, num_extruders), [&mv, &print_object, &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) {
throw_on_cancel_callback();
const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx));
@ -1732,7 +1743,7 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
continue;
const Transform3f tr = print_object.trafo().cast<float>() * mv->get_matrix().cast<float>();
tbb::parallel_for(tbb::blocked_range<size_t>(0, custom_facets.indices.size()), [&tr, &custom_facets, &print_object, &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) {
float min_z = std::numeric_limits<float>::max();
float max_z = std::numeric_limits<float>::lowest();
@ -1748,15 +1759,15 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
std::sort(facet.begin(), facet.end(), [](const Vec3f &p1, const Vec3f &p2) { return p1.z() < p2.z(); });
// Find lowest slice not below the triangle.
auto first_layer = std::upper_bound(print_object.layers().begin(), print_object.layers().end(), float(min_z - EPSILON),
auto first_layer = std::upper_bound(layers.begin(), layers.end(), float(min_z - EPSILON),
[](float z, const Layer *l1) { return z < l1->slice_z; });
auto last_layer = std::upper_bound(print_object.layers().begin(), print_object.layers().end(), float(max_z + EPSILON),
auto last_layer = std::upper_bound(layers.begin(), layers.end(), float(max_z + EPSILON),
[](float z, const Layer *l1) { return z < l1->slice_z; });
--last_layer;
for (auto layer_it = first_layer; layer_it != (last_layer + 1); ++layer_it) {
const Layer *layer = *layer_it;
size_t layer_idx = layer_it - print_object.layers().begin();
size_t layer_idx = layer_it - layers.begin();
if (input_expolygons[layer_idx].empty() || facet[0].z() > layer->slice_z || layer->slice_z > facet[2].z())
continue;
@ -1799,7 +1810,7 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
<< std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector<PaintedLine> &pl) { return !pl.empty(); });
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, print_object.layers().size()), [&edge_grids, &input_expolygons, &painted_lines, &segmented_regions, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&edge_grids, &input_expolygons, &painted_lines, &segmented_regions, &num_extruders, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback();
if (!painted_lines[layer_idx].empty()) {
@ -1832,8 +1843,7 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
assert(!color_poly.front().empty());
if (has_layer_only_one_color(color_poly)) {
// If the whole layer is painted using the same color, it is not needed to construct a Voronoi diagram for the segmentation of this layer.
for (const ExPolygon &ex_polygon : input_expolygons[layer_idx])
segmented_regions[layer_idx].emplace_back(ex_polygon, size_t(color_poly.front().front().color));
segmented_regions[layer_idx][size_t(color_poly.front().front().color)] = input_expolygons[layer_idx];
} else {
MMU_Graph graph = build_graph(layer_idx, color_poly);
remove_multiple_edges_in_vertices(graph, color_poly);
@ -1846,9 +1856,7 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
}
#endif // MMU_SEGMENTATION_DEBUG_GRAPH
std::vector<std::pair<Polygon, size_t>> segmentation = extract_colored_segments(graph);
for (std::pair<Polygon, size_t> &region : segmentation)
segmented_regions[layer_idx].emplace_back(std::move(region));
segmented_regions[layer_idx] = extract_colored_segments(graph, num_extruders);
}
#ifdef MMU_SEGMENTATION_DEBUG_REGIONS
@ -1868,11 +1876,11 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
throw_on_cancel_callback();
}
// return segmented_regions;
std::vector<std::vector<ExPolygons>> top_and_bottom_layers = mmu_segmentation_top_and_bottom_layers(print_object, input_expolygons, throw_on_cancel_callback);
// The first index is extruder number (includes default extruder), and the second one is layer number
std::vector<std::vector<ExPolygons>> top_and_bottom_layers = mmu_segmentation_top_and_bottom_layers(print_object, input_expolygons, throw_on_cancel_callback);
throw_on_cancel_callback();
std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions_merged = merge_segmented_layers(segmented_regions, std::move(top_and_bottom_layers), throw_on_cancel_callback);
std::vector<std::vector<ExPolygons>> segmented_regions_merged = merge_segmented_layers(segmented_regions, std::move(top_and_bottom_layers), num_extruders, throw_on_cancel_callback);
throw_on_cancel_callback();
#ifdef MMU_SEGMENTATION_DEBUG_REGIONS

View file

@ -11,7 +11,7 @@ class PrintObject;
class ExPolygon;
// Returns MMU segmentation based on painting in MMU segmentation gizmo
std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback);
std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback);
} // namespace Slic3r

View file

@ -534,6 +534,7 @@ static std::vector<std::string> s_Preset_sla_print_options {
};
static std::vector<std::string> s_Preset_sla_material_options {
"material_colour",
"material_type",
"initial_layer_height",
"bottle_cost",

View file

@ -3163,6 +3163,13 @@ void PrintConfigDef::init_sla_params()
// SLA Material settings.
def = this->add("material_colour", coStrings);
def->label = L("Color");
def->tooltip = L("This is only used in the Slic3r interface as a visual help.");
def->gui_type = ConfigOptionDef::GUIType::color;
def->set_default_value(new ConfigOptionStrings{ "#29B2B2" });
def = this->add("material_type", coString);
def->label = L("SLA material type");
def->tooltip = L("SLA material type");

View file

@ -538,7 +538,7 @@ template<typename ThrowOnCancel>
static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCancel throw_on_cancel)
{
// Returns MMU segmentation based on painting in MMU segmentation gizmo
std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmentation = multi_material_segmentation_by_painting(print_object, throw_on_cancel);
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))),
@ -568,9 +568,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
bool layer_split = false;
for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) {
ByExtruder &region = by_extruder[extruder_id];
for (const std::pair<ExPolygon, size_t> &colored_polygon : segmentation[layer_id])
if (colored_polygon.second == extruder_id)
region.expolygons.emplace_back(std::move(colored_polygon.first));
append(region.expolygons, std::move(segmentation[layer_id][extruder_id]));
if (! region.expolygons.empty()) {
region.bbox = get_extents(region.expolygons);
layer_split = true;
@ -632,6 +630,13 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
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()) {

View file

@ -1,3 +1,4 @@
#include <numeric>
#include "SlicesToTriangleMesh.hpp"
@ -22,11 +23,16 @@ inline indexed_triangle_set wall_strip(const Polygon &poly,
ret.vertices.reserve(ret.vertices.size() + 2 *offs);
// The expression unscaled(p).cast<float>().eval() is important here
// as it ensures identical conversion of 2D scaled coordinates to float 3D
// to that used by the tesselation. This way, the duplicated vertices in the
// output mesh can be found with the == operator of the points.
// its_merge_vertices will then reliably remove the duplicates.
for (const Point &p : poly.points)
ret.vertices.emplace_back(to_3d(unscaled<float>(p), float(lower_z_mm)));
ret.vertices.emplace_back(to_3d(unscaled(p).cast<float>().eval(), float(lower_z_mm)));
for (const Point &p : poly.points)
ret.vertices.emplace_back(to_3d(unscaled<float>(p), float(upper_z_mm)));
ret.vertices.emplace_back(to_3d(unscaled(p).cast<float>().eval(), float(upper_z_mm)));
for (size_t i = startidx + 1; i < startidx + offs; ++i) {
ret.indices.emplace_back(i - 1, i, i + offs - 1);
@ -84,12 +90,14 @@ indexed_triangle_set slices_to_mesh(
const ExPolygons &upper = slices[i + 1];
const ExPolygons &lower = slices[i];
ExPolygons dff1 = diff_ex(lower, upper);
ExPolygons dff2 = diff_ex(upper, lower);
its_merge(layers[i], triangulate_expolygons_3d(dff1, grid[i], NORMALS_UP));
its_merge(layers[i], triangulate_expolygons_3d(dff2, grid[i], NORMALS_DOWN));
// Small 0 area artefacts can be created by diff_ex, and the
// tesselation also can create 0 area triangles. These will be removed
// by its_remove_degenerate_faces.
ExPolygons free_top = diff_ex(lower, upper);
ExPolygons overhang = diff_ex(upper, lower);
its_merge(layers[i], triangulate_expolygons_3d(free_top, grid[i], NORMALS_UP));
its_merge(layers[i], triangulate_expolygons_3d(overhang, grid[i], NORMALS_DOWN));
its_merge(layers[i], straight_walls(upper, grid[i], grid[i + 1]));
});
auto merge_fn = []( const indexed_triangle_set &a, const indexed_triangle_set &b ) {
@ -99,37 +107,30 @@ indexed_triangle_set slices_to_mesh(
auto ret = execution::reduce(ex_tbb, layers.begin(), layers.end(),
indexed_triangle_set{}, merge_fn);
// sla::Contour3D ret = tbb::parallel_reduce(
// tbb::blocked_range(layers.begin(), layers.end()),
// sla::Contour3D{},
// [](const tbb::blocked_range<Layers::iterator>& r, sla::Contour3D
// init) {
// for(auto it = r.begin(); it != r.end(); ++it )
// init.merge(*it); return init;
// },
// []( const sla::Contour3D &a, const sla::Contour3D &b ) {
// sla::Contour3D res{a}; res.merge(b); return res;
// });
its_merge(ret, triangulate_expolygons_3d(slices.front(), zmin, NORMALS_DOWN));
its_merge(ret, straight_walls(slices.front(), zmin, grid.front()));
its_merge(ret, triangulate_expolygons_3d(slices.back(), grid.back(), NORMALS_UP));
// FIXME: these repairs do not fix the mesh entirely. There will be cracks
// in the output. It is very hard to do the meshing in a way that does not
// leave errors.
its_merge_vertices(ret);
its_remove_degenerate_faces(ret);
its_compactify_vertices(ret);
return ret;
}
void slices_to_mesh(indexed_triangle_set & mesh,
const std::vector<ExPolygons> &slices,
double zmin,
double lh,
double ilh)
const std::vector<ExPolygons> &slices,
double zmin,
double lh,
double ilh)
{
std::vector<indexed_triangle_set> wall_meshes(slices.size());
std::vector<float> grid(slices.size(), zmin + ilh);
for (size_t i = 1; i < grid.size(); ++i)
grid[i] = grid[i - 1] + lh;
for (size_t i = 1; i < grid.size(); ++i) grid[i] = grid[i - 1] + lh;
indexed_triangle_set cntr = slices_to_mesh(slices, zmin, grid);
its_merge(mesh, cntr);
}

View file

@ -7,10 +7,10 @@
namespace Slic3r {
void slices_to_mesh(indexed_triangle_set & mesh,
const std::vector<ExPolygons> &slices,
double zmin,
double lh,
double ilh);
const std::vector<ExPolygons> &slices,
double zmin,
double lh,
double ilh);
inline indexed_triangle_set slices_to_mesh(
const std::vector<ExPolygons> &slices, double zmin, double lh, double ilh)

View file

@ -705,22 +705,16 @@ void its_flip_triangles(indexed_triangle_set &its)
int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit)
{
int last = 0;
for (int i = 0; i < int(its.indices.size()); ++ i) {
const stl_triangle_vertex_indices &face = its.indices[i];
if (face(0) != face(1) && face(0) != face(2) && face(1) != face(2)) {
if (last < i)
its.indices[last] = its.indices[i];
++ last;
}
}
int removed = int(its.indices.size()) - last;
if (removed) {
its.indices.erase(its.indices.begin() + last, its.indices.end());
// Optionally shrink the vertices.
if (shrink_to_fit)
its.indices.shrink_to_fit();
}
auto it = std::remove_if(its.indices.begin(), its.indices.end(), [](auto &face) {
return face(0) == face(1) || face(0) == face(2) || face(1) == face(2);
});
int removed = std::distance(it, its.indices.end());
its.indices.erase(it, its.indices.end());
if (removed && shrink_to_fit)
its.indices.shrink_to_fit();
return removed;
}