PrusaSlicer/xs/src/libslic3r/SLAPrint.cpp
Ranvir Singh 52a94e8f40 remove deprecated code and add new one (#3775)
change auto_ptr to unique_ptr
2017-03-19 14:02:59 -05:00

334 lines
14 KiB
C++

#include "SLAPrint.hpp"
#include "ClipperUtils.hpp"
#include "ExtrusionEntity.hpp"
#include "Fill/Fill.hpp"
#include "Geometry.hpp"
#include "Surface.hpp"
#include <iostream>
#include <complex>
#include <cstdio>
namespace Slic3r {
void
SLAPrint::slice()
{
TriangleMesh mesh = this->model->mesh();
mesh.repair();
// align to origin taking raft into account
this->bb = mesh.bounding_box();
if (this->config.raft_layers > 0) {
this->bb.min.x -= this->config.raft_offset.value;
this->bb.min.y -= this->config.raft_offset.value;
this->bb.max.x += this->config.raft_offset.value;
this->bb.max.y += this->config.raft_offset.value;
}
mesh.translate(0, 0, -bb.min.z);
this->bb.translate(0, 0, -bb.min.z);
// if we are generating a raft, first_layer_height will not affect mesh slicing
const float lh = this->config.layer_height.value;
const float first_lh = this->config.first_layer_height.value;
// generate the list of Z coordinates for mesh slicing
// (we slice each layer at half of its thickness)
this->layers.clear();
{
const float first_slice_lh = (this->config.raft_layers > 0) ? lh : first_lh;
this->layers.push_back(Layer(first_slice_lh/2, first_slice_lh));
}
while (this->layers.back().print_z + lh/2 <= mesh.stl.stats.max.z) {
this->layers.push_back(Layer(this->layers.back().print_z + lh/2, this->layers.back().print_z + lh));
}
// perform slicing and generate layers
{
std::vector<float> slice_z;
for (size_t i = 0; i < this->layers.size(); ++i)
slice_z.push_back(this->layers[i].slice_z);
std::vector<ExPolygons> slices;
TriangleMeshSlicer<Z>(&mesh).slice(slice_z, &slices);
for (size_t i = 0; i < slices.size(); ++i)
this->layers[i].slices.expolygons = slices[i];
}
// generate infill
if (this->config.fill_density < 100) {
std::unique_ptr<Fill> fill(Fill::new_from_type(this->config.fill_pattern.value));
fill->bounding_box.merge(Point::new_scale(bb.min.x, bb.min.y));
fill->bounding_box.merge(Point::new_scale(bb.max.x, bb.max.y));
fill->min_spacing = this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value);
fill->angle = Geometry::deg2rad(this->config.fill_angle.value);
fill->density = this->config.fill_density.value/100;
parallelize<size_t>(
0,
this->layers.size()-1,
boost::bind(&SLAPrint::_infill_layer, this, _1, fill.get()),
this->config.threads.value
);
}
// generate support material
this->sm_pillars.clear();
ExPolygons overhangs;
if (this->config.support_material) {
// flatten and merge all the overhangs
{
Polygons pp;
for (std::vector<Layer>::const_iterator it = this->layers.begin()+1; it != this->layers.end(); ++it)
pp += diff(it->slices, (it - 1)->slices);
overhangs = union_ex(pp);
}
// generate points following the shape of each island
Points pillars_pos;
const coordf_t spacing = scale_(this->config.support_material_spacing);
const coordf_t radius = scale_(this->sm_pillars_radius());
for (ExPolygons::const_iterator it = overhangs.begin(); it != overhangs.end(); ++it) {
// leave a radius/2 gap between pillars and contour to prevent lateral adhesion
for (float inset = radius * 1.5;; inset += spacing) {
// inset according to the configured spacing
Polygons curr = offset(*it, -inset);
if (curr.empty()) break;
// generate points along the contours
for (Polygons::const_iterator pg = curr.begin(); pg != curr.end(); ++pg) {
Points pp = pg->equally_spaced_points(spacing);
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
pillars_pos.push_back(*p);
}
}
}
// for each pillar, check which layers it applies to
for (Points::const_iterator p = pillars_pos.begin(); p != pillars_pos.end(); ++p) {
SupportPillar pillar(*p);
bool object_hit = false;
// check layers top-down
for (int i = this->layers.size()-1; i >= 0; --i) {
// check whether point is void in this layer
if (!this->layers[i].slices.contains(*p)) {
// no slice contains the point, so it's in the void
if (pillar.top_layer > 0) {
// we have a pillar, so extend it
pillar.bottom_layer = i + this->config.raft_layers;
} else if (object_hit) {
// we don't have a pillar and we're below the object, so create one
pillar.top_layer = i + this->config.raft_layers;
}
} else {
if (pillar.top_layer > 0) {
// we have a pillar which is not needed anymore, so store it and initialize a new potential pillar
this->sm_pillars.push_back(pillar);
pillar = SupportPillar(*p);
}
object_hit = true;
}
}
if (pillar.top_layer > 0) this->sm_pillars.push_back(pillar);
}
}
// generate a solid raft if requested
// (do this after support material because we take support material shape into account)
if (this->config.raft_layers > 0) {
ExPolygons raft = this->layers.front().slices + overhangs; // take support material into account
raft = offset_ex(raft, scale_(this->config.raft_offset));
for (int i = this->config.raft_layers; i >= 1; --i) {
this->layers.insert(this->layers.begin(), Layer(0, first_lh + lh * (i-1)));
this->layers.front().slices = raft;
}
// prepend total raft height to all sliced layers
for (size_t i = this->config.raft_layers; i < this->layers.size(); ++i)
this->layers[i].print_z += first_lh + lh * (this->config.raft_layers-1);
}
}
void
SLAPrint::_infill_layer(size_t i, const Fill* _fill)
{
Layer &layer = this->layers[i];
const float shell_thickness = this->config.get_abs_value("perimeter_extrusion_width", this->config.layer_height.value);
// In order to detect what regions of this layer need to be solid,
// perform an intersection with layers within the requested shell thickness.
Polygons internal = layer.slices;
for (size_t j = 0; j < this->layers.size(); ++j) {
const Layer &other = this->layers[j];
if (std::abs(other.print_z - layer.print_z) > shell_thickness) continue;
if (j == 0 || j == this->layers.size()-1) {
internal.clear();
break;
} else if (i != j) {
internal = intersection(internal, other.slices);
if (internal.empty()) break;
}
}
// If we have no internal infill, just print the whole layer as a solid slice.
if (internal.empty()) return;
layer.solid = false;
const Polygons infill = offset(layer.slices, -scale_(shell_thickness));
// Generate solid infill
layer.solid_infill << diff_ex(infill, internal, true);
// Generate internal infill
{
std::unique_ptr<Fill> fill(_fill->clone());
fill->layer_id = i;
fill->z = layer.print_z;
ExtrusionPath templ(erInternalInfill);
templ.width = fill->spacing();
const ExPolygons internal_ex = intersection_ex(infill, internal);
for (ExPolygons::const_iterator it = internal_ex.begin(); it != internal_ex.end(); ++it) {
Polylines polylines = fill->fill_surface(Surface(stInternal, *it));
layer.infill.append(polylines, templ);
}
}
// Generate perimeter(s).
layer.perimeters << diff_ex(
layer.slices,
offset(layer.slices, -scale_(shell_thickness))
);
}
void
SLAPrint::write_svg(const std::string &outputfile) const
{
const Sizef3 size = this->bb.size();
const double support_material_radius = sm_pillars_radius();
FILE* f = fopen(outputfile.c_str(), "w");
fprintf(f,
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
"<svg width=\"%f\" height=\"%f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:slic3r=\"http://slic3r.org/namespaces/slic3r\" viewport-fill=\"black\">\n"
"<!-- Generated using Slic3r %s http://slic3r.org/ -->\n"
, size.x, size.y, SLIC3R_VERSION);
for (size_t i = 0; i < this->layers.size(); ++i) {
const Layer &layer = this->layers[i];
fprintf(f,
"\t<g id=\"layer%zu\" slic3r:z=\"%0.4f\" slic3r:slice-z=\"%0.4f\" slic3r:layer-height=\"%0.4f\">\n",
i,
layer.print_z,
layer.slice_z,
layer.print_z - ((i == 0) ? 0. : this->layers[i-1].print_z)
);
if (layer.solid) {
const ExPolygons &slices = layer.slices.expolygons;
for (ExPolygons::const_iterator it = slices.begin(); it != slices.end(); ++it) {
std::string pd = this->_SVG_path_d(*it);
fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:area=\"%0.4f\" />\n",
pd.c_str(), "white", "black", "0", unscale(unscale(it->area()))
);
}
} else {
// Perimeters.
for (ExPolygons::const_iterator it = layer.perimeters.expolygons.begin();
it != layer.perimeters.expolygons.end(); ++it) {
std::string pd = this->_SVG_path_d(*it);
fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"perimeter\" />\n",
pd.c_str(), "white", "black", "0"
);
}
// Solid infill.
for (ExPolygons::const_iterator it = layer.solid_infill.expolygons.begin();
it != layer.solid_infill.expolygons.end(); ++it) {
std::string pd = this->_SVG_path_d(*it);
fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n",
pd.c_str(), "white", "black", "0"
);
}
// Internal infill.
for (ExtrusionEntitiesPtr::const_iterator it = layer.infill.entities.begin();
it != layer.infill.entities.end(); ++it) {
const ExPolygons infill = union_ex((*it)->grow());
for (ExPolygons::const_iterator e = infill.begin(); e != infill.end(); ++e) {
std::string pd = this->_SVG_path_d(*e);
fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n",
pd.c_str(), "white", "black", "0"
);
}
}
}
// don't print support material in raft layers
if (i >= (size_t)this->config.raft_layers) {
// look for support material pillars belonging to this layer
for (std::vector<SupportPillar>::const_iterator it = this->sm_pillars.begin(); it != this->sm_pillars.end(); ++it) {
if (!(it->top_layer >= i && it->bottom_layer <= i)) continue;
// generate a conic tip
float radius = fminf(
support_material_radius,
(it->top_layer - i + 1) * this->config.layer_height.value
);
fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n",
unscale(it->x) - this->bb.min.x,
size.y - (unscale(it->y) - this->bb.min.y),
radius
);
}
}
fprintf(f,"\t</g>\n");
}
fprintf(f,"</svg>\n");
}
coordf_t
SLAPrint::sm_pillars_radius() const
{
coordf_t radius = this->config.support_material_extrusion_width.get_abs_value(this->config.support_material_spacing)/2;
if (radius == 0) radius = this->config.support_material_spacing / 3; // auto
return radius;
}
std::string
SLAPrint::_SVG_path_d(const Polygon &polygon) const
{
const Sizef3 size = this->bb.size();
std::ostringstream d;
d << "M ";
for (Points::const_iterator p = polygon.points.begin(); p != polygon.points.end(); ++p) {
d << unscale(p->x) - this->bb.min.x << " ";
d << size.y - (unscale(p->y) - this->bb.min.y) << " "; // mirror Y coordinates as SVG uses downwards Y
}
d << "z";
return d.str();
}
std::string
SLAPrint::_SVG_path_d(const ExPolygon &expolygon) const
{
std::string pd;
const Polygons pp = expolygon;
for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp)
pd += this->_SVG_path_d(*mp) + " ";
return pd;
}
}