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:
parent
f57744ad12
commit
ee626eb65a
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,14 @@ 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).
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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++;
|
||||
}
|
||||
};
|
||||
|
@ -226,12 +226,12 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
for (const LayerRegion *layerm : layer->regions()) {
|
||||
const PrintRegion ®ion = 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);
|
||||
|
@ -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,29 +440,25 @@ 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) {
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
if (! fill_surfaces.empty()) {
|
||||
// Separate the fill surfaces.
|
||||
for (LayerRegion *l : layerms)
|
||||
l->m_fill_expolygons = intersection_ex(fill_surfaces.surfaces, l->slices().surfaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
|
||||
@ -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;
|
||||
|
@ -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:
|
||||
Layer *m_layer;
|
||||
const PrintRegion *m_region;
|
||||
// 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:
|
||||
@ -131,8 +267,8 @@ public:
|
||||
// order will be applied by the G-code generator to the extrusions fitting into these lslices.
|
||||
// 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;
|
||||
ExPolygons lslices;
|
||||
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;
|
||||
|
@ -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 ®ion_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));
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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); }
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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())
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user