PrusaSlicer-NonPlainar/xs/src/libslic3r/Layer.cpp

343 lines
12 KiB
C++
Raw Normal View History

#include "Layer.hpp"
2014-08-03 16:41:09 +00:00
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "Print.hpp"
#include "SVG.hpp"
namespace Slic3r {
Layer::Layer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z,
coordf_t slice_z)
: upper_layer(NULL),
lower_layer(NULL),
regions(),
slicing_errors(false),
slice_z(slice_z),
print_z(print_z),
height(height),
slices(),
_id(id),
_object(object)
{
}
Layer::~Layer()
{
// remove references to self
if (NULL != this->upper_layer) {
this->upper_layer->lower_layer = NULL;
}
if (NULL != this->lower_layer) {
this->lower_layer->upper_layer = NULL;
}
this->clear_regions();
}
size_t
Layer::id() const
{
return this->_id;
}
void
Layer::set_id(size_t id)
{
this->_id = id;
}
PrintObject*
Layer::object()
{
return this->_object;
}
const PrintObject*
Layer::object() const
{
return this->_object;
}
size_t
2015-07-27 23:26:01 +00:00
Layer::region_count() const
{
return this->regions.size();
}
void
Layer::clear_regions()
{
for (int i = this->regions.size()-1; i >= 0; --i)
this->delete_region(i);
}
LayerRegion*
Layer::get_region(int idx)
{
return this->regions.at(idx);
}
LayerRegion*
Layer::add_region(PrintRegion* print_region)
{
LayerRegion* region = new LayerRegion(this, print_region);
this->regions.push_back(region);
return region;
}
void
Layer::delete_region(int idx)
{
LayerRegionPtrs::iterator i = this->regions.begin() + idx;
LayerRegion* item = *i;
this->regions.erase(i);
delete item;
}
2014-08-03 16:41:09 +00:00
// merge all regions' slices to get islands
void
Layer::make_slices()
{
ExPolygons slices;
if (this->regions.size() == 1) {
// optimization: if we only have one region, take its slices
slices = this->regions.front()->slices;
} else {
Polygons slices_p;
FOREACH_LAYERREGION(this, layerm) {
Polygons region_slices_p = (*layerm)->slices;
slices_p.insert(slices_p.end(), region_slices_p.begin(), region_slices_p.end());
}
union_(slices_p, &slices);
2014-08-03 16:41:09 +00:00
}
this->slices.expolygons.clear();
this->slices.expolygons.reserve(slices.size());
// prepare ordering points
Points ordering_points;
ordering_points.reserve(slices.size());
for (ExPolygons::const_iterator ex = slices.begin(); ex != slices.end(); ++ex)
ordering_points.push_back(ex->contour.first_point());
// sort slices
std::vector<Points::size_type> order;
Slic3r::Geometry::chained_path(ordering_points, order);
// populate slices vector
for (std::vector<Points::size_type>::const_iterator it = order.begin(); it != order.end(); ++it) {
this->slices.expolygons.push_back(slices[*it]);
}
}
2015-04-16 18:44:55 +00:00
void
Layer::merge_slices()
{
FOREACH_LAYERREGION(this, layerm) {
(*layerm)->merge_slices();
}
}
2014-12-25 10:37:54 +00:00
template <class T>
bool
Layer::any_internal_region_slice_contains(const T &item) const
{
FOREACH_LAYERREGION(this, layerm) {
if ((*layerm)->slices.any_internal_contains(item)) return true;
}
return false;
}
template bool Layer::any_internal_region_slice_contains<Polyline>(const Polyline &item) const;
2014-12-25 10:37:54 +00:00
template <class T>
bool
Layer::any_bottom_region_slice_contains(const T &item) const
{
FOREACH_LAYERREGION(this, layerm) {
if ((*layerm)->slices.any_bottom_contains(item)) return true;
}
return false;
}
template bool Layer::any_bottom_region_slice_contains<Polyline>(const Polyline &item) const;
// Here the perimeters are created cummulatively for all layer regions sharing the same parameters influencing the perimeters.
// The perimeter paths and the thin fills (ExtrusionEntityCollection) are assigned to the first compatible layer region.
// The resulting fill surface is split back among the originating regions.
2015-12-02 18:32:57 +00:00
void
Layer::make_perimeters()
{
#ifdef SLIC3R_DEBUG
printf("Making perimeters for layer %zu\n", this->id());
#endif
// keep track of regions whose perimeters we have already generated
std::set<size_t> done;
FOREACH_LAYERREGION(this, layerm) {
size_t region_id = layerm - this->regions.begin();
if (done.find(region_id) != done.end()) continue;
done.insert(region_id);
const PrintRegionConfig &config = (*layerm)->region()->config;
// find compatible regions
LayerRegionPtrs layerms;
layerms.push_back(*layerm);
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != this->regions.end(); ++it) {
LayerRegion* other_layerm = *it;
const PrintRegionConfig &other_config = other_layerm->region()->config;
if (config.perimeter_extruder == other_config.perimeter_extruder
&& config.perimeters == other_config.perimeters
&& config.perimeter_speed == other_config.perimeter_speed
&& config.gap_fill_speed == other_config.gap_fill_speed
&& config.overhangs == other_config.overhangs
&& config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0
&& config.thin_walls == other_config.thin_walls
&& config.external_perimeters_first == other_config.external_perimeters_first) {
layerms.push_back(other_layerm);
done.insert(it - this->regions.begin());
}
}
if (layerms.size() == 1) { // optimization
(*layerm)->fill_surfaces.surfaces.clear();
(*layerm)->perimeter_surfaces.surfaces.clear();
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->perimeter_surfaces, &(*layerm)->fill_surfaces);
this->perimeter_expolygons.expolygons.clear();
for (Surfaces::const_iterator it = (*layerm)->perimeter_surfaces.surfaces.begin(); it != (*layerm)->perimeter_surfaces.surfaces.end(); ++ it)
this->perimeter_expolygons.expolygons.push_back(it->expolygon);
2015-12-02 18:32:57 +00:00
} else {
// group slices (surfaces) according to number of extra perimeters
std::map<unsigned short,Surfaces> slices; // extra_perimeters => [ surface, surface... ]
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
for (Surfaces::iterator s = (*l)->slices.surfaces.begin(); s != (*l)->slices.surfaces.end(); ++s) {
slices[s->extra_perimeters].push_back(*s);
}
}
// merge the surfaces assigned to each group
SurfaceCollection new_slices;
for (std::map<unsigned short,Surfaces>::const_iterator it = slices.begin(); it != slices.end(); ++it) {
ExPolygons expp = union_ex(it->second, true);
for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) {
Surface s = it->second.front(); // clone type and extra_perimeters
s.expolygon = *ex;
new_slices.surfaces.push_back(s);
}
}
// make perimeters
SurfaceCollection perimeter_surfaces;
2015-12-02 18:32:57 +00:00
SurfaceCollection fill_surfaces;
(*layerm)->make_perimeters(new_slices, &perimeter_surfaces, &fill_surfaces);
// Copy the perimeter surfaces to the layer's surfaces before splitting them into the regions.
this->perimeter_expolygons.expolygons.clear();
for (Surfaces::const_iterator it = perimeter_surfaces.surfaces.begin(); it != perimeter_surfaces.surfaces.end(); ++ it)
this->perimeter_expolygons.expolygons.push_back(it->expolygon);
2015-12-02 18:32:57 +00:00
// assign fill_surfaces to each layer
if (!fill_surfaces.surfaces.empty()) {
2015-12-02 18:32:57 +00:00
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
// Separate the fill surfaces.
2015-12-02 18:32:57 +00:00
ExPolygons expp = intersection_ex(
fill_surfaces,
(*l)->slices
);
(*l)->fill_surfaces.surfaces.clear();
for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) {
Surface s = fill_surfaces.surfaces.front(); // clone type and extra_perimeters
s.expolygon = *ex;
(*l)->fill_surfaces.surfaces.push_back(s);
}
// Separate the perimeter surfaces.
expp = intersection_ex(
perimeter_surfaces,
(*l)->slices
);
(*l)->perimeter_surfaces.surfaces.clear();
for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) {
Surface s = fill_surfaces.surfaces.front(); // clone type and extra_perimeters
s.expolygon = *ex;
(*l)->perimeter_surfaces.surfaces.push_back(s);
}
2015-12-02 18:32:57 +00:00
}
}
}
}
}
void Layer::export_region_slices_to_svg(const char *path)
{
BoundingBox bbox;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface)
bbox.merge(get_extents(surface->expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min.x, bbox.max.y);
bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface)
svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency);
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}
// Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export.
void Layer::export_region_slices_to_svg_debug(const char *name)
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\Layer-slices-%s-%d.svg", name, idx ++);
this->export_region_slices_to_svg(path);
}
void Layer::export_region_fill_surfaces_to_svg(const char *path)
{
BoundingBox bbox;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface)
bbox.merge(get_extents(surface->expolygon));
Point legend_size = export_surface_type_legend_to_svg_box_size();
Point legend_pos(bbox.min.x, bbox.max.y);
bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
SVG svg(path, bbox);
const float transparency = 0.5f;
for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region)
for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface)
svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency);
export_surface_type_legend_to_svg(svg, legend_pos);
svg.Close();
}
// Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export.
void Layer::export_region_fill_surfaces_to_svg_debug(const char *name)
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\Layer-fill_surfaces-%s-%d.svg", name, idx ++);
this->export_region_fill_surfaces_to_svg(path);
}
SupportLayer::SupportLayer(size_t id, PrintObject *object, coordf_t height,
coordf_t print_z, coordf_t slice_z)
: Layer(id, object, height, print_z, slice_z)
{
}
SupportLayer::~SupportLayer()
{
}
}