mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-30 17:31:59 +08:00
Copied some useful methods from prusa3d/slic3r.
This commit is contained in:
parent
f1616ee295
commit
ccb8204fae
@ -52,13 +52,14 @@ class ExPolygon
|
||||
std::string dump_perl() const;
|
||||
};
|
||||
|
||||
inline Polygons
|
||||
to_polygons(const ExPolygons &expolygons)
|
||||
// Count a nuber of polygons stored inside the vector of expolygons.
|
||||
// Useful for allocating space for polygons when converting expolygons to polygons.
|
||||
inline size_t number_polygons(const ExPolygons &expolys)
|
||||
{
|
||||
Polygons pp;
|
||||
for (ExPolygons::const_iterator ex = expolygons.begin(); ex != expolygons.end(); ++ex)
|
||||
append_to(pp, (Polygons)*ex);
|
||||
return pp;
|
||||
size_t n_polygons = 0;
|
||||
for (ExPolygons::const_iterator it = expolys.begin(); it != expolys.end(); ++ it)
|
||||
n_polygons += it->holes.size() + 1;
|
||||
return n_polygons;
|
||||
}
|
||||
|
||||
inline ExPolygons
|
||||
@ -69,8 +70,110 @@ operator+(ExPolygons src1, const ExPolygons &src2) {
|
||||
|
||||
std::ostream& operator <<(std::ostream &s, const ExPolygons &expolygons);
|
||||
|
||||
|
||||
inline void
|
||||
polygons_append(Polygons &dst, const ExPolygon &src)
|
||||
{
|
||||
dst.reserve(dst.size() + src.holes.size() + 1);
|
||||
dst.push_back(src.contour);
|
||||
dst.insert(dst.end(), src.holes.begin(), src.holes.end());
|
||||
}
|
||||
|
||||
inline void
|
||||
polygons_append(Polygons &dst, const ExPolygons &src)
|
||||
{
|
||||
dst.reserve(dst.size() + number_polygons(src));
|
||||
for (ExPolygons::const_iterator it = src.begin(); it != src.end(); ++ it) {
|
||||
dst.push_back(it->contour);
|
||||
dst.insert(dst.end(), it->holes.begin(), it->holes.end());
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
polygons_append(Polygons &dst, ExPolygon &&src)
|
||||
{
|
||||
dst.reserve(dst.size() + src.holes.size() + 1);
|
||||
dst.push_back(std::move(src.contour));
|
||||
std::move(std::begin(src.holes), std::end(src.holes), std::back_inserter(dst));
|
||||
src.holes.clear();
|
||||
}
|
||||
|
||||
inline void
|
||||
polygons_append(Polygons &dst, ExPolygons &&src)
|
||||
{
|
||||
dst.reserve(dst.size() + number_polygons(src));
|
||||
for (ExPolygons::iterator it = src.begin(); it != src.end(); ++ it) {
|
||||
dst.push_back(std::move(it->contour));
|
||||
std::move(std::begin(it->holes), std::end(it->holes), std::back_inserter(dst));
|
||||
it->holes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
expolygons_append(ExPolygons &dst, const ExPolygons &src)
|
||||
{
|
||||
dst.insert(dst.end(), src.begin(), src.end());
|
||||
}
|
||||
|
||||
inline void
|
||||
expolygons_append(ExPolygons &dst, ExPolygons &&src)
|
||||
{
|
||||
if (dst.empty()) {
|
||||
dst = std::move(src);
|
||||
} else {
|
||||
std::move(std::begin(src), std::end(src), std::back_inserter(dst));
|
||||
src.clear();
|
||||
}
|
||||
}
|
||||
|
||||
inline Polygons
|
||||
to_polygons(const ExPolygon &src)
|
||||
{
|
||||
Polygons polygons;
|
||||
polygons.reserve(src.holes.size() + 1);
|
||||
polygons.push_back(src.contour);
|
||||
polygons.insert(polygons.end(), src.holes.begin(), src.holes.end());
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline Polygons
|
||||
to_polygons(const ExPolygons &src)
|
||||
{
|
||||
Polygons polygons;
|
||||
polygons.reserve(number_polygons(src));
|
||||
for (ExPolygons::const_iterator it = src.begin(); it != src.end(); ++it) {
|
||||
polygons.push_back(it->contour);
|
||||
polygons.insert(polygons.end(), it->holes.begin(), it->holes.end());
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline Polygons
|
||||
to_polygons(ExPolygon &&src)
|
||||
{
|
||||
Polygons polygons;
|
||||
polygons.reserve(src.holes.size() + 1);
|
||||
polygons.push_back(std::move(src.contour));
|
||||
std::move(std::begin(src.holes), std::end(src.holes), std::back_inserter(polygons));
|
||||
src.holes.clear();
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline Polygons
|
||||
to_polygons(ExPolygons &&src)
|
||||
{
|
||||
Polygons polygons;
|
||||
polygons.reserve(number_polygons(src));
|
||||
for (ExPolygons::iterator it = src.begin(); it != src.end(); ++it) {
|
||||
polygons.push_back(std::move(it->contour));
|
||||
std::move(std::begin(it->holes), std::end(it->holes), std::back_inserter(polygons));
|
||||
it->holes.clear();
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
// start Boost
|
||||
#include <boost/polygon/polygon.hpp>
|
||||
namespace boost { namespace polygon {
|
||||
|
@ -21,6 +21,7 @@ class Polygon : public MultiPoint {
|
||||
const Point& operator[](Points::size_type idx) const;
|
||||
|
||||
Polygon() {};
|
||||
|
||||
explicit Polygon(const Points &points): MultiPoint(points) {};
|
||||
Point last_point() const;
|
||||
virtual Lines lines() const;
|
||||
@ -52,6 +53,21 @@ class Polygon : public MultiPoint {
|
||||
static Polygon new_scale(const Pointfs& p);
|
||||
};
|
||||
|
||||
// Append a vector of polygons at the end of another vector of polygons.
|
||||
inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); }
|
||||
|
||||
inline void polygons_append(Polygons &dst, Polygons &&src)
|
||||
{
|
||||
if (dst.empty()) {
|
||||
dst = std::move(src);
|
||||
} else {
|
||||
std::move(std::begin(src), std::end(src), std::back_inserter(dst));
|
||||
src.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline Polygons
|
||||
operator+(Polygons src1, const Polygons &src2) {
|
||||
append_to(src1, src2);
|
||||
|
@ -160,6 +160,12 @@ class PrintObject
|
||||
bool has_support_material() const;
|
||||
void detect_surfaces_type();
|
||||
void process_external_surfaces();
|
||||
|
||||
/// Combine fill surfaces across layers.
|
||||
/// Idempotence of this method is guaranteed by the fact that we don't remove things from
|
||||
/// fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
|
||||
void combine_infill();
|
||||
|
||||
void bridge_over_infill();
|
||||
coordf_t adjust_layer_height(coordf_t layer_height) const;
|
||||
std::vector<coordf_t> generate_object_layers(coordf_t first_layer_height);
|
||||
@ -167,6 +173,18 @@ class PrintObject
|
||||
std::vector<ExPolygons> _slice_region(size_t region_id, std::vector<float> z, bool modifier);
|
||||
void _make_perimeters();
|
||||
void _infill();
|
||||
/// Find all horizontal shells in this object
|
||||
void discover_horizontal_shells();
|
||||
|
||||
/// Only active if config->infill_only_where_needed. This step trims the sparse infill,
|
||||
/// so it acts as an internal support. It maintains all other infill types intact.
|
||||
/// Here the internal surfaces and perimeters have to be supported by the sparse infill.
|
||||
///FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
|
||||
/// Likely the sparse infill will not be anchored correctly, so it will not work as intended.
|
||||
/// Also one wishes the perimeters to be supported by a full infill.
|
||||
/// Idempotence of this method is guaranteed by the fact that we don't remove things from
|
||||
/// fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
|
||||
void clip_fill_surfaces();
|
||||
|
||||
private:
|
||||
Print* _print;
|
||||
|
@ -1095,6 +1095,112 @@ PrintObject::_infill()
|
||||
this->state.set_done(posInfill);
|
||||
}
|
||||
|
||||
void
|
||||
PrintObject::combine_infill()
|
||||
{
|
||||
// Work on each region separately.
|
||||
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
|
||||
const PrintRegion *region = this->print()->regions[region_id];
|
||||
const int every = region->config.infill_every_layers.value;
|
||||
if (every < 2 || region->config.fill_density == 0.)
|
||||
continue;
|
||||
// Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
|
||||
//FIXME limit the layer height to max_layer_height
|
||||
double nozzle_diameter = std::min(
|
||||
this->print()->config.nozzle_diameter.get_at(region->config.infill_extruder.value - 1),
|
||||
this->print()->config.nozzle_diameter.get_at(region->config.solid_infill_extruder.value - 1));
|
||||
// define the combinations
|
||||
std::vector<size_t> combine(this->layers.size(), 0);
|
||||
{
|
||||
double current_height = 0.;
|
||||
size_t num_layers = 0;
|
||||
for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++ layer_idx) {
|
||||
const Layer *layer = this->layers[layer_idx];
|
||||
if (layer->id() == 0)
|
||||
// Skip first print layer (which may not be first layer in array because of raft).
|
||||
continue;
|
||||
// Check whether the combination of this layer with the lower layers' buffer
|
||||
// would exceed max layer height or max combined layer count.
|
||||
if (current_height + layer->height >= nozzle_diameter + EPSILON || num_layers >= every) {
|
||||
// Append combination to lower layer.
|
||||
combine[layer_idx - 1] = num_layers;
|
||||
current_height = 0.;
|
||||
num_layers = 0;
|
||||
}
|
||||
current_height += layer->height;
|
||||
++ num_layers;
|
||||
}
|
||||
|
||||
// Append lower layers (if any) to uppermost layer.
|
||||
combine[this->layers.size() - 1] = num_layers;
|
||||
}
|
||||
|
||||
// loop through layers to which we have assigned layers to combine
|
||||
for (size_t layer_idx = 0; layer_idx < this->layers.size(); ++ layer_idx) {
|
||||
size_t num_layers = combine[layer_idx];
|
||||
if (num_layers <= 1)
|
||||
continue;
|
||||
// Get all the LayerRegion objects to be combined.
|
||||
std::vector<LayerRegion*> layerms;
|
||||
layerms.reserve(num_layers);
|
||||
for (size_t i = layer_idx + 1 - num_layers; i <= layer_idx; ++ i)
|
||||
layerms.emplace_back(this->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));
|
||||
// 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(
|
||||
to_polygons(intersection),
|
||||
to_polygons(layerms[i]->fill_surfaces.filter_by_type(stInternal)),
|
||||
false);
|
||||
double area_threshold = layerms.front()->infill_area_threshold();
|
||||
if (! intersection.empty() && area_threshold > 0.)
|
||||
intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
|
||||
[area_threshold](const ExPolygon &expoly) { return expoly.area() <= area_threshold; }),
|
||||
intersection.end());
|
||||
if (intersection.empty())
|
||||
continue;
|
||||
// Slic3r::debugf " combining %d %s regions from layers %d-%d\n",
|
||||
// scalar(@$intersection),
|
||||
// ($type == S_TYPE_INTERNAL ? 'internal' : 'internal-solid'),
|
||||
// $layer_idx-($every-1), $layer_idx;
|
||||
// intersection now contains the regions that can be combined across the full amount of layers,
|
||||
// so let's remove those areas from all layers.
|
||||
Polygons intersection_with_clearance;
|
||||
intersection_with_clearance.reserve(intersection.size());
|
||||
float clearance_offset =
|
||||
0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
|
||||
// Because fill areas for rectilinear and honeycomb are grown
|
||||
// later to overlap perimeters, we need to counteract that too.
|
||||
((region->config.fill_pattern == ipRectilinear ||
|
||||
region->config.fill_pattern == ipGrid ||
|
||||
region->config.fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
|
||||
layerms.back()->flow(frSolidInfill).scaled_width();
|
||||
for (ExPolygon &expoly : intersection)
|
||||
polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
|
||||
for (LayerRegion *layerm : layerms) {
|
||||
Polygons internal = to_polygons(layerm->fill_surfaces.filter_by_type(stInternal));
|
||||
layerm->fill_surfaces.remove_type(stInternal);
|
||||
layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance, false), stInternal);
|
||||
if (layerm == layerms.back()) {
|
||||
// Apply surfaces back with adjusted depth to the uppermost layer.
|
||||
Surface templ(stInternal, ExPolygon());
|
||||
templ.thickness = 0.;
|
||||
for (LayerRegion *layerm2 : layerms)
|
||||
templ.thickness += layerm2->layer()->height;
|
||||
templ.thickness_layers = (unsigned short)layerms.size();
|
||||
layerm->fill_surfaces.append(intersection, templ);
|
||||
} else {
|
||||
// Save void surfaces.
|
||||
layerm->fill_surfaces.append(
|
||||
intersection_ex(internal, intersection_with_clearance, false),
|
||||
stInternalVoid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SupportMaterial *
|
||||
PrintObject::_support_material()
|
||||
{
|
||||
@ -1182,4 +1288,77 @@ PrintObject::generate_support_material()
|
||||
|
||||
}
|
||||
#endif // SLIC3RXS
|
||||
void PrintObject::clip_fill_surfaces()
|
||||
{
|
||||
if (! this->config.infill_only_where_needed.value ||
|
||||
! std::any_of(this->print()->regions.begin(), this->print()->regions.end(),
|
||||
[](const PrintRegion *region) { return region->config.fill_density > 0; }))
|
||||
return;
|
||||
|
||||
// We only want infill under ceilings; this is almost like an
|
||||
// internal support material.
|
||||
// Proceed top-down, skipping the bottom layer.
|
||||
Polygons upper_internal;
|
||||
for (int layer_id = int(this->layers.size()) - 1; layer_id > 0; -- layer_id) {
|
||||
Layer *layer = this->layers[layer_id];
|
||||
Layer *lower_layer = this->layers[layer_id - 1];
|
||||
// Detect things that we need to support.
|
||||
// Cummulative slices.
|
||||
Polygons slices;
|
||||
for (const ExPolygon &expoly : layer->slices.expolygons)
|
||||
polygons_append(slices, to_polygons(expoly));
|
||||
// Cummulative fill surfaces.
|
||||
Polygons fill_surfaces;
|
||||
// Solid surfaces to be supported.
|
||||
Polygons overhangs;
|
||||
for (const LayerRegion *layerm : layer->regions)
|
||||
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
|
||||
Polygons polygons = to_polygons(surface.expolygon);
|
||||
if (surface.is_solid())
|
||||
polygons_append(overhangs, polygons);
|
||||
polygons_append(fill_surfaces, std::move(polygons));
|
||||
}
|
||||
Polygons lower_layer_fill_surfaces;
|
||||
Polygons lower_layer_internal_surfaces;
|
||||
for (const LayerRegion *layerm : lower_layer->regions)
|
||||
for (const Surface &surface : layerm->fill_surfaces.surfaces) {
|
||||
Polygons polygons = to_polygons(surface.expolygon);
|
||||
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
polygons_append(lower_layer_internal_surfaces, polygons);
|
||||
polygons_append(lower_layer_fill_surfaces, std::move(polygons));
|
||||
}
|
||||
// We also need to support perimeters when there's at least one full unsupported loop
|
||||
{
|
||||
// Get perimeters area as the difference between slices and fill_surfaces
|
||||
// Only consider the area that is not supported by lower perimeters
|
||||
Polygons perimeters = intersection(diff(slices, fill_surfaces), lower_layer_fill_surfaces);
|
||||
// Only consider perimeter areas that are at least one extrusion width thick.
|
||||
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
|
||||
//Should the pw not be half of the current value?
|
||||
float pw = FLT_MAX;
|
||||
for (const LayerRegion *layerm : layer->regions)
|
||||
pw = std::min<float>(pw, layerm->flow(frPerimeter).scaled_width());
|
||||
// Append such thick perimeters to the areas that need support
|
||||
polygons_append(overhangs, offset2(perimeters, -pw, +pw));
|
||||
}
|
||||
// Find new internal infill.
|
||||
polygons_append(overhangs, std::move(upper_internal));
|
||||
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
|
||||
// Apply new internal infill to regions.
|
||||
for (LayerRegion *layerm : lower_layer->regions) {
|
||||
if (layerm->region()->config.fill_density.value == 0)
|
||||
continue;
|
||||
Polygons internal;
|
||||
for (Surface &surface : layerm->fill_surfaces.surfaces)
|
||||
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
polygons_append(internal, std::move(surface.expolygon));
|
||||
layerm->fill_surfaces.remove_types({ stInternal, stInternalVoid });
|
||||
layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, true), stInternal);
|
||||
layerm->fill_surfaces.append(diff_ex (internal, upper_internal, true), 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,5 +147,71 @@ SurfaceCollection::polygons_count() const
|
||||
count += 1 + it->expolygon.holes.size();
|
||||
return count;
|
||||
}
|
||||
void
|
||||
SurfaceCollection::remove_type(const SurfaceType type)
|
||||
{
|
||||
// Use stl remove_if to remove
|
||||
auto ptr {std::remove_if(surfaces.begin(), surfaces.end(),[type] (Surface& s) { return s.surface_type == type; })};
|
||||
surfaces.erase(ptr, surfaces.end());
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceCollection::remove_types(const SurfaceType *types, size_t ntypes)
|
||||
{
|
||||
for (size_t i = 0; i < ntypes; ++i)
|
||||
this->remove_type(types[i]);
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceCollection::remove_types(std::initializer_list<SurfaceType> types) {
|
||||
for (const auto& t : types) {
|
||||
this->remove_type(t);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceCollection::keep_type(const SurfaceType type)
|
||||
{
|
||||
// Use stl remove_if to remove
|
||||
auto ptr {std::remove_if(surfaces.begin(), surfaces.end(),[type] (Surface& s) { return s.surface_type != type; })};
|
||||
surfaces.erase(ptr, surfaces.end());
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceCollection::keep_types(const SurfaceType *types, size_t ntypes)
|
||||
{
|
||||
for (size_t i = 0; i < ntypes; ++i)
|
||||
this->keep_type(types[i]);
|
||||
}
|
||||
|
||||
void
|
||||
SurfaceCollection::keep_types(std::initializer_list<SurfaceType> types) {
|
||||
for (const auto& t : types) {
|
||||
this->keep_type(t);
|
||||
}
|
||||
}
|
||||
/* group surfaces by common properties */
|
||||
void
|
||||
SurfaceCollection::group(std::vector<SurfacesPtr> *retval)
|
||||
{
|
||||
for (Surfaces::iterator it = this->surfaces.begin(); it != this->surfaces.end(); ++it) {
|
||||
// find a group with the same properties
|
||||
SurfacesPtr* group = NULL;
|
||||
for (std::vector<SurfacesPtr>::iterator git = retval->begin(); git != retval->end(); ++git)
|
||||
if (! git->empty() && surfaces_could_merge(*git->front(), *it)) {
|
||||
group = &*git;
|
||||
break;
|
||||
}
|
||||
// if no group with these properties exists, add one
|
||||
if (group == NULL) {
|
||||
retval->resize(retval->size() + 1);
|
||||
group = &retval->back();
|
||||
}
|
||||
// append surface to group
|
||||
group->push_back(&*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,25 @@ class SurfaceCollection
|
||||
SurfacesPtr filter_by_type(SurfaceType type);
|
||||
void filter_by_type(SurfaceType type, Polygons* polygons);
|
||||
|
||||
/// deletes all surfaces that match the supplied type.
|
||||
void remove_type(const SurfaceType type);
|
||||
|
||||
void remove_types(std::initializer_list<SurfaceType> types);
|
||||
|
||||
template<int N>
|
||||
void remove_types(std::array<SurfaceType, N> types) {
|
||||
remove_types(types.data(), types.size());
|
||||
}
|
||||
/// group surfaces by common properties
|
||||
void group(std::vector<SurfacesPtr> *retval);
|
||||
|
||||
void keep_type(const SurfaceType type);
|
||||
void keep_types(std::initializer_list<SurfaceType> types);
|
||||
void keep_types(const SurfaceType *types, int ntypes);
|
||||
|
||||
/// deletes all surfaces that match the supplied aggregate of types.
|
||||
void remove_types(const SurfaceType *types, size_t ntypes);
|
||||
|
||||
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); }
|
||||
@ -42,6 +61,10 @@ class SurfaceCollection
|
||||
size_t size() const { return this->surfaces.size(); };
|
||||
void clear() { this->surfaces.clear(); };
|
||||
void erase(size_t i) { this->surfaces.erase(this->surfaces.begin() + i); };
|
||||
Surfaces::iterator begin() { return this->surfaces.begin();}
|
||||
Surfaces::iterator end() { return this->surfaces.end();}
|
||||
Surfaces::const_iterator cbegin() const { return this->surfaces.cbegin();}
|
||||
Surfaces::const_iterator cend() const { return this->surfaces.cend();}
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user