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) #3326 Fixes Model with holes in the base does not slice properly in "Vase Mode" #5359
This commit is contained in:
parent
5470af3938
commit
364300055e
@ -55,14 +55,22 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
|||||||
this->perimeters.clear();
|
this->perimeters.clear();
|
||||||
this->thin_fills.clear();
|
this->thin_fills.clear();
|
||||||
|
|
||||||
|
const PrintConfig &print_config = this->layer()->object()->print()->config();
|
||||||
|
const PrintRegionConfig ®ion_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(
|
PerimeterGenerator g(
|
||||||
// input:
|
// input:
|
||||||
&slices,
|
&slices,
|
||||||
this->layer()->height,
|
this->layer()->height,
|
||||||
this->flow(frPerimeter),
|
this->flow(frPerimeter),
|
||||||
&this->region()->config(),
|
®ion_config,
|
||||||
&this->layer()->object()->config(),
|
&this->layer()->object()->config(),
|
||||||
&this->layer()->object()->print()->config(),
|
&print_config,
|
||||||
|
spiral_vase,
|
||||||
|
|
||||||
// output:
|
// output:
|
||||||
&this->perimeters,
|
&this->perimeters,
|
||||||
|
@ -312,7 +312,7 @@ void PerimeterGenerator::process()
|
|||||||
for (ExPolygon &ex : expp)
|
for (ExPolygon &ex : expp)
|
||||||
ex.medial_axis(ext_perimeter_width + ext_perimeter_spacing2, min_width, &thin_walls);
|
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.
|
// Remove all but the largest area polygon.
|
||||||
keep_largest_contour_only(offsets);
|
keep_largest_contour_only(offsets);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ public:
|
|||||||
const PrintRegionConfig* config,
|
const PrintRegionConfig* config,
|
||||||
const PrintObjectConfig* object_config,
|
const PrintObjectConfig* object_config,
|
||||||
const PrintConfig* print_config,
|
const PrintConfig* print_config,
|
||||||
|
const bool spiral_vase,
|
||||||
// Output:
|
// Output:
|
||||||
// Loops with the external thin walls
|
// Loops with the external thin walls
|
||||||
ExtrusionEntityCollection* loops,
|
ExtrusionEntityCollection* loops,
|
||||||
@ -48,6 +49,7 @@ public:
|
|||||||
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
|
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
|
||||||
overhang_flow(flow), solid_infill_flow(flow),
|
overhang_flow(flow), solid_infill_flow(flow),
|
||||||
config(config), object_config(object_config), print_config(print_config),
|
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),
|
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)
|
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; }
|
Polygons lower_slices_polygons() const { return m_lower_slices_polygons; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_spiral_vase;
|
||||||
double m_ext_mm3_per_mm;
|
double m_ext_mm3_per_mm;
|
||||||
double m_mm3_per_mm;
|
double m_mm3_per_mm;
|
||||||
double m_mm3_per_mm_overhang;
|
double m_mm3_per_mm_overhang;
|
||||||
|
@ -259,9 +259,16 @@ private:
|
|||||||
// so that next call to make_perimeters() performs a union() before computing loops
|
// so that next call to make_perimeters() performs a union() before computing loops
|
||||||
bool m_typed_slices = false;
|
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_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, 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;
|
std::vector<ExPolygons> slice_volume(const std::vector<float> &z, const std::vector<t_layer_height_range> &ranges, SlicingMode mode, const ModelVolume &volume) const;
|
||||||
};
|
};
|
||||||
|
@ -1747,14 +1747,24 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
// Slice all non-modifier volumes.
|
// Slice all non-modifier volumes.
|
||||||
bool clipped = false;
|
bool clipped = false;
|
||||||
bool upscaled = 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)) {
|
if (! has_z_ranges && (! m_config.clip_multipart_objects.value || all_volumes_single_region >= 0)) {
|
||||||
// Cheap path: Slice regions without mutual clipping.
|
// 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.
|
// 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) {
|
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
|
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
|
||||||
// slicing in parallel
|
// 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();
|
m_print->throw_if_canceled();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
|
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)
|
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.
|
// 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;
|
std::vector<const ModelVolume*> volumes;
|
||||||
if (region_id < this->region_volumes.size()) {
|
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);
|
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.
|
// 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);
|
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;
|
std::vector<ExPolygons> layers;
|
||||||
if (! volumes.empty()) {
|
if (! volumes.empty()) {
|
||||||
@ -2153,7 +2166,7 @@ std::vector<ExPolygons> PrintObject::slice_volumes(const std::vector<float> &z,
|
|||||||
mesh.require_shared_vertices();
|
mesh.require_shared_vertices();
|
||||||
TriangleMeshSlicer mslicer;
|
TriangleMeshSlicer mslicer;
|
||||||
mslicer.init(&mesh, callback);
|
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();
|
m_print->throw_if_canceled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -775,9 +775,10 @@ void TriangleMeshSlicer::set_up_direction(const Vec3f& up)
|
|||||||
m_use_quaternion = true;
|
m_use_quaternion = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TriangleMeshSlicer::slice(
|
||||||
|
const std::vector<float> &z,
|
||||||
void TriangleMeshSlicer::slice(const std::vector<float> &z, SlicingMode mode, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
|
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";
|
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
|
||||||
|
|
||||||
@ -832,20 +833,21 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, SlicingMode mode, st
|
|||||||
layers->resize(z.size());
|
layers->resize(z.size());
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<size_t>(0, z.size()),
|
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) {
|
for (size_t line_idx = range.begin(); line_idx < range.end(); ++ line_idx) {
|
||||||
if ((line_idx & 0x0ffff) == 0)
|
if ((line_idx & 0x0ffff) == 0)
|
||||||
throw_on_cancel();
|
throw_on_cancel();
|
||||||
|
|
||||||
Polygons &polygons = (*layers)[line_idx];
|
Polygons &polygons = (*layers)[line_idx];
|
||||||
this->make_loops(lines[line_idx], &polygons);
|
this->make_loops(lines[line_idx], &polygons);
|
||||||
|
|
||||||
|
auto this_mode = line_idx < alternate_mode_first_n_layers ? alternate_mode : mode;
|
||||||
if (! polygons.empty()) {
|
if (! polygons.empty()) {
|
||||||
if (mode == SlicingMode::Positive) {
|
if (this_mode == SlicingMode::Positive) {
|
||||||
// Reorient all loops to be CCW.
|
// Reorient all loops to be CCW.
|
||||||
for (Polygon& p : polygons)
|
for (Polygon& p : polygons)
|
||||||
p.make_counter_clockwise();
|
p.make_counter_clockwise();
|
||||||
} else if (mode == SlicingMode::PositiveLargestContour) {
|
} else if (this_mode == SlicingMode::PositiveLargestContour) {
|
||||||
// Keep just the largest polygon, make it CCW.
|
// Keep just the largest polygon, make it CCW.
|
||||||
double max_area = 0.;
|
double max_area = 0.;
|
||||||
Polygon* max_area_polygon = nullptr;
|
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;
|
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";
|
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - start";
|
||||||
layers->resize(z.size());
|
layers->resize(z.size());
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<size_t>(0, z.size()),
|
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) {
|
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||||
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
|
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
|
||||||
printf("Layer %zu (slice_z = %.2f):\n", layer_id, z[layer_id]);
|
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();
|
throw_on_cancel();
|
||||||
ExPolygons &expolygons = (*layers)[layer_id];
|
ExPolygons &expolygons = (*layers)[layer_id];
|
||||||
this->make_expolygons(layers_p[layer_id], closing_radius, &expolygons);
|
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);
|
keep_largest_contour_only(expolygons);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -179,8 +179,17 @@ public:
|
|||||||
TriangleMeshSlicer() : mesh(nullptr) {}
|
TriangleMeshSlicer() : mesh(nullptr) {}
|
||||||
TriangleMeshSlicer(const TriangleMesh* mesh) { this->init(mesh, [](){}); }
|
TriangleMeshSlicer(const TriangleMesh* mesh) { this->init(mesh, [](){}); }
|
||||||
void init(const TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
|
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(
|
||||||
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;
|
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 {
|
enum FacetSliceType {
|
||||||
NoSlice = 0,
|
NoSlice = 0,
|
||||||
Slicing = 1,
|
Slicing = 1,
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
dynamic_cast<PrintRegionConfig*>(region_config),
|
dynamic_cast<PrintRegionConfig*>(region_config),
|
||||||
dynamic_cast<PrintObjectConfig*>(object_config),
|
dynamic_cast<PrintObjectConfig*>(object_config),
|
||||||
dynamic_cast<PrintConfig*>(print_config),
|
dynamic_cast<PrintConfig*>(print_config),
|
||||||
|
false,
|
||||||
loops, gap_fill, fill_surfaces); %};
|
loops, gap_fill, fill_surfaces); %};
|
||||||
~PerimeterGenerator();
|
~PerimeterGenerator();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user