4e11552da9
Fixes Connecting / expanding Bottom Layers to Vase Perimeter #253 Fixes Slicing error in vase mode #452 Fixes Slicing Issue (Vase Mode, 0.6mm dmr nozzle) #1887 Fixes Top fill pattern isn't used in spiral vase mode #2533 Fixes Cisar's vase doesn't slice correctly, creates artefacts #3595 When the model is sliced, all the contours are newly oriented counter-clockwise (even holes), merged and then only the largest area contour is retained. In perimeter generator, if the largest contour splits into multiple perimeters, newly only the largest area perimeter is retained in spiral vase mode. These two changes solve #3595 and similar. The infill is newly calculated only for the bottom solid layers if the spiral vase mode is active (removes various unwanted infill along the vase walls), and the last bottom solid layer is switched to a top solid pattern (solves #2533). The thin walls are newly enforced to be disabled in spiral vase mode, and the "ensure vertical shell wall" is enforced in spiral vase mode to extend the bottom of the vase to the vase hull (fixes #253).
88 lines
3.2 KiB
C++
88 lines
3.2 KiB
C++
#include "SpiralVase.hpp"
|
||
#include "GCode.hpp"
|
||
#include <sstream>
|
||
|
||
namespace Slic3r {
|
||
|
||
std::string SpiralVase::process_layer(const std::string &gcode)
|
||
{
|
||
/* This post-processor relies on several assumptions:
|
||
- all layers are processed through it, including those that are not supposed
|
||
to be transformed, in order to update the reader with the XY positions
|
||
- each call to this method includes a full layer, with a single Z move
|
||
at the beginning
|
||
- each layer is composed by suitable geometry (i.e. a single complete loop)
|
||
- loops were not clipped before calling this method */
|
||
|
||
// If we're not going to modify G-code, just feed it to the reader
|
||
// in order to update positions.
|
||
if (! this->enable) {
|
||
m_reader.parse_buffer(gcode);
|
||
return gcode;
|
||
}
|
||
|
||
// Get total XY length for this layer by summing all extrusion moves.
|
||
float total_layer_length = 0;
|
||
float layer_height = 0;
|
||
float z = 0.f;
|
||
bool set_z = false;
|
||
|
||
{
|
||
//FIXME Performance warning: This copies the GCodeConfig of the reader.
|
||
GCodeReader r = m_reader; // clone
|
||
r.parse_buffer(gcode, [&total_layer_length, &layer_height, &z, &set_z]
|
||
(GCodeReader &reader, const GCodeReader::GCodeLine &line) {
|
||
if (line.cmd_is("G1")) {
|
||
if (line.extruding(reader)) {
|
||
total_layer_length += line.dist_XY(reader);
|
||
} else if (line.has(Z)) {
|
||
layer_height += line.dist_Z(reader);
|
||
if (!set_z) {
|
||
z = line.new_Z(reader);
|
||
set_z = true;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// Remove layer height from initial Z.
|
||
z -= layer_height;
|
||
|
||
std::string new_gcode;
|
||
m_reader.parse_buffer(gcode, [&new_gcode, &z, &layer_height, &total_layer_length]
|
||
(GCodeReader &reader, GCodeReader::GCodeLine line) {
|
||
if (line.cmd_is("G1")) {
|
||
if (line.has_z()) {
|
||
// If this is the initial Z move of the layer, replace it with a
|
||
// (redundant) move to the last Z of previous layer.
|
||
line.set(reader, Z, z);
|
||
new_gcode += line.raw() + '\n';
|
||
return;
|
||
} else {
|
||
float dist_XY = line.dist_XY(reader);
|
||
if (dist_XY > 0) {
|
||
// horizontal move
|
||
if (line.extruding(reader)) {
|
||
z += dist_XY * layer_height / total_layer_length;
|
||
line.set(reader, Z, z);
|
||
new_gcode += line.raw() + '\n';
|
||
}
|
||
return;
|
||
|
||
/* Skip travel moves: the move to first perimeter point will
|
||
cause a visible seam when loops are not aligned in XY; by skipping
|
||
it we blend the first loop move in the XY plane (although the smoothness
|
||
of such blend depend on how long the first segment is; maybe we should
|
||
enforce some minimum length?). */
|
||
}
|
||
}
|
||
}
|
||
new_gcode += line.raw() + '\n';
|
||
});
|
||
|
||
return new_gcode;
|
||
}
|
||
|
||
}
|