Better support material in SVG export with conic tips

This commit is contained in:
Alessandro Ranellucci 2016-11-22 18:07:07 +01:00
parent bca95a98c8
commit 0a15af5488
2 changed files with 85 additions and 22 deletions

View File

@ -42,41 +42,83 @@ SVGExport::writeSVG(const std::string &outputfile)
TriangleMeshSlicer(&this->mesh).slice(slice_z, &layers); TriangleMeshSlicer(&this->mesh).slice(slice_z, &layers);
// generate support material // generate support material
std::vector<Points> support_material(layers.size()); std::vector<SupportPillar> sm_pillars;
ExPolygons overhangs;
if (this->config.support_material) { if (this->config.support_material) {
// generate a grid of points according to the configured spacing, // flatten and merge all the overhangs
// covering the entire object bounding box {
Points support_material_points; Polygons pp;
for (coordf_t x = bb.min.x; x <= bb.max.x; x += this->config.support_material_spacing) { for (std::vector<ExPolygons>::const_iterator it = layers.begin()+1; it != layers.end(); ++it) {
for (coordf_t y = bb.min.y; y <= bb.max.y; y += this->config.support_material_spacing) { Polygons oh = diff(*it, *(it - 1));
support_material_points.push_back(Point(scale_(x), scale_(y))); pp.insert(pp.end(), oh.begin(), oh.end());
}
overhangs = union_ex(pp);
}
// generate points following the shape of each island
Points pillars_pos;
const float spacing = scale_(this->config.support_material_spacing);
for (ExPolygons::const_iterator it = overhangs.begin(); it != overhangs.end(); ++it) {
for (float inset = -spacing/2; 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);
}
} }
} }
// check overhangs, starting from the upper layer, and detect which points apply // for each pillar, check which layers it applies to
// to each layer for (Points::const_iterator p = pillars_pos.begin(); p != pillars_pos.end(); ++p) {
ExPolygons overhangs; SupportPillar pillar(*p);
for (int i = layer_z.size()-1; i >= 0; --i) { bool object_hit = false;
overhangs = diff_ex(union_(overhangs, layers[i+1]), layers[i]);
for (Points::const_iterator it = support_material_points.begin(); it != support_material_points.end(); ++it) { // check layers top-down
for (ExPolygons::const_iterator e = overhangs.begin(); e != overhangs.end(); ++e) { for (int i = layer_z.size()-1; i >= 0; --i) {
if (e->contains(*it)) { // check whether point is void in this layer
support_material[i].push_back(*it); bool is_void = true;
for (ExPolygons::const_iterator it = layers[i].begin(); it != layers[i].end(); ++it) {
if (it->contains(*p)) {
is_void = false;
break; break;
} }
} }
if (is_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
sm_pillars.push_back(pillar);
pillar = SupportPillar(*p);
}
object_hit = true;
}
} }
if (pillar.top_layer > 0) sm_pillars.push_back(pillar);
} }
} }
// generate a solid raft if requested // generate a solid raft if requested
// (do this after support material because we take support material shape into account) // (do this after support material because we take support material shape into account)
if (this->config.raft_layers > 0) { if (this->config.raft_layers > 0) {
ExPolygons raft = offset_ex(layers.front(), scale_(this->config.raft_offset)); ExPolygons raft = layers.front();
raft.insert(raft.end(), overhangs.begin(), overhangs.end()); // take support material into account
raft = offset_ex(raft, scale_(this->config.raft_offset));
for (int i = this->config.raft_layers; i >= 1; --i) { for (int i = this->config.raft_layers; i >= 1; --i) {
layer_z.insert(layer_z.begin(), first_lh + lh * (i-1)); layer_z.insert(layer_z.begin(), first_lh + lh * (i-1));
layers.insert(layers.begin(), raft); layers.insert(layers.begin(), raft);
support_material.insert(support_material.begin(), Points()); // no support on this layer, we have raft
} }
// prepend total raft height to all sliced layers // prepend total raft height to all sliced layers
@ -113,11 +155,25 @@ SVGExport::writeSVG(const std::string &outputfile)
pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) pd.c_str(), "white", "black", "0", unscale(unscale(it->area()))
); );
} }
for (Points::const_iterator it = support_material[i].begin(); it != support_material[i].end(); ++it) {
fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n", // don't print support material in raft layers
unscale(it->x), unscale(it->y), support_material_radius if (i >= this->config.raft_layers) {
); // look for support material pillars belonging to this layer
for (std::vector<SupportPillar>::const_iterator it = sm_pillars.begin(); it != 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) * lh
);
fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n",
unscale(it->x), unscale(it->y), radius
);
}
} }
fprintf(f,"\t</g>\n"); fprintf(f,"\t</g>\n");
} }
fprintf(f,"</svg>\n"); fprintf(f,"</svg>\n");

View File

@ -19,6 +19,13 @@ class SVGExport
this->mesh.mirror_x(); this->mesh.mirror_x();
}; };
void writeSVG(const std::string &outputfile); void writeSVG(const std::string &outputfile);
private:
class SupportPillar : public Point {
public:
size_t top_layer, bottom_layer;
SupportPillar(const Point &p) : Point(p), top_layer(0), bottom_layer(0) {};
};
}; };
} }