Merged with dev

This commit is contained in:
bubnikv
2018-09-12 11:59:02 +02:00
1491 changed files with 514153 additions and 29226 deletions

View File

@@ -14,7 +14,7 @@ static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
static const float INCHES_TO_MM = 25.4f;
static const float DEFAULT_FEEDRATE = 0.0f;
static const unsigned int DEFAULT_EXTRUDER_ID = 0;
static const Slic3r::Pointf3 DEFAULT_START_POSITION = Slic3r::Pointf3(0.0f, 0.0f, 0.0f);
static const Slic3r::Vec3d DEFAULT_START_POSITION = Slic3r::Vec3d(0.0f, 0.0f, 0.0f);
static const float DEFAULT_START_EXTRUSION = 0.0f;
namespace Slic3r {
@@ -71,7 +71,7 @@ bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other)
return false;
}
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder)
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder)
: type(type)
, data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate)
, start_position(start_position)
@@ -80,7 +80,7 @@ GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusi
{
}
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder)
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder)
: type(type)
, data(data)
, start_position(start_position)
@@ -97,8 +97,8 @@ GCodeAnalyzer::GCodeAnalyzer()
void GCodeAnalyzer::reset()
{
_set_units(Millimeters);
_set_positioning_xyz_type(Absolute);
_set_positioning_e_type(Relative);
_set_global_positioning_type(Absolute);
_set_e_local_positioning_type(Absolute);
_set_extrusion_role(erNone);
_set_extruder_id(DEFAULT_EXTRUDER_ID);
_set_mm3_per_mm(Default_mm3_per_mm);
@@ -177,6 +177,16 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi
_processG1(line);
break;
}
case 10: // Retract
{
_processG10(line);
break;
}
case 11: // Unretract
{
_processG11(line);
break;
}
case 22: // Firmware controlled Retract
{
_processG22(line);
@@ -237,13 +247,13 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi
}
// Returns the new absolute position on the given axis in dependence of the given parameters
float axis_absolute_position_from_G1_line(GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeAnalyzer::EUnits units, GCodeAnalyzer::EPositioningType type, float current_absolute_position)
float axis_absolute_position_from_G1_line(GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeAnalyzer::EUnits units, bool is_relative, float current_absolute_position)
{
float lengthsScaleFactor = (units == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f;
if (lineG1.has(Slic3r::Axis(axis)))
{
float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
return (type == GCodeAnalyzer::Absolute) ? ret : current_absolute_position + ret;
return is_relative ? current_absolute_position + ret : ret;
}
else
return current_absolute_position;
@@ -256,7 +266,11 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
float new_pos[Num_Axis];
for (unsigned char a = X; a < Num_Axis; ++a)
{
new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, (a == E) ? _get_positioning_e_type() : _get_positioning_xyz_type(), _get_axis_position((EAxis)a));
bool is_relative = (_get_global_positioning_type() == Relative);
if (a == E)
is_relative |= (_get_e_local_positioning_type() == Relative);
new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, is_relative, _get_axis_position((EAxis)a));
}
// updates feedrate from line, if present
@@ -305,6 +319,18 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
_store_move(type);
}
void GCodeAnalyzer::_processG10(const GCodeReader::GCodeLine& line)
{
// stores retract move
_store_move(GCodeMove::Retract);
}
void GCodeAnalyzer::_processG11(const GCodeReader::GCodeLine& line)
{
// stores unretract move
_store_move(GCodeMove::Unretract);
}
void GCodeAnalyzer::_processG22(const GCodeReader::GCodeLine& line)
{
// stores retract move
@@ -319,12 +345,12 @@ void GCodeAnalyzer::_processG23(const GCodeReader::GCodeLine& line)
void GCodeAnalyzer::_processG90(const GCodeReader::GCodeLine& line)
{
_set_positioning_xyz_type(Absolute);
_set_global_positioning_type(Absolute);
}
void GCodeAnalyzer::_processG91(const GCodeReader::GCodeLine& line)
{
_set_positioning_xyz_type(Relative);
_set_global_positioning_type(Relative);
}
void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
@@ -367,12 +393,12 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
void GCodeAnalyzer::_processM82(const GCodeReader::GCodeLine& line)
{
_set_positioning_e_type(Absolute);
_set_e_local_positioning_type(Absolute);
}
void GCodeAnalyzer::_processM83(const GCodeReader::GCodeLine& line)
{
_set_positioning_e_type(Relative);
_set_e_local_positioning_type(Relative);
}
void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line)
@@ -466,24 +492,24 @@ GCodeAnalyzer::EUnits GCodeAnalyzer::_get_units() const
return m_state.units;
}
void GCodeAnalyzer::_set_positioning_xyz_type(GCodeAnalyzer::EPositioningType type)
void GCodeAnalyzer::_set_global_positioning_type(GCodeAnalyzer::EPositioningType type)
{
m_state.positioning_xyz_type = type;
m_state.global_positioning_type = type;
}
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_positioning_xyz_type() const
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_global_positioning_type() const
{
return m_state.positioning_xyz_type;
return m_state.global_positioning_type;
}
void GCodeAnalyzer::_set_positioning_e_type(GCodeAnalyzer::EPositioningType type)
void GCodeAnalyzer::_set_e_local_positioning_type(GCodeAnalyzer::EPositioningType type)
{
m_state.positioning_e_type = type;
m_state.e_local_positioning_type = type;
}
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_positioning_e_type() const
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_e_local_positioning_type() const
{
return m_state.positioning_e_type;
return m_state.e_local_positioning_type;
}
void GCodeAnalyzer::_set_extrusion_role(ExtrusionRole extrusion_role)
@@ -561,12 +587,12 @@ void GCodeAnalyzer::_reset_axes_position()
::memset((void*)m_state.position, 0, Num_Axis * sizeof(float));
}
void GCodeAnalyzer::_set_start_position(const Pointf3& position)
void GCodeAnalyzer::_set_start_position(const Vec3d& position)
{
m_state.start_position = position;
}
const Pointf3& GCodeAnalyzer::_get_start_position() const
const Vec3d& GCodeAnalyzer::_get_start_position() const
{
return m_state.start_position;
}
@@ -586,9 +612,9 @@ float GCodeAnalyzer::_get_delta_extrusion() const
return _get_axis_position(E) - m_state.start_extrusion;
}
Pointf3 GCodeAnalyzer::_get_end_position() const
Vec3d GCodeAnalyzer::_get_end_position() const
{
return Pointf3(m_state.position[X], m_state.position[Y], m_state.position[Z]);
return Vec3d(m_state.position[X], m_state.position[Y], m_state.position[Z]);
}
void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
@@ -647,15 +673,17 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
Metadata data;
float z = FLT_MAX;
Polyline polyline;
Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX);
Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
float volumetric_rate = FLT_MAX;
GCodePreviewData::Range height_range;
GCodePreviewData::Range width_range;
GCodePreviewData::Range feedrate_range;
GCodePreviewData::Range volumetric_rate_range;
// constructs the polylines while traversing the moves
for (const GCodeMove& move : extrude_moves->second)
{
if ((data != move.data) || (data.feedrate != move.data.feedrate) || (z != move.start_position.z) || (position != move.start_position))
if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm))
{
// store current polyline
polyline.remove_duplicate_points();
@@ -665,19 +693,21 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
polyline = Polyline();
// add both vertices of the move
polyline.append(Point(scale_(move.start_position.x), scale_(move.start_position.y)));
polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y)));
polyline.append(Point(scale_(move.start_position.x()), scale_(move.start_position.y())));
polyline.append(Point(scale_(move.end_position.x()), scale_(move.end_position.y())));
// update current values
data = move.data;
z = move.start_position.z;
z = move.start_position.z();
volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
height_range.update_from(move.data.height);
width_range.update_from(move.data.width);
feedrate_range.update_from(move.data.feedrate);
volumetric_rate_range.update_from(volumetric_rate);
}
else
// append end vertex of the move to current polyline
polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y)));
polyline.append(Point(scale_(move.end_position.x()), scale_(move.end_position.y())));
// update current values
position = move.end_position;
@@ -688,9 +718,10 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
Helper::store_polyline(polyline, data, z, preview_data);
// updates preview ranges data
preview_data.extrusion.ranges.height.set_from(height_range);
preview_data.extrusion.ranges.width.set_from(width_range);
preview_data.extrusion.ranges.feedrate.set_from(feedrate_range);
preview_data.ranges.height.update_from(height_range);
preview_data.ranges.width.update_from(width_range);
preview_data.ranges.feedrate.update_from(feedrate_range);
preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range);
}
void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
@@ -711,17 +742,21 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
return;
Polyline3 polyline;
Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX);
Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types;
GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions;
float feedrate = FLT_MAX;
unsigned int extruder_id = -1;
GCodePreviewData::Range height_range;
GCodePreviewData::Range width_range;
GCodePreviewData::Range feedrate_range;
// constructs the polylines while traversing the moves
for (const GCodeMove& move : travel_moves->second)
{
GCodePreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? GCodePreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? GCodePreviewData::Travel::Extrude : GCodePreviewData::Travel::Move);
GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x != move.end_position.x) || (move.start_position.y != move.end_position.y)) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical;
GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x() != move.end_position.x()) || (move.start_position.y() != move.end_position.y())) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical;
if ((type != move_type) || (direction != move_direction) || (feedrate != move.data.feedrate) || (position != move.start_position) || (extruder_id != move.data.extruder_id))
{
@@ -733,23 +768,31 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
polyline = Polyline3();
// add both vertices of the move
polyline.append(Point3(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)));
polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z)));
polyline.append(Vec3crd(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())));
polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
}
else
// append end vertex of the move to current polyline
polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z)));
polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
// update current values
position = move.end_position;
type = move_type;
feedrate = move.data.feedrate;
extruder_id = move.data.extruder_id;
height_range.update_from(move.data.height);
width_range.update_from(move.data.width);
feedrate_range.update_from(move.data.feedrate);
}
// store last polyline
polyline.remove_duplicate_points();
Helper::store_polyline(polyline, type, direction, feedrate, extruder_id, preview_data);
// updates preview ranges data
preview_data.ranges.height.update_from(height_range);
preview_data.ranges.width.update_from(width_range);
preview_data.ranges.feedrate.update_from(feedrate_range);
}
void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data)
@@ -761,7 +804,7 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da
for (const GCodeMove& move : retraction_moves->second)
{
// store position
Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z));
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
}
}
@@ -775,7 +818,7 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_
for (const GCodeMove& move : unretraction_moves->second)
{
// store position
Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z));
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
}
}

View File

@@ -75,12 +75,12 @@ public:
EType type;
Metadata data;
Pointf3 start_position;
Pointf3 end_position;
Vec3d start_position;
Vec3d end_position;
float delta_extruder;
GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder);
GCodeMove(EType type, const Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder);
GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder);
GCodeMove(EType type, const Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder);
};
typedef std::vector<GCodeMove> GCodeMovesList;
@@ -90,10 +90,10 @@ private:
struct State
{
EUnits units;
EPositioningType positioning_xyz_type;
EPositioningType positioning_e_type;
EPositioningType global_positioning_type;
EPositioningType e_local_positioning_type;
Metadata data;
Pointf3 start_position;
Vec3d start_position = Vec3d::Zero();
float start_extrusion;
float position[Num_Axis];
};
@@ -127,6 +127,12 @@ private:
// Move
void _processG1(const GCodeReader::GCodeLine& line);
// Retract
void _processG10(const GCodeReader::GCodeLine& line);
// Unretract
void _processG11(const GCodeReader::GCodeLine& line);
// Firmware controlled Retract
void _processG22(const GCodeReader::GCodeLine& line);
@@ -170,11 +176,11 @@ private:
void _set_units(EUnits units);
EUnits _get_units() const;
void _set_positioning_xyz_type(EPositioningType type);
EPositioningType _get_positioning_xyz_type() const;
void _set_global_positioning_type(EPositioningType type);
EPositioningType _get_global_positioning_type() const;
void _set_positioning_e_type(EPositioningType type);
EPositioningType _get_positioning_e_type() const;
void _set_e_local_positioning_type(EPositioningType type);
EPositioningType _get_e_local_positioning_type() const;
void _set_extrusion_role(ExtrusionRole extrusion_role);
ExtrusionRole _get_extrusion_role() const;
@@ -200,15 +206,15 @@ private:
// Sets axes position to zero
void _reset_axes_position();
void _set_start_position(const Pointf3& position);
const Pointf3& _get_start_position() const;
void _set_start_position(const Vec3d& position);
const Vec3d& _get_start_position() const;
void _set_start_extrusion(float extrusion);
float _get_start_extrusion() const;
float _get_delta_extrusion() const;
// Returns current xyz position (from m_state.position[])
Pointf3 _get_end_position() const;
Vec3d _get_end_position() const;
// Adds a new move with the given data
void _store_move(GCodeMove::EType type);

File diff suppressed because it is too large Load Diff

View File

@@ -9,13 +9,17 @@ namespace Slic3r {
class GCode;
class Layer;
class PerExtruderAdjustments;
/*
A standalone G-code filter, to control cooling of the print.
The G-code is processed per layer. Once a layer is collected, fan start / stop commands are edited
and the print is modified to stretch over a minimum layer time.
*/
// A standalone G-code filter, to control cooling of the print.
// The G-code is processed per layer. Once a layer is collected, fan start / stop commands are edited
// and the print is modified to stretch over a minimum layer time.
//
// The simple it sounds, the actual implementation is significantly more complex.
// Namely, for a multi-extruder print, each material may require a different cooling logic.
// For example, some materials may not like to print too slowly, while with some materials
// we may slow down significantly.
//
class CoolingBuffer {
public:
CoolingBuffer(GCode &gcodegen);
@@ -25,7 +29,12 @@ public:
GCode* gcodegen() { return &m_gcodegen; }
private:
CoolingBuffer& operator=(const CoolingBuffer&);
CoolingBuffer& operator=(const CoolingBuffer&) = delete;
std::vector<PerExtruderAdjustments> parse_layer_gcode(const std::string &gcode, std::vector<float> &current_pos) const;
float calculate_layer_slowdown(std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
// Apply slow down over G-code lines stored in per_extruder_adjustments, enable fan if needed.
// Returns the adjusted G-code.
std::string apply_layer_cooldown(const std::string &gcode, size_t layer_id, float layer_time, std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
GCode& m_gcodegen;
std::string m_gcode;
@@ -34,6 +43,9 @@ private:
std::vector<char> m_axis;
std::vector<float> m_current_pos;
unsigned int m_current_extruder;
// Old logic: proportional.
bool m_cooling_logic_proportional = false;
};
}

View File

@@ -2,7 +2,12 @@
#include "PreviewData.hpp"
#include <float.h>
#include <wx/intl.h>
#include "slic3r/GUI/GUI.hpp"
#include <I18N.hpp>
#include <boost/format.hpp>
//! macro used to mark string used at localization,
#define L(s) (s)
namespace Slic3r {
@@ -85,6 +90,12 @@ void GCodePreviewData::Range::update_from(float value)
max = std::max(max, value);
}
void GCodePreviewData::Range::update_from(const Range& other)
{
min = std::min(min, other.min);
max = std::max(max, other.max);
}
void GCodePreviewData::Range::set_from(const Range& other)
{
min = other.min;
@@ -93,17 +104,31 @@ void GCodePreviewData::Range::set_from(const Range& other)
float GCodePreviewData::Range::step_size() const
{
return (max - min) / (float)Colors_Count;
return (max - min) / (float)(Colors_Count - 1);
}
const GCodePreviewData::Color& GCodePreviewData::Range::get_color_at_max() const
GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const
{
return colors[Colors_Count - 1];
}
if (empty())
return Color::Dummy;
const GCodePreviewData::Color& GCodePreviewData::Range::get_color_at(float value) const
{
return empty() ? get_color_at_max() : colors[clamp((unsigned int)0, Colors_Count - 1, (unsigned int)((value - min) / step_size()))];
float global_t = (value - min) / step_size();
unsigned int low = (unsigned int)global_t;
unsigned int high = clamp((unsigned int)0, Colors_Count - 1, low + 1);
Color color_low = colors[low];
Color color_high = colors[high];
float local_t = global_t - (float)low;
// interpolate in RGB space
Color ret;
for (unsigned int i = 0; i < 4; ++i)
{
ret.rgba[i] = lerp(color_low.rgba[i], color_high.rgba[i], local_t);
}
return ret;
}
GCodePreviewData::LegendItem::LegendItem(const std::string& text, const GCodePreviewData::Color& color)
@@ -158,9 +183,6 @@ void GCodePreviewData::Extrusion::set_default()
view_type = Default_View_Type;
::memcpy((void*)role_colors, (const void*)Default_Extrusion_Role_Colors, Num_Extrusion_Roles * sizeof(Color));
::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
for (unsigned int i = 0; i < Num_Extrusion_Roles; ++i)
{
@@ -198,12 +220,13 @@ void GCodePreviewData::Travel::set_default()
width = Default_Width;
height = Default_Height;
::memcpy((void*)type_colors, (const void*)Default_Type_Colors, Num_Types * sizeof(Color));
is_visible = false;
}
const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
GCodePreviewData::Retraction::Position::Position(const Point3& position, float width, float height)
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
: position(position)
, width(width)
, height(height)
@@ -228,6 +251,11 @@ GCodePreviewData::GCodePreviewData()
void GCodePreviewData::set_default()
{
::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
::memcpy((void*)ranges.volumetric_rate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
extrusion.set_default();
travel.set_default();
retraction.set_default();
@@ -237,6 +265,10 @@ void GCodePreviewData::set_default()
void GCodePreviewData::reset()
{
ranges.width.reset();
ranges.height.reset();
ranges.feedrate.reset();
ranges.volumetric_rate.reset();
extrusion.layers.clear();
travel.polylines.clear();
retraction.positions.clear();
@@ -248,24 +280,29 @@ bool GCodePreviewData::empty() const
return extrusion.layers.empty() && travel.polylines.empty() && retraction.positions.empty() && unretraction.positions.empty();
}
const GCodePreviewData::Color& GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
GCodePreviewData::Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
{
return extrusion.role_colors[role];
}
const GCodePreviewData::Color& GCodePreviewData::get_extrusion_height_color(float height) const
GCodePreviewData::Color GCodePreviewData::get_height_color(float height) const
{
return extrusion.ranges.height.get_color_at(height);
return ranges.height.get_color_at(height);
}
const GCodePreviewData::Color& GCodePreviewData::get_extrusion_width_color(float width) const
GCodePreviewData::Color GCodePreviewData::get_width_color(float width) const
{
return extrusion.ranges.width.get_color_at(width);
return ranges.width.get_color_at(width);
}
const GCodePreviewData::Color& GCodePreviewData::get_extrusion_feedrate_color(float feedrate) const
GCodePreviewData::Color GCodePreviewData::get_feedrate_color(float feedrate) const
{
return extrusion.ranges.feedrate.get_color_at(feedrate);
return ranges.feedrate.get_color_at(feedrate);
}
GCodePreviewData::Color GCodePreviewData::get_volumetric_rate_color(float rate) const
{
return ranges.volumetric_rate.get_color_at(rate);
}
void GCodePreviewData::set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha)
@@ -334,6 +371,8 @@ std::string GCodePreviewData::get_legend_title() const
return L("Width (mm)");
case Extrusion::Feedrate:
return L("Speed (mm/s)");
case Extrusion::VolumetricRate:
return L("Volumetric flow rate (mm3/s)");
case Extrusion::Tool:
return L("Tool");
}
@@ -348,11 +387,12 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
static void FillListFromRange(LegendItemsList& list, const Range& range, unsigned int decimals, float scale_factor)
{
list.reserve(Range::Colors_Count);
float step = range.step_size();
for (unsigned int i = 0; i < Range::Colors_Count; ++i)
for (int i = Range::Colors_Count - 1; i >= 0; --i)
{
char buf[32];
sprintf(buf, "%.*f/%.*f", decimals, scale_factor * (range.min + (float)i * step), decimals, scale_factor * (range.min + (float)(i + 1) * step));
char buf[1024];
sprintf(buf, "%.*f", decimals, scale_factor * (range.min + (float)i * step));
list.emplace_back(buf, range.colors[i]);
}
}
@@ -370,24 +410,29 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
items.reserve(last_valid - first_valid + 1);
for (unsigned int i = (unsigned int)first_valid; i <= (unsigned int)last_valid; ++i)
{
items.emplace_back(_CHB(extrusion.role_names[i].c_str()).data(), extrusion.role_colors[i]);
items.emplace_back(Slic3r::I18N::translate(extrusion.role_names[i]), extrusion.role_colors[i]);
}
break;
}
case Extrusion::Height:
{
Helper::FillListFromRange(items, extrusion.ranges.height, 3, 1.0f);
Helper::FillListFromRange(items, ranges.height, 3, 1.0f);
break;
}
case Extrusion::Width:
{
Helper::FillListFromRange(items, extrusion.ranges.width, 3, 1.0f);
Helper::FillListFromRange(items, ranges.width, 3, 1.0f);
break;
}
case Extrusion::Feedrate:
{
Helper::FillListFromRange(items, extrusion.ranges.feedrate, 0, 1.0f);
Helper::FillListFromRange(items, ranges.feedrate, 1, 1.0f);
break;
}
case Extrusion::VolumetricRate:
{
Helper::FillListFromRange(items, ranges.volumetric_rate, 3, 1.0f);
break;
}
case Extrusion::Tool:
@@ -396,13 +441,9 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
items.reserve(tools_colors_count);
for (unsigned int i = 0; i < tools_colors_count; ++i)
{
char buf[MIN_BUF_LENGTH_FOR_L];
sprintf(buf, _CHB(L("Extruder %d")), i + 1);
GCodePreviewData::Color color;
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
items.emplace_back(buf, color);
items.emplace_back((boost::format(Slic3r::I18N::translate(L("Extruder %d"))) % (i + 1)).str(), color);
}
break;

View File

@@ -37,11 +37,19 @@ public:
void reset();
bool empty() const;
void update_from(float value);
void update_from(const Range& other);
void set_from(const Range& other);
float step_size() const;
const Color& get_color_at(float value) const;
const Color& get_color_at_max() const;
Color get_color_at(float value) const;
};
struct Ranges
{
Range height;
Range width;
Range feedrate;
Range volumetric_rate;
};
struct LegendItem
@@ -62,6 +70,7 @@ public:
Height,
Width,
Feedrate,
VolumetricRate,
Tool,
Num_View_Types
};
@@ -71,13 +80,6 @@ public:
static const std::string Default_Extrusion_Role_Names[Num_Extrusion_Roles];
static const EViewType Default_View_Type;
struct Ranges
{
Range height;
Range width;
Range feedrate;
};
struct Layer
{
float z;
@@ -91,7 +93,6 @@ public:
EViewType view_type;
Color role_colors[Num_Extrusion_Roles];
std::string role_names[Num_Extrusion_Roles];
Ranges ranges;
LayersList layers;
unsigned int role_flags;
@@ -150,11 +151,11 @@ public:
struct Position
{
Point3 position;
Vec3crd position;
float width;
float height;
Position(const Point3& position, float width, float height);
Position(const Vec3crd& position, float width, float height);
};
typedef std::vector<Position> PositionsList;
@@ -178,6 +179,7 @@ public:
Retraction retraction;
Retraction unretraction;
Shell shell;
Ranges ranges;
GCodePreviewData();
@@ -185,10 +187,11 @@ public:
void reset();
bool empty() const;
const Color& get_extrusion_role_color(ExtrusionRole role) const;
const Color& get_extrusion_height_color(float height) const;
const Color& get_extrusion_width_color(float width) const;
const Color& get_extrusion_feedrate_color(float feedrate) const;
Color get_extrusion_role_color(ExtrusionRole role) const;
Color get_height_color(float height) const;
Color get_width_color(float width) const;
Color get_feedrate_color(float feedrate) const;
Color get_volumetric_rate_color(float rate) const;
void set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha);
void set_extrusion_paths_colors(const std::vector<std::string>& colors);

View File

@@ -19,10 +19,10 @@ static inline BoundingBox extrusion_polyline_extents(const Polyline &polyline, c
if (! polyline.points.empty())
bbox.merge(polyline.points.front());
for (const Point &pt : polyline.points) {
bbox.min.x = std::min(bbox.min.x, pt.x - radius);
bbox.min.y = std::min(bbox.min.y, pt.y - radius);
bbox.max.x = std::max(bbox.max.x, pt.x + radius);
bbox.max.y = std::max(bbox.max.y, pt.y + radius);
bbox.min(0) = std::min(bbox.min(0), pt(0) - radius);
bbox.min(1) = std::min(bbox.min(1), pt(1) - radius);
bbox.max(0) = std::max(bbox.max(0), pt(0) + radius);
bbox.max(1) = std::max(bbox.max(1), pt(1) + radius);
}
return bbox;
}
@@ -32,8 +32,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionPath &extrusio
BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width));
BoundingBoxf bboxf;
if (! empty(bbox)) {
bboxf.min = Pointf::new_unscale(bbox.min);
bboxf.max = Pointf::new_unscale(bbox.max);
bboxf.min = unscale(bbox.min);
bboxf.max = unscale(bbox.max);
bboxf.defined = true;
}
return bboxf;
@@ -46,8 +46,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionLoop &extrusio
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
BoundingBoxf bboxf;
if (! empty(bbox)) {
bboxf.min = Pointf::new_unscale(bbox.min);
bboxf.max = Pointf::new_unscale(bbox.max);
bboxf.min = unscale(bbox.min);
bboxf.max = unscale(bbox.max);
bboxf.defined = true;
}
return bboxf;
@@ -60,8 +60,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionMultiPath &ext
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
BoundingBoxf bboxf;
if (! empty(bbox)) {
bboxf.min = Pointf::new_unscale(bbox.min);
bboxf.max = Pointf::new_unscale(bbox.max);
bboxf.min = unscale(bbox.min);
bboxf.max = unscale(bbox.max);
bboxf.defined = true;
}
return bboxf;
@@ -121,9 +121,9 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object
if (support_layer)
for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities)
bbox_this.merge(extrusionentity_extents(extrusion_entity));
for (const Point &offset : print_object._shifted_copies) {
for (const Point &offset : print_object.copies()) {
BoundingBoxf bbox_translated(bbox_this);
bbox_translated.translate(Pointf::new_unscale(offset));
bbox_translated.translate(unscale(offset));
bbox.merge(bbox_translated);
}
}
@@ -134,6 +134,12 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object
// The projection does not contain the priming regions.
BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z)
{
// Wipe tower extrusions are saved as if the tower was at the origin with no rotation
// We need to get position and angle of the wipe tower to transform them to actual position.
Transform2d trafo =
Eigen::Translation2d(print.config().wipe_tower_x.value, print.config().wipe_tower_y.value) *
Eigen::Rotation2Dd(print.config().wipe_tower_rotation_angle.value);
BoundingBoxf bbox;
for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.wipe_tower_data().tool_changes) {
if (! tool_changes.empty() && tool_changes.front().print_z > max_print_z)
@@ -142,14 +148,11 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
const WipeTower::Extrusion &e = tcr.extrusions[i];
if (e.width > 0) {
Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y);
Pointf p2(e.pos.x, e.pos.y);
bbox.merge(p1);
coordf_t radius = 0.5 * e.width;
bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius);
bbox.min.y = std::min(bbox.min.y, std::min(p1.y, p2.y) - radius);
bbox.max.x = std::max(bbox.max.x, std::max(p1.x, p2.x) + radius);
bbox.max.y = std::max(bbox.max.y, std::max(p1.y, p2.y) + radius);
Vec2d delta = 0.5 * Vec2d(e.width, e.width);
Vec2d p1 = trafo * Vec2d((&e - 1)->pos.x, (&e - 1)->pos.y);
Vec2d p2 = trafo * Vec2d(e.pos.x, e.pos.y);
bbox.merge(p1.cwiseMin(p2) - delta);
bbox.merge(p1.cwiseMax(p2) + delta);
}
}
}
@@ -166,14 +169,14 @@ BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print)
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
const WipeTower::Extrusion &e = tcr.extrusions[i];
if (e.width > 0) {
Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y);
Pointf p2(e.pos.x, e.pos.y);
Vec2d p1((&e - 1)->pos.x, (&e - 1)->pos.y);
Vec2d p2(e.pos.x, e.pos.y);
bbox.merge(p1);
coordf_t radius = 0.5 * e.width;
bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius);
bbox.min.y = std::min(bbox.min.y, std::min(p1.y, p2.y) - radius);
bbox.max.x = std::max(bbox.max.x, std::max(p1.x, p2.x) + radius);
bbox.max.y = std::max(bbox.max.y, std::max(p1.y, p2.y) + radius);
bbox.min(0) = std::min(bbox.min(0), std::min(p1(0), p2(0)) - radius);
bbox.min(1) = std::min(bbox.min(1), std::min(p1(1), p2(1)) - radius);
bbox.max(0) = std::max(bbox.max(0), std::max(p1(0), p2(0)) + radius);
bbox.max(1) = std::max(bbox.max(1), std::max(p1(1), p2(1)) + radius);
}
}
}

View File

@@ -15,6 +15,24 @@
namespace Slic3r {
// Returns true in case that extruder a comes before b (b does not have to be present). False otherwise.
bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
{
if (a==b)
return false;
for (auto extruder : extruders) {
if (extruder == a)
return true;
if (extruder == b)
return false;
}
return false;
}
// For the use case when each object is printed separately
// (print.config().complete_objects is true).
ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material)
@@ -48,11 +66,14 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
// (print.config().complete_objects is false).
ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
{
m_print_config_ptr = &print.config();
PrintObjectPtrs objects = print.get_printable_objects();
// Initialize the print layers for all objects and all layers.
coordf_t object_bottom_z = 0.;
{
std::vector<coordf_t> zs;
for (auto object : print.objects()) {
for (auto object : objects) {
zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
for (auto layer : object->layers())
zs.emplace_back(layer->print_z);
@@ -65,7 +86,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
}
// Collect extruders reuqired to print the layers.
for (auto object : print.objects())
for (auto object : objects)
this->collect_extruders(*object);
// Reorder the extruders to minimize tool switches.
@@ -76,9 +97,10 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
this->collect_extruder_statistics(prime_multi_material);
}
ToolOrdering::LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z)
LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z)
{
auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), ToolOrdering::LayerTools(print_z - EPSILON));
auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON));
assert(it_layer_tools != m_layer_tools.end());
coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z);
for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++it_layer_tools) {
@@ -102,7 +124,7 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
coordf_t zmax = zs[i] + EPSILON;
for (; j < zs.size() && zs[j] <= zmax; ++ j) ;
// Assign an average print_z to the set of layers with nearly equal print_z.
m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1])));
m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]), m_print_config_ptr));
i = j;
}
}
@@ -134,12 +156,29 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
if (layerm == nullptr)
continue;
const PrintRegion &region = *object.print()->regions()[region_id];
if (! layerm->perimeters.entities.empty()) {
layer_tools.extruders.push_back(region.config().perimeter_extruder.value);
bool something_nonoverriddable = true;
if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
something_nonoverriddable = false;
for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities
if (!layer_tools.wiping_extrusions().is_overriddable(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) {
something_nonoverriddable = true;
break;
}
}
if (something_nonoverriddable)
layer_tools.extruders.push_back(region.config().perimeter_extruder.value);
layer_tools.has_object = true;
}
bool has_infill = false;
bool has_solid_infill = false;
bool something_nonoverriddable = false;
for (const ExtrusionEntity *ee : layerm->fills.entities) {
// fill represents infill extrusions of a single island.
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
@@ -148,19 +187,33 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
has_solid_infill = true;
else if (role != erNone)
has_infill = true;
if (m_print_config_ptr) {
if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable(*fill, *m_print_config_ptr, object, region))
something_nonoverriddable = true;
}
}
if (something_nonoverriddable || !m_print_config_ptr)
{
if (has_solid_infill)
layer_tools.extruders.push_back(region.config().solid_infill_extruder);
if (has_infill)
layer_tools.extruders.push_back(region.config().infill_extruder);
}
if (has_solid_infill)
layer_tools.extruders.push_back(region.config().solid_infill_extruder);
if (has_infill)
layer_tools.extruders.push_back(region.config().infill_extruder);
if (has_solid_infill || has_infill)
layer_tools.has_object = true;
}
}
// Sort and remove duplicates
for (LayerTools &lt : m_layer_tools)
sort_remove_duplicates(lt.extruders);
for (auto& layer : m_layer_tools) {
// Sort and remove duplicates
sort_remove_duplicates(layer.extruders);
// make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector)
if (layer.extruders.empty() && layer.has_object)
layer.extruders.push_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders
}
}
// Reorder extruders to minimize layer changes.
@@ -217,6 +270,8 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
}
}
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z)
{
if (m_layer_tools.empty())
@@ -327,4 +382,250 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
}
}
// This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual)
void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies)
{
something_overridden = true;
auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first; // (add and) return iterator
auto& copies_vector = entity_map_it->second;
if (copies_vector.size() < num_of_copies)
copies_vector.resize(num_of_copies, -1);
if (copies_vector[copy_id] != -1)
std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen.
copies_vector[copy_id] = extruder;
}
// Finds first non-soluble extruder on the layer
int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const
{
const LayerTools& lt = *m_layer_tools;
for (auto extruders_it = lt.extruders.begin(); extruders_it != lt.extruders.end(); ++extruders_it)
if (!print_config.filament_soluble.get_at(*extruders_it))
return (*extruders_it);
return (-1);
}
// Finds last non-soluble extruder on the layer
int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const
{
const LayerTools& lt = *m_layer_tools;
for (auto extruders_it = lt.extruders.rbegin(); extruders_it != lt.extruders.rend(); ++extruders_it)
if (!print_config.filament_soluble.get_at(*extruders_it))
return (*extruders_it);
return (-1);
}
// Decides whether this entity could be overridden
bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const
{
if (print_config.filament_soluble.get_at(Print::get_extruder(eec, region)))
return false;
if (object.config().wipe_into_objects)
return true;
if (!region.config().wipe_into_infill || eec.role() != erInternalInfill)
return false;
return true;
}
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
// and returns volume that is left to be wiped on the wipe tower.
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe)
{
const LayerTools& lt = *m_layer_tools;
const float min_infill_volume = 0.f; // ignore infill with smaller volume than this
if (print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder))
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it
// we will sort objects so that dedicated for wiping are at the beginning:
PrintObjectPtrs object_list = print.get_printable_objects();
std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config().wipe_into_objects; });
// We will now iterate through
// - first the dedicated objects to mark perimeters or infills (depending on infill_first)
// - second through the dedicated ones again to mark infills or perimeters (depending on infill_first)
// - then all the others to mark infills (in case that !infill_first, we must also check that the perimeter is finished already
// this is controlled by the following variable:
bool perimeters_done = false;
for (int i=0 ; i<(int)object_list.size() + (perimeters_done ? 0 : 1); ++i) {
if (!perimeters_done && (i==(int)object_list.size() || !object_list[i]->config().wipe_into_objects)) { // we passed the last dedicated object in list
perimeters_done = true;
i=-1; // let's go from the start again
continue;
}
const auto& object = object_list[i];
// Finds this layer:
auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [&lt](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
if (this_layer_it == object->layers().end())
continue;
const Layer* this_layer = *this_layer_it;
unsigned int num_of_copies = object->copies().size();
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
for (size_t region_id = 0; region_id < object->print()->regions().size(); ++ region_id) {
const auto& region = *object->print()->regions()[region_id];
if (!region.config().wipe_into_infill && !object->config().wipe_into_objects)
continue;
if ((!print.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) {
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->fills.entities) { // iterate through all infill Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!is_overriddable(*fill, print.config(), *object, region))
continue;
// What extruder would this normally be printed with?
unsigned int correct_extruder = Print::get_extruder(*fill, region);
if (volume_to_wipe<=0)
continue;
if (!object->config().wipe_into_objects && !print.config().infill_first && region.config().wipe_into_infill)
// In this case we must check that the original extruder is used on this layer before the one we are overridding
// (and the perimeters will be finished before the infill is printed):
if (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder))
continue;
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder
set_extruder_override(fill, copy, new_extruder, num_of_copies);
volume_to_wipe -= fill->total_volume();
}
}
}
// Now the same for perimeters - see comments above for explanation:
if (object->config().wipe_into_objects && (print.config().infill_first ? perimeters_done : !perimeters_done))
{
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) {
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!is_overriddable(*fill, print.config(), *object, region))
continue;
if (volume_to_wipe<=0)
continue;
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) {
set_extruder_override(fill, copy, new_extruder, num_of_copies);
volume_to_wipe -= fill->total_volume();
}
}
}
}
}
}
return std::max(0.f, volume_to_wipe);
}
// Called after all toolchanges on a layer were mark_infill_overridden. There might still be overridable entities,
// that were not actually overridden. If they are part of a dedicated object, printing them with the extruder
// they were initially assigned to might mean violating the perimeter-infill order. We will therefore go through
// them again and make sure we override it.
void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
{
const LayerTools& lt = *m_layer_tools;
unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config());
unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config());
PrintObjectPtrs printable_objects = print.get_printable_objects();
for (const PrintObject* object : printable_objects) {
// Finds this layer:
auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [&lt](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
if (this_layer_it == object->layers().end())
continue;
const Layer* this_layer = *this_layer_it;
unsigned int num_of_copies = object->copies().size();
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
for (size_t region_id = 0; region_id < object->print()->regions().size(); ++ region_id) {
const auto& region = *object->print()->regions()[region_id];
if (!region.config().wipe_into_infill && !object->config().wipe_into_objects)
continue;
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->fills.entities) { // iterate through all infill Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!is_overriddable(*fill, print.config(), *object, region)
|| is_entity_overridden(fill, copy) )
continue;
// This infill could have been overridden but was not - unless we do something, it could be
// printed before its perimeter, or not be printed at all (in case its original extruder has
// not been added to LayerTools
// Either way, we will now force-override it with something suitable:
if (print.config().infill_first
|| object->config().wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely
|| lt.is_extruder_order(region.config().perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints
|| std::find(lt.extruders.begin(), lt.extruders.end(), region.config().infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME)
)
set_extruder_override(fill, copy, (print.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies);
else {
// In this case we can (and should) leave it to be printed normally.
// Force overriding would mean it gets printed before its perimeter.
}
}
// Now the same for perimeters - see comments above for explanation:
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) { // iterate through all perimeter Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!is_overriddable(*fill, print.config(), *object, region)
|| is_entity_overridden(fill, copy) )
continue;
set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);
}
}
}
}
}
// Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity.
// It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy
// It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known,
// so -1 was used as "print as usual".
// The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden,
// its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero).
const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies)
{
auto entity_map_it = entity_map.find(entity);
if (entity_map_it == entity_map.end())
entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first;
// Now the entity_map_it should be valid, let's make sure the vector is long enough:
entity_map_it->second.resize(num_of_copies, -1);
// Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information):
std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1);
return &(entity_map_it->second);
}
} // namespace Slic3r

View File

@@ -9,38 +9,99 @@ namespace Slic3r {
class Print;
class PrintObject;
class LayerTools;
class ToolOrdering
// Object of this class holds information about whether an extrusion is printed immediately
// after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part
// of several copies - this has to be taken into account.
class WipingExtrusions
{
public:
struct LayerTools
{
LayerTools(const coordf_t z) :
print_z(z),
has_object(false),
has_support(false),
has_wipe_tower(false),
wipe_tower_partitions(0),
wipe_tower_layer_height(0.) {}
bool is_anything_overridden() const { // if there are no overrides, all the agenda can be skipped - this function can tell us if that's the case
return something_overridden;
}
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
// This is called from GCode::process_layer - see implementation for further comments:
const std::vector<int>* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies);
coordf_t print_z;
bool has_object;
bool has_support;
// Zero based extruder IDs, ordered to minimize tool switches.
std::vector<unsigned int> extruders;
// Will there be anything extruded on this layer for the wipe tower?
// Due to the support layers possibly interleaving the object layers,
// wipe tower will be disabled for some support only layers.
bool has_wipe_tower;
// Number of wipe tower partitions to support the required number of tool switches
// and to support the wipe tower partitions above this one.
size_t wipe_tower_partitions;
coordf_t wipe_tower_layer_height;
};
// This function goes through all infill entities, decides which ones will be used for wiping and
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
float mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe);
void ensure_perimeters_infills_order(const Print& print);
bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const;
void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; }
private:
int first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const;
int last_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const;
// This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies);
// Returns true in case that entity is not printed with its usual extruder for a given copy:
bool is_entity_overridden(const ExtrusionEntity* entity, int copy_id) const {
return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1);
}
std::map<const ExtrusionEntity*, std::vector<int>> entity_map; // to keep track of who prints what
bool something_overridden = false;
const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to
};
class LayerTools
{
public:
LayerTools(const coordf_t z, const PrintConfig* print_config_ptr = nullptr) :
print_z(z),
has_object(false),
has_support(false),
has_wipe_tower(false),
wipe_tower_partitions(0),
wipe_tower_layer_height(0.) {}
// Changing these operators to epsilon version can make a problem in cases where support and object layers get close to each other.
// In case someone tries to do it, make sure you know what you're doing and test it properly (slice multiple objects at once with supports).
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
bool is_extruder_order(unsigned int a, unsigned int b) const;
coordf_t print_z;
bool has_object;
bool has_support;
// Zero based extruder IDs, ordered to minimize tool switches.
std::vector<unsigned int> extruders;
// Will there be anything extruded on this layer for the wipe tower?
// Due to the support layers possibly interleaving the object layers,
// wipe tower will be disabled for some support only layers.
bool has_wipe_tower;
// Number of wipe tower partitions to support the required number of tool switches
// and to support the wipe tower partitions above this one.
size_t wipe_tower_partitions;
coordf_t wipe_tower_layer_height;
WipingExtrusions& wiping_extrusions() {
m_wiping_extrusions.set_layer_tools_ptr(this);
return m_wiping_extrusions;
}
private:
// This object holds list of extrusion that will be used for extruder wiping
WipingExtrusions m_wiping_extrusions;
};
class ToolOrdering
{
public:
ToolOrdering() {}
// For the use case when each object is printed separately
@@ -72,7 +133,7 @@ public:
std::vector<LayerTools>::const_iterator begin() const { return m_layer_tools.begin(); }
std::vector<LayerTools>::const_iterator end() const { return m_layer_tools.end(); }
bool empty() const { return m_layer_tools.empty(); }
const std::vector<LayerTools>& layer_tools() const { return m_layer_tools; }
std::vector<LayerTools>& layer_tools() { return m_layer_tools; }
bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; }
private:
@@ -80,17 +141,22 @@ private:
void collect_extruders(const PrintObject &object);
void reorder_extruders(unsigned int last_extruder_id);
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
void collect_extruder_statistics(bool prime_multi_material);
void collect_extruder_statistics(bool prime_multi_material);
std::vector<LayerTools> m_layer_tools;
// First printing extruder, including the multi-material priming sequence.
unsigned int m_first_printing_extruder = (unsigned int)-1;
// Final printing extruder.
unsigned int m_last_printing_extruder = (unsigned int)-1;
// All extruders, which extrude some material over m_layer_tools.
std::vector<unsigned int> m_all_printing_extruders;
std::vector<LayerTools> m_layer_tools;
// First printing extruder, including the multi-material priming sequence.
unsigned int m_first_printing_extruder = (unsigned int)-1;
// Final printing extruder.
unsigned int m_last_printing_extruder = (unsigned int)-1;
// All extruders, which extrude some material over m_layer_tools.
std::vector<unsigned int> m_all_printing_extruders;
const PrintConfig* m_print_config_ptr = nullptr;
};
} // namespace SLic3r
#endif /* slic3r_ToolOrdering_hpp_ */

View File

@@ -17,12 +17,37 @@ public:
struct xy
{
xy(float x = 0.f, float y = 0.f) : x(x), y(y) {}
xy(const xy& pos,float xp,float yp) : x(pos.x+xp), y(pos.y+yp) {}
xy operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; }
xy operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; }
xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; }
xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
bool operator==(const xy &rhs) const { return x == rhs.x && y == rhs.y; }
bool operator!=(const xy &rhs) const { return x != rhs.x || y != rhs.y; }
// Rotate the point around center of the wipe tower about given angle (in degrees)
xy rotate(float width, float depth, float angle) const {
xy out(0,0);
float temp_x = x - width / 2.f;
float temp_y = y - depth / 2.f;
angle *= float(M_PI/180.);
out.x += temp_x * cos(angle) - temp_y * sin(angle) + width / 2.f;
out.y += temp_x * sin(angle) + temp_y * cos(angle) + depth / 2.f;
return out;
}
// Rotate the point around origin about given angle in degrees
void rotate(float angle) {
float temp_x = x * cos(angle) - y * sin(angle);
y = x * sin(angle) + y * cos(angle);
x = temp_x;
}
void translate(const xy& vect) {
x += vect.x;
y += vect.y;
}
float x;
float y;
};
@@ -90,6 +115,9 @@ public:
// This is useful not only for the print time estimation, but also for the control of layer cooling.
float elapsed_time;
// Is this a priming extrusion? (If so, the wipe tower rotation & translation will not be applied later)
bool priming;
// Sum the total length of the extrusion.
float total_extrusion_length_in_plane() {
float e_length = 0.f;
@@ -112,17 +140,15 @@ public:
const std::vector<unsigned int> &tools,
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
bool last_wipe_inside_wipe_tower,
// May be used by a stand alone post processor.
Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
bool last_wipe_inside_wipe_tower) = 0;
// Returns gcode for toolchange and the end position.
// if new_tool == -1, just unload the current filament over the wipe tower.
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer) = 0;
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
// Call this method only if layer_finished() is false.
virtual ToolChangeResult finish_layer(Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
virtual ToolChangeResult finish_layer() = 0;
// Is the current layer finished? A layer is finished if either the wipe tower is finished, or
// the wipe tower has been completely covered by the tool change extrusions,

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,15 @@
#ifndef WipeTowerPrusaMM_hpp_
#define WipeTowerPrusaMM_hpp_
#include <algorithm>
#include <cmath>
#include <string>
#include <sstream>
#include <utility>
#include <algorithm>
#include "WipeTower.hpp"
namespace Slic3r
{
@@ -15,6 +17,8 @@ namespace PrusaMultiMaterial {
class Writer;
};
class WipeTowerPrusaMM : public WipeTower
{
public:
@@ -39,65 +43,103 @@ public:
// y -- y coordinates of wipe tower in mm ( left bottom corner )
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
// wipe_area -- space available for one toolchange in mm
WipeTowerPrusaMM(float x, float y, float width, float wipe_area, unsigned int initial_tool) :
WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction,
float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, float bridging,
const std::vector<std::vector<float>>& wiping_matrix, unsigned int initial_tool) :
m_wipe_tower_pos(x, y),
m_wipe_tower_width(width),
m_wipe_area(wipe_area),
m_wipe_tower_rotation_angle(rotation_angle),
m_y_shift(0.f),
m_z_pos(0.f),
m_current_tool(initial_tool)
{
for (size_t i = 0; i < 4; ++ i) {
// Extruder specific parameters.
m_material[i] = PLA;
m_temperature[i] = 0;
m_first_layer_temperature[i] = 0;
}
}
m_is_first_layer(false),
m_cooling_tube_retraction(cooling_tube_retraction),
m_cooling_tube_length(cooling_tube_length),
m_parking_pos_retraction(parking_pos_retraction),
m_extra_loading_move(extra_loading_move),
m_bridging(bridging),
m_current_tool(initial_tool),
wipe_volumes(wiping_matrix)
{}
virtual ~WipeTowerPrusaMM() {}
// _retract - retract value in mm
void set_retract(float retract) { m_retract = retract; }
// _zHop - z hop value in mm
void set_zhop(float zhop) { m_zhop = zhop; }
// Set the extruder properties.
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp)
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp, float loading_speed, float loading_speed_start,
float unloading_speed, float unloading_speed_start, float delay, int cooling_moves,
float cooling_initial_speed, float cooling_final_speed, std::string ramming_parameters, float nozzle_diameter)
{
m_material[idx] = material;
m_temperature[idx] = temp;
m_first_layer_temperature[idx] = first_layer_temp;
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
m_filpar.push_back(FilamentParameters());
m_filpar[idx].material = material;
m_filpar[idx].temperature = temp;
m_filpar[idx].first_layer_temperature = first_layer_temp;
m_filpar[idx].loading_speed = loading_speed;
m_filpar[idx].loading_speed_start = loading_speed_start;
m_filpar[idx].unloading_speed = unloading_speed;
m_filpar[idx].unloading_speed_start = unloading_speed_start;
m_filpar[idx].delay = delay;
m_filpar[idx].cooling_moves = cooling_moves;
m_filpar[idx].cooling_initial_speed = cooling_initial_speed;
m_filpar[idx].cooling_final_speed = cooling_final_speed;
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
std::stringstream stream{ramming_parameters};
float speed = 0.f;
stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
m_filpar[idx].ramming_line_width_multiplicator /= 100;
m_filpar[idx].ramming_step_multiplicator /= 100;
while (stream >> speed)
m_filpar[idx].ramming_speed.push_back(speed);
}
// Appends into internal structure m_plan containing info about the future wipe tower
// to be used before building begins. The entries must be added ordered in z.
void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume = 0.f);
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
void generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &result);
float get_depth() const { return m_wipe_tower_depth; }
// Switch to a next layer.
virtual void set_layer(
// Print height of this layer.
float print_z,
// Layer height, used to calculate extrusion the rate.
float layer_height,
float print_z,
// Layer height, used to calculate extrusion the rate.
float layer_height,
// Maximum number of tool changes on this layer or the layers below.
size_t max_tool_changes,
size_t max_tool_changes,
// Is this the first layer of the print? In that case print the brim first.
bool is_first_layer,
bool is_first_layer,
// Is this the last layer of the waste tower?
bool is_last_layer)
bool is_last_layer)
{
m_z_pos = print_z;
m_layer_height = layer_height;
m_max_color_changes = max_tool_changes;
m_is_first_layer = is_first_layer;
m_is_last_layer = is_last_layer;
// Start counting the color changes from zero. Special case: -1 - extrude a brim first.
m_idx_tool_change_in_layer = is_first_layer ? (unsigned int)(-1) : 0;
m_current_wipe_start_y = 0.f;
m_print_brim = is_first_layer;
m_depth_traversed = 0.f;
m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
++ m_num_layer_changes;
// Extrusion rate for an extrusion aka perimeter width 0.35mm.
// Clamp the extrusion height to a 0.2mm layer height, independent of the nozzle diameter.
// m_extrusion_flow = std::min(0.2f, layer_height) * 0.145f;
// Use a strictly
m_extrusion_flow = layer_height * 0.145f;
if (is_first_layer) {
this->m_num_layer_changes = 0;
this->m_num_tool_changes = 0;
}
else
++ m_num_layer_changes;
// Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
m_extrusion_flow = extrusion_flow(layer_height);
// Advance m_layer_info iterator, making sure we got it right
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
++m_layer_info;
}
// Return the wipe tower position.
@@ -115,79 +157,120 @@ public:
const std::vector<unsigned int> &tools,
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
bool last_wipe_inside_wipe_tower,
// May be used by a stand alone post processor.
Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE);
bool last_wipe_inside_wipe_tower);
// Returns gcode for a toolchange and a final print head position.
// On the first layer, extrude a brim around the future wipe tower first.
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose);
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer);
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
// Fill the unfilled space with a sparse infill.
// Call this method only if layer_finished() is false.
virtual ToolChangeResult finish_layer(Purpose purpose);
virtual ToolChangeResult finish_layer();
// Is the current layer finished?
virtual bool layer_finished() const {
return ( (m_is_first_layer ? m_wipe_tower_depth - m_perimeter_width : m_layer_info->depth) - WT_EPSILON < m_depth_traversed);
}
// Is the current layer finished? A layer is finished if either the wipe tower is finished, or
// the wipe tower has been completely covered by the tool change extrusions,
// or the rest of the tower has been filled by a sparse infill with the finish_layer() method.
virtual bool layer_finished() const
{ return m_idx_tool_change_in_layer == m_max_color_changes; }
private:
WipeTowerPrusaMM();
// A fill-in direction (positive Y, negative Y) alternates with each layer.
enum wipe_shape
enum wipe_shape // A fill-in direction
{
SHAPE_NORMAL = 1,
SHAPE_NORMAL = 1,
SHAPE_REVERSED = -1
};
// Left front corner of the wipe tower in mm.
xy m_wipe_tower_pos;
// Width of the wipe tower.
float m_wipe_tower_width;
// Per color Y span.
float m_wipe_area;
// Current Z position.
float m_z_pos = 0.f;
// Current layer height.
float m_layer_height = 0.f;
// Maximum number of color changes per layer.
size_t m_max_color_changes = 0;
// Is this the 1st layer of the print? If so, print the brim around the waste tower.
bool m_is_first_layer = false;
// Is this the last layer of this waste tower?
bool m_is_last_layer = false;
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
const float Filament_Area = M_PI * 1.75f * 1.75f / 4.f; // filament area in mm^2
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
const float WT_EPSILON = 1e-3f;
xy m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
float m_wipe_tower_width; // Width of the wipe tower.
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
float m_internal_rotation = 0.f;
float m_y_shift = 0.f; // y shift passed to writer
float m_z_pos = 0.f; // Current Z position.
float m_layer_height = 0.f; // Current layer height.
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
bool m_is_first_layer = false;// Is this the 1st layer of the print? If so, print the brim around the waste tower.
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
// G-code generator parameters.
float m_zhop = 0.5f;
float m_retract = 4.f;
// Width of an extrusion line, also a perimeter spacing for 100% infill.
float m_perimeter_width = 0.5f;
// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
float m_extrusion_flow = 0.029f;
float m_cooling_tube_retraction = 0.f;
float m_cooling_tube_length = 0.f;
float m_parking_pos_retraction = 0.f;
float m_extra_loading_move = 0.f;
float m_bridging = 0.f;
bool m_adhesion = true;
float m_perimeter_width = 0.4 * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
float m_extrusion_flow = 0.038; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
struct FilamentParameters {
material_type material = PLA;
int temperature = 0;
int first_layer_temperature = 0;
float loading_speed = 0.f;
float loading_speed_start = 0.f;
float unloading_speed = 0.f;
float unloading_speed_start = 0.f;
float delay = 0.f ;
int cooling_moves = 0;
float cooling_initial_speed = 0.f;
float cooling_final_speed = 0.f;
float ramming_line_width_multiplicator = 0.f;
float ramming_step_multiplicator = 0.f;
std::vector<float> ramming_speed;
float nozzle_diameter;
};
// Extruder specific parameters.
material_type m_material[4];
int m_temperature[4];
int m_first_layer_temperature[4];
std::vector<FilamentParameters> m_filpar;
// State of the wiper tower generator.
// Layer change counter for the output statistics.
unsigned int m_num_layer_changes = 0;
// Tool change change counter for the output statistics.
unsigned int m_num_tool_changes = 0;
// Layer change counter in this layer. Counting up to m_max_color_changes.
unsigned int m_idx_tool_change_in_layer = 0;
// State of the wipe tower generator.
unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.
///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
bool m_print_brim = true;
// A fill-in direction (positive Y, negative Y) alternates with each layer.
wipe_shape m_current_shape = SHAPE_NORMAL;
unsigned int m_current_tool = 0;
// Current y position at the wipe tower.
float m_current_wipe_start_y = 0.f;
// How much to wipe the 1st extruder over the wipe tower at the 1st layer
// after the wipe tower brim has been extruded?
float m_initial_extra_wipe = 0.f;
const std::vector<std::vector<float>> wipe_volumes;
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
bool m_left_to_right = true;
float m_extra_spacing = 1.f;
// Calculates extrusion flow needed to produce required line width for given layer height
float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow
{
if ( layer_height < 0 )
return m_extrusion_flow;
return layer_height * ( m_perimeter_width - layer_height * (1-M_PI/4.f)) / Filament_Area;
}
// Calculates length of extrusion line to extrude given volume
float volume_to_length(float volume, float line_width, float layer_height) const {
return std::max(0., volume / (layer_height * (line_width - layer_height * (1. - M_PI / 4.))));
}
// Calculates depth for all layers and propagates them downwards
void plan_tower();
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
void make_wipe_tower_square();
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
void save_on_last_wipe();
struct box_coordinates
{
@@ -216,14 +299,43 @@ private:
}
xy ld; // left down
xy lu; // left upper
xy ru; // right upper
xy rd; // right lower
xy ru; // right upper
};
// to store information about tool changes for a given layer
struct WipeTowerInfo{
struct ToolChange {
unsigned int old_tool;
unsigned int new_tool;
float required_depth;
float ramming_depth;
float first_wipe_line;
float wipe_volume;
ToolChange(unsigned int old, unsigned int newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {}
};
float z; // z position of the layer
float height; // layer height
float depth; // depth of the layer based on all layers above
float extra_spacing;
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
std::vector<ToolChange> tool_changes;
WipeTowerInfo(float z_par, float layer_height_par)
: z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {}
};
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end();
// Returns gcode for wipe tower brim
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
// offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
ToolChangeResult toolchange_Brim(Purpose purpose, bool sideOnly = false, float y_offset = 0.f);
ToolChangeResult toolchange_Brim(bool sideOnly = false, float y_offset = 0.f);
void toolchange_Unload(
PrusaMultiMaterial::Writer &writer,
@@ -243,11 +355,12 @@ private:
void toolchange_Wipe(
PrusaMultiMaterial::Writer &writer,
const box_coordinates &cleaning_box,
bool skip_initial_y_move);
void toolchange_Perimeter();
float wipe_volume);
};
}; // namespace Slic3r
#endif /* WipeTowerPrusaMM_hpp_ */