WIP: Layers split into islands, islands overlapping in Z interconnected

into a graph with links to the layer above / below.

In addition:
Members of LayerRegion were made private, public interface const only.
this->m_xxx replaced with just m_xxx
SurfacesPtr was made a vector of const pointers.
This commit is contained in:
Vojtech Bubnik 2022-10-26 18:41:39 +02:00
parent f57744ad12
commit ee626eb65a
39 changed files with 751 additions and 356 deletions

View File

@ -53,7 +53,7 @@ static ExPolygons get_print_object_bottom_layer_expolygons(const PrintObject &pr
{
ExPolygons ex_polygons;
for (LayerRegion *region : print_object.layers().front()->regions())
Slic3r::append(ex_polygons, closing_ex(region->slices.surfaces, float(SCALED_EPSILON)));
Slic3r::append(ex_polygons, closing_ex(region->slices().surfaces, float(SCALED_EPSILON)));
return ex_polygons;
}

View File

@ -218,7 +218,7 @@ ColorRGBA ColorRGBA::operator * (float value) const
for (size_t i = 0; i < 3; ++i) {
ret.m_data[i] = std::clamp(value * m_data[i], 0.0f, 1.0f);
}
ret.m_data[3] = this->m_data[3];
ret.m_data[3] = m_data[3];
return ret;
}

View File

@ -45,6 +45,13 @@ public:
~ExtrusionEntityCollection() override { clear(); }
explicit operator ExtrusionPaths() const;
ExtrusionEntitiesPtr::const_iterator cbegin() const { return this->entities.cbegin(); }
ExtrusionEntitiesPtr::const_iterator cend() const { return this->entities.cend(); }
ExtrusionEntitiesPtr::const_iterator begin() const { return this->entities.cbegin(); }
ExtrusionEntitiesPtr::const_iterator end() const { return this->entities.cend(); }
ExtrusionEntitiesPtr::iterator begin() { return this->entities.begin(); }
ExtrusionEntitiesPtr::iterator end() { return this->entities.end(); }
bool is_collection() const override { return true; }
ExtrusionRole role() const override {
ExtrusionRole out = erNone;
@ -102,6 +109,9 @@ public:
{ Polygons out; this->polygons_covered_by_width(out, scaled_epsilon); return out; }
Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
{ Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; }
size_t size() const { return entities.size(); }
// Recursively count paths and loops contained in this collection.
// this->items_count() >= this->size()
size_t items_count() const;
/// Returns a flattened copy of this ExtrusionEntityCollection. That is, all of the items in its entities vector are not collections.
/// You should be iterating over flatten().entities if you are interested in the underlying ExtrusionEntities (and don't care about hierarchy).

View File

@ -121,8 +121,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
bool has_internal_voids = false;
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
const LayerRegion &layerm = *layer.regions()[region_id];
region_to_surface_params[region_id].assign(layerm.fill_surfaces.size(), nullptr);
for (const Surface &surface : layerm.fill_surfaces.surfaces)
region_to_surface_params[region_id].assign(layerm.fill_surfaces().size(), nullptr);
for (const Surface &surface : layerm.fill_surfaces())
if (surface.surface_type == stInternalVoid)
has_internal_voids = true;
else {
@ -180,7 +180,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
auto it_params = set_surface_params.find(params);
if (it_params == set_surface_params.end())
it_params = set_surface_params.insert(it_params, params);
region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()] = &(*it_params);
region_to_surface_params[region_id][&surface - &layerm.fill_surfaces().surfaces.front()] = &(*it_params);
}
}
@ -192,9 +192,9 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
const LayerRegion &layerm = *layer.regions()[region_id];
for (const Surface &surface : layerm.fill_surfaces.surfaces)
for (const Surface &surface : layerm.fill_surfaces())
if (surface.surface_type != stInternalVoid) {
const SurfaceFillParams *params = region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()];
const SurfaceFillParams *params = region_to_surface_params[region_id][&surface - &layerm.fill_surfaces().surfaces.front()];
if (params != nullptr) {
SurfaceFill &fill = surface_fills[params->idx];
if (fill.region_id == size_t(-1)) {
@ -325,7 +325,7 @@ void export_group_fills_to_svg(const char *path, const std::vector<SurfaceFill>
void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator)
{
for (LayerRegion *layerm : m_regions)
layerm->fills.clear();
layerm->m_fills.clear();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
@ -420,7 +420,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
}
// Save into layer.
ExtrusionEntityCollection* eec = nullptr;
m_regions[surface_fill.region_id]->fills.entities.push_back(eec = new ExtrusionEntityCollection());
m_regions[surface_fill.region_id]->m_fills.entities.push_back(eec = new ExtrusionEntityCollection());
// Only concentric fills are not sorted.
eec->no_sort = f->no_sort();
if (params.use_arachne) {
@ -453,16 +453,16 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
// The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection.
// Why the paths are unpacked?
for (LayerRegion *layerm : m_regions)
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
for (const ExtrusionEntity *thin_fill : layerm->thin_fills().entities) {
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
layerm->fills.entities.push_back(&collection);
layerm->m_fills.entities.push_back(&collection);
collection.entities.push_back(thin_fill->clone());
}
#ifndef NDEBUG
for (LayerRegion *layerm : m_regions)
for (size_t i = 0; i < layerm->fills.entities.size(); ++ i)
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != nullptr);
for (const ExtrusionEntity *e : layerm->fills())
assert(dynamic_cast<const ExtrusionEntityCollection*>(e) != nullptr);
#endif
}
@ -539,7 +539,7 @@ void Layer::make_ironing()
double default_layer_height = this->object()->config().layer_height;
for (LayerRegion *layerm : m_regions)
if (! layerm->slices.empty()) {
if (! layerm->slices().empty()) {
IroningParams ironing_params;
const PrintRegionConfig &config = layerm->region().config();
if (config.ironing &&
@ -602,7 +602,7 @@ void Layer::make_ironing()
if (iron_everything) {
// Check whether there is any non-solid hole in the regions.
bool internal_infill_solid = region_config.fill_density.value > 95.;
for (const Surface &surface : ironing_params.layerm->fill_surfaces.surfaces)
for (const Surface &surface : ironing_params.layerm->fill_surfaces())
if ((! internal_infill_solid && surface.surface_type == stInternal) || surface.surface_type == stInternalBridge || surface.surface_type == stInternalVoid) {
// Some fill region is not quite solid. Don't iron over the whole surface.
iron_completely = false;
@ -611,10 +611,10 @@ void Layer::make_ironing()
}
if (iron_completely) {
// Iron everything. This is likely only good for solid transparent objects.
for (const Surface &surface : ironing_params.layerm->slices.surfaces)
for (const Surface &surface : ironing_params.layerm->slices())
polygons_append(polys, surface.expolygon);
} else {
for (const Surface &surface : ironing_params.layerm->slices.surfaces)
for (const Surface &surface : ironing_params.layerm->slices())
if (surface.surface_type == stTop || (iron_everything && surface.surface_type == stBottom))
// stBottomBridge is not being ironed on purpose, as it would likely destroy the bridges.
polygons_append(polys, surface.expolygon);
@ -622,7 +622,7 @@ void Layer::make_ironing()
if (iron_everything && ! iron_completely) {
// Add solid fill surfaces. This may not be ideal, as one will not iron perimeters touching these
// solid fill surfaces, but it is likely better than nothing.
for (const Surface &surface : ironing_params.layerm->fill_surfaces.surfaces)
for (const Surface &surface : ironing_params.layerm->fill_surfaces())
if (surface.surface_type == stInternalSolid)
polygons_append(infills, surface.expolygon);
}
@ -659,7 +659,7 @@ void Layer::make_ironing()
if (! polylines.empty()) {
// Save into layer.
ExtrusionEntityCollection *eec = nullptr;
ironing_params.layerm->fills.entities.push_back(eec = new ExtrusionEntityCollection());
ironing_params.layerm->m_fills.entities.push_back(eec = new ExtrusionEntityCollection());
// Don't sort the ironing infill lines as they are monotonicly ordered.
eec->no_sort = true;
extrusion_entities_append_paths(

View File

@ -316,9 +316,9 @@ std::pair<double, double> adaptive_fill_line_spacing(const PrintObject &print_ob
for (const Layer *layer : print_object.layers())
for (size_t region_id = 0; region_id < layer->regions().size(); ++ region_id) {
RegionFillData &rd = region_fill_data[region_id];
if (rd.has_adaptive_infill == Tristate::Maybe && ! layer->regions()[region_id]->fill_surfaces.empty())
if (rd.has_adaptive_infill == Tristate::Maybe && ! layer->regions()[region_id]->fill_surfaces().empty())
rd.has_adaptive_infill = Tristate::Yes;
if (rd.has_support_infill == Tristate::Maybe && ! layer->regions()[region_id]->fill_surfaces.empty())
if (rd.has_support_infill == Tristate::Maybe && ! layer->regions()[region_id]->fill_surfaces().empty())
rd.has_support_infill = Tristate::Yes;
}

View File

@ -62,7 +62,7 @@ void Generator::generateInitialInternalOverhangs(const PrintObject &print_object
throw_on_cancel_callback();
Polygons infill_area_here;
for (const LayerRegion* layerm : print_object.get_layer(layer_nr)->regions())
for (const Surface& surface : layerm->fill_surfaces.surfaces)
for (const Surface& surface : layerm->fill_surfaces())
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
append(infill_area_here, to_polygons(surface.expolygon));
@ -93,7 +93,7 @@ void Generator::generateTrees(const PrintObject &print_object, const std::functi
for (int layer_id = int(print_object.layers().size()) - 1; layer_id >= 0; layer_id--) {
throw_on_cancel_callback();
for (const LayerRegion *layerm : print_object.get_layer(layer_id)->regions())
for (const Surface &surface : layerm->fill_surfaces.surfaces)
for (const Surface &surface : layerm->fill_surfaces())
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
append(infill_outlines[layer_id], to_polygons(surface.expolygon));

View File

@ -849,7 +849,7 @@ namespace DoExport {
region.config().get_abs_value("small_perimeter_speed") == 0 ||
region.config().get_abs_value("external_perimeter_speed") == 0 ||
region.config().get_abs_value("bridge_speed") == 0)
mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
mm3_per_mm.push_back(layerm->perimeters().min_mm3_per_mm());
if (region.config().get_abs_value("infill_speed") == 0 ||
region.config().get_abs_value("solid_infill_speed") == 0 ||
region.config().get_abs_value("top_solid_infill_speed") == 0 ||
@ -866,7 +866,7 @@ namespace DoExport {
return min;
};
mm3_per_mm.push_back(min_mm3_per_mm_no_ironing(layerm->fills));
mm3_per_mm.push_back(min_mm3_per_mm_no_ironing(layerm->fills()));
}
}
}
@ -1502,7 +1502,7 @@ void GCode::process_layers(
}
});
const auto spiral_vase = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[&spiral_vase = *this->m_spiral_vase](LayerResult in) -> LayerResult {
[&spiral_vase = *m_spiral_vase](LayerResult in) -> LayerResult {
if (in.nop_layer_result)
return in;
@ -1510,18 +1510,18 @@ void GCode::process_layers(
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush};
});
const auto pressure_equalizer = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[&pressure_equalizer = *this->m_pressure_equalizer](LayerResult in) -> LayerResult {
[&pressure_equalizer = *m_pressure_equalizer](LayerResult in) -> LayerResult {
return pressure_equalizer.process_layer(std::move(in));
});
const auto cooling = tbb::make_filter<LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&cooling_buffer = *this->m_cooling_buffer](LayerResult in) -> std::string {
[&cooling_buffer = *m_cooling_buffer](LayerResult in) -> std::string {
if (in.nop_layer_result)
return in.gcode;
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
});
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&self = *this->m_find_replace](std::string s) -> std::string {
[&self = *m_find_replace](std::string s) -> std::string {
return self.process_layer(std::move(s));
});
const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
@ -1584,24 +1584,24 @@ void GCode::process_layers(
}
});
const auto spiral_vase = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[&spiral_vase = *this->m_spiral_vase](LayerResult in)->LayerResult {
[&spiral_vase = *m_spiral_vase](LayerResult in)->LayerResult {
if (in.nop_layer_result)
return in;
spiral_vase.enable(in.spiral_vase_enable);
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
});
const auto pressure_equalizer = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[&pressure_equalizer = *this->m_pressure_equalizer](LayerResult in) -> LayerResult {
[&pressure_equalizer = *m_pressure_equalizer](LayerResult in) -> LayerResult {
return pressure_equalizer.process_layer(std::move(in));
});
const auto cooling = tbb::make_filter<LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&cooling_buffer = *this->m_cooling_buffer](LayerResult in)->std::string {
[&cooling_buffer = *m_cooling_buffer](LayerResult in)->std::string {
if (in.nop_layer_result)
return in.gcode;
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
});
const auto find_replace = tbb::make_filter<std::string, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&self = *this->m_find_replace](std::string s) -> std::string {
[&self = *m_find_replace](std::string s) -> std::string {
return self.process_layer(std::move(s));
});
const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
@ -2108,8 +2108,8 @@ LayerResult GCode::process_layer(
if (enable) {
for (const LayerRegion *layer_region : layer.regions())
if (size_t(layer_region->region().config().bottom_solid_layers.value) > layer.id() ||
layer_region->perimeters.items_count() > 1u ||
layer_region->fills.items_count() > 0) {
layer_region->perimeters().items_count() > 1u ||
layer_region->fills().items_count() > 0) {
enable = false;
break;
}
@ -2252,20 +2252,11 @@ LayerResult GCode::process_layer(
// option
// (Still, we have to keep track of regions because we need to apply their config)
size_t n_slices = layer.lslices.size();
const std::vector<BoundingBox> &layer_surface_bboxes = layer.lslices_bboxes;
const LayerSlices &layer_surfaces = layer.lslices_ex;
// Traverse the slices in an increasing order of bounding box size, so that the islands inside another islands are tested first,
// so we can just test a point inside ExPolygon::contour and we may skip testing the holes.
std::vector<size_t> slices_test_order;
slices_test_order.reserve(n_slices);
for (size_t i = 0; i < n_slices; ++ i)
slices_test_order.emplace_back(i);
std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](size_t i, size_t j) {
const Vec2d s1 = layer_surface_bboxes[i].size().cast<double>();
const Vec2d s2 = layer_surface_bboxes[j].size().cast<double>();
return s1.x() * s1.y() < s2.x() * s2.y();
});
auto point_inside_surface = [&layer, &layer_surface_bboxes](const size_t i, const Point &point) {
const BoundingBox &bbox = layer_surface_bboxes[i];
auto point_inside_surface = [&layer, &layer_surfaces](const size_t i, const Point &point) {
const BoundingBox &bbox = layer_surfaces[i].bbox;
return point(0) >= bbox.min(0) && point(0) < bbox.max(0) &&
point(1) >= bbox.min(1) && point(1) < bbox.max(1) &&
layer.lslices[i].contour.contains(point);
@ -2284,7 +2275,7 @@ LayerResult GCode::process_layer(
// The process is almost the same for perimeters and infills - we will do it in a cycle that repeats twice:
std::vector<unsigned int> printing_extruders;
for (const ObjectByExtruder::Island::Region::Type entity_type : { ObjectByExtruder::Island::Region::INFILL, ObjectByExtruder::Island::Region::PERIMETERS }) {
for (const ExtrusionEntity *ee : (entity_type == ObjectByExtruder::Island::Region::INFILL) ? layerm->fills.entities : layerm->perimeters.entities) {
for (const ExtrusionEntity *ee : (entity_type == ObjectByExtruder::Island::Region::INFILL) ? layerm->fills() : layerm->perimeters()) {
// extrusions represents infill or perimeter extrusions of a single island.
assert(dynamic_cast<const ExtrusionEntityCollection*>(ee) != nullptr);
const auto *extrusions = static_cast<const ExtrusionEntityCollection*>(ee);
@ -2329,7 +2320,9 @@ LayerResult GCode::process_layer(
layers.size(), n_slices+1);
for (size_t i = 0; i <= n_slices; ++ i) {
bool last = i == n_slices;
size_t island_idx = last ? n_slices : slices_test_order[i];
// Traverse lslices back to front: lslices are produced by traversing ClipperLib::PolyTree, emitting parent contour before its children.
// Therefore traversing layer_surfaces back to front will traverse children contours before their parents.
size_t island_idx = last ? n_slices : layer_surfaces.size() - i - 1;
if (// extrusions->first_point does not fit inside any slice
last ||
// extrusions->first_point fits inside ith slice

View File

@ -487,7 +487,7 @@ static float get_perimeter_spacing(const Layer &layer)
size_t regions_count = 0;
float perimeter_spacing = 0.f;
for (const LayerRegion *layer_region : layer.regions())
if (layer_region != nullptr && !layer_region->slices.empty()) {
if (layer_region != nullptr && ! layer_region->slices().empty()) {
perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing();
++regions_count;
}
@ -508,7 +508,7 @@ static float get_perimeter_spacing_external(const Layer &layer)
for (const PrintObject *object : layer.object()->print()->objects())
if (const Layer *l = object->get_layer_at_printz(layer.print_z, EPSILON); l)
for (const LayerRegion *layer_region : l->regions())
if (layer_region != nullptr && !layer_region->slices.empty()) {
if (layer_region != nullptr && ! layer_region->slices().empty()) {
perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing();
++ regions_count;
}
@ -527,7 +527,7 @@ static float get_external_perimeter_width(const Layer &layer)
size_t regions_count = 0;
float perimeter_width = 0.f;
for (const LayerRegion *layer_region : layer.regions())
if (layer_region != nullptr && !layer_region->slices.empty()) {
if (layer_region != nullptr && ! layer_region->slices().empty()) {
perimeter_width += float(layer_region->flow(frExternalPerimeter).scaled_width());
++regions_count;
}
@ -1070,14 +1070,14 @@ static ExPolygons get_boundary(const Layer &layer)
// Collect all top layers that will not be crossed.
size_t polygons_count = 0;
for (const LayerRegion *layer_region : layer.regions())
for (const Surface &surface : layer_region->fill_surfaces.surfaces)
for (const Surface &surface : layer_region->fill_surfaces())
if (surface.is_top()) ++polygons_count;
if (polygons_count > 0) {
ExPolygons top_layer_polygons;
top_layer_polygons.reserve(polygons_count);
for (const LayerRegion *layer_region : layer.regions())
for (const Surface &surface : layer_region->fill_surfaces.surfaces)
for (const Surface &surface : layer_region->fill_surfaces())
if (surface.is_top()) top_layer_polygons.emplace_back(surface.expolygon);
top_layer_polygons = union_ex(top_layer_polygons);

View File

@ -2735,8 +2735,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (volume_extruded_filament != 0.)
m_used_filaments.increase_caches(volume_extruded_filament,
this->m_extruder_id, area_filament_cross_section * this->m_parking_position,
area_filament_cross_section * this->m_extra_loading_move);
m_extruder_id, area_filament_cross_section * m_parking_position,
area_filament_cross_section * m_extra_loading_move);
const EMoveType type = move_type(delta_pos);
if (type == EMoveType::Extrude) {
@ -4303,7 +4303,7 @@ void GCodeProcessor::process_filaments(CustomGCode::Type code)
m_used_filaments.process_color_change_cache();
if (code == CustomGCode::ToolChange)
m_used_filaments.process_extruder_cache(this->m_extruder_id);
m_used_filaments.process_extruder_cache(m_extruder_id);
}
void GCodeProcessor::simulate_st_synchronize(float additional_time)

View File

@ -690,7 +690,7 @@ inline bool is_just_line_with_extrude_set_speed_tag(const std::string &line)
void PressureEqualizer::push_line_to_output(const size_t line_idx, const float new_feedrate, const char *comment)
{
const GCodeLine &line = this->m_gcode_lines[line_idx];
const GCodeLine &line = m_gcode_lines[line_idx];
if (line_idx > 0 && output_buffer_length > 0) {
const std::string prev_line_str = std::string(output_buffer.begin() + int(this->output_buffer_prev_length),
output_buffer.begin() + int(this->output_buffer_length) + 1);

View File

@ -113,8 +113,8 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object
break;
BoundingBoxf bbox_this;
for (const LayerRegion *layerm : layer->regions()) {
bbox_this.merge(extrusionentity_extents(layerm->perimeters));
for (const ExtrusionEntity *ee : layerm->fills.entities)
bbox_this.merge(extrusionentity_extents(layerm->perimeters()));
for (const ExtrusionEntity *ee : layerm->fills())
// fill represents infill extrusions of a single island.
bbox_this.merge(extrusionentity_extents(*dynamic_cast<const ExtrusionEntityCollection*>(ee)));
}

View File

@ -401,7 +401,7 @@ struct GlobalModelInfo {
Polygons extract_perimeter_polygons(const Layer *layer, std::vector<const LayerRegion*> &corresponding_regions_out) {
Polygons polygons;
for (const LayerRegion *layer_region : layer->regions()) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters()) {
if (ex_entity->is_collection()) { //collection of inner, outer, and overhang perimeters
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
ExtrusionRole role = perimeter->role();
@ -1060,7 +1060,7 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) {
size_t regions_with_perimeter = 0;
for (const LayerRegion *region : po->layers()[layer_idx]->regions()) {
if (region->perimeters.entities.size() > 0) {
if (region->perimeters().size() > 0) {
regions_with_perimeter++;
}
};

View File

@ -226,12 +226,12 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
for (const LayerRegion *layerm : layer->regions()) {
const PrintRegion &region = layerm->region();
if (! layerm->perimeters.entities.empty()) {
if (! layerm->perimeters().empty()) {
bool something_nonoverriddable = true;
if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
something_nonoverriddable = false;
for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities
for (const ExtrusionEntity *eec : layerm->perimeters()) // let's check if there are nonoverriddable entities
if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region))
something_nonoverriddable = true;
}
@ -245,7 +245,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
bool has_infill = false;
bool has_solid_infill = false;
bool something_nonoverriddable = false;
for (const ExtrusionEntity *ee : layerm->fills.entities) {
for (const ExtrusionEntity *ee : layerm->fills()) {
// fill represents infill extrusions of a single island.
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
ExtrusionRole role = fill->entities.empty() ? erNone : fill->entities.front()->role();
@ -692,7 +692,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
bool wipe_into_infill_only = ! object->config().wipe_into_objects && region.config().wipe_into_infill;
if (print.config().infill_first != perimeters_done || wipe_into_infill_only) {
for (const ExtrusionEntity* ee : layerm->fills.entities) { // iterate through all infill Collections
for (const ExtrusionEntity* ee : layerm->fills()) { // iterate through all infill Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!is_overriddable(*fill, print.config(), *object, region))
@ -716,7 +716,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
// Now the same for perimeters - see comments above for explanation:
if (object->config().wipe_into_objects && print.config().infill_first == perimeters_done)
{
for (const ExtrusionEntity* ee : layerm->perimeters.entities) {
for (const ExtrusionEntity* ee : layerm->perimeters()) {
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (is_overriddable(*fill, print.config(), *object, region) && !is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) {
set_extruder_override(fill, copy, new_extruder, num_of_copies);
@ -762,7 +762,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
if (!region.config().wipe_into_infill && !object->config().wipe_into_objects)
continue;
for (const ExtrusionEntity* ee : layerm->fills.entities) { // iterate through all infill Collections
for (const ExtrusionEntity* ee : layerm->fills()) { // iterate through all infill Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!is_overriddable(*fill, print.config(), *object, region)
@ -785,7 +785,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
}
// Now the same for perimeters - see comments above for explanation:
for (const ExtrusionEntity* ee : layerm->perimeters.entities) { // iterate through all perimeter Collections
for (const ExtrusionEntity* ee : layerm->perimeters()) { // iterate through all perimeter Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (is_overriddable(*fill, print.config(), *object, region) && ! is_entity_overridden(fill, copy))
set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);

View File

@ -22,7 +22,7 @@ Layer::~Layer()
bool Layer::empty() const
{
for (const LayerRegion *layerm : m_regions)
if (layerm != nullptr && ! layerm->slices.empty())
if (layerm != nullptr && ! layerm->slices().empty())
// Non empty layer.
return false;
return true;
@ -40,11 +40,11 @@ void Layer::make_slices()
ExPolygons slices;
if (m_regions.size() == 1) {
// optimization: if we only have one region, take its slices
slices = to_expolygons(m_regions.front()->slices.surfaces);
slices = to_expolygons(m_regions.front()->slices().surfaces);
} else {
Polygons slices_p;
for (LayerRegion *layerm : m_regions)
polygons_append(slices_p, to_polygons(layerm->slices.surfaces));
polygons_append(slices_p, to_polygons(layerm->slices().surfaces));
slices = union_safety_offset_ex(slices_p);
}
@ -65,6 +65,245 @@ void Layer::make_slices()
this->lslices.emplace_back(std::move(slices[i]));
}
// used by Layer::build_up_down_graph()
[[nodiscard]] static ClipperLib_Z::Paths expolygons_to_zpaths(const ExPolygons &expolygons, coord_t isrc)
{
size_t num_paths = 0;
for (const ExPolygon &expolygon : expolygons)
num_paths += expolygon.num_contours();
ClipperLib_Z::Paths out;
out.reserve(num_paths);
for (const ExPolygon &expolygon : expolygons) {
for (size_t icontour = 0; icontour < expolygon.num_contours(); ++ icontour) {
const Polygon &contour = expolygon.contour_or_hole(icontour);
out.emplace_back();
ClipperLib_Z::Path &path = out.back();
path.reserve(contour.size());
for (const Point &p : contour.points)
path.push_back({ p.x(), p.y(), isrc });
}
++ isrc;
}
return out;
}
// used by Layer::build_up_down_graph()
static void connect_layer_slices(
Layer &below,
Layer &above,
const ClipperLib_Z::PolyTree &polytree,
const std::vector<std::pair<coord_t, coord_t>> &intersections,
const coord_t offset_below,
const coord_t offset_above,
const coord_t offset_end)
{
class Visitor {
public:
Visitor(const std::vector<std::pair<coord_t, coord_t>> &intersections,
Layer &below, Layer &above, const coord_t offset_below, const coord_t offset_above, const coord_t offset_end) :
m_intersections(intersections), m_below(below), m_above(above), m_offset_below(offset_below), m_offset_above(offset_above), m_offset_end(offset_end) {}
void visit(const ClipperLib_Z::PolyNode &polynode)
{
if (polynode.Contour.size() >= 3) {
int32_t i = 0, j = 0;
double area = 0;
for (int icontour = 0; icontour <= polynode.ChildCount(); ++ icontour) {
const ClipperLib_Z::Path &contour = icontour == 0 ? polynode.Contour : polynode.Childs[icontour - 1]->Contour;
if (contour.size() >= 3) {
area = ClipperLib_Z::Area(contour);
int32_t i = contour.front().z();
int32_t j = i;
if (i < 0) {
std::tie(i, j) = m_intersections[-i - 1];
} else {
for (const ClipperLib_Z::IntPoint& pt : contour) {
j = pt.z();
if (j < 0) {
std::tie(i, j) = m_intersections[-j - 1];
goto end;
}
else if (i != j)
goto end;
}
}
}
}
end:
bool found = false;
if (i == j) {
// The contour is completely inside another contour.
Point pt(polynode.Contour.front().x(), polynode.Contour.front().y());
if (i < m_offset_above) {
// Index of an island below. Look-it up in the island above.
assert(i >= m_offset_below);
i -= m_offset_below;
for (int l = int(m_above.lslices_ex.size()) - 1; l >= 0; -- l) {
LayerSlice &lslice = m_above.lslices_ex[l];
if (lslice.bbox.contains(pt) && m_above.lslices[l].contains(pt)) {
found = true;
j = l;
break;
}
}
} else {
// Index of an island above. Look-it up in the island below.
assert(j < m_offset_end);
j -= m_offset_below;
for (int l = int(m_below.lslices_ex.size()) - 1; l >= 0; -- l) {
LayerSlice &lslice = m_below.lslices_ex[l];
if (lslice.bbox.contains(pt) && m_below.lslices[l].contains(pt)) {
found = true;
i = l;
break;
}
}
}
} else {
if (i > j)
std::swap(i, j);
assert(i >= m_offset_below);
assert(i < m_offset_above);
i -= m_offset_below;
assert(j >= m_offset_above);
assert(j < m_offset_end);
j -= m_offset_above;
found = true;
}
if (found) {
// Subtract area of holes from the area of outer contour.
for (int icontour = 0; icontour < polynode.ChildCount(); ++ icontour)
area -= ClipperLib_Z::Area(polynode.Childs[icontour]->Contour);
// Store the links and area into the contours.
LayerSlice::Links &links_below = m_below.lslices_ex[i].overlaps_above;
LayerSlice::Links &links_above = m_above.lslices_ex[i].overlaps_below;
LayerSlice::Link key{ j };
auto it_below = std::lower_bound(links_below.begin(), links_below.end(), key, [](auto &l, auto &r){ return l.slice_idx < r.slice_idx; });
if (it_below != links_below.end() && it_below->slice_idx == j) {
it_below->area += area;
} else {
auto it_above = std::lower_bound(links_above.begin(), links_above.end(), key, [](auto &l, auto &r){ return l.slice_idx < r.slice_idx; });
if (it_above != links_above.end() && it_above->slice_idx == i) {
it_above->area += area;
} else {
// Insert into one of the two vectors.
bool take_below = false;
if (links_below.size() < LayerSlice::LinksStaticSize)
take_below = false;
else if (links_above.size() >= LayerSlice::LinksStaticSize) {
size_t shift_below = links_below.end() - it_below;
size_t shift_above = links_above.end() - it_above;
take_below = shift_below < shift_above;
}
if (take_below)
links_below.insert(it_below, { j, float(area) });
else
links_above.insert(it_above, { i, float(area) });
}
}
}
}
for (int i = 0; i < polynode.ChildCount(); ++ i)
for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j)
this->visit(*polynode.Childs[i]->Childs[j]);
}
private:
const std::vector<std::pair<coord_t, coord_t>> &m_intersections;
Layer &m_below;
Layer &m_above;
const coord_t m_offset_below;
const coord_t m_offset_above;
const coord_t m_offset_end;
} visitor(intersections, below, above, offset_below, offset_above, offset_end);
for (int i = 0; i < polytree.ChildCount(); ++ i)
visitor.visit(*polytree.Childs[i]);
#ifndef NDEBUG
// Verify that only one directional link is stored: either from bottom slice up or from upper slice down.
for (int32_t islice = 0; islice < below.lslices_ex.size(); ++ islice) {
LayerSlice::Links &links1 = below.lslices_ex[islice].overlaps_above;
for (LayerSlice::Link &link1 : links1) {
LayerSlice::Links &links2 = above.lslices_ex[link1.slice_idx].overlaps_below;
assert(! std::binary_search(links2.begin(), links2.end(), link1, [](auto &l, auto &r){ return l.slice_idx < r.slice_idx; }));
}
}
for (int32_t islice = 0; islice < above.lslices_ex.size(); ++ islice) {
LayerSlice::Links &links1 = above.lslices_ex[islice].overlaps_above;
for (LayerSlice::Link &link1 : links1) {
LayerSlice::Links &links2 = below.lslices_ex[link1.slice_idx].overlaps_below;
assert(! std::binary_search(links2.begin(), links2.end(), link1, [](auto &l, auto &r){ return l.slice_idx < r.slice_idx; }));
}
}
#endif // NDEBUG
// Scatter the links, but don't sort them yet.
for (int32_t islice = 0; islice < below.lslices_ex.size(); ++ islice)
for (LayerSlice::Link &link : below.lslices_ex[islice].overlaps_above)
above.lslices_ex[link.slice_idx].overlaps_below.push_back({ islice, link.area });
for (int32_t islice = 0; islice < above.lslices_ex.size(); ++ islice)
for (LayerSlice::Link &link : above.lslices_ex[islice].overlaps_below)
below.lslices_ex[link.slice_idx].overlaps_above.push_back({ islice, link.area });
// Sort the links.
for (LayerSlice &lslice : below.lslices_ex)
std::sort(lslice.overlaps_above.begin(), lslice.overlaps_above.end(), [](const LayerSlice::Link &l, const LayerSlice::Link &r){ return l.slice_idx < r.slice_idx; });
for (LayerSlice &lslice : above.lslices_ex)
std::sort(lslice.overlaps_below.begin(), lslice.overlaps_below.end(), [](const LayerSlice::Link &l, const LayerSlice::Link &r){ return l.slice_idx < r.slice_idx; });
}
void Layer::build_up_down_graph(Layer& below, Layer& above)
{
coord_t paths_below_offset = 0;
ClipperLib_Z::Paths paths_below = expolygons_to_zpaths(below.lslices, paths_below_offset);
coord_t paths_above_offset = paths_below_offset + coord_t(below.lslices.size());
ClipperLib_Z::Paths paths_above = expolygons_to_zpaths(above.lslices, paths_above_offset);
coord_t paths_end = paths_above_offset + coord_t(above.lslices.size());
class ZFill {
public:
ZFill() = default;
void reset() { m_intersections.clear(); }
void operator()(
const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top,
const ClipperLib_Z::IntPoint& e2bot, const ClipperLib_Z::IntPoint& e2top,
ClipperLib_Z::IntPoint& pt) {
coord_t srcs[4]{ e1bot.z(), e1top.z(), e2bot.z(), e2top.z() };
coord_t* begin = srcs;
coord_t* end = srcs + 4;
std::sort(begin, end);
end = std::unique(begin, end);
assert(begin + 2 == end);
if (begin + 1 == end)
pt.z() = *begin;
else if (begin + 2 <= end) {
// store a -1 based negative index into the "intersections" vector here.
m_intersections.emplace_back(srcs[0], srcs[1]);
pt.z() = -coord_t(m_intersections.size());
}
}
const std::vector<std::pair<coord_t, coord_t>>& intersections() const { return m_intersections; }
private:
std::vector<std::pair<coord_t, coord_t>> m_intersections;
} zfill;
ClipperLib_Z::Clipper clipper;
ClipperLib_Z::PolyTree result;
clipper.ZFillFunction(
[&zfill](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top,
const ClipperLib_Z::IntPoint &e2bot, const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt)
{ return zfill(e1bot, e1top, e2bot, e2top, pt); });
clipper.AddPaths(paths_below, ClipperLib_Z::ptSubject, true);
clipper.AddPaths(paths_above, ClipperLib_Z::ptClip, true);
clipper.Execute(ClipperLib_Z::ctIntersection, result, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero);
connect_layer_slices(below, above, result, zfill.intersections(), paths_below_offset, paths_above_offset, paths_end);
}
static inline bool layer_needs_raw_backup(const Layer *layer)
{
return ! (layer->regions().size() == 1 && (layer->id() > 0 || layer->object()->config().elefant_foot_compensation.value == 0));
@ -74,10 +313,10 @@ void Layer::backup_untyped_slices()
{
if (layer_needs_raw_backup(this)) {
for (LayerRegion *layerm : m_regions)
layerm->raw_slices = to_expolygons(layerm->slices.surfaces);
layerm->m_raw_slices = to_expolygons(layerm->slices().surfaces);
} else {
assert(m_regions.size() == 1);
m_regions.front()->raw_slices.clear();
m_regions.front()->m_raw_slices.clear();
}
}
@ -85,10 +324,10 @@ void Layer::restore_untyped_slices()
{
if (layer_needs_raw_backup(this)) {
for (LayerRegion *layerm : m_regions)
layerm->slices.set(layerm->raw_slices, stInternal);
layerm->m_slices.set(layerm->m_raw_slices, stInternal);
} else {
assert(m_regions.size() == 1);
m_regions.front()->slices.set(this->lslices, stInternal);
m_regions.front()->m_slices.set(this->lslices, stInternal);
}
}
@ -101,13 +340,13 @@ void Layer::restore_untyped_slices_no_extra_perimeters()
if (layer_needs_raw_backup(this)) {
for (LayerRegion *layerm : m_regions)
if (! layerm->region().config().extra_perimeters.value)
layerm->slices.set(layerm->raw_slices, stInternal);
layerm->m_slices.set(layerm->m_raw_slices, stInternal);
} else {
assert(m_regions.size() == 1);
LayerRegion *layerm = m_regions.front();
// This optimization is correct, as extra_perimeters are only reused by prepare_infill() with multi-regions.
//if (! layerm->region().config().extra_perimeters.value)
layerm->slices.set(this->lslices, stInternal);
layerm->m_slices.set(this->lslices, stInternal);
}
}
@ -125,7 +364,7 @@ ExPolygons Layer::merged(float offset_scaled) const
const PrintRegionConfig &config = layerm->region().config();
// Our users learned to bend Slic3r to produce empty volumes to act as subtracters. Only add the region if it is non-empty.
if (config.bottom_solid_layers > 0 || config.top_solid_layers > 0 || config.fill_density > 0. || config.perimeters > 0)
append(polygons, offset(layerm->slices.surfaces, offset_scaled));
append(polygons, offset(layerm->slices().surfaces, offset_scaled));
}
ExPolygons out = union_ex(polygons);
if (offset_scaled2 != 0.f)
@ -143,11 +382,12 @@ void Layer::make_perimeters()
// keep track of regions whose perimeters we have already generated
std::vector<unsigned char> done(m_regions.size(), false);
LayerRegionPtrs layerms;
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm)
if ((*layerm)->slices.empty()) {
(*layerm)->perimeters.clear();
(*layerm)->fills.clear();
(*layerm)->thin_fills.clear();
if ((*layerm)->slices().empty()) {
(*layerm)->m_perimeters.clear();
(*layerm)->m_fills.clear();
(*layerm)->m_thin_fills.clear();
} else {
size_t region_id = layerm - m_regions.begin();
if (done[region_id])
@ -157,10 +397,10 @@ void Layer::make_perimeters()
const PrintRegionConfig &config = (*layerm)->region().config();
// find compatible regions
LayerRegionPtrs layerms;
layerms.clear();
layerms.push_back(*layerm);
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it)
if (! (*it)->slices.empty()) {
if (! (*it)->slices().empty()) {
LayerRegion* other_layerm = *it;
const PrintRegionConfig &other_config = other_layerm->region().config();
if (config.perimeter_extruder == other_config.perimeter_extruder
@ -178,18 +418,20 @@ void Layer::make_perimeters()
&& config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness
&& config.fuzzy_skin_point_dist == other_config.fuzzy_skin_point_dist)
{
other_layerm->perimeters.clear();
other_layerm->fills.clear();
other_layerm->thin_fills.clear();
other_layerm->m_perimeters.clear();
other_layerm->m_fills.clear();
other_layerm->m_thin_fills.clear();
layerms.push_back(other_layerm);
done[it - m_regions.begin()] = true;
}
}
SurfaceCollection fill_surfaces;
if (layerms.size() == 1) { // optimization
(*layerm)->fill_surfaces.surfaces.clear();
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
(*layerm)->m_fill_expolygons.clear();
(*layerm)->m_fill_surfaces.clear();
(*layerm)->make_perimeters((*layerm)->slices(), &fill_surfaces);
(*layerm)->m_fill_expolygons = to_expolygons(fill_surfaces.surfaces);
} else {
SurfaceCollection new_slices;
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
@ -198,28 +440,24 @@ void Layer::make_perimeters()
// group slices (surfaces) according to number of extra perimeters
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
for (LayerRegion *layerm : layerms) {
for (const Surface &surface : layerm->slices.surfaces)
for (const Surface &surface : layerm->slices())
slices[surface.extra_perimeters].emplace_back(surface);
if (layerm->region().config().fill_density > layerm_config->region().config().fill_density)
layerm_config = layerm;
layerm->m_fill_surfaces.clear();
layerm->m_fill_expolygons.clear();
}
// merge the surfaces assigned to each group
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
new_slices.append(offset_ex(surfaces_with_extra_perimeters.second, ClipperSafetyOffset), surfaces_with_extra_perimeters.second.front());
}
// make perimeters
SurfaceCollection fill_surfaces;
layerm_config->make_perimeters(new_slices, &fill_surfaces);
// assign fill_surfaces to each layer
if (!fill_surfaces.surfaces.empty()) {
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
if (! fill_surfaces.empty()) {
// Separate the fill surfaces.
ExPolygons expp = intersection_ex(fill_surfaces.surfaces, (*l)->slices.surfaces);
(*l)->fill_expolygons = expp;
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
}
for (LayerRegion *l : layerms)
l->m_fill_expolygons = intersection_ex(fill_surfaces.surfaces, l->slices().surfaces);
}
}
}
@ -230,7 +468,7 @@ void Layer::export_region_slices_to_svg(const char *path) const
{
BoundingBox bbox;
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
for (const auto &surface : region->slices())
bbox.merge(get_extents(surface.expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min(0), bbox.max(1));
@ -239,7 +477,7 @@ void Layer::export_region_slices_to_svg(const char *path) const
SVG svg(path, bbox);
const float transparency = 0.5f;
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
for (const auto &surface : region->slices())
svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
@ -256,7 +494,7 @@ void Layer::export_region_fill_surfaces_to_svg(const char *path) const
{
BoundingBox bbox;
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
for (const auto &surface : region->slices())
bbox.merge(get_extents(surface.expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min(0), bbox.max(1));
@ -265,7 +503,7 @@ void Layer::export_region_fill_surfaces_to_svg(const char *path) const
SVG svg(path, bbox);
const float transparency = 0.5f;
for (const auto *region : m_regions)
for (const auto &surface : region->slices.surfaces)
for (const auto &surface : region->slices())
svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
@ -281,9 +519,9 @@ void Layer::export_region_fill_surfaces_to_svg_debug(const char *name) const
BoundingBox get_extents(const LayerRegion &layer_region)
{
BoundingBox bbox;
if (!layer_region.slices.surfaces.empty()) {
bbox = get_extents(layer_region.slices.surfaces.front());
for (auto it = layer_region.slices.surfaces.cbegin() + 1; it != layer_region.slices.surfaces.cend(); ++it)
if (! layer_region.slices().empty()) {
bbox = get_extents(layer_region.slices().surfaces.front());
for (auto it = layer_region.slices().surfaces.cbegin() + 1; it != layer_region.slices().surfaces.cend(); ++ it)
bbox.merge(get_extents(*it));
}
return bbox;

View File

@ -2,10 +2,13 @@
#define slic3r_Layer_hpp_
#include "libslic3r.h"
#include "BoundingBox.hpp"
#include "Flow.hpp"
#include "SurfaceCollection.hpp"
#include "ExtrusionEntityCollection.hpp"
#include <boost/container/small_vector.hpp>
namespace Slic3r {
class ExPolygon;
@ -25,50 +28,38 @@ namespace FillLightning {
class Generator;
};
namespace FillLightning {
class Generator;
};
class LayerRegion
{
public:
Layer* layer() { return m_layer; }
const Layer* layer() const { return m_layer; }
const PrintRegion& region() const { return *m_region; }
[[nodiscard]] Layer* layer() { return m_layer; }
[[nodiscard]] const Layer* layer() const { return m_layer; }
[[nodiscard]] const PrintRegion& region() const { return *m_region; }
// collection of surfaces generated by slicing the original geometry
// divided by type top/bottom/internal
SurfaceCollection slices;
// Backed up slices before they are split into top/bottom/internal.
// Only backed up for multi-region layers or layers with elephant foot compensation.
//FIXME Review whether not to simplify the code by keeping the raw_slices all the time.
ExPolygons raw_slices;
[[nodiscard]] const SurfaceCollection& slices() const { return m_slices; }
[[nodiscard]] const ExPolygons& fill_expolygons() const { return m_fill_expolygons; }
// collection of surfaces generated by slicing the original geometry
// divided by type top/bottom/internal
[[nodiscard]] const SurfaceCollection& fill_surfaces() const { return m_fill_surfaces; }
// collection of extrusion paths/loops filling gaps
// These fills are generated by the perimeter generator.
// They are not printed on their own, but they are copied to this->fills during infill generation.
ExtrusionEntityCollection thin_fills;
// Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature")
// and for re-starting of infills.
ExPolygons fill_expolygons;
// collection of surfaces for infill generation
SurfaceCollection fill_surfaces;
// collection of expolygons representing the bridged areas (thus not
// needing support material)
// Polygons bridged;
[[nodiscard]] const ExtrusionEntityCollection& thin_fills() const { return m_thin_fills; }
// collection of polylines representing the unsupported bridge edges
Polylines unsupported_bridge_edges;
[[nodiscard]] const Polylines& unsupported_bridge_edges() const { return m_unsupported_bridge_edges; }
// ordered collection of extrusion paths/loops to build all perimeters
// (this collection contains only ExtrusionEntityCollection objects)
ExtrusionEntityCollection perimeters;
[[nodiscard]] const ExtrusionEntityCollection& perimeters() const { return m_perimeters; }
// ordered collection of extrusion paths to fill surfaces
// (this collection contains only ExtrusionEntityCollection objects)
ExtrusionEntityCollection fills;
[[nodiscard]] const ExtrusionEntityCollection& fills() const { return m_fills; }
Flow flow(FlowRole role) const;
Flow flow(FlowRole role, double layer_height) const;
@ -92,20 +83,165 @@ public:
void export_region_fill_surfaces_to_svg_debug(const char *name) const;
// Is there any valid extrusion assigned to this LayerRegion?
bool has_extrusions() const { return ! this->perimeters.entities.empty() || ! this->fills.entities.empty(); }
bool has_extrusions() const { return ! this->perimeters().empty() || ! this->fills().empty(); }
protected:
friend class Layer;
friend class PrintObject;
LayerRegion(Layer *layer, const PrintRegion *region) : m_layer(layer), m_region(region) {}
~LayerRegion() {}
~LayerRegion() = default;
private:
// Modifying m_slices
friend std::string fix_slicing_errors(LayerPtrs&, const std::function<void()>&);
template<typename ThrowOnCancel>
friend void apply_mm_segmentation(PrintObject& print_object, ThrowOnCancel throw_on_cancel);
Layer *m_layer;
const PrintRegion *m_region;
// Backed up slices before they are split into top/bottom/internal.
// Only backed up for multi-region layers or layers with elephant foot compensation.
//FIXME Review whether not to simplify the code by keeping the raw_slices all the time.
ExPolygons m_raw_slices;
//FIXME make m_slices public for unit tests
public:
// collection of surfaces generated by slicing the original geometry
// divided by type top/bottom/internal
SurfaceCollection m_slices;
private:
// Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature")
// and for re-starting of infills.
ExPolygons m_fill_expolygons;
// collection of surfaces for infill generation
SurfaceCollection m_fill_surfaces;
// collection of extrusion paths/loops filling gaps
// These fills are generated by the perimeter generator.
// They are not printed on their own, but they are copied to this->fills during infill generation.
ExtrusionEntityCollection m_thin_fills;
// collection of polylines representing the unsupported bridge edges
Polylines m_unsupported_bridge_edges;
// ordered collection of extrusion paths/loops to build all perimeters
// (this collection contains only ExtrusionEntityCollection objects)
ExtrusionEntityCollection m_perimeters;
// ordered collection of extrusion paths to fill surfaces
// (this collection contains only ExtrusionEntityCollection objects)
ExtrusionEntityCollection m_fills;
// collection of expolygons representing the bridged areas (thus not
// needing support material)
// Polygons bridged;
};
// Range of two indices, providing support for range based loops.
template<typename T>
class IndexRange
{
public:
IndexRange(T ibegin, T iend) : m_begin(ibegin), m_end(iend) {}
IndexRange() = default;
T begin() const { assert(m_begin <= m_end); return m_begin; };
T end() const { assert(m_begin <= m_end); return m_end; };
bool empty() const { assert(m_begin <= m_end); return m_begin >= m_end; }
T size() const { assert(m_begin <= m_end); return m_end - m_begin; }
private:
// Index of the first extrusion in LayerRegion.
T m_begin { 0 };
// Index of the last extrusion in LayerRegion.
T m_end { 0 };
};
class LayerExtrusionRange : public IndexRange<uint32_t>
{
public:
LayerExtrusionRange(uint32_t iregion, uint32_t ibegin, uint32_t iend) : m_region(iregion), IndexRange<uint32_t>(ibegin, iend) {}
LayerExtrusionRange() = default;
// Index of LayerRegion in Layer.
uint32_t region() const { return m_region; };
private:
// Index of LayerRegion in Layer.
uint32_t m_region { 0 };
};
static constexpr const size_t LayerExtrusionRangesStaticSize = 1;
using LayerExtrusionRanges =
#ifdef NDEBUG
// To reduce memory allocation in release mode.
boost::container::small_vector<LayerExtrusionRange, LayerExtrusionRangesStaticSize>;
#else // NDEBUG
// To ease debugging.
std::vector<LayerExtrusionRange>;
#endif // NDEBUG
using ExPolygonRange = IndexRange<uint32_t>();
// LayerSlice contains one or more LayerIsland objects,
// each LayerIsland containing a set of perimeter extrusions extruded with one particular PrintRegionConfig parameters
// and one or multiple
struct LayerIsland
{
// Perimeter extrusions in LayerRegion belonging to this island.
LayerExtrusionRange perimeters;
// Infill + gapfill extrusions in LayerRegion belonging to this island.
LayerExtrusionRanges fills;
// Region that is to be filled with the fills above.
ExPolygonRange fill_expolygons;
// Centroid of this island used for path planning.
Point centroid;
bool has_extrusions() const { return ! this->perimeters.empty() || ! this->fills.empty(); }
};
static constexpr const size_t LayerIslandsStaticSize = 1;
using LayerIslands =
#ifdef NDEBUG
// To reduce memory allocation in release mode.
boost::container::small_vector<LayerIsland, LayerIslandsStaticSize>;
#else // NDEBUG
// To ease debugging.
std::vector<LayerIsland>;
#endif // NDEBUG
//
struct LayerSlice
{
struct Link {
int32_t slice_idx;
float area;
};
static constexpr const size_t LinksStaticSize = 4;
using Links =
#ifdef NDEBUG
// To reduce memory allocation in release mode.
boost::container::small_vector<Link, LinksStaticSize>;
#else // NDEBUG
// To ease debugging.
std::vector<Link>;
#endif // NDEBUG
BoundingBox bbox;
Links overlaps_above;
Links overlaps_below;
LayerIslands islands;
bool has_extrusions() const { for (const LayerIsland &island : islands) if (island.has_extrusions()) return true; return false; }
};
using LayerSlices = std::vector<LayerSlice>;
class Layer
{
public:
@ -132,7 +268,7 @@ public:
// These lslices are also used to detect overhangs and overlaps between successive layers, therefore it is important
// that the 1st lslice is not compensated by the Elephant foot compensation algorithm.
ExPolygons lslices;
std::vector<BoundingBox> lslices_bboxes;
LayerSlices lslices_ex;
size_t region_count() const { return m_regions.size(); }
const LayerRegion* get_region(int idx) const { return m_regions[idx]; }
@ -142,6 +278,8 @@ public:
// Test whether whether there are any slices assigned to this layer.
bool empty() const;
void make_slices();
// After creating the slices on all layers, chain the islands overlapping in Z.
static void build_up_down_graph(Layer &below, Layer &above);
// Backup and restore raw sliced regions if needed.
//FIXME Review whether not to simplify the code by keeping the raw_slices all the time.
void backup_untyped_slices();
@ -151,11 +289,11 @@ public:
// Slices merged into islands, to be used by the elephant foot compensation to trim the individual surfaces with the shrunk merged slices.
ExPolygons merged(float offset) const;
template <class T> bool any_internal_region_slice_contains(const T &item) const {
for (const LayerRegion *layerm : m_regions) if (layerm->slices.any_internal_contains(item)) return true;
for (const LayerRegion *layerm : m_regions) if (layerm->slices().any_internal_contains(item)) return true;
return false;
}
template <class T> bool any_bottom_region_slice_contains(const T &item) const {
for (const LayerRegion *layerm : m_regions) if (layerm->slices.any_bottom_contains(item)) return true;
for (const LayerRegion *layerm : m_regions) if (layerm->slices().any_bottom_contains(item)) return true;
return false;
}
void make_perimeters();
@ -172,6 +310,7 @@ public:
// Is there any valid extrusion assigned to this LayerRegion?
virtual bool has_extrusions() const { for (auto layerm : m_regions) if (layerm->has_extrusions()) return true; return false; }
// virtual bool has_extrusions() const { for (const LayerSlice &lslice : lslices_ex) if (lslice.has_extrusions()) return true; return false; }
protected:
friend class PrintObject;

View File

@ -43,30 +43,26 @@ Flow LayerRegion::bridging_flow(FlowRole role) const
}
}
// 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 layerm->fill_expolygons.
void LayerRegion::slices_to_fill_surfaces_clipped()
{
// Note: this method should be idempotent, but fill_surfaces gets modified
// in place. However we're now only using its boundaries (which are invariant)
// so we're safe. This guarantees idempotence of prepare_infill() also in case
// that combine_infill() turns some fill_surface into VOID surfaces.
// Collect polygons per surface type.
std::array<SurfacesPtr, size_t(stCount)> by_surface;
for (Surface &surface : this->slices.surfaces)
std::array<std::vector<const Surface*>, size_t(stCount)> by_surface;
for (const Surface &surface : this->slices())
by_surface[size_t(surface.surface_type)].emplace_back(&surface);
// Trim surfaces by the fill_boundaries.
this->fill_surfaces.surfaces.clear();
m_fill_surfaces.surfaces.clear();
for (size_t surface_type = 0; surface_type < size_t(stCount); ++ surface_type) {
const SurfacesPtr &this_surfaces = by_surface[surface_type];
const std::vector<const Surface*> &this_surfaces = by_surface[surface_type];
if (! this_surfaces.empty())
this->fill_surfaces.append(intersection_ex(this_surfaces, this->fill_expolygons), SurfaceType(surface_type));
m_fill_surfaces.append(intersection_ex(this_surfaces, this->fill_expolygons()), SurfaceType(surface_type));
}
}
void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
{
this->perimeters.clear();
this->thin_fills.clear();
m_perimeters.clear();
m_thin_fills.clear();
const PrintConfig &print_config = this->layer()->object()->print()->config();
const PrintRegionConfig &region_config = this->region().config();
@ -87,8 +83,8 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
spiral_vase,
// output:
&this->perimeters,
&this->thin_fills,
&m_perimeters,
&m_thin_fills,
fill_surfaces
);
@ -131,7 +127,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// Internal surfaces, not grown.
Surfaces internal;
// Areas, where an infill of various types (top, bottom, bottom bride, sparse, void) could be placed.
Polygons fill_boundaries = to_polygons(this->fill_expolygons);
Polygons fill_boundaries = to_polygons(this->fill_expolygons());
Polygons lower_layer_covered_tmp;
// Collect top surfaces and internal surfaces.
@ -141,7 +137,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
{
// Voids are sparse infills if infill rate is zero.
Polygons voids;
for (const Surface &surface : this->fill_surfaces.surfaces) {
for (const Surface &surface : this->fill_surfaces()) {
if (surface.is_top()) {
// Collect the top surfaces, inflate them and trim them by the bottom surfaces.
// This gives the priority to bottom surfaces.
@ -292,7 +288,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
bridges[idx_last].bridge_angle = bd.angle;
if (this->layer()->object()->has_support()) {
// polygons_append(this->bridged, bd.coverage());
append(this->unsupported_bridge_edges, bd.unsupported_edges());
append(m_unsupported_bridge_edges, bd.unsupported_edges());
}
} else if (custom_angle > 0) {
// Bridge was not detected (likely it is only supported at one side). Still it is a surface filled in
@ -365,7 +361,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
surfaces_append(new_surfaces, std::move(new_expolys), s1);
}
this->fill_surfaces.surfaces = std::move(new_surfaces);
m_fill_surfaces.surfaces = std::move(new_surfaces);
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-final");
@ -389,12 +385,12 @@ void LayerRegion::prepare_fill_surfaces()
// For Lightning infill, infill_only_where_needed is ignored because both
// do a similar thing, and their combination doesn't make much sense.
if (! spiral_vase && this->region().config().top_solid_layers == 0) {
for (Surface &surface : this->fill_surfaces.surfaces)
for (Surface &surface : m_fill_surfaces)
if (surface.is_top())
surface.surface_type = this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid : stInternal;
}
if (this->region().config().bottom_solid_layers == 0) {
for (Surface &surface : this->fill_surfaces.surfaces)
for (Surface &surface : m_fill_surfaces)
if (surface.is_bottom()) // (surface.surface_type == stBottom)
surface.surface_type = stInternal;
}
@ -403,7 +399,7 @@ void LayerRegion::prepare_fill_surfaces()
if (! spiral_vase && this->region().config().fill_density.value > 0) {
// scaling an area requires two calls!
double min_area = scale_(scale_(this->region().config().solid_infill_below_area.value));
for (Surface &surface : this->fill_surfaces.surfaces)
for (Surface &surface : m_fill_surfaces)
if (surface.surface_type == stInternal && surface.area() <= min_area)
surface.surface_type = stInternalSolid;
}
@ -423,38 +419,38 @@ double LayerRegion::infill_area_threshold() const
void LayerRegion::trim_surfaces(const Polygons &trimming_polygons)
{
#ifndef NDEBUG
for (const Surface &surface : this->slices.surfaces)
for (const Surface &surface : this->slices())
assert(surface.surface_type == stInternal);
#endif /* NDEBUG */
this->slices.set(intersection_ex(this->slices.surfaces, trimming_polygons), stInternal);
m_slices.set(intersection_ex(this->slices().surfaces, trimming_polygons), stInternal);
}
void LayerRegion::elephant_foot_compensation_step(const float elephant_foot_compensation_perimeter_step, const Polygons &trimming_polygons)
{
#ifndef NDEBUG
for (const Surface &surface : this->slices.surfaces)
for (const Surface &surface : this->slices())
assert(surface.surface_type == stInternal);
#endif /* NDEBUG */
Polygons tmp = intersection(this->slices.surfaces, trimming_polygons);
append(tmp, diff(this->slices.surfaces, opening(this->slices.surfaces, elephant_foot_compensation_perimeter_step)));
this->slices.set(union_ex(tmp), stInternal);
Polygons tmp = intersection(this->slices().surfaces, trimming_polygons);
append(tmp, diff(this->slices().surfaces, opening(this->slices().surfaces, elephant_foot_compensation_perimeter_step)));
m_slices.set(union_ex(tmp), stInternal);
}
void LayerRegion::export_region_slices_to_svg(const char *path) const
{
BoundingBox bbox;
for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++surface)
bbox.merge(get_extents(surface->expolygon));
for (const Surface &surface : this->slices())
bbox.merge(get_extents(surface.expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min(0), bbox.max(1));
bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++surface)
svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency);
for (Surfaces::const_iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
svg.draw(surface->expolygon.lines(), surface_type_to_color_name(surface->surface_type));
for (const Surface &surface : this->slices())
svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
for (const Surface &surface : this->fill_surfaces())
svg.draw(surface.expolygon.lines(), surface_type_to_color_name(surface.surface_type));
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}
@ -470,15 +466,15 @@ void LayerRegion::export_region_slices_to_svg_debug(const char *name) const
void LayerRegion::export_region_fill_surfaces_to_svg(const char *path) const
{
BoundingBox bbox;
for (Surfaces::const_iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
bbox.merge(get_extents(surface->expolygon));
for (const Surface &surface : this->fill_surfaces())
bbox.merge(get_extents(surface.expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min(0), bbox.max(1));
bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (const Surface &surface : this->fill_surfaces.surfaces) {
for (const Surface &surface : this->fill_surfaces()) {
svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
svg.draw_outline(surface.expolygon, "black", "blue", scale_(0.05));
}

View File

@ -713,7 +713,7 @@ struct MMU_Graph
[[nodiscard]] const Vec2d &point_double() const { return m_point_double; }
[[nodiscard]] const Point &point() const { return m_point; }
bool operator==(const CPoint &rhs) const { return this->m_point_double == rhs.m_point_double && this->m_contour_idx == rhs.m_contour_idx && this->m_point_idx == rhs.m_point_idx; }
bool operator==(const CPoint &rhs) const { return m_point_double == rhs.m_point_double && m_contour_idx == rhs.m_contour_idx && m_point_idx == rhs.m_point_idx; }
};
struct CPointAccessor { const Point* operator()(const CPoint &pt) const { return &pt.point(); }};
typedef ClosestPointInRadiusLookup<CPoint, CPointAccessor> CPointLookupType;
@ -1697,7 +1697,7 @@ std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(con
throw_on_cancel_callback();
ExPolygons ex_polygons;
for (LayerRegion *region : layers[layer_idx]->regions())
for (const Surface &surface : region->slices.surfaces)
for (const Surface &surface : region->slices())
Slic3r::append(ex_polygons, offset_ex(surface.expolygon, float(10 * SCALED_EPSILON)));
// All expolygons are expanded by SCALED_EPSILON, merged, and then shrunk again by SCALED_EPSILON
// to ensure that very close polygons will be merged.

View File

@ -418,7 +418,7 @@ public:
size_t first_compatible_idx(PreferedCondition prefered_condition) const
{
size_t i = m_default_suppressed ? m_num_default_presets : 0;
size_t n = this->m_presets.size();
size_t n = m_presets.size();
size_t i_compatible = n;
int match_quality = -1;
for (; i < n; ++ i)

View File

@ -103,7 +103,7 @@ std::string PrintBase::output_filepath(const std::string &path, const std::strin
void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel /* warning_level */, const std::string &message, const PrintObjectBase* print_object)
{
if (this->m_status_callback) {
if (m_status_callback) {
auto status = print_object ? SlicingStatus(*print_object, step) : SlicingStatus(*this, step);
m_status_callback(status);
}

View File

@ -157,7 +157,7 @@ void PrintObject::make_perimeters()
m_print->throw_if_canceled();
LayerRegion &layerm = *m_layers[layer_idx]->get_region(region_id);
const LayerRegion &upper_layerm = *m_layers[layer_idx+1]->get_region(region_id);
const Polygons upper_layerm_polygons = to_polygons(upper_layerm.slices.surfaces);
const Polygons upper_layerm_polygons = to_polygons(upper_layerm.slices().surfaces);
// Filter upper layer polygons in intersection_ppl by their bounding boxes?
// my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ];
const double total_loop_length = total_length(upper_layerm_polygons);
@ -166,7 +166,8 @@ void PrintObject::make_perimeters()
const coord_t ext_perimeter_width = ext_perimeter_flow.scaled_width();
const coord_t ext_perimeter_spacing = ext_perimeter_flow.scaled_spacing();
for (Surface &slice : layerm.slices.surfaces) {
// slice is not const because slice.extra_perimeters is being incremented.
for (Surface &slice : layerm.m_slices.surfaces) {
for (;;) {
// compute the total thickness of perimeters
const coord_t perimeters_thickness = ext_perimeter_width/2 + ext_perimeter_spacing/2
@ -418,7 +419,7 @@ void PrintObject::generate_support_spots()
BOOST_LOG_TRIVIAL(debug)
<< "Searching support spots - start";
m_print->set_status(75, L("Searching support spots"));
if (this->m_config.support_material && !this->m_config.support_material_auto &&
if (m_config.support_material && !m_config.support_material_auto &&
std::all_of(this->model_object()->volumes.begin(), this->model_object()->volumes.end(),
[](const ModelVolume* mv){return mv->supported_facets.empty();})
) {
@ -500,7 +501,7 @@ std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare
m_print->throw_if_canceled();
const Layer *layer = this->layers()[idx_layer];
for (const LayerRegion *layerm : layer->regions())
for (const Surface &surface : layerm->fill_surfaces.surfaces)
for (const Surface &surface : layerm->fill_surfaces())
if (surface.surface_type == stInternalBridge)
append(out, triangulate_expolygon_3d(surface.expolygon, layer->bottom_z()));
}
@ -883,13 +884,13 @@ void PrintObject::detect_surfaces_type()
Surfaces top;
if (upper_layer) {
ExPolygons upper_slices = interface_shells ?
diff_ex(layerm->slices.surfaces, upper_layer->m_regions[region_id]->slices.surfaces, ApplySafetyOffset::Yes) :
diff_ex(layerm->slices.surfaces, upper_layer->lslices, ApplySafetyOffset::Yes);
diff_ex(layerm->slices().surfaces, upper_layer->m_regions[region_id]->slices().surfaces, ApplySafetyOffset::Yes) :
diff_ex(layerm->slices().surfaces, upper_layer->lslices, ApplySafetyOffset::Yes);
surfaces_append(top, opening_ex(upper_slices, offset), stTop);
} else {
// if no upper layer, all surfaces of this one are solid
// we clone surfaces because we're going to clear the slices collection
top = layerm->slices.surfaces;
top = layerm->slices().surfaces;
for (Surface &surface : top)
surface.surface_type = stTop;
}
@ -910,7 +911,7 @@ void PrintObject::detect_surfaces_type()
surfaces_append(
bottom,
opening_ex(
diff_ex(layerm->slices.surfaces, lower_layer->lslices, ApplySafetyOffset::Yes),
diff_ex(layerm->slices().surfaces, lower_layer->lslices, ApplySafetyOffset::Yes),
offset),
surface_type_bottom_other);
// if user requested internal shells, we need to identify surfaces
@ -922,8 +923,8 @@ void PrintObject::detect_surfaces_type()
bottom,
opening_ex(
diff_ex(
intersection(layerm->slices.surfaces, lower_layer->lslices), // supported
lower_layer->m_regions[region_id]->slices.surfaces,
intersection(layerm->slices().surfaces, lower_layer->lslices), // supported
lower_layer->m_regions[region_id]->slices().surfaces,
ApplySafetyOffset::Yes),
offset),
stBottom);
@ -932,7 +933,7 @@ void PrintObject::detect_surfaces_type()
} else {
// if no lower layer, all surfaces of this one are solid
// we clone surfaces because we're going to clear the slices collection
bottom = layerm->slices.surfaces;
bottom = layerm->slices().surfaces;
for (Surface &surface : bottom)
surface.surface_type = stBottom;
}
@ -961,13 +962,13 @@ void PrintObject::detect_surfaces_type()
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
// save surfaces to layer
Surfaces &surfaces_out = interface_shells ? surfaces_new[idx_layer] : layerm->slices.surfaces;
Surfaces &surfaces_out = interface_shells ? surfaces_new[idx_layer] : layerm->slices().surfaces;
Surfaces surfaces_backup;
if (! interface_shells) {
surfaces_backup = std::move(surfaces_out);
surfaces_out.clear();
}
const Surfaces &surfaces_prev = interface_shells ? layerm->slices.surfaces : surfaces_backup;
const Surfaces &surfaces_prev = interface_shells ? layerm->slices().surfaces : surfaces_backup;
// find internal surfaces (difference between top/bottom surfaces and others)
{
@ -993,15 +994,15 @@ void PrintObject::detect_surfaces_type()
if (interface_shells) {
// Move surfaces_new to layerm->slices.surfaces
for (size_t idx_layer = 0; idx_layer < num_layers; ++ idx_layer)
m_layers[idx_layer]->m_regions[region_id]->slices.surfaces = std::move(surfaces_new[idx_layer]);
m_layers[idx_layer]->m_regions[region_id]->m_slices.set(std::move(surfaces_new[idx_layer]));
}
if (spiral_vase) {
if (num_layers > 1)
// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
m_layers[num_layers - 1]->m_regions[region_id]->slices.set_type(stTop);
m_layers[num_layers - 1]->m_regions[region_id]->m_slices.set_type(stTop);
for (size_t i = num_layers; i < m_layers.size(); ++ i)
m_layers[i]->m_regions[region_id]->slices.set_type(stInternal);
m_layers[i]->m_regions[region_id]->m_slices.set_type(stInternal);
}
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - start";
@ -1048,7 +1049,7 @@ void PrintObject::process_external_surfaces()
bool expansions = false;
bool voids = false;
for (const LayerRegion *layerm : layer->regions()) {
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
for (const Surface &surface : layerm->fill_surfaces()) {
if (surface.surface_type == stInternal)
voids = true;
else
@ -1073,7 +1074,7 @@ void PrintObject::process_external_surfaces()
Polygons voids;
for (const LayerRegion *layerm : m_layers[layer_idx]->regions()) {
if (layerm->region().config().fill_density.value == 0.)
for (const Surface &surface : layerm->fill_surfaces.surfaces)
for (const Surface &surface : layerm->fill_surfaces())
// Shrink the holes, let the layer above expand slightly inside the unsupported areas.
polygons_append(voids, offset(surface.expolygon, unsupported_width));
}
@ -1102,7 +1103,7 @@ void PrintObject::process_external_surfaces()
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
}
}
} // void PrintObject::process_external_surfaces()
void PrintObject::discover_vertical_shells()
{
@ -1170,15 +1171,15 @@ void PrintObject::discover_vertical_shells()
LayerRegion &layerm = *layer.m_regions[region_id];
float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f;
// Top surfaces.
append(cache.top_surfaces, offset(layerm.slices.filter_by_type(stTop), min_perimeter_infill_spacing));
append(cache.top_surfaces, offset(layerm.fill_surfaces.filter_by_type(stTop), min_perimeter_infill_spacing));
append(cache.top_surfaces, offset(layerm.slices().filter_by_type(stTop), min_perimeter_infill_spacing));
append(cache.top_surfaces, offset(layerm.fill_surfaces().filter_by_type(stTop), min_perimeter_infill_spacing));
// Bottom surfaces.
append(cache.bottom_surfaces, offset(layerm.slices.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing));
append(cache.bottom_surfaces, offset(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing));
append(cache.bottom_surfaces, offset(layerm.slices().filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing));
append(cache.bottom_surfaces, offset(layerm.fill_surfaces().filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing));
// Calculate the maximum perimeter offset as if the slice was extruded with a single extruder only.
// First find the maxium number of perimeters per region slice.
unsigned int perimeters = 0;
for (Surface &s : layerm.slices.surfaces)
for (const Surface &s : layerm.slices())
perimeters = std::max<unsigned int>(perimeters, s.extra_perimeters);
perimeters += layerm.region().config().perimeters.value;
// Then calculate the infill offset.
@ -1189,7 +1190,7 @@ void PrintObject::discover_vertical_shells()
0.5f * float(extflow.scaled_width() + extflow.scaled_spacing()) + (float(perimeters) - 1.f) * flow.scaled_spacing());
perimeter_min_spacing = std::min(perimeter_min_spacing, float(std::min(extflow.scaled_spacing(), flow.scaled_spacing())));
}
polygons_append(cache.holes, to_polygons(layerm.fill_expolygons));
polygons_append(cache.holes, to_polygons(layerm.fill_expolygons()));
}
// Save some computing time by reducing the number of polygons.
cache.top_surfaces = union_(cache.top_surfaces);
@ -1242,15 +1243,15 @@ void PrintObject::discover_vertical_shells()
float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f;
// Top surfaces.
auto &cache = cache_top_botom_regions[idx_layer];
cache.top_surfaces = offset(layerm.slices.filter_by_type(stTop), min_perimeter_infill_spacing);
append(cache.top_surfaces, offset(layerm.fill_surfaces.filter_by_type(stTop), min_perimeter_infill_spacing));
cache.top_surfaces = offset(layerm.slices().filter_by_type(stTop), min_perimeter_infill_spacing);
append(cache.top_surfaces, offset(layerm.fill_surfaces().filter_by_type(stTop), min_perimeter_infill_spacing));
// Bottom surfaces.
cache.bottom_surfaces = offset(layerm.slices.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing);
append(cache.bottom_surfaces, offset(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing));
cache.bottom_surfaces = offset(layerm.slices().filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing);
append(cache.bottom_surfaces, offset(layerm.fill_surfaces().filter_by_types(surfaces_bottom, 2), min_perimeter_infill_spacing));
// 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));
polygons_append(cache.holes, to_polygons(layer.regions()[region_id]->fill_expolygons()));
}
}
});
@ -1407,14 +1408,14 @@ void PrintObject::discover_vertical_shells()
// Trim the shells region by the internal & internal void surfaces.
const SurfaceType surfaceTypesInternal[] = { stInternal, stInternalVoid, stInternalSolid };
const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 3));
const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces().filter_by_types(surfaceTypesInternal, 3));
shell = intersection(shell, polygonsInternal, ApplySafetyOffset::Yes);
polygons_append(shell, diff(polygonsInternal, holes));
if (shell.empty())
continue;
// Append the internal solids, so they will be merged with the new ones.
polygons_append(shell, to_polygons(layerm->fill_surfaces.filter_by_type(stInternalSolid)));
polygons_append(shell, to_polygons(layerm->fill_surfaces().filter_by_type(stInternalSolid)));
// These regions will be filled by a rectilinear full infill. Currently this type of infill
// only fills regions, which fit at least a single line. To avoid gaps in the sparse infill,
@ -1461,8 +1462,8 @@ void PrintObject::discover_vertical_shells()
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
// Trim the internal & internalvoid by the shell.
Slic3r::ExPolygons new_internal = diff_ex(layerm->fill_surfaces.filter_by_type(stInternal), shell);
Slic3r::ExPolygons new_internal_void = diff_ex(layerm->fill_surfaces.filter_by_type(stInternalVoid), shell);
Slic3r::ExPolygons new_internal = diff_ex(layerm->fill_surfaces().filter_by_type(stInternal), shell);
Slic3r::ExPolygons new_internal_void = diff_ex(layerm->fill_surfaces().filter_by_type(stInternalVoid), shell);
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
@ -1474,10 +1475,10 @@ void PrintObject::discover_vertical_shells()
// Assign resulting internal surfaces to layer.
const SurfaceType surfaceTypesKeep[] = { stTop, stBottom, stBottomBridge };
layerm->fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType));
layerm->fill_surfaces.append(new_internal, stInternal);
layerm->fill_surfaces.append(new_internal_void, stInternalVoid);
layerm->fill_surfaces.append(new_internal_solid, stInternalSolid);
layerm->m_fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType));
layerm->m_fill_surfaces.append(new_internal, stInternal);
layerm->m_fill_surfaces.append(new_internal_void, stInternalVoid);
layerm->m_fill_surfaces.append(new_internal_solid, stInternalSolid);
} // for each layer
});
m_print->throw_if_canceled();
@ -1491,7 +1492,7 @@ void PrintObject::discover_vertical_shells()
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
} // for each region
}
} // void PrintObject::discover_vertical_shells()
// This method applies bridge flow to the first internal solid layer above sparse infill.
void PrintObject::bridge_over_infill()
@ -1514,7 +1515,7 @@ void PrintObject::bridge_over_infill()
for (Layer *layer : m_layers) {
Polygons sum;
for (const LayerRegion *layerm : layer->m_regions)
layerm->fill_surfaces.filter_by_type(stInternal, &sum);
layerm->fill_surfaces().filter_by_type(stInternal, &sum);
internals.emplace_back(std::move(sum));
}
@ -1531,7 +1532,7 @@ void PrintObject::bridge_over_infill()
// Extract the stInternalSolid surfaces that might be transformed into bridges.
ExPolygons internal_solid;
layerm->fill_surfaces.remove_type(stInternalSolid, &internal_solid);
layerm->m_fill_surfaces.remove_type(stInternalSolid, &internal_solid);
if (internal_solid.empty())
// No internal solid -> no new bridges for this layer region.
continue;
@ -1563,7 +1564,7 @@ void PrintObject::bridge_over_infill()
if (to_bridge_pp.empty()) {
// Restore internal_solid surfaces.
for (ExPolygon &ex : internal_solid)
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
layerm->m_fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
continue;
}
// convert into ExPolygons
@ -1579,9 +1580,9 @@ void PrintObject::bridge_over_infill()
to_bridge = intersection_ex(to_bridge, internal_solid, ApplySafetyOffset::Yes);
// build the new collection of fill_surfaces
for (ExPolygon &ex : to_bridge)
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalBridge, std::move(ex)));
layerm->m_fill_surfaces.surfaces.push_back(Surface(stInternalBridge, std::move(ex)));
for (ExPolygon &ex : not_to_bridge)
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
layerm->m_fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex)));
/*
# exclude infill from the layers below if needed
# see discussion at https://github.com/alexrj/Slic3r/issues/240
@ -1622,7 +1623,7 @@ void PrintObject::bridge_over_infill()
m_print->throw_if_canceled();
}
});
}
} // void PrintObject::bridge_over_infill()
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
{
@ -1829,7 +1830,7 @@ void PrintObject::clip_fill_surfaces()
// Solid surfaces to be supported.
Polygons overhangs;
for (const LayerRegion *layerm : layer->m_regions)
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
for (const Surface &surface : layerm->fill_surfaces()) {
Polygons polygons = to_polygons(surface.expolygon);
if (surface.is_solid())
polygons_append(overhangs, polygons);
@ -1838,7 +1839,7 @@ void PrintObject::clip_fill_surfaces()
Polygons lower_layer_fill_surfaces;
Polygons lower_layer_internal_surfaces;
for (const LayerRegion *layerm : lower_layer->m_regions)
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
for (const Surface &surface : layerm->fill_surfaces()) {
Polygons polygons = to_polygons(surface.expolygon);
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
polygons_append(lower_layer_internal_surfaces, polygons);
@ -1873,12 +1874,12 @@ void PrintObject::clip_fill_surfaces()
continue;
SurfaceType internal_surface_types[] = { stInternal, stInternalVoid };
Polygons internal;
for (Surface &surface : layerm->fill_surfaces.surfaces)
for (Surface &surface : layerm->m_fill_surfaces.surfaces)
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
polygons_append(internal, std::move(surface.expolygon));
layerm->fill_surfaces.remove_types(internal_surface_types, 2);
layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, ApplySafetyOffset::Yes), stInternal);
layerm->fill_surfaces.append(diff_ex (internal, upper_internal, ApplySafetyOffset::Yes), stInternalVoid);
layerm->m_fill_surfaces.remove_types(internal_surface_types, 2);
layerm->m_fill_surfaces.append(intersection_ex(internal, upper_internal, ApplySafetyOffset::Yes), stInternal);
layerm->m_fill_surfaces.append(diff_ex (internal, upper_internal, ApplySafetyOffset::Yes), stInternalVoid);
// If there are voids it means that our internal infill is not adjacent to
// perimeters. In this case it would be nice to add a loop around infill to
// make it more robust and nicer. TODO.
@ -1888,7 +1889,7 @@ void PrintObject::clip_fill_surfaces()
}
m_print->throw_if_canceled();
}
}
} // void PrintObject::clip_fill_surfaces()
void PrintObject::discover_horizontal_shells()
{
@ -1904,7 +1905,7 @@ void PrintObject::discover_horizontal_shells()
(i % region_config.solid_infill_every_layers) == 0) {
// Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge.
SurfaceType type = (region_config.fill_density == 100 || region_config.solid_infill_every_layers == 1) ? stInternalSolid : stInternalBridge;
for (Surface &surface : layerm->fill_surfaces.surfaces)
for (Surface &surface : layerm->m_fill_surfaces.surfaces)
if (surface.surface_type == stInternal)
surface.surface_type = type;
}
@ -1935,11 +1936,11 @@ void PrintObject::discover_horizontal_shells()
// (not covered by a layer above / below).
// This does not contain the areas covered by perimeters!
Polygons solid;
for (const Surface &surface : layerm->slices.surfaces)
for (const Surface &surface : layerm->slices())
if (surface.surface_type == type)
polygons_append(solid, to_polygons(surface.expolygon));
// Infill areas (slices without the perimeters).
for (const Surface &surface : layerm->fill_surfaces.surfaces)
for (const Surface &surface : layerm->fill_surfaces())
if (surface.surface_type == type)
polygons_append(solid, to_polygons(surface.expolygon));
if (solid.empty())
@ -1972,7 +1973,7 @@ void PrintObject::discover_horizontal_shells()
Polygons new_internal_solid;
{
Polygons internal;
for (const Surface &surface : neighbor_layerm->fill_surfaces.surfaces)
for (const Surface &surface : neighbor_layerm->fill_surfaces())
if (surface.surface_type == stInternal || surface.surface_type == stInternalSolid)
polygons_append(internal, to_polygons(surface.expolygon));
new_internal_solid = intersection(solid, internal, ApplySafetyOffset::Yes);
@ -2028,7 +2029,7 @@ void PrintObject::discover_horizontal_shells()
// additional area in the next shell too
// make sure our grown surfaces don't exceed the fill area
Polygons internal;
for (const Surface &surface : neighbor_layerm->fill_surfaces.surfaces)
for (const Surface &surface : neighbor_layerm->fill_surfaces())
if (surface.is_internal() && !surface.is_bridge())
polygons_append(internal, to_polygons(surface.expolygon));
polygons_append(new_internal_solid,
@ -2047,16 +2048,16 @@ void PrintObject::discover_horizontal_shells()
// internal-solid are the union of the existing internal-solid surfaces
// and new ones
SurfaceCollection backup = std::move(neighbor_layerm->fill_surfaces);
SurfaceCollection backup = std::move(neighbor_layerm->m_fill_surfaces);
polygons_append(new_internal_solid, to_polygons(backup.filter_by_type(stInternalSolid)));
ExPolygons internal_solid = union_ex(new_internal_solid);
// assign new internal-solid surfaces to layer
neighbor_layerm->fill_surfaces.set(internal_solid, stInternalSolid);
neighbor_layerm->m_fill_surfaces.set(internal_solid, stInternalSolid);
// subtract intersections from layer surfaces to get resulting internal surfaces
Polygons polygons_internal = to_polygons(std::move(internal_solid));
ExPolygons internal = diff_ex(backup.filter_by_type(stInternal), polygons_internal, ApplySafetyOffset::Yes);
// assign resulting internal surfaces to layer
neighbor_layerm->fill_surfaces.append(internal, stInternal);
neighbor_layerm->m_fill_surfaces.append(internal, stInternal);
polygons_append(polygons_internal, to_polygons(std::move(internal)));
// assign top and bottom surfaces to layer
SurfaceType surface_types_solid[] = { stTop, stBottom, stBottomBridge };
@ -2064,7 +2065,7 @@ void PrintObject::discover_horizontal_shells()
std::vector<SurfacesPtr> top_bottom_groups;
backup.group(&top_bottom_groups);
for (SurfacesPtr &group : top_bottom_groups)
neighbor_layerm->fill_surfaces.append(
neighbor_layerm->m_fill_surfaces.append(
diff_ex(group, polygons_internal),
// Use an existing surface as a template, it carries the bridge angle etc.
*group.front());
@ -2083,7 +2084,7 @@ void PrintObject::discover_horizontal_shells()
} // for each layer
} // for each region
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
}
} // void PrintObject::discover_horizontal_shells()
// combine fill surfaces across layers to honor the "infill every N layers" option
// Idempotence of this method is guaranteed by the fact that we don't remove things from
@ -2141,10 +2142,10 @@ void PrintObject::combine_infill()
layerms.emplace_back(m_layers[i]->regions()[region_id]);
// We need to perform a multi-layer intersection, so let's split it in pairs.
// Initialize the intersection with the candidates of the lowest layer.
ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal));
ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces().filter_by_type(stInternal));
// Start looping from the second layer and intersect the current intersection with it.
for (size_t i = 1; i < layerms.size(); ++ i)
intersection = intersection_ex(layerms[i]->fill_surfaces.filter_by_type(stInternal), intersection);
intersection = intersection_ex(layerms[i]->fill_surfaces().filter_by_type(stInternal), intersection);
double area_threshold = layerms.front()->infill_area_threshold();
if (! intersection.empty() && area_threshold > 0.)
intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
@ -2173,9 +2174,9 @@ void PrintObject::combine_infill()
for (ExPolygon &expoly : intersection)
polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
for (LayerRegion *layerm : layerms) {
Polygons internal = to_polygons(std::move(layerm->fill_surfaces.filter_by_type(stInternal)));
layerm->fill_surfaces.remove_type(stInternal);
layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance), stInternal);
Polygons internal = to_polygons(std::move(layerm->fill_surfaces().filter_by_type(stInternal)));
layerm->m_fill_surfaces.remove_type(stInternal);
layerm->m_fill_surfaces.append(diff_ex(internal, intersection_with_clearance), stInternal);
if (layerm == layerms.back()) {
// Apply surfaces back with adjusted depth to the uppermost layer.
Surface templ(stInternal, ExPolygon());
@ -2183,17 +2184,17 @@ void PrintObject::combine_infill()
for (LayerRegion *layerm2 : layerms)
templ.thickness += layerm2->layer()->height;
templ.thickness_layers = (unsigned short)layerms.size();
layerm->fill_surfaces.append(intersection, templ);
layerm->m_fill_surfaces.append(intersection, templ);
} else {
// Save void surfaces.
layerm->fill_surfaces.append(
layerm->m_fill_surfaces.append(
intersection_ex(internal, intersection_with_clearance),
stInternalVoid);
}
}
}
}
}
} // void PrintObject::combine_infill()
void PrintObject::_generate_support_material()
{

View File

@ -432,12 +432,12 @@ std::string fix_slicing_errors(LayerPtrs &layers, const std::function<void()> &t
const Surfaces *lower_surfaces = nullptr;
for (size_t j = idx_layer + 1; j < layers.size(); ++ j)
if (! layers[j]->slicing_errors) {
upper_surfaces = &layers[j]->regions()[region_id]->slices.surfaces;
upper_surfaces = &layers[j]->regions()[region_id]->slices().surfaces;
break;
}
for (int j = int(idx_layer) - 1; j >= 0; -- j)
if (! layers[j]->slicing_errors) {
lower_surfaces = &layers[j]->regions()[region_id]->slices.surfaces;
lower_surfaces = &layers[j]->regions()[region_id]->slices().surfaces;
break;
}
// Collect outer contours and holes from the valid layers above & below.
@ -464,7 +464,7 @@ std::string fix_slicing_errors(LayerPtrs &layers, const std::function<void()> &t
if (lower_surfaces)
for (const auto &surface : *lower_surfaces)
polygons_append(holes, surface.expolygon.holes);
layerm->slices.set(diff_ex(union_(outer), holes), stInternal);
layerm->m_slices.set(diff_ex(union_(outer), holes), stInternal);
}
// Update layer slices after repairing the single regions.
layer->make_slices();
@ -517,17 +517,26 @@ void PrintObject::slice()
// Update bounding boxes, back up raw slices of complex models.
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this](const tbb::blocked_range<size_t>& range) {
[this](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
m_print->throw_if_canceled();
Layer &layer = *m_layers[layer_idx];
layer.lslices_bboxes.clear();
layer.lslices_bboxes.reserve(layer.lslices.size());
layer.lslices_ex.clear();
layer.lslices_ex.reserve(layer.lslices.size());
for (const ExPolygon &expoly : layer.lslices)
layer.lslices_bboxes.emplace_back(get_extents(expoly));
layer.lslices_ex.push_back({ get_extents(expoly) });
layer.backup_untyped_slices();
}
});
// Interlink the lslices into a Z graph.
tbb::parallel_for(
tbb::blocked_range<size_t>(1, m_layers.size()),
[this](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
m_print->throw_if_canceled();
Layer::build_up_down_graph(*m_layers[layer_idx - 1], *m_layers[layer_idx]);
}
});
if (m_layers.empty())
throw Slic3r::SlicingError("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n");
this->set_done(posSlice);
@ -579,9 +588,9 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
// layer_range.painted_regions are sorted by extruder ID and parent PrintObject region ID.
auto it_painted_region = layer_range.painted_regions.begin();
for (int region_id = 0; region_id < int(layer->region_count()); ++ region_id)
if (LayerRegion &layerm = *layer->get_region(region_id); ! layerm.slices.surfaces.empty()) {
if (LayerRegion &layerm = *layer->get_region(region_id); ! layerm.slices().empty()) {
assert(layerm.region().print_object_region_id() == region_id);
const BoundingBox bbox = get_extents(layerm.slices.surfaces);
const BoundingBox bbox = get_extents(layerm.slices().surfaces);
assert(it_painted_region < layer_range.painted_regions.end());
// Find the first it_painted_region which overrides this region.
for (; layer_range.volume_regions[it_painted_region->parent].region->print_object_region_id() < region_id; ++ it_painted_region)
@ -604,7 +613,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
}
// Steal from this region.
int target_region_id = it_painted_region->region->print_object_region_id();
ExPolygons stolen = intersection_ex(layerm.slices.surfaces, segmented.expolygons);
ExPolygons stolen = intersection_ex(layerm.slices().surfaces, segmented.expolygons);
if (! stolen.empty()) {
ByRegion &dst = by_region[target_region_id];
if (dst.expolygons.empty()) {
@ -622,7 +631,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
}
if (! self_trimmed) {
// Trim slices of this LayerRegion with all the MMU regions.
Polygons mine = to_polygons(std::move(layerm.slices.surfaces));
Polygons mine = to_polygons(std::move(layerm.slices().surfaces));
for (auto &segmented : by_extruder)
if (&segmented - by_extruder.data() + 1 != self_extruder_id && segmented.bbox.defined && bbox.overlap(segmented.bbox)) {
mine = diff(mine, segmented.expolygons);
@ -653,7 +662,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
if (src.needs_merge)
// Multiple regions were merged into one.
src.expolygons = closing_ex(src.expolygons, float(scale_(10 * EPSILON)));
layer->get_region(region_id)->slices.set(std::move(src.expolygons), stInternal);
layer->get_region(region_id)->m_slices.set(std::move(src.expolygons), stInternal);
}
}
});
@ -693,7 +702,7 @@ void PrintObject::slice_volumes()
for (size_t region_id = 0; region_id < region_slices.size(); ++ region_id) {
std::vector<ExPolygons> &by_layer = region_slices[region_id];
for (size_t layer_id = 0; layer_id < by_layer.size(); ++ layer_id)
m_layers[layer_id]->regions()[region_id]->slices.append(std::move(by_layer[layer_id]), stInternal);
m_layers[layer_id]->regions()[region_id]->m_slices.append(std::move(by_layer[layer_id]), stInternal);
}
region_slices.clear();
@ -754,14 +763,14 @@ void PrintObject::slice_volumes()
LayerRegion *layerm = layer->m_regions.front();
if (elfoot > 0) {
// Apply the elephant foot compensation and store the 1st layer slices without the Elephant foot compensation applied.
lslices_1st_layer = to_expolygons(std::move(layerm->slices.surfaces));
lslices_1st_layer = to_expolygons(std::move(layerm->m_slices.surfaces));
float delta = xy_compensation_scaled;
if (delta > elfoot) {
delta -= elfoot;
elfoot = 0.f;
} else if (delta > 0)
elfoot -= delta;
layerm->slices.set(
layerm->m_slices.set(
union_ex(
Slic3r::elephant_foot_compensation(
(delta == 0.f) ? lslices_1st_layer : offset_ex(lslices_1st_layer, delta),
@ -771,8 +780,8 @@ void PrintObject::slice_volumes()
lslices_1st_layer = offset_ex(std::move(lslices_1st_layer), xy_compensation_scaled);
} else if (xy_compensation_scaled < 0.f) {
// Apply the XY compensation.
layerm->slices.set(
offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), xy_compensation_scaled),
layerm->m_slices.set(
offset_ex(to_expolygons(std::move(layerm->m_slices.surfaces)), xy_compensation_scaled),
stInternal);
}
} else {

View File

@ -180,7 +180,7 @@ bool DefaultSupportTree::interconnect(const Pillar &pillar,
Vec3d eupper = pillar.endpoint();
Vec3d elower = nextpillar.endpoint();
double zmin = ground_level(this->m_sm) + m_sm.cfg.base_height_mm;
double zmin = ground_level(m_sm) + m_sm.cfg.base_height_mm;
eupper.z() = std::max(eupper.z(), zmin);
elower.z() = std::max(elower.z(), zmin);

View File

@ -650,14 +650,14 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t
// 1) Count the new polygons first.
size_t n_polygons_new = 0;
for (const LayerRegion *region : layer.regions())
for (const Surface &surface : region->slices.surfaces)
for (const Surface &surface : region->slices())
if (surface.surface_type == surface_type)
n_polygons_new += surface.expolygon.holes.size() + 1;
// 2) Collect the new polygons.
Polygons out;
out.reserve(n_polygons_new);
for (const LayerRegion *region : layer.regions())
for (const Surface &surface : region->slices.surfaces)
for (const Surface &surface : region->slices())
if (surface.surface_type == surface_type)
polygons_append(out, surface.expolygon);
return out;
@ -1213,9 +1213,9 @@ namespace SupportMaterialInternal {
static bool has_bridging_extrusions(const Layer &layer)
{
for (const LayerRegion *region : layer.regions()) {
if (SupportMaterialInternal::has_bridging_perimeters(region->perimeters))
if (SupportMaterialInternal::has_bridging_perimeters(region->perimeters()))
return true;
if (region->fill_surfaces.has(stBottomBridge) && has_bridging_fills(region->fills))
if (region->fill_surfaces().has(stBottomBridge) && has_bridging_fills(region->fills()))
return true;
}
return false;
@ -1287,7 +1287,7 @@ namespace SupportMaterialInternal {
// Trim the perimeters of this layer by the lower layer to get the unsupported pieces of perimeters.
overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices);
#else
Polylines overhang_perimeters = diff_pl(layerm.perimeters.as_polylines(), lower_grown_slices);
Polylines overhang_perimeters = diff_pl(layerm.perimeters().as_polylines(), lower_grown_slices);
#endif
// only consider straight overhangs
@ -1311,7 +1311,7 @@ namespace SupportMaterialInternal {
bool supported[2] = { false, false };
for (size_t i = 0; i < lower_layer.lslices.size() && ! (supported[0] && supported[1]); ++ i)
for (int j = 0; j < 2; ++ j)
if (! supported[j] && lower_layer.lslices_bboxes[i].contains(pts[j]) && lower_layer.lslices[i].contains(pts[j]))
if (! supported[j] && lower_layer.lslices_ex[i].bbox.contains(pts[j]) && lower_layer.lslices[i].contains(pts[j]))
supported[j] = true;
if (supported[0] && supported[1])
// Offset a polyline into a thick line.
@ -1321,7 +1321,7 @@ namespace SupportMaterialInternal {
}
// remove the entire bridges and only support the unsupported edges
//FIXME the brided regions are already collected as layerm.bridged. Use it?
for (const Surface &surface : layerm.fill_surfaces.surfaces)
for (const Surface &surface : layerm.fill_surfaces())
if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1)
polygons_append(bridges, surface.expolygon);
//FIXME add the gap filled areas. Extrude the gaps with a bridge flow?
@ -1329,14 +1329,14 @@ namespace SupportMaterialInternal {
//FIXME add supports at regular intervals to support long bridges!
bridges = diff(bridges,
// Offset unsupported edges into polygons.
offset(layerm.unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS));
offset(layerm.unsupported_bridge_edges(), scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS));
// Remove bridged areas from the supported areas.
contact_polygons = diff(contact_polygons, bridges, ApplySafetyOffset::Yes);
#ifdef SLIC3R_DEBUG
static int iRun = 0;
SVG::export_expolygons(debug_out_path("support-top-contacts-remove-bridges-run%d.svg", iRun ++),
{ { { union_ex(offset(layerm.unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)) }, { "unsupported_bridge_edges", "orange", 0.5f } },
{ { { union_ex(offset(layerm.unsupported_bridge_edges(), scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)) }, { "unsupported_bridge_edges", "orange", 0.5f } },
{ { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } },
{ { union_ex(bridges) }, { "bridges", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
#endif /* SLIC3R_DEBUG */
@ -1487,7 +1487,7 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs(
0.5f * fw);
// Overhang polygons for this layer and region.
Polygons diff_polygons;
Polygons layerm_polygons = to_polygons(layerm->slices.surfaces);
Polygons layerm_polygons = to_polygons(layerm->slices().surfaces);
if (lower_layer_offset == 0.f) {
// Support everything.
diff_polygons = diff(layerm_polygons, lower_layer_polygons);
@ -2858,10 +2858,10 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
break;
some_region_overlaps = true;
polygons_append(polygons_trimming,
offset(region->fill_surfaces.filter_by_type(stBottomBridge), gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
offset(region->fill_surfaces().filter_by_type(stBottomBridge), gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
if (region->region().config().overhangs.value)
// Add bridging perimeters.
SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters, gap_xy_scaled, polygons_trimming);
SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters(), gap_xy_scaled, polygons_trimming);
}
if (! some_region_overlaps)
break;

View File

@ -1039,12 +1039,12 @@ std::tuple<Issues, std::vector<LayerIslands>> check_extrusions_and_build_graph(c
// PREPARE BASE LAYER
const Layer *layer = po->layers()[0];
for (const LayerRegion *layer_region : layer->regions()) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters()) {
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
push_lines(perimeter, layer_lines);
} // perimeter
} // ex_entity
for (const ExtrusionEntity *ex_entity : layer_region->fills.entities) {
for (const ExtrusionEntity *ex_entity : layer_region->fills()) {
for (const ExtrusionEntity *fill : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
push_lines(fill, layer_lines);
} // fill
@ -1083,13 +1083,13 @@ std::tuple<Issues, std::vector<LayerIslands>> check_extrusions_and_build_graph(c
for (size_t layer_idx = 1; layer_idx < po->layer_count(); ++layer_idx) {
const Layer *layer = po->layers()[layer_idx];
for (const LayerRegion *layer_region : layer->regions()) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters()) {
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
check_extrusion_entity_stability(perimeter, layer_lines, layer->slice_z, layer_region,
external_lines, issues, params);
} // perimeter
} // ex_entity
for (const ExtrusionEntity *ex_entity : layer_region->fills.entities) {
for (const ExtrusionEntity *ex_entity : layer_region->fills()) {
for (const ExtrusionEntity *fill : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
if (fill->role() == ExtrusionRole::erGapFill
|| fill->role() == ExtrusionRole::erBridgeInfill) {

View File

@ -104,7 +104,7 @@ public:
};
typedef std::vector<Surface> Surfaces;
typedef std::vector<Surface*> SurfacesPtr;
typedef std::vector<const Surface*> SurfacesPtr;
inline Polygons to_polygons(const Surface &surface)
{
@ -221,6 +221,7 @@ inline void polygons_append(Polygons &dst, const SurfacesPtr &src)
}
}
/*
inline void polygons_append(Polygons &dst, SurfacesPtr &&src)
{
dst.reserve(dst.size() + number_polygons(src));
@ -230,6 +231,7 @@ inline void polygons_append(Polygons &dst, SurfacesPtr &&src)
(*it)->expolygon.holes.clear();
}
}
*/
// Append a vector of Surfaces at the end of another vector of polygons.
inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType)

View File

@ -22,46 +22,45 @@ void SurfaceCollection::simplify(double tolerance)
}
/* group surfaces by common properties */
void SurfaceCollection::group(std::vector<SurfacesPtr> *retval)
void SurfaceCollection::group(std::vector<SurfacesPtr> *retval) const
{
for (Surfaces::iterator it = this->surfaces.begin(); it != this->surfaces.end(); ++it) {
for (const Surface &surface : this->surfaces) {
// find a group with the same properties
SurfacesPtr* group = NULL;
SurfacesPtr *group = nullptr;
for (std::vector<SurfacesPtr>::iterator git = retval->begin(); git != retval->end(); ++git)
if (! git->empty() && surfaces_could_merge(*git->front(), *it)) {
if (! git->empty() && surfaces_could_merge(*git->front(), surface)) {
group = &*git;
break;
}
// if no group with these properties exists, add one
if (group == NULL) {
if (group == nullptr) {
retval->resize(retval->size() + 1);
group = &retval->back();
}
// append surface to group
group->push_back(&*it);
group->push_back(&surface);
}
}
SurfacesPtr SurfaceCollection::filter_by_type(const SurfaceType type)
SurfacesPtr SurfaceCollection::filter_by_type(const SurfaceType type) const
{
SurfacesPtr ss;
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
if (surface->surface_type == type) ss.push_back(&*surface);
}
for (const Surface &surface : this->surfaces)
if (surface.surface_type == type)
ss.push_back(&surface);
return ss;
}
SurfacesPtr SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes)
SurfacesPtr SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes) const
{
SurfacesPtr ss;
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
for (const Surface &surface : this->surfaces)
for (int i = 0; i < ntypes; ++ i) {
if (surface->surface_type == types[i]) {
ss.push_back(&*surface);
if (surface.surface_type == types[i]) {
ss.push_back(&surface);
break;
}
}
}
return ss;
}

View File

@ -17,7 +17,7 @@ public:
SurfaceCollection(Surfaces &&surfaces) : surfaces(std::move(surfaces)) {};
void simplify(double tolerance);
void group(std::vector<SurfacesPtr> *retval);
void group(std::vector<SurfacesPtr> *retval) const;
template <class T> bool any_internal_contains(const T &item) const {
for (const Surface &surface : this->surfaces) if (surface.is_internal() && surface.expolygon.contains(item)) return true;
return false;
@ -26,8 +26,8 @@ public:
for (const Surface &surface : this->surfaces) if (surface.is_bottom() && surface.expolygon.contains(item)) return true;
return false;
}
SurfacesPtr filter_by_type(const SurfaceType type);
SurfacesPtr filter_by_types(const SurfaceType *types, int ntypes);
SurfacesPtr filter_by_type(const SurfaceType type) const;
SurfacesPtr filter_by_types(const SurfaceType *types, int ntypes) const;
void keep_type(const SurfaceType type);
void keep_types(const SurfaceType *types, int ntypes);
void remove_type(const SurfaceType type);
@ -48,6 +48,13 @@ public:
return false;
}
Surfaces::const_iterator cbegin() const { return this->surfaces.cbegin(); }
Surfaces::const_iterator cend() const { return this->surfaces.cend(); }
Surfaces::const_iterator begin() const { return this->surfaces.cbegin(); }
Surfaces::const_iterator end() const { return this->surfaces.cend(); }
Surfaces::iterator begin() { return this->surfaces.begin(); }
Surfaces::iterator end() { return this->surfaces.end(); }
void set(const SurfaceCollection &coll) { surfaces = coll.surfaces; }
void set(SurfaceCollection &&coll) { surfaces = std::move(coll.surfaces); }
void set(const ExPolygons &src, SurfaceType surfaceType) { clear(); this->append(src, surfaceType); }

View File

@ -284,7 +284,7 @@ void TriangleMesh::rotate(float angle, const Axis &axis)
case Z: its_rotate_z(this->its, angle); break;
default: assert(false); return;
}
update_bounding_box(this->its, this->m_stats);
update_bounding_box(this->its, m_stats);
}
}
@ -295,7 +295,7 @@ void TriangleMesh::rotate(float angle, const Vec3d& axis)
Transform3d m = Transform3d::Identity();
m.rotate(Eigen::AngleAxisd(angle, axis_norm));
its_transform(its, m);
update_bounding_box(this->its, this->m_stats);
update_bounding_box(this->its, m_stats);
}
}
@ -334,7 +334,7 @@ void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
det = -det;
}
m_stats.volume *= det;
update_bounding_box(this->its, this->m_stats);
update_bounding_box(this->its, m_stats);
}
void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed)
@ -346,7 +346,7 @@ void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed)
det = -det;
}
m_stats.volume *= det;
update_bounding_box(this->its, this->m_stats);
update_bounding_box(this->its, m_stats);
}
void TriangleMesh::flip_triangles()
@ -512,7 +512,7 @@ std::vector<ExPolygons> TriangleMesh::slice(const std::vector<double> &z) const
size_t TriangleMesh::memsize() const
{
size_t memsize = 8 + this->its.memsize() + sizeof(this->m_stats);
size_t memsize = 8 + this->its.memsize() + sizeof(m_stats);
return memsize;
}

View File

@ -92,7 +92,7 @@ public:
TriangleMesh(std::vector<Vec3f> &&vertices, const std::vector<Vec3i> &&faces);
explicit TriangleMesh(const indexed_triangle_set &M);
explicit TriangleMesh(indexed_triangle_set &&M, const RepairedMeshErrors& repaired_errors = RepairedMeshErrors());
void clear() { this->its.clear(); this->m_stats.clear(); }
void clear() { this->its.clear(); m_stats.clear(); }
bool ReadSTLFile(const char* input_file, bool repair = true);
bool write_ascii(const char* output_file);
bool write_binary(const char* output_file);

View File

@ -371,7 +371,7 @@ std::pair<std::vector<Vec3i>, std::vector<Vec3i>> TriangleSelector::precompute_a
{
std::vector<Vec3i> neighbors(m_triangles.size(), Vec3i(-1, -1, -1));
std::vector<Vec3i> neighbors_propagated(m_triangles.size(), Vec3i(-1, -1, -1));
for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) {
for (int facet_idx = 0; facet_idx < m_orig_size_indices; ++facet_idx) {
neighbors[facet_idx] = m_neighbors[facet_idx];
neighbors_propagated[facet_idx] = neighbors[facet_idx];
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors[facet_idx]));
@ -1480,7 +1480,7 @@ void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const
std::vector<Vec2i> TriangleSelector::get_seed_fill_contour() const {
std::vector<Vec2i> edges_out;
for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) {
for (int facet_idx = 0; facet_idx < m_orig_size_indices; ++facet_idx) {
const Vec3i neighbors = m_neighbors[facet_idx];
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
this->get_seed_fill_contour_recursive(facet_idx, neighbors, neighbors, edges_out);

View File

@ -7165,7 +7165,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
if (is_selected_separate_extruder) {
bool at_least_one_has_correct_extruder = false;
for (const LayerRegion* layerm : layer->regions()) {
if (layerm->slices.surfaces.empty())
if (layerm->slices().empty())
continue;
const PrintRegionConfig& cfg = layerm->region().config();
if (cfg.perimeter_extruder.value == m_selected_extruder ||
@ -7208,14 +7208,14 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
}
if (ctxt.has_perimeters)
#if ENABLE_LEGACY_OPENGL_REMOVAL
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
_3DScene::extrusionentity_to_verts(layerm->perimeters(), float(layer->print_z), copy,
select_geometry(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
#else
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
volume(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
if (ctxt.has_infill) {
for (const ExtrusionEntity *ee : layerm->fills.entities) {
for (const ExtrusionEntity *ee : layerm->fills()) {
// fill represents infill extrusions of a single island.
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (! fill->entities.empty())

View File

@ -3244,7 +3244,7 @@ void GUI_App::app_updater(bool from_user)
app_data.target_path =dwnld_dlg.get_download_path();
// start download
this->plater_->get_notification_manager()->push_download_progress_notification(_utf8("Download"), std::bind(&AppUpdater::cancel_callback, this->m_app_updater.get()));
this->plater_->get_notification_manager()->push_download_progress_notification(_utf8("Download"), std::bind(&AppUpdater::cancel_callback, m_app_updater.get()));
app_data.start_after = dwnld_dlg.run_after_download();
m_app_updater->set_app_data(std::move(app_data));
m_app_updater->sync_download();

View File

@ -1158,18 +1158,18 @@ void TriangleSelectorGUI::update_render_data()
#if !ENABLE_LEGACY_OPENGL_REMOVAL
void GLPaintContour::render() const
{
assert(this->m_contour_VBO_id != 0);
assert(this->m_contour_EBO_id != 0);
assert(m_contour_VBO_id != 0);
assert(m_contour_EBO_id != 0);
glsafe(::glLineWidth(4.0f));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_contour_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
if (this->contour_indices_size > 0) {
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_contour_EBO_id));
glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
@ -1181,20 +1181,20 @@ void GLPaintContour::render() const
void GLPaintContour::finalize_geometry()
{
assert(this->m_contour_VBO_id == 0);
assert(this->m_contour_EBO_id == 0);
assert(m_contour_VBO_id == 0);
assert(m_contour_EBO_id == 0);
if (!this->contour_vertices.empty()) {
glsafe(::glGenBuffers(1, &this->m_contour_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id));
glsafe(::glGenBuffers(1, &m_contour_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_contour_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->contour_vertices.clear();
}
if (!this->contour_indices.empty()) {
glsafe(::glGenBuffers(1, &this->m_contour_EBO_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id));
glsafe(::glGenBuffers(1, &m_contour_EBO_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_contour_EBO_id));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
this->contour_indices.clear();
@ -1203,13 +1203,13 @@ void GLPaintContour::finalize_geometry()
void GLPaintContour::release_geometry()
{
if (this->m_contour_VBO_id) {
glsafe(::glDeleteBuffers(1, &this->m_contour_VBO_id));
this->m_contour_VBO_id = 0;
if (m_contour_VBO_id) {
glsafe(::glDeleteBuffers(1, &m_contour_VBO_id));
m_contour_VBO_id = 0;
}
if (this->m_contour_EBO_id) {
glsafe(::glDeleteBuffers(1, &this->m_contour_EBO_id));
this->m_contour_EBO_id = 0;
if (m_contour_EBO_id) {
glsafe(::glDeleteBuffers(1, &m_contour_EBO_id));
m_contour_EBO_id = 0;
}
this->clear();
}

View File

@ -41,7 +41,7 @@ public:
void render() const;
inline bool has_VBO() const { return this->m_contour_EBO_id != 0; }
inline bool has_VBO() const { return m_contour_EBO_id != 0; }
// Release the geometry data, release OpenGL VBOs.
void release_geometry();

View File

@ -101,7 +101,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
this->back_to_initial_value(opt_id);
};
field->m_back_to_sys_value = [this](std::string opt_id) {
if (!this->m_disabled)
if (!m_disabled)
this->back_to_sys_value(opt_id);
};

View File

@ -168,7 +168,7 @@ bool AppUpdater::priv::http_get_file(const std::string& url, size_t size_limit,
.size_limit(size_limit)
.on_progress([&, progress_fn](Http::Progress progress, bool& cancel) {
// progress function returns true as success (to continue)
cancel = (this->m_cancel ? true : !progress_fn(std::move(progress)));
cancel = (m_cancel ? true : !progress_fn(std::move(progress)));
if (cancel) {
error_message = GUI::format("Error getting: `%1%`: Download was canceled.", //lm:typo //dk: am i blind? :)
url);
@ -259,7 +259,7 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d
);
if (!res)
{
if (this->m_cancel)
if (m_cancel)
{
BOOST_LOG_TRIVIAL(info) << error_message; //lm:Is this an error? // dk: changed to info
wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_APP_DOWNLOAD_FAILED); // FAILED with empty msg only closes progress notification

View File

@ -459,8 +459,8 @@ SCENARIO("Some weird coverage test", "[Perimeters]")
object->slice();
Layer *layer = object->get_layer(1);
LayerRegion *layerm = layer->get_region(0);
layerm->slices.clear();
layerm->slices.append({ expolygon }, stInternal);
layerm->m_slices.clear();
layerm->m_slices.append({ expolygon }, stInternal);
// make perimeters
layer->make_perimeters();
@ -472,22 +472,22 @@ SCENARIO("Some weird coverage test", "[Perimeters]")
Polygons covered_by_infill;
{
Polygons acc;
for (const ExtrusionEntity *ee : layerm->perimeters.entities)
for (const ExtrusionEntity *ee : layerm->perimeters())
for (const ExtrusionEntity *ee : dynamic_cast<const ExtrusionEntityCollection*>(ee)->entities)
append(acc, offset(dynamic_cast<const ExtrusionLoop*>(ee)->polygon().split_at_first_point(), float(pflow.scaled_width() / 2.f + SCALED_EPSILON)));
covered_by_perimeters = union_(acc);
}
{
Polygons acc;
for (const Surface &surface : layerm->fill_surfaces.surfaces)
append(acc, to_polygons(surface.expolygon));
for (const ExtrusionEntity *ee : layerm->thin_fills.entities)
for (const ExPolygon &expolygon : layerm->fill_expolygons())
append(acc, to_polygons(expolygon));
for (const ExtrusionEntity *ee : layerm->thin_fills().entities)
append(acc, offset(dynamic_cast<const ExtrusionPath*>(ee)->polyline, float(iflow.scaled_width() / 2.f + SCALED_EPSILON)));
covered_by_infill = union_(acc);
}
// compute the non covered area
ExPolygons non_covered = diff_ex(to_polygons(layerm->slices.surfaces), union_(covered_by_perimeters, covered_by_infill));
ExPolygons non_covered = diff_ex(to_polygons(layerm->slices().surfaces), union_(covered_by_perimeters, covered_by_infill));
/*
if (0) {
@ -506,7 +506,8 @@ SCENARIO("Some weird coverage test", "[Perimeters]")
}
*/
THEN("no gap between perimeters and infill") {
size_t num_non_convered = std::count_if(non_covered.begin(), non_covered.end(), [&iflow](const ExPolygon &ex){ return ex.area() > sqr(double(iflow.scaled_width())); });
size_t num_non_convered = std::count_if(non_covered.begin(), non_covered.end(),
[&iflow](const ExPolygon &ex){ return ex.area() > sqr(double(iflow.scaled_width())); });
REQUIRE(num_non_convered == 0);
}
}

View File

@ -20,11 +20,11 @@ SCENARIO("PrintObject: Perimeter generation", "[PrintObject]") {
}
THEN("Every layer in region 0 has 1 island of perimeters") {
for (const Layer *layer : object.layers())
REQUIRE(layer->regions().front()->perimeters.entities.size() == 1);
REQUIRE(layer->regions().front()->perimeters().size() == 1);
}
THEN("Every layer in region 0 has 3 paths in its perimeters list.") {
for (const Layer *layer : object.layers())
REQUIRE(layer->regions().front()->perimeters.items_count() == 3);
REQUIRE(layer->regions().front()->perimeters().items_count() == 3);
}
}
}
@ -66,7 +66,7 @@ SCENARIO("Print: Changing number of solid surfaces does not cause all surfaces t
// iterate over all of the regions in the layer
for (const LayerRegion *region : layer.regions()) {
// for each region, iterate over the fill surfaces
for (const Surface &surface : region->fill_surfaces.surfaces)
for (const Surface &surface : region->fill_surfaces())
CHECK(surface.is_solid());
}
};

View File

@ -13,15 +13,15 @@
%code%{ RETVAL = &THIS->region(); %};
Ref<SurfaceCollection> slices()
%code%{ RETVAL = &THIS->slices; %};
%code%{ RETVAL = const_cast<SurfaceCollection*>(&THIS->slices()); %};
Ref<ExtrusionEntityCollection> thin_fills()
%code%{ RETVAL = &THIS->thin_fills; %};
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->thin_fills()); %};
Ref<SurfaceCollection> fill_surfaces()
%code%{ RETVAL = &THIS->fill_surfaces; %};
%code%{ RETVAL = const_cast<SurfaceCollection*>(&THIS->fill_surfaces()); %};
Ref<ExtrusionEntityCollection> perimeters()
%code%{ RETVAL = &THIS->perimeters; %};
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->perimeters()); %};
Ref<ExtrusionEntityCollection> fills()
%code%{ RETVAL = &THIS->fills; %};
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->fills()); %};
void prepare_fill_surfaces();
void make_perimeters(SurfaceCollection* slices, SurfaceCollection* fill_surfaces)