mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-30 20:31:09 +00:00
Generate walls and split solid infill in parallel
Same output, ~2.2 min for the LOTR map plate, was ~2.6.
This commit is contained in:
+22
-11
@@ -9,6 +9,8 @@
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../Surface.hpp"
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
#include "AABBTreeLines.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "Fill.hpp"
|
||||
@@ -630,24 +632,28 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
|
||||
if (!line_based_pattern) {
|
||||
const coord_t scaled_spacing = scaled<coord_t>(fill.params.spacing);
|
||||
|
||||
for (const ExPolygon &expolygon : fill.expolygons) {
|
||||
// Each expolygon is split on its own, so they run in parallel and are collected in their original order.
|
||||
std::vector<std::pair<ExPolygons, ExPolygons>> split_parts(fill.expolygons.size()); // normal, narrow
|
||||
tbb::parallel_for(size_t(0), fill.expolygons.size(), [&](size_t idx) {
|
||||
const ExPolygon &expolygon = fill.expolygons[idx];
|
||||
Polygons filled_area = to_polygons(expolygon);
|
||||
|
||||
// "Core" area: open (erode+dilate) to drop thin features, then clamp back to the original polygon.
|
||||
Polygons inner_area = intersection(filled_area, opening(filled_area, scaled_spacing, scaled_spacing));
|
||||
|
||||
if (inner_area.empty()) {
|
||||
narrow_infill.emplace_back(expolygon);
|
||||
continue;
|
||||
split_parts[idx].second.emplace_back(expolygon);
|
||||
return;
|
||||
}
|
||||
|
||||
ExPolygons inner_ex = union_ex(inner_area);
|
||||
ExPolygons expolys{expolygon};
|
||||
ExPolygons narrow_ex = diff_ex(expolys, inner_ex);
|
||||
ExPolygons normal_ex = intersection_ex(expolys, inner_ex);
|
||||
|
||||
append(normal_infill, normal_ex); // normal infill area
|
||||
append(narrow_infill, narrow_ex); // narrow infill area
|
||||
split_parts[idx].second = diff_ex(expolys, inner_ex); // narrow infill area
|
||||
split_parts[idx].first = intersection_ex(expolys, inner_ex); // normal infill area
|
||||
});
|
||||
for (auto &[normal_ex, narrow_ex] : split_parts) {
|
||||
append(normal_infill, std::move(normal_ex));
|
||||
append(narrow_infill, std::move(narrow_ex));
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -669,7 +675,10 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
|
||||
}
|
||||
const double aligning_angle = -base_angle + PI;
|
||||
|
||||
for (const ExPolygon &expolygon : fill.expolygons) {
|
||||
// Each expolygon is reconstructed on its own, so they run in parallel and are collected in their original order.
|
||||
std::vector<Polygons> split_reconstructed(fill.expolygons.size());
|
||||
tbb::parallel_for(size_t(0), fill.expolygons.size(), [&](size_t expolygon_idx) {
|
||||
const ExPolygon &expolygon = fill.expolygons[expolygon_idx];
|
||||
Polygons filled_area = to_polygons(expolygon);
|
||||
polygons_rotate(filled_area, aligning_angle);
|
||||
BoundingBox bb = get_extents(filled_area);
|
||||
@@ -800,8 +809,10 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
|
||||
}
|
||||
}
|
||||
|
||||
polygons_append(normal_fill_areas, reconstructed_area);
|
||||
}
|
||||
split_reconstructed[expolygon_idx] = std::move(reconstructed_area);
|
||||
});
|
||||
for (Polygons &reconstructed_area : split_reconstructed)
|
||||
polygons_append(normal_fill_areas, std::move(reconstructed_area));
|
||||
|
||||
polygons_rotate(normal_fill_areas, -aligning_angle);
|
||||
|
||||
|
||||
@@ -1448,22 +1448,25 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
&shell_triangles_by_color_top, &shell_triangles_by_color_bottom](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 painted_exploys;
|
||||
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
||||
// The per-colour unions below are independent of each other, so they run in parallel (a painted top or
|
||||
// bottom face puts all of its colours on one layer); whatever combines the colours stays in colour order.
|
||||
const auto merge_colour_union = [&](size_t color_idx) {
|
||||
auto &self = triangles_by_color_merged[color_idx][layer_idx];
|
||||
append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx]));
|
||||
append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx + num_layers]));
|
||||
append(self, std::move(triangles_by_color_top[color_idx][layer_idx]));
|
||||
append(self, std::move(triangles_by_color_top[color_idx][layer_idx + num_layers]));
|
||||
self = union_ex(self);
|
||||
};
|
||||
tbb::parallel_for(size_t(0), triangles_by_color_merged.size(), merge_colour_union);
|
||||
|
||||
append(painted_exploys, self);
|
||||
}
|
||||
|
||||
ExPolygons painted_exploys;
|
||||
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx)
|
||||
append(painted_exploys, triangles_by_color_merged[color_idx][layer_idx]);
|
||||
painted_exploys = union_ex(painted_exploys);
|
||||
|
||||
//BBS: merge the top and bottom shell layers
|
||||
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
||||
tbb::parallel_for(size_t(0), triangles_by_color_merged.size(), [&](size_t color_idx) {
|
||||
auto &self = triangles_by_color_merged[color_idx][layer_idx];
|
||||
|
||||
auto top_area = diff_ex(union_ex(shell_triangles_by_color_top[color_idx][layer_idx],
|
||||
@@ -1477,7 +1480,7 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
|
||||
append(self, top_area);
|
||||
append(self, bottom_area);
|
||||
self = union_ex(self);
|
||||
}
|
||||
});
|
||||
// Trim one region by the other if some of the regions overlap.
|
||||
ExPolygons painted_regions;
|
||||
for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <cassert>
|
||||
#include <unordered_set>
|
||||
#include <thread>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include "libslic3r/AABBTreeLines.hpp"
|
||||
#include "Print.hpp"
|
||||
static const int overhang_sampling_number = 6;
|
||||
@@ -2481,7 +2483,22 @@ void PerimeterGenerator::process_arachne()
|
||||
const bool only_one_wall_first_layer = this->config->only_one_wall_first_layer && has_bottom_shell_layers(*this->config);
|
||||
// we need to process each island separately because we might have different
|
||||
// extra perimeters for each one
|
||||
for (const Surface& surface : all_surfaces) {
|
||||
// Each island is independent up to its outputs, so they are generated in parallel - a layer split into thousands
|
||||
// of islands (e.g. by colour painting) otherwise ran on one thread - and the outputs are then committed in the
|
||||
// original island order, which is what the extra overhang perimeters (applied to the last island's loops and to
|
||||
// all fill surfaces so far) depend on.
|
||||
struct ArachneSurfaceResult
|
||||
{
|
||||
ExtrusionEntityCollection loops;
|
||||
bool has_loops = false;
|
||||
ExPolygons infill;
|
||||
ExPolygons no_overlap;
|
||||
};
|
||||
std::vector<ArachneSurfaceResult> results(all_surfaces.size());
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, all_surfaces.size()), [&](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t surface_idx = range.begin(); surface_idx < range.end(); ++surface_idx) {
|
||||
const Surface &surface = all_surfaces[surface_idx];
|
||||
ArachneSurfaceResult &result = results[surface_idx];
|
||||
coord_t bead_width_0 = ext_perimeter_spacing;
|
||||
// detect how many perimeters must be generated for this island
|
||||
int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops
|
||||
@@ -2617,7 +2634,7 @@ void PerimeterGenerator::process_arachne()
|
||||
static int iRun = 0;
|
||||
export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour()));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// All closed ExtrusionLine should have the same the first and the last point.
|
||||
// But in rare cases, Arachne produce ExtrusionLine marked as closed but without
|
||||
@@ -2838,7 +2855,8 @@ void PerimeterGenerator::process_arachne()
|
||||
this->config->overhang_reverse_internal_only);
|
||||
}
|
||||
defer_unsupported_loops(*this, extrusion_coll);
|
||||
this->loops->append(extrusion_coll);
|
||||
result.loops = std::move(extrusion_coll);
|
||||
result.has_loops = true;
|
||||
}
|
||||
|
||||
const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
|
||||
@@ -2881,9 +2899,7 @@ void PerimeterGenerator::process_arachne()
|
||||
if (!top_expolygons.empty()) {
|
||||
infill_exp = union_ex(infill_exp, offset_ex(top_expolygons, double(top_inset)));
|
||||
}
|
||||
this->fill_surfaces->append(infill_exp, stInternal);
|
||||
|
||||
apply_extra_perimeters(infill_exp);
|
||||
result.infill = std::move(infill_exp);
|
||||
|
||||
// BBS: get the no-overlap infill expolygons
|
||||
{
|
||||
@@ -2894,9 +2910,17 @@ void PerimeterGenerator::process_arachne()
|
||||
float(+min_perimeter_infill_spacing / 2.));
|
||||
if (!top_expolygons.empty())
|
||||
polyWithoutOverlap = union_ex(polyWithoutOverlap, top_expolygons);
|
||||
this->fill_no_overlap->insert(this->fill_no_overlap->end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
|
||||
result.no_overlap = std::move(polyWithoutOverlap);
|
||||
}
|
||||
}
|
||||
});
|
||||
for (ArachneSurfaceResult &result : results) {
|
||||
if (result.has_loops)
|
||||
this->loops->append(result.loops);
|
||||
this->fill_surfaces->append(result.infill, stInternal);
|
||||
apply_extra_perimeters(result.infill);
|
||||
this->fill_no_overlap->insert(this->fill_no_overlap->end(), result.no_overlap.begin(), result.no_overlap.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool PerimeterGeneratorLoop::is_internal_contour() const
|
||||
|
||||
Reference in New Issue
Block a user