Merge branch 'vb_organic_interfaces'
This commit is contained in:
commit
daa9bf7cd9
8 changed files with 716 additions and 509 deletions
|
@ -4,6 +4,7 @@
|
|||
#include "../Layer.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "../Fill/FillBase.hpp"
|
||||
#include "../MutablePolygon.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include "../Point.hpp"
|
||||
|
||||
|
@ -119,6 +120,195 @@ void remove_bridges_from_contacts(
|
|||
#endif /* SLIC3R_DEBUG */
|
||||
}
|
||||
|
||||
// Convert some of the intermediate layers into top/bottom interface layers as well as base interface layers.
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
||||
const PrintObjectConfig &config,
|
||||
const SupportParameters &support_params,
|
||||
const SupportGeneratorLayersPtr &bottom_contacts,
|
||||
const SupportGeneratorLayersPtr &top_contacts,
|
||||
// Input / output, will be merged with output. Only provided for Organic supports.
|
||||
SupportGeneratorLayersPtr &top_interface_layers,
|
||||
SupportGeneratorLayersPtr &top_base_interface_layers,
|
||||
// Input, will be trimmed with the newly created interface layers.
|
||||
SupportGeneratorLayersPtr &intermediate_layers,
|
||||
SupportGeneratorLayerStorage &layer_storage)
|
||||
{
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> base_and_interface_layers;
|
||||
|
||||
if (! intermediate_layers.empty() && support_params.has_interfaces()) {
|
||||
// For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers.
|
||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
|
||||
const bool snug_supports = config.support_material_style.value == smsSnug;
|
||||
const bool smooth_supports = config.support_material_style.value != smsGrid;
|
||||
SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
|
||||
SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
|
||||
interface_layers.assign(intermediate_layers.size(), nullptr);
|
||||
if (support_params.has_base_interfaces())
|
||||
base_interface_layers.assign(intermediate_layers.size(), nullptr);
|
||||
const auto smoothing_distance = support_params.support_material_interface_flow.scaled_spacing() * 1.5;
|
||||
const auto minimum_island_radius = support_params.support_material_interface_flow.scaled_spacing() / support_params.interface_density;
|
||||
const auto closing_distance = smoothing_distance; // scaled<float>(config.support_material_closing_radius.value);
|
||||
// Insert a new layer into base_interface_layers, if intersection with base exists.
|
||||
auto insert_layer = [&layer_storage, smooth_supports, closing_distance, smoothing_distance, minimum_island_radius](
|
||||
SupportGeneratorLayer &intermediate_layer, Polygons &bottom, Polygons &&top, SupportGeneratorLayer *top_interface_layer,
|
||||
const Polygons *subtract, SupporLayerType type) -> SupportGeneratorLayer* {
|
||||
bool has_top_interface = top_interface_layer && ! top_interface_layer->polygons.empty();
|
||||
assert(! bottom.empty() || ! top.empty() || has_top_interface);
|
||||
// Merge top into bottom, unite them with a safety offset.
|
||||
append(bottom, std::move(top));
|
||||
// Merge top / bottom interfaces. For snug supports, merge using closing distance and regularize (close concave corners).
|
||||
bottom = intersection(
|
||||
smooth_supports ?
|
||||
smooth_outward(closing(std::move(bottom), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) :
|
||||
union_safety_offset(std::move(bottom)),
|
||||
intermediate_layer.polygons);
|
||||
if (has_top_interface) {
|
||||
// Don't trim the precomputed Organic supports top interface with base layer
|
||||
// as the precomputed top interface likely expands over multiple tree tips.
|
||||
bottom = union_(std::move(top_interface_layer->polygons), bottom);
|
||||
top_interface_layer->polygons.clear();
|
||||
}
|
||||
if (! bottom.empty()) {
|
||||
//FIXME Remove non-printable tiny islands, let them be printed using the base support.
|
||||
//bottom = opening(std::move(bottom), minimum_island_radius);
|
||||
if (! bottom.empty()) {
|
||||
SupportGeneratorLayer &layer_new = top_interface_layer ? *top_interface_layer : layer_storage.allocate(type);
|
||||
layer_new.polygons = std::move(bottom);
|
||||
layer_new.print_z = intermediate_layer.print_z;
|
||||
layer_new.bottom_z = intermediate_layer.bottom_z;
|
||||
layer_new.height = intermediate_layer.height;
|
||||
layer_new.bridging = intermediate_layer.bridging;
|
||||
// Subtract the interface from the base regions.
|
||||
intermediate_layer.polygons = diff(intermediate_layer.polygons, layer_new.polygons);
|
||||
if (subtract)
|
||||
// Trim the base interface layer with the interface layer.
|
||||
layer_new.polygons = diff(std::move(layer_new.polygons), *subtract);
|
||||
//FIXME filter layer_new.polygons islands by a minimum area?
|
||||
// $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ];
|
||||
return &layer_new;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
|
||||
[&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params,
|
||||
snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
|
||||
// Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below
|
||||
// this intermediate layer.
|
||||
// Index of the first top contact layer intersecting the current intermediate layer.
|
||||
auto idx_top_contact_first = -1;
|
||||
// Index of the first bottom contact layer intersecting the current intermediate layer.
|
||||
auto idx_bottom_contact_first = -1;
|
||||
// Index of the first top interface layer intersecting the current intermediate layer.
|
||||
auto idx_top_interface_first = -1;
|
||||
// Index of the first top contact interface layer intersecting the current intermediate layer.
|
||||
auto idx_top_base_interface_first = -1;
|
||||
auto num_intermediate = int(intermediate_layers.size());
|
||||
for (int idx_intermediate_layer = range.begin(); idx_intermediate_layer < range.end(); ++ idx_intermediate_layer) {
|
||||
SupportGeneratorLayer &intermediate_layer = *intermediate_layers[idx_intermediate_layer];
|
||||
Polygons polygons_top_contact_projected_interface;
|
||||
Polygons polygons_top_contact_projected_base;
|
||||
Polygons polygons_bottom_contact_projected_interface;
|
||||
Polygons polygons_bottom_contact_projected_base;
|
||||
if (support_params.num_top_interface_layers > 0) {
|
||||
// Top Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
|
||||
coordf_t top_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers) - 1)]->print_z;
|
||||
coordf_t top_inteface_z = std::numeric_limits<coordf_t>::max();
|
||||
if (support_params.num_top_base_interface_layers > 0)
|
||||
// Some top base interface layers will be generated.
|
||||
top_inteface_z = support_params.num_top_interface_layers_only() == 0 ?
|
||||
// Only base interface layers to generate.
|
||||
- std::numeric_limits<coordf_t>::max() :
|
||||
intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers_only()) - 1)]->print_z;
|
||||
// Move idx_top_contact_first up until above the current print_z.
|
||||
idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const SupportGeneratorLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON
|
||||
// Collect the top contact areas above this intermediate layer, below top_z.
|
||||
for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++ idx_top_contact) {
|
||||
const SupportGeneratorLayer &top_contact_layer = *top_contacts[idx_top_contact];
|
||||
//FIXME maybe this adds one interface layer in excess?
|
||||
if (top_contact_layer.bottom_z - EPSILON > top_z)
|
||||
break;
|
||||
polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface,
|
||||
// For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers.
|
||||
// For grid supports, merging of support regions will be performed by the projection into grid.
|
||||
snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
|
||||
}
|
||||
}
|
||||
if (support_params.num_bottom_interface_layers > 0) {
|
||||
// Bottom Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
|
||||
coordf_t bottom_z = intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers) + 1)]->bottom_z;
|
||||
coordf_t bottom_interface_z = - std::numeric_limits<coordf_t>::max();
|
||||
if (support_params.num_bottom_base_interface_layers > 0)
|
||||
// Some bottom base interface layers will be generated.
|
||||
bottom_interface_z = support_params.num_bottom_interface_layers_only() == 0 ?
|
||||
// Only base interface layers to generate.
|
||||
std::numeric_limits<coordf_t>::max() :
|
||||
intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers_only()))]->bottom_z;
|
||||
// Move idx_bottom_contact_first up until touching bottom_z.
|
||||
idx_bottom_contact_first = idx_higher_or_equal(bottom_contacts, idx_bottom_contact_first, [bottom_z](const SupportGeneratorLayer *layer){ return layer->print_z >= bottom_z - EPSILON; });
|
||||
// Collect the top contact areas above this intermediate layer, below top_z.
|
||||
for (int idx_bottom_contact = idx_bottom_contact_first; idx_bottom_contact < int(bottom_contacts.size()); ++ idx_bottom_contact) {
|
||||
const SupportGeneratorLayer &bottom_contact_layer = *bottom_contacts[idx_bottom_contact];
|
||||
if (bottom_contact_layer.print_z - EPSILON > intermediate_layer.bottom_z)
|
||||
break;
|
||||
polygons_append(bottom_contact_layer.print_z - EPSILON > bottom_interface_z ? polygons_bottom_contact_projected_interface : polygons_bottom_contact_projected_base, bottom_contact_layer.polygons);
|
||||
}
|
||||
}
|
||||
auto resolve_same_layer = [](SupportGeneratorLayersPtr &layers, int &idx, coordf_t print_z) -> SupportGeneratorLayer* {
|
||||
if (! layers.empty()) {
|
||||
idx = idx_higher_or_equal(layers, idx, [print_z](const SupportGeneratorLayer *layer) { return layer->print_z > print_z - EPSILON; });
|
||||
if (idx < int(layers.size()) && layers[idx]->print_z < print_z + EPSILON)
|
||||
return layers[idx];
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
SupportGeneratorLayer *top_interface_layer = resolve_same_layer(top_interface_layers, idx_top_interface_first, intermediate_layer.print_z);
|
||||
SupportGeneratorLayer *top_base_interface_layer = resolve_same_layer(top_base_interface_layers, idx_top_base_interface_first, intermediate_layer.print_z);
|
||||
SupportGeneratorLayer *interface_layer = nullptr;
|
||||
if (! polygons_bottom_contact_projected_interface.empty() || ! polygons_top_contact_projected_interface.empty() ||
|
||||
(top_interface_layer && ! top_interface_layer->polygons.empty())) {
|
||||
interface_layer = insert_layer(
|
||||
intermediate_layer, polygons_bottom_contact_projected_interface, std::move(polygons_top_contact_projected_interface), top_interface_layer,
|
||||
nullptr, polygons_top_contact_projected_interface.empty() ? SupporLayerType::BottomInterface : SupporLayerType::TopInterface);
|
||||
interface_layers[idx_intermediate_layer] = interface_layer;
|
||||
}
|
||||
if (! polygons_bottom_contact_projected_base.empty() || ! polygons_top_contact_projected_base.empty() ||
|
||||
(top_base_interface_layer && ! top_base_interface_layer->polygons.empty()))
|
||||
base_interface_layers[idx_intermediate_layer] = insert_layer(
|
||||
intermediate_layer, polygons_bottom_contact_projected_base, std::move(polygons_top_contact_projected_base), top_base_interface_layer,
|
||||
interface_layer ? &interface_layer->polygons : nullptr, SupporLayerType::Base);
|
||||
}
|
||||
});
|
||||
|
||||
// Compress contact_out, remove the nullptr items.
|
||||
// The parallel_for above may not have merged all the interface and base_interface layers
|
||||
// generated by the Organic supports code, do it here.
|
||||
auto merge_remove_empty = [](SupportGeneratorLayersPtr &in1, SupportGeneratorLayersPtr &in2) {
|
||||
auto remove_empty = [](SupportGeneratorLayersPtr &vec) {
|
||||
vec.erase(
|
||||
std::remove_if(vec.begin(), vec.end(), [](const SupportGeneratorLayer *ptr) { return ptr == nullptr || ptr->polygons.empty(); }),
|
||||
vec.end());
|
||||
};
|
||||
remove_empty(in1);
|
||||
remove_empty(in2);
|
||||
if (in2.empty())
|
||||
return std::move(in1);
|
||||
else if (in1.empty())
|
||||
return std::move(in2);
|
||||
else {
|
||||
SupportGeneratorLayersPtr out(in1.size() + in2.size(), nullptr);
|
||||
std::merge(in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(), [](auto* l, auto* r) { return l->print_z < r->print_z; });
|
||||
return std::move(out);
|
||||
}
|
||||
};
|
||||
interface_layers = merge_remove_empty(interface_layers, top_interface_layers);
|
||||
base_interface_layers = merge_remove_empty(base_interface_layers, top_base_interface_layers);
|
||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - end";
|
||||
}
|
||||
|
||||
return base_and_interface_layers;
|
||||
}
|
||||
|
||||
SupportGeneratorLayersPtr generate_raft_base(
|
||||
const PrintObject &object,
|
||||
const SupportParameters &support_params,
|
||||
|
|
|
@ -21,6 +21,23 @@ void remove_bridges_from_contacts(
|
|||
float fw,
|
||||
Polygons &contact_polygons);
|
||||
|
||||
// Turn some of the base layers into base interface layers.
|
||||
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
|
||||
// extruder to improve adhesion of the soluble filament to the base.
|
||||
// For Organic supports, merge top_interface_layers & top_base_interface_layers with the interfaces
|
||||
// produced by this function.
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
||||
const PrintObjectConfig &config,
|
||||
const SupportParameters &support_params,
|
||||
const SupportGeneratorLayersPtr &bottom_contacts,
|
||||
const SupportGeneratorLayersPtr &top_contacts,
|
||||
// Input / output, will be merged with output
|
||||
SupportGeneratorLayersPtr &top_interface_layers,
|
||||
SupportGeneratorLayersPtr &top_base_interface_layers,
|
||||
// Input, will be trimmed with the newly created interface layers.
|
||||
SupportGeneratorLayersPtr &intermediate_layers,
|
||||
SupportGeneratorLayerStorage &layer_storage);
|
||||
|
||||
// Generate raft layers, also expand the 1st support layer
|
||||
// in case there is no raft layer to improve support adhesion.
|
||||
SupportGeneratorLayersPtr generate_raft_base(
|
||||
|
|
|
@ -335,14 +335,16 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
|
|||
|
||||
// Propagate top / bottom contact layers to generate interface layers
|
||||
// and base interface layers (for soluble interface / non souble base only)
|
||||
auto [interface_layers, base_interface_layers] = this->generate_interface_layers(bottom_contacts, top_contacts, intermediate_layers, layer_storage);
|
||||
SupportGeneratorLayersPtr empty_layers;
|
||||
auto [interface_layers, base_interface_layers] = FFFSupport::generate_interface_layers(
|
||||
*m_object_config, m_support_params, bottom_contacts, top_contacts, empty_layers, empty_layers, intermediate_layers, layer_storage);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Support generator - Creating raft";
|
||||
|
||||
// If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette with holes filled.
|
||||
// There is also a 1st intermediate layer containing bases of support columns.
|
||||
// Inflate the bases of the support columns and create the raft base under the object.
|
||||
SupportGeneratorLayersPtr raft_layers = generate_raft_base(object, m_support_params, m_slicing_params, top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage);
|
||||
SupportGeneratorLayersPtr raft_layers = FFFSupport::generate_raft_base(object, m_support_params, m_slicing_params, top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage);
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
for (const SupportGeneratorLayer *l : interface_layers)
|
||||
|
@ -2514,169 +2516,6 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
|
|||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::trim_support_layers_by_object() in parallel - end";
|
||||
}
|
||||
|
||||
// Convert some of the intermediate layers into top/bottom interface layers as well as base interface layers.
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> PrintObjectSupportMaterial::generate_interface_layers(
|
||||
const SupportGeneratorLayersPtr &bottom_contacts,
|
||||
const SupportGeneratorLayersPtr &top_contacts,
|
||||
SupportGeneratorLayersPtr &intermediate_layers,
|
||||
SupportGeneratorLayerStorage &layer_storage) const
|
||||
{
|
||||
// my $area_threshold = $self->interface_flow->scaled_spacing ** 2;
|
||||
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> base_and_interface_layers;
|
||||
SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
|
||||
SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
|
||||
|
||||
// distinguish between interface and base interface layers
|
||||
// Contact layer is considered an interface layer, therefore run the following block only if support_material_interface_layers > 1.
|
||||
// Contact layer needs a base_interface layer, therefore run the following block if support_material_interface_layers > 0, has soluble support and extruders are different.
|
||||
bool soluble_interface_non_soluble_base =
|
||||
// Zero z-gap between the overhangs and the support interface.
|
||||
m_slicing_params.soluble_interface &&
|
||||
// Interface extruder soluble.
|
||||
m_object_config->support_material_interface_extruder.value > 0 && m_print_config->filament_soluble.get_at(m_object_config->support_material_interface_extruder.value - 1) &&
|
||||
// Base extruder: Either "print with active extruder" not soluble.
|
||||
(m_object_config->support_material_extruder.value == 0 || ! m_print_config->filament_soluble.get_at(m_object_config->support_material_extruder.value - 1));
|
||||
bool snug_supports = m_object_config->support_material_style.value != smsGrid;
|
||||
int num_interface_layers_top = m_object_config->support_material_interface_layers;
|
||||
int num_interface_layers_bottom = m_object_config->support_material_bottom_interface_layers;
|
||||
if (num_interface_layers_bottom < 0)
|
||||
num_interface_layers_bottom = num_interface_layers_top;
|
||||
int num_base_interface_layers_top = soluble_interface_non_soluble_base ? std::min(num_interface_layers_top / 2, 2) : 0;
|
||||
int num_base_interface_layers_bottom = soluble_interface_non_soluble_base ? std::min(num_interface_layers_bottom / 2, 2) : 0;
|
||||
|
||||
if (! intermediate_layers.empty() && (num_interface_layers_top > 1 || num_interface_layers_bottom > 1)) {
|
||||
// For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers.
|
||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
|
||||
// Since the intermediate layer index starts at zero the number of interface layer needs to be reduced by 1.
|
||||
-- num_interface_layers_top;
|
||||
-- num_interface_layers_bottom;
|
||||
int num_interface_layers_only_top = num_interface_layers_top - num_base_interface_layers_top;
|
||||
int num_interface_layers_only_bottom = num_interface_layers_bottom - num_base_interface_layers_bottom;
|
||||
interface_layers.assign(intermediate_layers.size(), nullptr);
|
||||
if (num_base_interface_layers_top || num_base_interface_layers_bottom)
|
||||
base_interface_layers.assign(intermediate_layers.size(), nullptr);
|
||||
auto smoothing_distance = m_support_params.support_material_interface_flow.scaled_spacing() * 1.5;
|
||||
auto minimum_island_radius = m_support_params.support_material_interface_flow.scaled_spacing() / m_support_params.interface_density;
|
||||
auto closing_distance = smoothing_distance; // scaled<float>(m_object_config->support_material_closing_radius.value);
|
||||
// Insert a new layer into base_interface_layers, if intersection with base exists.
|
||||
auto insert_layer = [&layer_storage, snug_supports, closing_distance, smoothing_distance, minimum_island_radius](
|
||||
SupportGeneratorLayer &intermediate_layer, Polygons &bottom, Polygons &&top, const Polygons *subtract, SupporLayerType type) -> SupportGeneratorLayer* {
|
||||
assert(! bottom.empty() || ! top.empty());
|
||||
// Merge top into bottom, unite them with a safety offset.
|
||||
append(bottom, std::move(top));
|
||||
// Merge top / bottom interfaces. For snug supports, merge using closing distance and regularize (close concave corners).
|
||||
bottom = intersection(
|
||||
snug_supports ?
|
||||
smooth_outward(closing(std::move(bottom), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) :
|
||||
union_safety_offset(std::move(bottom)),
|
||||
intermediate_layer.polygons);
|
||||
if (! bottom.empty()) {
|
||||
//FIXME Remove non-printable tiny islands, let them be printed using the base support.
|
||||
//bottom = opening(std::move(bottom), minimum_island_radius);
|
||||
if (! bottom.empty()) {
|
||||
SupportGeneratorLayer &layer_new = layer_storage.allocate(type);
|
||||
layer_new.polygons = std::move(bottom);
|
||||
layer_new.print_z = intermediate_layer.print_z;
|
||||
layer_new.bottom_z = intermediate_layer.bottom_z;
|
||||
layer_new.height = intermediate_layer.height;
|
||||
layer_new.bridging = intermediate_layer.bridging;
|
||||
// Subtract the interface from the base regions.
|
||||
intermediate_layer.polygons = diff(intermediate_layer.polygons, layer_new.polygons);
|
||||
if (subtract)
|
||||
// Trim the base interface layer with the interface layer.
|
||||
layer_new.polygons = diff(std::move(layer_new.polygons), *subtract);
|
||||
//FIXME filter layer_new.polygons islands by a minimum area?
|
||||
// $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ];
|
||||
return &layer_new;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
|
||||
[&bottom_contacts, &top_contacts, &intermediate_layers, &insert_layer,
|
||||
num_interface_layers_top, num_interface_layers_bottom, num_base_interface_layers_top, num_base_interface_layers_bottom, num_interface_layers_only_top, num_interface_layers_only_bottom,
|
||||
snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
|
||||
// Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below
|
||||
// this intermediate layer.
|
||||
// Index of the first top contact layer intersecting the current intermediate layer.
|
||||
auto idx_top_contact_first = -1;
|
||||
// Index of the first bottom contact layer intersecting the current intermediate layer.
|
||||
auto idx_bottom_contact_first = -1;
|
||||
auto num_intermediate = int(intermediate_layers.size());
|
||||
for (int idx_intermediate_layer = range.begin(); idx_intermediate_layer < range.end(); ++ idx_intermediate_layer) {
|
||||
SupportGeneratorLayer &intermediate_layer = *intermediate_layers[idx_intermediate_layer];
|
||||
Polygons polygons_top_contact_projected_interface;
|
||||
Polygons polygons_top_contact_projected_base;
|
||||
Polygons polygons_bottom_contact_projected_interface;
|
||||
Polygons polygons_bottom_contact_projected_base;
|
||||
if (num_interface_layers_top > 0) {
|
||||
// Top Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
|
||||
coordf_t top_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + num_interface_layers_top - 1)]->print_z;
|
||||
coordf_t top_inteface_z = std::numeric_limits<coordf_t>::max();
|
||||
if (num_base_interface_layers_top > 0)
|
||||
// Some top base interface layers will be generated.
|
||||
top_inteface_z = num_interface_layers_only_top == 0 ?
|
||||
// Only base interface layers to generate.
|
||||
- std::numeric_limits<coordf_t>::max() :
|
||||
intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + num_interface_layers_only_top - 1)]->print_z;
|
||||
// Move idx_top_contact_first up until above the current print_z.
|
||||
idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const SupportGeneratorLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON
|
||||
// Collect the top contact areas above this intermediate layer, below top_z.
|
||||
for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++ idx_top_contact) {
|
||||
const SupportGeneratorLayer &top_contact_layer = *top_contacts[idx_top_contact];
|
||||
//FIXME maybe this adds one interface layer in excess?
|
||||
if (top_contact_layer.bottom_z - EPSILON > top_z)
|
||||
break;
|
||||
polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface,
|
||||
// For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers.
|
||||
// For grid supports, merging of support regions will be performed by the projection into grid.
|
||||
snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
|
||||
}
|
||||
}
|
||||
if (num_interface_layers_bottom > 0) {
|
||||
// Bottom Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
|
||||
coordf_t bottom_z = intermediate_layers[std::max(0, idx_intermediate_layer - num_interface_layers_bottom + 1)]->bottom_z;
|
||||
coordf_t bottom_interface_z = - std::numeric_limits<coordf_t>::max();
|
||||
if (num_base_interface_layers_bottom > 0)
|
||||
// Some bottom base interface layers will be generated.
|
||||
bottom_interface_z = num_interface_layers_only_bottom == 0 ?
|
||||
// Only base interface layers to generate.
|
||||
std::numeric_limits<coordf_t>::max() :
|
||||
intermediate_layers[std::max(0, idx_intermediate_layer - num_interface_layers_only_bottom)]->bottom_z;
|
||||
// Move idx_bottom_contact_first up until touching bottom_z.
|
||||
idx_bottom_contact_first = idx_higher_or_equal(bottom_contacts, idx_bottom_contact_first, [bottom_z](const SupportGeneratorLayer *layer){ return layer->print_z >= bottom_z - EPSILON; });
|
||||
// Collect the top contact areas above this intermediate layer, below top_z.
|
||||
for (int idx_bottom_contact = idx_bottom_contact_first; idx_bottom_contact < int(bottom_contacts.size()); ++ idx_bottom_contact) {
|
||||
const SupportGeneratorLayer &bottom_contact_layer = *bottom_contacts[idx_bottom_contact];
|
||||
if (bottom_contact_layer.print_z - EPSILON > intermediate_layer.bottom_z)
|
||||
break;
|
||||
polygons_append(bottom_contact_layer.print_z - EPSILON > bottom_interface_z ? polygons_bottom_contact_projected_interface : polygons_bottom_contact_projected_base, bottom_contact_layer.polygons);
|
||||
}
|
||||
}
|
||||
SupportGeneratorLayer *interface_layer = nullptr;
|
||||
if (! polygons_bottom_contact_projected_interface.empty() || ! polygons_top_contact_projected_interface.empty()) {
|
||||
interface_layer = insert_layer(
|
||||
intermediate_layer, polygons_bottom_contact_projected_interface, std::move(polygons_top_contact_projected_interface), nullptr,
|
||||
polygons_top_contact_projected_interface.empty() ? SupporLayerType::BottomInterface : SupporLayerType::TopInterface);
|
||||
interface_layers[idx_intermediate_layer] = interface_layer;
|
||||
}
|
||||
if (! polygons_bottom_contact_projected_base.empty() || ! polygons_top_contact_projected_base.empty())
|
||||
base_interface_layers[idx_intermediate_layer] = insert_layer(
|
||||
intermediate_layer, polygons_bottom_contact_projected_base, std::move(polygons_top_contact_projected_base),
|
||||
interface_layer ? &interface_layer->polygons : nullptr, SupporLayerType::Base);
|
||||
}
|
||||
});
|
||||
|
||||
// Compress contact_out, remove the nullptr items.
|
||||
remove_nulls(interface_layers);
|
||||
remove_nulls(base_interface_layers);
|
||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - end";
|
||||
}
|
||||
|
||||
return base_and_interface_layers;
|
||||
}
|
||||
|
||||
/*
|
||||
void PrintObjectSupportMaterial::clip_by_pillars(
|
||||
const PrintObject &object,
|
||||
|
|
|
@ -72,16 +72,6 @@ private:
|
|||
SupportGeneratorLayersPtr &intermediate_layers,
|
||||
const std::vector<Polygons> &layer_support_areas) const;
|
||||
|
||||
// Turn some of the base layers into base interface layers.
|
||||
// For soluble interfaces with non-soluble bases, print maximum two first interface layers with the base
|
||||
// extruder to improve adhesion of the soluble filament to the base.
|
||||
std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interface_layers(
|
||||
const SupportGeneratorLayersPtr &bottom_contacts,
|
||||
const SupportGeneratorLayersPtr &top_contacts,
|
||||
SupportGeneratorLayersPtr &intermediate_layers,
|
||||
SupportGeneratorLayerStorage &layer_storage) const;
|
||||
|
||||
|
||||
// Trim support layers by an object to leave a defined gap between
|
||||
// the support volume and the object.
|
||||
void trim_support_layers_by_object(
|
||||
|
|
|
@ -11,6 +11,33 @@ SupportParameters::SupportParameters(const PrintObject &object)
|
|||
const PrintObjectConfig &object_config = object.config();
|
||||
const SlicingParameters &slicing_params = object.slicing_parameters();
|
||||
|
||||
this->soluble_interface = slicing_params.soluble_interface;
|
||||
this->soluble_interface_non_soluble_base =
|
||||
// Zero z-gap between the overhangs and the support interface.
|
||||
slicing_params.soluble_interface &&
|
||||
// Interface extruder soluble.
|
||||
object_config.support_material_interface_extruder.value > 0 && print_config.filament_soluble.get_at(object_config.support_material_interface_extruder.value - 1) &&
|
||||
// Base extruder: Either "print with active extruder" not soluble.
|
||||
(object_config.support_material_extruder.value == 0 || ! print_config.filament_soluble.get_at(object_config.support_material_extruder.value - 1));
|
||||
|
||||
{
|
||||
int num_top_interface_layers = std::max(0, object_config.support_material_interface_layers.value);
|
||||
int num_bottom_interface_layers = object_config.support_material_bottom_interface_layers < 0 ?
|
||||
num_top_interface_layers : object_config.support_material_bottom_interface_layers;
|
||||
this->has_top_contacts = num_top_interface_layers > 0;
|
||||
this->has_bottom_contacts = num_bottom_interface_layers > 0;
|
||||
this->num_top_interface_layers = this->has_top_contacts ? size_t(num_top_interface_layers - 1) : 0;
|
||||
this->num_bottom_interface_layers = this->has_bottom_contacts ? size_t(num_bottom_interface_layers - 1) : 0;
|
||||
if (this->soluble_interface_non_soluble_base) {
|
||||
// Try to support soluble dense interfaces with non-soluble dense interfaces.
|
||||
this->num_top_base_interface_layers = size_t(std::min(num_top_interface_layers / 2, 2));
|
||||
this->num_bottom_base_interface_layers = size_t(std::min(num_bottom_interface_layers / 2, 2));
|
||||
} else {
|
||||
this->num_top_base_interface_layers = 0;
|
||||
this->num_bottom_base_interface_layers = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this->first_layer_flow = Slic3r::support_material_1st_layer_flow(&object, float(slicing_params.first_print_layer_height));
|
||||
this->support_material_flow = Slic3r::support_material_flow(&object, float(slicing_params.layer_height));
|
||||
this->support_material_interface_flow = Slic3r::support_material_interface_flow(&object, float(slicing_params.layer_height));
|
||||
|
@ -54,7 +81,6 @@ SupportParameters::SupportParameters(const PrintObject &object)
|
|||
this->can_merge_support_regions = true;
|
||||
}
|
||||
|
||||
|
||||
double interface_spacing = object_config.support_material_interface_spacing.value + this->support_material_interface_flow.spacing();
|
||||
this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / interface_spacing);
|
||||
double raft_interface_spacing = object_config.support_material_interface_spacing.value + this->raft_interface_flow.spacing();
|
||||
|
|
|
@ -14,6 +14,30 @@ namespace FFFSupport {
|
|||
struct SupportParameters {
|
||||
SupportParameters(const PrintObject &object);
|
||||
|
||||
// Both top / bottom contacts and interfaces are soluble.
|
||||
bool soluble_interface;
|
||||
// Support contact & interface are soluble, but support base is non-soluble.
|
||||
bool soluble_interface_non_soluble_base;
|
||||
|
||||
// Is there at least a top contact layer extruded above support base?
|
||||
bool has_top_contacts;
|
||||
// Is there at least a bottom contact layer extruded below support base?
|
||||
bool has_bottom_contacts;
|
||||
// Number of top interface layers without counting the contact layer.
|
||||
size_t num_top_interface_layers;
|
||||
// Number of bottom interface layers without counting the contact layer.
|
||||
size_t num_bottom_interface_layers;
|
||||
// Number of top base interface layers. Zero if not soluble_interface_non_soluble_base.
|
||||
size_t num_top_base_interface_layers;
|
||||
// Number of bottom base interface layers. Zero if not soluble_interface_non_soluble_base.
|
||||
size_t num_bottom_base_interface_layers;
|
||||
|
||||
bool has_contacts() const { return this->has_top_contacts || this->has_bottom_contacts; }
|
||||
bool has_interfaces() const { return this->num_top_interface_layers + this->num_bottom_interface_layers > 0; }
|
||||
bool has_base_interfaces() const { return this->num_top_base_interface_layers + this->num_bottom_base_interface_layers > 0; }
|
||||
size_t num_top_interface_layers_only() const { return this->num_top_interface_layers - this->num_top_base_interface_layers; }
|
||||
size_t num_bottom_interface_layers_only() const { return this->num_bottom_interface_layers - this->num_bottom_base_interface_layers; }
|
||||
|
||||
// Flow at the 1st print layer.
|
||||
Flow first_layer_flow;
|
||||
// Flow at the support base (neither top, nor bottom interface).
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -364,10 +364,6 @@ public:
|
|||
* \brief Amount of layers distance required from the top of the model to the bottom of a support structure.
|
||||
*/
|
||||
size_t z_distance_bottom_layers;
|
||||
/*!
|
||||
* \brief used for performance optimization at the support floor. Should have no impact on the resulting tree.
|
||||
*/
|
||||
size_t performance_interface_skip_layers;
|
||||
/*!
|
||||
* \brief User specified angles for the support infill.
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue