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
@ -54,15 +54,23 @@ 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 ®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(
|
||||
// input:
|
||||
&slices,
|
||||
this->layer()->height,
|
||||
this->flow(frPerimeter),
|
||||
&this->region()->config(),
|
||||
®ion_config,
|
||||
&this->layer()->object()->config(),
|
||||
&this->layer()->object()->print()->config(),
|
||||
&print_config,
|
||||
spiral_vase,
|
||||
|
||||
// output:
|
||||
&this->perimeters,
|
||||
|
@ -271,7 +271,7 @@ void PerimeterGenerator::process()
|
||||
double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder-1);
|
||||
m_lower_slices_polygons = offset(*this->lower_slices, float(scale_(+nozzle_diameter/2)));
|
||||
}
|
||||
|
||||
|
||||
// we need to process each island separately because we might have different
|
||||
// extra perimeters for each one
|
||||
for (const Surface &surface : this->slices->surfaces) {
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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,20 +833,21 @@ 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();
|
||||
|
||||
Polygons &polygons = (*layers)[line_idx];
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user