mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-13 02:41:16 +00:00
* Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced Generated with include-what-you-use and applied conservatively. Only OrcaSlicer's own headers, the ones under src/ and tests/, are removed or forward-declared; standard-library and third-party includes are left alone. An include is removed only when both the Release and the Debug configuration leave it unused, never from inside a conditional block, and never from a file with platform-specific blocks, which only gain includes. Files whose only use of a header sits behind a feature or debug macro (libvgcode's OpenGL ES and marker code, the ARACHNE/TESTS_EXPORT_SVGS debug output) keep their includes. clonable_ptr.hpp gains #pragma once; it had no include guard and was only safe while Config.hpp was its sole includer. * Remove Unused Project Includes From Files With Platform-Specific Code A Linux include-what-you-use run cannot see the code inside _WIN32, __APPLE__ or __linux__ blocks, so its verdict is only taken where nothing the removed header declares, directly or through what it includes, is named inside those blocks. Removals also have to hold in both the Release and Debug configuration and never touch a line inside a conditional block. * Restore the libslic3r Precompiled Header and Direct Includes Lost in the Platform Pass The platform-file pass treated pchheader.hpp as an ordinary header and emptied it, and left GUI_Preview.hpp and 14 other files relying on headers they no longer reached directly. * Restore MainFrame.hpp in ParamsDialog.cpp for the Windows-Only Reparent Call * Include Headers That Files Reached Through Ones the Cleanup Removed * Drop Includes Duplicated by the Cleanup or by Main's Own Additions * Leave PreciseSeam.cpp as Main Has It After the Precise Seam Rework
225 lines
11 KiB
C++
225 lines
11 KiB
C++
#include "SpiralVase.hpp"
|
||
#include "libslic3r/libslic3r.h"
|
||
#include <algorithm>
|
||
#include <cstddef>
|
||
#include <sstream>
|
||
#include <cmath>
|
||
#include <limits>
|
||
#include <vector>
|
||
#include <string>
|
||
#include "libslic3r/GCodeReader.hpp"
|
||
#include "libslic3r/PrintConfig.hpp"
|
||
|
||
namespace Slic3r {
|
||
|
||
namespace SpiralVaseHelpers {
|
||
/** == Smooth Spiral Helpers == */
|
||
/** Distance between a and b */
|
||
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b) { return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2)); }
|
||
|
||
SpiralVase::SpiralPoint subtract(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
|
||
{
|
||
return SpiralVase::SpiralPoint(a.x - b.x, a.y - b.y);
|
||
}
|
||
|
||
SpiralVase::SpiralPoint add(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b) { return SpiralVase::SpiralPoint(a.x + b.x, a.y + b.y); }
|
||
|
||
SpiralVase::SpiralPoint scale(SpiralVase::SpiralPoint a, float factor) { return SpiralVase::SpiralPoint(a.x * factor, a.y * factor); }
|
||
|
||
/** dot product */
|
||
float dot(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b) { return a.x * b.x + a.y * b.y; }
|
||
|
||
/** Find the point on line ab closes to point c */
|
||
SpiralVase::SpiralPoint nearest_point_on_line(SpiralVase::SpiralPoint c, SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b, float& dist)
|
||
{
|
||
SpiralVase::SpiralPoint ab = subtract(b, a);
|
||
SpiralVase::SpiralPoint ca = subtract(c, a);
|
||
float t = dot(ca, ab) / dot(ab, ab);
|
||
t = t > 1 ? 1 : t;
|
||
t = t < 0 ? 0 : t;
|
||
SpiralVase::SpiralPoint closest = SpiralVase::SpiralPoint(add(a, scale(ab, t)));
|
||
dist = distance(c, closest);
|
||
return closest;
|
||
}
|
||
|
||
/** Given a set of lines defined by points such as line[n] is the line from points[n] to points[n+1],
|
||
* find the closest point to p that falls on any of the lines */
|
||
SpiralVase::SpiralPoint nearest_point_on_lines(SpiralVase::SpiralPoint p,
|
||
std::vector<SpiralVase::SpiralPoint>* points,
|
||
bool& found,
|
||
float& dist)
|
||
{
|
||
if (points->size() < 2) {
|
||
found = false;
|
||
return SpiralVase::SpiralPoint(0, 0);
|
||
}
|
||
float min = std::numeric_limits<float>::max();
|
||
SpiralVase::SpiralPoint closest(0, 0);
|
||
for (unsigned long i = 0; i < points->size() - 1; i++) {
|
||
float currentDist = 0;
|
||
SpiralVase::SpiralPoint current = nearest_point_on_line(p, points->at(i), points->at(i + 1), currentDist);
|
||
if (currentDist < min) {
|
||
min = currentDist;
|
||
closest = current;
|
||
found = true;
|
||
}
|
||
}
|
||
dist = min;
|
||
return closest;
|
||
}
|
||
} // namespace SpiralVase
|
||
|
||
std::string SpiralVase::process_layer(const std::string &gcode, bool last_layer)
|
||
{
|
||
/* 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 (! m_enabled) {
|
||
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;
|
||
|
||
{
|
||
//FIXME Performance warning: This copies the GCodeConfig of the reader.
|
||
GCodeReader r = m_reader; // clone
|
||
bool set_z = false;
|
||
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::vector<SpiralVase::SpiralPoint>* current_layer = new std::vector<SpiralVase::SpiralPoint>();
|
||
std::vector<SpiralVase::SpiralPoint>* previous_layer = m_previous_layer;
|
||
|
||
bool smooth_spiral = m_smooth_spiral;
|
||
std::string new_gcode;
|
||
std::string transition_gcode;
|
||
float max_xy_dist_for_smoothing = m_max_xy_smoothing;
|
||
//FIXME Tapering of the transition layer only works reliably with relative extruder distances.
|
||
// For absolute extruder distances it will be switched off.
|
||
// Tapering the absolute extruder distances requires to process every extrusion value after the first transition
|
||
// layer.
|
||
bool transition_in = m_transition_layer && m_config.use_relative_e_distances.value;
|
||
bool transition_out = last_layer && m_config.use_relative_e_distances.value;
|
||
|
||
float starting_flowrate = float(m_config.spiral_starting_flow_ratio.value);
|
||
float finishing_flowrate = float(m_config.spiral_finishing_flow_ratio.value);
|
||
const float min_segment_length = std::max(float(EPSILON), 2 * float(m_config.resolution.value));
|
||
|
||
float len = 0.f;
|
||
SpiralVase::SpiralPoint last_point = previous_layer != NULL && previous_layer->size() >0? previous_layer->at(previous_layer->size()-1): SpiralVase::SpiralPoint(0,0);
|
||
m_reader.parse_buffer(gcode, [&new_gcode, &z, total_layer_length, layer_height, transition_in, &len, ¤t_layer, &previous_layer, &transition_gcode, transition_out, smooth_spiral, &max_xy_dist_for_smoothing, &last_point, starting_flowrate, finishing_flowrate, min_segment_length]
|
||
(GCodeReader &reader, GCodeReader::GCodeLine line) {
|
||
if (line.cmd_is("G1")) {
|
||
// Orca: Filter out retractions at layer change
|
||
if (line.retracting(reader) || (line.extruding(reader) && line.dist_XY(reader) < min_segment_length)) return;
|
||
if (line.has_z() && !(line.has_x() || line.has_y())) {
|
||
// 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(Z, z);
|
||
new_gcode += line.raw() + '\n';
|
||
return;
|
||
} else {
|
||
float dist_XY = line.dist_XY(reader);
|
||
if (line.has_x() || line.has_y()) { // Sometimes lines have X/Y but the move is to the last position
|
||
if (dist_XY > 0 && line.extruding(reader)) { // Exclude wipe and retract
|
||
len += dist_XY;
|
||
float factor = len / total_layer_length;
|
||
if (transition_in){
|
||
// Transition layer, interpolate the amount of extrusion starting from spiral_vase_starting_flow_rate to 100%.
|
||
float starting_e_factor = starting_flowrate + (factor * (1.f - starting_flowrate));
|
||
line.set(E, line.e() * starting_e_factor, 5 /*decimal_digits*/);
|
||
} else if (transition_out) {
|
||
// We want the last layer to ramp down extrusion, but without changing z height!
|
||
// So clone the line before we mess with its Z and duplicate it into a new layer that ramps down E
|
||
// We add this new layer at the very end
|
||
// As with transition_in, the amount is ramped down from 100% to spiral_vase_finishing_flow_rate
|
||
GCodeReader::GCodeLine transitionLine(line);
|
||
float finishing_e_factor = finishing_flowrate + ((1.f -factor) * (1.f - finishing_flowrate));
|
||
transitionLine.set(E, line.e() * finishing_e_factor, 5 /*decimal_digits*/);
|
||
transition_gcode += transitionLine.raw() + '\n';
|
||
}
|
||
// This line is the core of Spiral Vase mode, ramp up the Z smoothly
|
||
line.set(Z, z + factor * layer_height);
|
||
if (smooth_spiral) {
|
||
// Now we also need to try to interpolate X and Y
|
||
SpiralVase::SpiralPoint p(line.x(), line.y()); // Get current x/y coordinates
|
||
current_layer->push_back(p); // Store that point for later use on the next layer
|
||
if (previous_layer != NULL) {
|
||
bool found = false;
|
||
float dist = 0;
|
||
SpiralVase::SpiralPoint nearestp = SpiralVaseHelpers::nearest_point_on_lines(p, previous_layer, found, dist);
|
||
if (found && dist < max_xy_dist_for_smoothing) {
|
||
// Interpolate between the point on this layer and the point on the previous layer
|
||
SpiralVase::SpiralPoint target = SpiralVaseHelpers::add(SpiralVaseHelpers::scale(nearestp, 1 - factor), SpiralVaseHelpers::scale(p, factor));
|
||
|
||
// Remove tiny movement
|
||
// We need to figure out the distance of this new line!
|
||
float modified_dist_XY = SpiralVaseHelpers::distance(last_point, target);
|
||
if (modified_dist_XY < min_segment_length)
|
||
line.clear();
|
||
else {
|
||
line.set(X, target.x);
|
||
line.set(Y, target.y);
|
||
// Scale the extrusion amount according to change in length
|
||
line.set(E, line.e() * modified_dist_XY / dist_XY, 5 /*decimal_digits*/);
|
||
last_point = target;
|
||
}
|
||
} else {
|
||
last_point = p;
|
||
}
|
||
}
|
||
}
|
||
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?).
|
||
When smooth_spiral is enabled, we're gonna end up exactly where the next layer should
|
||
start anyway, so we don't need the travel move */
|
||
}
|
||
}
|
||
}
|
||
new_gcode += line.raw() + '\n';
|
||
if(transition_out) {
|
||
transition_gcode += line.raw() + '\n';
|
||
}
|
||
});
|
||
|
||
delete m_previous_layer;
|
||
m_previous_layer = current_layer;
|
||
|
||
return new_gcode + transition_gcode;
|
||
}
|
||
|
||
}
|