mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 19:01:02 +00:00
Run a layer's regions in parallel where they are independent
detect_surfaces_type, process_external_surfaces and the vertical shells each waited on their own heaviest layer in turn. The LOTR map plate slices in ~10.5 min at 0.1 mm / 2000k, was ~11.5; ~87 s at normal settings, was ~97.
This commit is contained in:
+181
-137
@@ -1666,7 +1666,9 @@ void PrintObject::detect_surfaces_type()
|
|||||||
bool interface_shells = ! spiral_mode && m_config.interface_shells.value;
|
bool interface_shells = ! spiral_mode && m_config.interface_shells.value;
|
||||||
size_t num_layers = spiral_mode ? std::min(size_t(this->printing_region(0).config().bottom_shell_layers), m_layers.size()) : m_layers.size();
|
size_t num_layers = spiral_mode ? std::min(size_t(this->printing_region(0).config().bottom_shell_layers), m_layers.size()) : m_layers.size();
|
||||||
|
|
||||||
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
|
// The regions of a layer do not see each other here, and a layer cut through a fine relief takes far longer than the
|
||||||
|
// others, so the regions run next to each other instead of one after another, each still over all layers.
|
||||||
|
tbb::parallel_for(size_t(0), this->num_printing_regions(), [&](size_t region_id) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " in parallel - start";
|
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " in parallel - start";
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
for (Layer *layer : m_layers)
|
for (Layer *layer : m_layers)
|
||||||
@@ -2086,29 +2088,31 @@ void PrintObject::detect_surfaces_type()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// ==============================================================================================================
|
|
||||||
// === ORCA: Interim workaround - for now the new stInternalAfterExternalBridge surfaace is re-classified ==============
|
|
||||||
// === back to a bottom bridge. As a starting point, this improves bridging reliability as it extrudes ==========
|
|
||||||
// === two external bridge layers. However, TODO: Implement a new surface type throughout the codebase ==========
|
|
||||||
// ==============================================================================================================
|
|
||||||
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
|
|
||||||
tbb::parallel_for( tbb::blocked_range<size_t>(0, m_layers.size()), [this, region_id](const tbb::blocked_range<size_t> &range) {
|
|
||||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) {
|
|
||||||
Surfaces &surfs = m_layers[idx_layer]->m_regions[region_id]->slices.surfaces;
|
|
||||||
for (Surface &s : surfs) {
|
|
||||||
if (s.surface_type == stInternalAfterExternalBridge) {
|
|
||||||
s.surface_type = stBottomBridge;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
// === ORCA: End of second external bridge layer changes =======================================================
|
// === ORCA: End of second external bridge layer changes =======================================================
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
|
|
||||||
|
}); // for each this->print->region_count
|
||||||
|
|
||||||
|
// ==============================================================================================================
|
||||||
|
// === ORCA: Interim workaround - for now the new stInternalAfterExternalBridge surfaace is re-classified ==============
|
||||||
|
// === back to a bottom bridge. As a starting point, this improves bridging reliability as it extrudes ==========
|
||||||
|
// === two external bridge layers. However, TODO: Implement a new surface type throughout the codebase ==========
|
||||||
|
// ==============================================================================================================
|
||||||
|
// Once all the regions have their second bridge layer, and before their slices are trimmed into fill surfaces below.
|
||||||
|
if ((this->config().enable_extra_bridge_layer.value == eblApplyToAll) || (this->config().enable_extra_bridge_layer.value == eblExternalBridgeOnly)) {
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_layers.size()), [this](const tbb::blocked_range<size_t> &range) {
|
||||||
|
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer)
|
||||||
|
for (LayerRegion *layerm : m_layers[idx_layer]->regions())
|
||||||
|
for (Surface &s : layerm->slices.surfaces)
|
||||||
|
if (s.surface_type == stInternalAfterExternalBridge)
|
||||||
|
s.surface_type = stBottomBridge;
|
||||||
|
});
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
}
|
||||||
|
|
||||||
|
tbb::parallel_for(size_t(0), this->num_printing_regions(), [&](size_t region_id) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - start";
|
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - start";
|
||||||
// Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
|
// Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
@@ -2125,7 +2129,7 @@ void PrintObject::detect_surfaces_type()
|
|||||||
});
|
});
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - end";
|
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - end";
|
||||||
} // for each this->print->region_count
|
});
|
||||||
|
|
||||||
// Mark the object to have the region slices classified (typed, which also means they are split based on whether they are supported, bridging, top layers etc.)
|
// Mark the object to have the region slices classified (typed, which also means they are split based on whether they are supported, bridging, top layers etc.)
|
||||||
m_typed_slices = true;
|
m_typed_slices = true;
|
||||||
@@ -2192,8 +2196,10 @@ void PrintObject::process_external_surfaces()
|
|||||||
BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - end";
|
BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - end";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
|
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces in parallel - start";
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - start";
|
// The regions of a layer do not see each other here, and a layer cut through a fine relief takes far longer than the
|
||||||
|
// others, so the regions run next to each other instead of one after another, each still over all layers.
|
||||||
|
tbb::parallel_for(size_t(0), this->num_printing_regions(), [this, &surfaces_covered](size_t region_id) {
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<size_t>(0, m_layers.size()),
|
tbb::blocked_range<size_t>(0, m_layers.size()),
|
||||||
[this, &surfaces_covered, region_id](const tbb::blocked_range<size_t>& range) {
|
[this, &surfaces_covered, region_id](const tbb::blocked_range<size_t>& range) {
|
||||||
@@ -2208,9 +2214,9 @@ void PrintObject::process_external_surfaces()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
});
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
|
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces in parallel - end";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintObject::discover_vertical_shells()
|
void PrintObject::discover_vertical_shells()
|
||||||
@@ -2330,123 +2336,21 @@ void PrintObject::discover_vertical_shells()
|
|||||||
// region-specific but the shell settings and the external perimeter spacing, so a region sharing them with an earlier
|
// region-specific but the shell settings and the external perimeter spacing, so a region sharing them with an earlier
|
||||||
// one reuses its result instead of repeating it: that accumulation is a union over several layers of top/bottom
|
// one reuses its result instead of repeating it: that accumulation is a union over several layers of top/bottom
|
||||||
// surfaces, and a multi-material print has a region per filament.
|
// surfaces, and a multi-material print has a region per filament.
|
||||||
|
using AccumulationKey = std::array<double, 5>;
|
||||||
struct ShellAccumulation
|
struct ShellAccumulation
|
||||||
{
|
{
|
||||||
std::array<double, 5> key;
|
AccumulationKey key;
|
||||||
Polygons shell;
|
Polygons shell;
|
||||||
Polygons holes;
|
Polygons holes;
|
||||||
};
|
};
|
||||||
std::vector<std::vector<ShellAccumulation>> shell_accumulations(top_bottom_surfaces_all_regions ? num_layers : 0);
|
const auto accumulation_key = [](const PrintRegionConfig ®ion_config, const LayerRegion *layerm) {
|
||||||
|
return AccumulationKey{ double(region_config.top_shell_layers.value), region_config.top_shell_thickness.value,
|
||||||
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
|
|
||||||
const PrintRegion ®ion = this->printing_region(region_id);
|
|
||||||
if (region.config().ensure_vertical_shell_thickness.value != evstAll )
|
|
||||||
// This region will be handled by discover_horizontal_shells().
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//FIXME Improve the heuristics for a grain size.
|
|
||||||
size_t grain_size = std::max(num_layers / 16, size_t(1));
|
|
||||||
|
|
||||||
if (! top_bottom_surfaces_all_regions) {
|
|
||||||
// This is either a single material print, or a multi-material print and interface_shells are enabled, meaning that the vertical shell thickness
|
|
||||||
// is calculated over a single material.
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : cache top / bottom";
|
|
||||||
tbb::parallel_for(
|
|
||||||
tbb::blocked_range<size_t>(0, num_layers, grain_size),
|
|
||||||
[this, region_id, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) {
|
|
||||||
const std::initializer_list<SurfaceType> surfaces_bottom { stBottom, stBottomBridge };
|
|
||||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
|
||||||
m_print->throw_if_canceled();
|
|
||||||
Layer &layer = *m_layers[idx_layer];
|
|
||||||
LayerRegion &layerm = *layer.m_regions[region_id];
|
|
||||||
float top_bottom_expansion = float(layerm.flow(frSolidInfill).scaled_spacing()) * top_bottom_expansion_coeff;
|
|
||||||
// Top surfaces.
|
|
||||||
auto &cache = cache_top_botom_regions[idx_layer];
|
|
||||||
cache.top_surfaces = offset(layerm.slices.filter_by_type(stTop), top_bottom_expansion);
|
|
||||||
// append(cache.top_surfaces, offset(layerm.fill_surfaces.filter_by_type(stTop), top_bottom_expansion));
|
|
||||||
// Bottom surfaces.
|
|
||||||
cache.bottom_surfaces = offset(layerm.slices.filter_by_types(surfaces_bottom), top_bottom_expansion);
|
|
||||||
// append(cache.bottom_surfaces, offset(layerm.fill_surfaces.filter_by_types(surfaces_bottom), top_bottom_expansion));
|
|
||||||
// Holes over all regions. Only collect them once, they are valid for all region_id iterations.
|
|
||||||
if (cache.holes.empty()) {
|
|
||||||
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id)
|
|
||||||
polygons_append(cache.holes, to_polygons(layer.regions()[region_id]->fill_expolygons));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
m_print->throw_if_canceled();
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - end : cache top / bottom";
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : ensure vertical wall thickness";
|
|
||||||
grain_size = 1;
|
|
||||||
tbb::parallel_for(
|
|
||||||
tbb::blocked_range<size_t>(0, num_layers, grain_size),
|
|
||||||
[this, region_id, &cache_top_botom_regions, &shell_accumulations]
|
|
||||||
(const tbb::blocked_range<size_t>& range) {
|
|
||||||
// printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
|
|
||||||
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
|
||||||
m_print->throw_if_canceled();
|
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
|
||||||
static size_t debug_idx = 0;
|
|
||||||
++ debug_idx;
|
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
|
||||||
|
|
||||||
Layer *layer = m_layers[idx_layer];
|
|
||||||
LayerRegion *layerm = layer->m_regions[region_id];
|
|
||||||
const PrintRegionConfig ®ion_config = layerm->region().config();
|
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
|
||||||
layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-initial");
|
|
||||||
layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-initial");
|
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
|
||||||
|
|
||||||
Flow solid_infill_flow = layerm->flow(frSolidInfill);
|
|
||||||
coord_t infill_line_spacing = solid_infill_flow.scaled_spacing();
|
|
||||||
// Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
|
|
||||||
Polygons shell;
|
|
||||||
Polygons holes;
|
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
|
||||||
ExPolygons shell_ex;
|
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
|
||||||
float min_perimeter_infill_spacing = float(infill_line_spacing) * 1.05f;
|
|
||||||
#if 0
|
|
||||||
// #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
|
||||||
{
|
|
||||||
Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box());
|
|
||||||
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) {
|
|
||||||
if (n < 0 || n >= (int)m_layers.size())
|
|
||||||
continue;
|
|
||||||
ExPolygons &expolys = m_layers[n]->perimeter_expolygons;
|
|
||||||
for (size_t i = 0; i < expolys.size(); ++ i) {
|
|
||||||
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", debug_idx, n, i), get_extents(expolys[i]));
|
|
||||||
svg.draw(expolys[i]);
|
|
||||||
svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
|
|
||||||
svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
|
|
||||||
svg.Close();
|
|
||||||
|
|
||||||
svg_cummulative.draw(expolys[i]);
|
|
||||||
svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
|
|
||||||
svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
|
||||||
const std::array<double, 5> accumulation_key{ double(region_config.top_shell_layers.value), region_config.top_shell_thickness.value,
|
|
||||||
double(region_config.bottom_shell_layers.value), region_config.bottom_shell_thickness.value,
|
double(region_config.bottom_shell_layers.value), region_config.bottom_shell_thickness.value,
|
||||||
double(layerm->flow(frExternalPerimeter).scaled_spacing()) };
|
double(layerm->flow(frExternalPerimeter).scaled_spacing()) };
|
||||||
std::vector<ShellAccumulation> *accumulations = shell_accumulations.empty() ? nullptr : &shell_accumulations[idx_layer];
|
};
|
||||||
const auto reused = accumulations == nullptr ? nullptr :
|
const auto accumulate_shell = [this, &cache_top_botom_regions](size_t idx_layer, const PrintRegionConfig ®ion_config,
|
||||||
[&]() -> const ShellAccumulation * {
|
const LayerRegion *layerm, Polygons &shell, Polygons &holes) {
|
||||||
for (const ShellAccumulation &a : *accumulations)
|
const Layer *layer = m_layers[idx_layer];
|
||||||
if (a.key == accumulation_key)
|
|
||||||
return &a;
|
|
||||||
return nullptr;
|
|
||||||
}();
|
|
||||||
if (reused != nullptr) {
|
|
||||||
shell = reused->shell;
|
|
||||||
holes = reused->holes;
|
|
||||||
} else {
|
|
||||||
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
|
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
|
||||||
auto combine_holes = [&holes](const Polygons &holes2) {
|
auto combine_holes = [&holes](const Polygons &holes2) {
|
||||||
if (holes.empty() || holes2.empty())
|
if (holes.empty() || holes2.empty())
|
||||||
@@ -2521,9 +2425,141 @@ void PrintObject::discover_vertical_shells()
|
|||||||
(i > ibottom || bottom_z - m_layers[i]->print_z < region_config.bottom_shell_thickness - EPSILON))
|
(i > ibottom || bottom_z - m_layers[i]->print_z < region_config.bottom_shell_thickness - EPSILON))
|
||||||
combine_holes(cache_top_botom_regions[i].holes);
|
combine_holes(cache_top_botom_regions[i].holes);
|
||||||
}
|
}
|
||||||
if (accumulations != nullptr)
|
};
|
||||||
accumulations->push_back({ accumulation_key, shell, holes });
|
std::vector<std::vector<ShellAccumulation>> shell_accumulations(top_bottom_surfaces_all_regions ? num_layers : 0);
|
||||||
|
if (! shell_accumulations.empty()) {
|
||||||
|
// Every (layer, key) pair is accumulated once, before the regions, so that nothing in the loop below is shared
|
||||||
|
// between them and they can run next to each other.
|
||||||
|
std::vector<std::array<size_t, 3>> todo; // layer, its slot, a region holding the key
|
||||||
|
for (size_t idx_layer = 0; idx_layer < num_layers; ++ idx_layer) {
|
||||||
|
std::vector<ShellAccumulation> &accumulations = shell_accumulations[idx_layer];
|
||||||
|
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
|
||||||
|
if (this->printing_region(region_id).config().ensure_vertical_shell_thickness.value != evstAll)
|
||||||
|
continue;
|
||||||
|
const LayerRegion *layerm = m_layers[idx_layer]->m_regions[region_id];
|
||||||
|
const AccumulationKey key = accumulation_key(layerm->region().config(), layerm);
|
||||||
|
if (std::none_of(accumulations.begin(), accumulations.end(), [&key](const ShellAccumulation &a) { return a.key == key; })) {
|
||||||
|
todo.push_back({ idx_layer, accumulations.size(), region_id });
|
||||||
|
accumulations.push_back({ key, {}, {} });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tbb::parallel_for(size_t(0), todo.size(), [this, &todo, &shell_accumulations, &accumulate_shell](size_t i) {
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
const LayerRegion *layerm = m_layers[todo[i][0]]->m_regions[todo[i][2]];
|
||||||
|
ShellAccumulation &out = shell_accumulations[todo[i][0]][todo[i][1]];
|
||||||
|
accumulate_shell(todo[i][0], layerm->region().config(), layerm, out.shell, out.holes);
|
||||||
|
});
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto process_region = [&](size_t region_id) {
|
||||||
|
const PrintRegion ®ion = this->printing_region(region_id);
|
||||||
|
if (region.config().ensure_vertical_shell_thickness.value != evstAll )
|
||||||
|
// This region will be handled by discover_horizontal_shells().
|
||||||
|
return;
|
||||||
|
|
||||||
|
//FIXME Improve the heuristics for a grain size.
|
||||||
|
size_t grain_size = std::max(num_layers / 16, size_t(1));
|
||||||
|
|
||||||
|
if (! top_bottom_surfaces_all_regions) {
|
||||||
|
// This is either a single material print, or a multi-material print and interface_shells are enabled, meaning that the vertical shell thickness
|
||||||
|
// is calculated over a single material.
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : cache top / bottom";
|
||||||
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<size_t>(0, num_layers, grain_size),
|
||||||
|
[this, region_id, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) {
|
||||||
|
const std::initializer_list<SurfaceType> surfaces_bottom { stBottom, stBottomBridge };
|
||||||
|
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
Layer &layer = *m_layers[idx_layer];
|
||||||
|
LayerRegion &layerm = *layer.m_regions[region_id];
|
||||||
|
float top_bottom_expansion = float(layerm.flow(frSolidInfill).scaled_spacing()) * top_bottom_expansion_coeff;
|
||||||
|
// Top surfaces.
|
||||||
|
auto &cache = cache_top_botom_regions[idx_layer];
|
||||||
|
cache.top_surfaces = offset(layerm.slices.filter_by_type(stTop), top_bottom_expansion);
|
||||||
|
// append(cache.top_surfaces, offset(layerm.fill_surfaces.filter_by_type(stTop), top_bottom_expansion));
|
||||||
|
// Bottom surfaces.
|
||||||
|
cache.bottom_surfaces = offset(layerm.slices.filter_by_types(surfaces_bottom), top_bottom_expansion);
|
||||||
|
// append(cache.bottom_surfaces, offset(layerm.fill_surfaces.filter_by_types(surfaces_bottom), top_bottom_expansion));
|
||||||
|
// Holes over all regions. Only collect them once, they are valid for all region_id iterations.
|
||||||
|
if (cache.holes.empty()) {
|
||||||
|
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id)
|
||||||
|
polygons_append(cache.holes, to_polygons(layer.regions()[region_id]->fill_expolygons));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - end : cache top / bottom";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : ensure vertical wall thickness";
|
||||||
|
grain_size = 1;
|
||||||
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<size_t>(0, num_layers, grain_size),
|
||||||
|
[this, region_id, &shell_accumulations, &accumulation_key, &accumulate_shell]
|
||||||
|
(const tbb::blocked_range<size_t>& range) {
|
||||||
|
// printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
|
||||||
|
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
static size_t debug_idx = 0;
|
||||||
|
++ debug_idx;
|
||||||
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
|
||||||
|
Layer *layer = m_layers[idx_layer];
|
||||||
|
LayerRegion *layerm = layer->m_regions[region_id];
|
||||||
|
const PrintRegionConfig ®ion_config = layerm->region().config();
|
||||||
|
|
||||||
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-initial");
|
||||||
|
layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-initial");
|
||||||
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
|
||||||
|
Flow solid_infill_flow = layerm->flow(frSolidInfill);
|
||||||
|
coord_t infill_line_spacing = solid_infill_flow.scaled_spacing();
|
||||||
|
// Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
|
||||||
|
Polygons shell;
|
||||||
|
Polygons holes;
|
||||||
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
ExPolygons shell_ex;
|
||||||
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
float min_perimeter_infill_spacing = float(infill_line_spacing) * 1.05f;
|
||||||
|
#if 0
|
||||||
|
// #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
{
|
||||||
|
Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box());
|
||||||
|
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) {
|
||||||
|
if (n < 0 || n >= (int)m_layers.size())
|
||||||
|
continue;
|
||||||
|
ExPolygons &expolys = m_layers[n]->perimeter_expolygons;
|
||||||
|
for (size_t i = 0; i < expolys.size(); ++ i) {
|
||||||
|
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", debug_idx, n, i), get_extents(expolys[i]));
|
||||||
|
svg.draw(expolys[i]);
|
||||||
|
svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
|
||||||
|
svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
|
||||||
|
svg.Close();
|
||||||
|
|
||||||
|
svg_cummulative.draw(expolys[i]);
|
||||||
|
svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
|
||||||
|
svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
const AccumulationKey key = accumulation_key(region_config, layerm);
|
||||||
|
const ShellAccumulation *reused = shell_accumulations.empty() ? nullptr :
|
||||||
|
[&]() -> const ShellAccumulation * {
|
||||||
|
for (const ShellAccumulation &a : shell_accumulations[idx_layer])
|
||||||
|
if (a.key == key)
|
||||||
|
return &a;
|
||||||
|
return nullptr;
|
||||||
|
}();
|
||||||
|
if (reused != nullptr) {
|
||||||
|
shell = reused->shell;
|
||||||
|
holes = reused->holes;
|
||||||
|
} else
|
||||||
|
accumulate_shell(idx_layer, region_config, layerm, shell, holes);
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
{
|
{
|
||||||
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
|
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
|
||||||
@@ -2707,7 +2743,15 @@ void PrintObject::discover_vertical_shells()
|
|||||||
layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-final");
|
layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-final");
|
||||||
}
|
}
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
} // for each region
|
}; // for each region
|
||||||
|
if (top_bottom_surfaces_all_regions)
|
||||||
|
// Nothing is shared between the regions, and a layer cut through a fine relief takes far longer than the others,
|
||||||
|
// so they run next to each other instead of one after another.
|
||||||
|
tbb::parallel_for(size_t(0), this->num_printing_regions(), process_region);
|
||||||
|
else
|
||||||
|
// Here every region fills the one top/bottom cache with its own surfaces first.
|
||||||
|
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id)
|
||||||
|
process_region(region_id);
|
||||||
} // void PrintObject::discover_vertical_shells()
|
} // void PrintObject::discover_vertical_shells()
|
||||||
|
|
||||||
// #define DEBUG_BRIDGE_OVER_INFILL
|
// #define DEBUG_BRIDGE_OVER_INFILL
|
||||||
|
|||||||
Reference in New Issue
Block a user