Fix of spiral vase mode with holes in the bottom: Holes in the bottom layers

(non-spiral vase layers) were being closed.
Fixes Bad slicing in vase mode (unexpected bridge and solid infill layers) 
Fixes Model with holes in the base does not slice properly in "Vase Mode" 
This commit is contained in:
Vojtech Bubnik 2020-12-09 14:07:22 +01:00
parent 5470af3938
commit 364300055e
8 changed files with 77 additions and 26 deletions

View file

@ -55,14 +55,22 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
this->perimeters.clear();
this->thin_fills.clear();
const PrintConfig &print_config = this->layer()->object()->print()->config();
const PrintRegionConfig &region_config = this->region()->config();
// This needs to be in sync with PrintObject::_slice() slicing_mode_normal_below_layer!
bool spiral_vase = print_config.spiral_vase &&
(this->layer()->id() >= region_config.bottom_solid_layers.value &&
this->layer()->print_z >= region_config.bottom_solid_min_thickness - EPSILON);
PerimeterGenerator g(
// input:
&slices,
this->layer()->height,
this->flow(frPerimeter),
&this->region()->config(),
&region_config,
&this->layer()->object()->config(),
&this->layer()->object()->print()->config(),
&print_config,
spiral_vase,
// output:
&this->perimeters,

View file

@ -312,7 +312,7 @@ void PerimeterGenerator::process()
for (ExPolygon &ex : expp)
ex.medial_axis(ext_perimeter_width + ext_perimeter_spacing2, min_width, &thin_walls);
}
if (print_config->spiral_vase && offsets.size() > 1) {
if (m_spiral_vase && offsets.size() > 1) {
// Remove all but the largest area polygon.
keep_largest_contour_only(offsets);
}

View file

@ -37,6 +37,7 @@ public:
const PrintRegionConfig* config,
const PrintObjectConfig* object_config,
const PrintConfig* print_config,
const bool spiral_vase,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection* loops,
@ -48,6 +49,7 @@ public:
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config),
m_spiral_vase(spiral_vase),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1)
{}
@ -60,6 +62,7 @@ public:
Polygons lower_slices_polygons() const { return m_lower_slices_polygons; }
private:
bool m_spiral_vase;
double m_ext_mm3_per_mm;
double m_mm3_per_mm;
double m_mm3_per_mm_overhang;

View file

@ -259,9 +259,16 @@ private:
// so that next call to make_perimeters() performs a union() before computing loops
bool m_typed_slices = false;
std::vector<ExPolygons> slice_region(size_t region_id, const std::vector<float> &z, SlicingMode mode) const;
std::vector<ExPolygons> slice_region(size_t region_id, const std::vector<float> &z, SlicingMode mode, size_t slicing_mode_normal_below_layer, SlicingMode mode_below) const;
std::vector<ExPolygons> slice_region(size_t region_id, const std::vector<float> &z, SlicingMode mode) const
{ return this->slice_region(region_id, z, mode, 0, mode); }
std::vector<ExPolygons> slice_modifiers(size_t region_id, const std::vector<float> &z) const;
std::vector<ExPolygons> slice_volumes(const std::vector<float> &z, SlicingMode mode, const std::vector<const ModelVolume*> &volumes) const;
std::vector<ExPolygons> slice_volumes(
const std::vector<float> &z,
SlicingMode mode, size_t slicing_mode_normal_below_layer, SlicingMode mode_below,
const std::vector<const ModelVolume*> &volumes) const;
std::vector<ExPolygons> slice_volumes(const std::vector<float> &z, SlicingMode mode, const std::vector<const ModelVolume*> &volumes) const
{ return this->slice_volumes(z, mode, 0, mode, volumes); }
std::vector<ExPolygons> slice_volume(const std::vector<float> &z, SlicingMode mode, const ModelVolume &volume) const;
std::vector<ExPolygons> slice_volume(const std::vector<float> &z, const std::vector<t_layer_height_range> &ranges, SlicingMode mode, const ModelVolume &volume) const;
};

View file

@ -1747,14 +1747,24 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
// Slice all non-modifier volumes.
bool clipped = false;
bool upscaled = false;
auto slicing_mode = this->print()->config().spiral_vase ? SlicingMode::PositiveLargestContour : SlicingMode::Regular;
bool spiral_vase = this->print()->config().spiral_vase;
auto slicing_mode = spiral_vase ? SlicingMode::PositiveLargestContour : SlicingMode::Regular;
if (! has_z_ranges && (! m_config.clip_multipart_objects.value || all_volumes_single_region >= 0)) {
// Cheap path: Slice regions without mutual clipping.
// The cheap path is possible if no clipping is allowed or if slicing volumes of just a single region.
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
// slicing in parallel
std::vector<ExPolygons> expolygons_by_layer = this->slice_region(region_id, slice_zs, slicing_mode);
size_t slicing_mode_normal_below_layer = 0;
if (spiral_vase) {
// Slice the bottom layers with SlicingMode::Regular.
// This needs to be in sync with LayerRegion::make_perimeters() spiral_vase!
const PrintRegionConfig &config = this->print()->regions()[region_id]->config();
slicing_mode_normal_below_layer = size_t(config.bottom_solid_layers.value);
for (; slicing_mode_normal_below_layer < slice_zs.size() && slice_zs[slicing_mode_normal_below_layer] < config.bottom_solid_min_thickness - EPSILON;
++ slicing_mode_normal_below_layer);
}
std::vector<ExPolygons> expolygons_by_layer = this->slice_region(region_id, slice_zs, slicing_mode, slicing_mode_normal_below_layer, SlicingMode::Regular);
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
@ -2001,7 +2011,7 @@ end:
}
// To be used only if there are no layer span specific configurations applied, which would lead to z ranges being generated for this region.
std::vector<ExPolygons> PrintObject::slice_region(size_t region_id, const std::vector<float> &z, SlicingMode mode) const
std::vector<ExPolygons> PrintObject::slice_region(size_t region_id, const std::vector<float> &z, SlicingMode mode, size_t slicing_mode_normal_below_layer, SlicingMode mode_below) const
{
std::vector<const ModelVolume*> volumes;
if (region_id < this->region_volumes.size()) {
@ -2011,7 +2021,7 @@ std::vector<ExPolygons> PrintObject::slice_region(size_t region_id, const std::v
volumes.emplace_back(volume);
}
}
return this->slice_volumes(z, mode, volumes);
return this->slice_volumes(z, mode, slicing_mode_normal_below_layer, mode_below, volumes);
}
// Z ranges are not applicable to modifier meshes, therefore a single volume will be found in volume_and_range at most once.
@ -2123,7 +2133,10 @@ std::vector<ExPolygons> PrintObject::slice_support_volumes(const ModelVolumeType
return this->slice_volumes(zs, SlicingMode::Regular, volumes);
}
std::vector<ExPolygons> PrintObject::slice_volumes(const std::vector<float> &z, SlicingMode mode, const std::vector<const ModelVolume*> &volumes) const
std::vector<ExPolygons> PrintObject::slice_volumes(
const std::vector<float> &z,
SlicingMode mode, size_t slicing_mode_normal_below_layer, SlicingMode mode_below,
const std::vector<const ModelVolume*> &volumes) const
{
std::vector<ExPolygons> layers;
if (! volumes.empty()) {
@ -2153,7 +2166,7 @@ std::vector<ExPolygons> PrintObject::slice_volumes(const std::vector<float> &z,
mesh.require_shared_vertices();
TriangleMeshSlicer mslicer;
mslicer.init(&mesh, callback);
mslicer.slice(z, mode, float(m_config.slice_closing_radius.value), &layers, callback);
mslicer.slice(z, mode, slicing_mode_normal_below_layer, mode_below, float(m_config.slice_closing_radius.value), &layers, callback);
m_print->throw_if_canceled();
}
}

View file

@ -775,9 +775,10 @@ void TriangleMeshSlicer::set_up_direction(const Vec3f& up)
m_use_quaternion = true;
}
void TriangleMeshSlicer::slice(const std::vector<float> &z, SlicingMode mode, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
void TriangleMeshSlicer::slice(
const std::vector<float> &z,
SlicingMode mode, size_t alternate_mode_first_n_layers, SlicingMode alternate_mode,
std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
{
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
@ -832,7 +833,7 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, SlicingMode mode, st
layers->resize(z.size());
tbb::parallel_for(
tbb::blocked_range<size_t>(0, z.size()),
[&lines, &layers, mode, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
[&lines, &layers, mode, alternate_mode_first_n_layers, alternate_mode, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
for (size_t line_idx = range.begin(); line_idx < range.end(); ++ line_idx) {
if ((line_idx & 0x0ffff) == 0)
throw_on_cancel();
@ -840,12 +841,13 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, SlicingMode mode, st
Polygons &polygons = (*layers)[line_idx];
this->make_loops(lines[line_idx], &polygons);
auto this_mode = line_idx < alternate_mode_first_n_layers ? alternate_mode : mode;
if (! polygons.empty()) {
if (mode == SlicingMode::Positive) {
if (this_mode == SlicingMode::Positive) {
// Reorient all loops to be CCW.
for (Polygon& p : polygons)
p.make_counter_clockwise();
} else if (mode == SlicingMode::PositiveLargestContour) {
} else if (this_mode == SlicingMode::PositiveLargestContour) {
// Keep just the largest polygon, make it CCW.
double max_area = 0.;
Polygon* max_area_polygon = nullptr;
@ -941,16 +943,23 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
}
}
void TriangleMeshSlicer::slice(const std::vector<float> &z, SlicingMode mode, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
void TriangleMeshSlicer::slice(
const std::vector<float> &z, SlicingMode mode, size_t alternate_mode_first_n_layers, SlicingMode alternate_mode, const float closing_radius,
std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
{
std::vector<Polygons> layers_p;
this->slice(z, (mode == SlicingMode::PositiveLargestContour) ? SlicingMode::Positive : mode, &layers_p, throw_on_cancel);
this->slice(z,
(mode == SlicingMode::PositiveLargestContour) ? SlicingMode::Positive : mode,
alternate_mode_first_n_layers,
(alternate_mode == SlicingMode::PositiveLargestContour) ? SlicingMode::Positive : alternate_mode,
&layers_p, throw_on_cancel);
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - start";
layers->resize(z.size());
tbb::parallel_for(
tbb::blocked_range<size_t>(0, z.size()),
[&layers_p, mode, closing_radius, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
[&layers_p, mode, alternate_mode_first_n_layers, alternate_mode, closing_radius, layers, throw_on_cancel, this]
(const tbb::blocked_range<size_t>& range) {
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
printf("Layer %zu (slice_z = %.2f):\n", layer_id, z[layer_id]);
@ -958,7 +967,8 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, SlicingMode mode, co
throw_on_cancel();
ExPolygons &expolygons = (*layers)[layer_id];
this->make_expolygons(layers_p[layer_id], closing_radius, &expolygons);
if (mode == SlicingMode::PositiveLargestContour)
const auto this_mode = layer_id < alternate_mode_first_n_layers ? alternate_mode : mode;
if (this_mode == SlicingMode::PositiveLargestContour)
keep_largest_contour_only(expolygons);
}
});

View file

@ -179,8 +179,17 @@ public:
TriangleMeshSlicer() : mesh(nullptr) {}
TriangleMeshSlicer(const TriangleMesh* mesh) { this->init(mesh, [](){}); }
void init(const TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
void slice(const std::vector<float> &z, SlicingMode mode, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
void slice(const std::vector<float> &z, SlicingMode mode, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
void slice(
const std::vector<float> &z, SlicingMode mode, size_t alternate_mode_first_n_layers, SlicingMode alternate_mode,
std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
void slice(const std::vector<float> &z, SlicingMode mode, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
{ return this->slice(z, mode, 0, mode, layers, throw_on_cancel); }
void slice(
const std::vector<float> &z, SlicingMode mode, size_t alternate_mode_first_n_layers, SlicingMode alternate_mode, const float closing_radius,
std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
void slice(const std::vector<float> &z, SlicingMode mode, const float closing_radius,
std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
{ this->slice(z, mode, 0, mode, closing_radius, layers, throw_on_cancel); }
enum FacetSliceType {
NoSlice = 0,
Slicing = 1,

View file

@ -16,6 +16,7 @@
dynamic_cast<PrintRegionConfig*>(region_config),
dynamic_cast<PrintObjectConfig*>(object_config),
dynamic_cast<PrintConfig*>(print_config),
false,
loops, gap_fill, fill_surfaces); %};
~PerimeterGenerator();