mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 22:31:02 +00:00
Apron bands looked up their filament and nozzle config slot with a running counter, while object layers use Layer::id(), so band N read the map of object layer N. They precede layer 0 and now use its assignment. Raised in Hanif Koh's review of #14394.
962 lines
50 KiB
C++
962 lines
50 KiB
C++
#ifndef slic3r_GCode_hpp_
|
|
#define slic3r_GCode_hpp_
|
|
|
|
#include "libslic3r.h"
|
|
#include "ExPolygon.hpp"
|
|
#include "GCodeWriter.hpp"
|
|
#include "GCode/BeltKinematics.hpp"
|
|
#include "FirstLayerPlane.hpp"
|
|
#include "Layer.hpp"
|
|
#include "Point.hpp"
|
|
#include "PlaceholderParser.hpp"
|
|
#include "PrintConfig.hpp"
|
|
#include "GCode/AvoidCrossingPerimeters.hpp"
|
|
#include "GCode/CoolingBuffer.hpp"
|
|
#include "GCode/FanMover.hpp"
|
|
#include "GCode/RetractWhenCrossingPerimeters.hpp"
|
|
#include "GCode/SpiralVase.hpp"
|
|
#include "GCode/ToolOrdering.hpp"
|
|
#include "GCode/WipeTower.hpp"
|
|
#include "GCode/SeamPlacer.hpp"
|
|
#include "GCode/GCodeProcessor.hpp"
|
|
#include "EdgeGrid.hpp"
|
|
#include "GCode/ThumbnailData.hpp"
|
|
#include "libslic3r/ObjectID.hpp"
|
|
#include "GCode/ExtrusionProcessor.hpp"
|
|
|
|
#include "GCode/PressureEqualizer.hpp"
|
|
#include "GCode/SmallAreaInfillFlowCompensator.hpp"
|
|
// ORCA: post processor below used for Dynamic Pressure advance
|
|
#include "GCode/AdaptivePAProcessor.hpp"
|
|
|
|
#include "GCode/TimelapsePosPicker.hpp"
|
|
|
|
#include <memory>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <set>
|
|
#include <string>
|
|
#include <cfloat>
|
|
|
|
namespace Slic3r {
|
|
|
|
// Forward declarations.
|
|
class GCode;
|
|
|
|
namespace CustomGCode{ struct Item; }
|
|
struct PrintInstance;
|
|
class ConstPrintObjectPtrsAdaptor;
|
|
|
|
class OozePrevention {
|
|
public:
|
|
bool enable;
|
|
|
|
OozePrevention() : enable(false) {}
|
|
std::string pre_toolchange(GCode &gcodegen);
|
|
std::string post_toolchange(GCode &gcodegen);
|
|
|
|
private:
|
|
int _get_temp(const GCode &gcodegen) const;
|
|
};
|
|
|
|
class Wipe {
|
|
public:
|
|
bool enable;
|
|
Polyline path;
|
|
|
|
// Orca:
|
|
struct RetractionValues{
|
|
double retraction_length_before_wipe = 0.;
|
|
double retraction_length_during_wipe = 0.;
|
|
double retraction_length_after_wipe = 0.;
|
|
};
|
|
|
|
Wipe() : enable(false) {}
|
|
bool has_path() const { return !this->path.points.empty(); }
|
|
void reset_path() { this->path = Polyline(); }
|
|
std::string wipe(GCode &gcodegen, double length, bool toolchange = false, bool is_last = false);
|
|
|
|
// Orca:
|
|
RetractionValues calculateWipeRetractionLengths(GCode& gcodegen, bool toolchange);
|
|
};
|
|
|
|
class WipeTowerIntegration {
|
|
public:
|
|
WipeTowerIntegration(
|
|
const PrintConfig &print_config,
|
|
// BBS: add partplate logic
|
|
const int plate_idx,
|
|
const Vec3d plate_origin,
|
|
const std::vector<WipeTower::ToolChangeResult> &priming,
|
|
const std::vector<std::vector<WipeTower::ToolChangeResult>> &tool_changes,
|
|
const WipeTower::ToolChangeResult &final_purge,
|
|
const std::vector<unsigned int> &slice_used_filaments) :
|
|
m_left(/*float(print_config.wipe_tower_x.value)*/ 0.f),
|
|
m_right(float(/*print_config.wipe_tower_x.value +*/ print_config.prime_tower_width.value)),
|
|
m_wipe_tower_pos(float(print_config.wipe_tower_x.get_at(plate_idx)), float(print_config.wipe_tower_y.get_at(plate_idx))),
|
|
m_wipe_tower_rotation(float(print_config.wipe_tower_rotation_angle)),
|
|
m_priming(priming),
|
|
m_tool_changes(tool_changes),
|
|
m_final_purge(final_purge),
|
|
m_layer_idx(-1),
|
|
m_tool_change_idx(0),
|
|
m_plate_origin(plate_origin),
|
|
m_single_extruder_multi_material(print_config.single_extruder_multi_material),
|
|
m_enable_timelapse_print(print_config.timelapse_type.value == TimelapseType::tlSmooth),
|
|
m_enable_wrapping_detection(print_config.enable_wrapping_detection && (print_config.wrapping_exclude_area.values.size() > 2) && (slice_used_filaments.size() <= 1)),
|
|
m_is_first_print(true),
|
|
m_print_config(&print_config),
|
|
m_last_wipe_tower_print_z(print_config.z_offset.value)
|
|
{
|
|
// initialize with the extruder offset of master extruder id
|
|
m_extruder_offsets.resize(print_config.filament_map.size(), print_config.extruder_offset.get_at(print_config.master_extruder_id.value - 1));
|
|
const auto& filament_map = print_config.filament_map.values; // 1 based idx
|
|
for (size_t idx = 0; idx < filament_map.size(); ++idx)
|
|
m_extruder_offsets[idx] = print_config.extruder_offset.get_at(filament_map[idx] - 1);
|
|
}
|
|
|
|
std::string prime(GCode &gcodegen);
|
|
void next_layer() { ++ m_layer_idx; m_tool_change_idx = 0; }
|
|
std::string tool_change(GCode &gcodegen, int extruder_id, bool finish_layer);
|
|
bool is_empty_wipe_tower_gcode(GCode &gcodegen, int extruder_id, bool finish_layer);
|
|
std::string finalize(GCode &gcodegen);
|
|
std::vector<float> used_filament_length() const;
|
|
|
|
bool is_first_print() const { return m_is_first_print;}
|
|
void set_is_first_print(bool is) { m_is_first_print = is; }
|
|
|
|
bool enable_timelapse_print() const { return m_enable_timelapse_print; }
|
|
void set_wipe_tower_depth(float depth) { m_wipe_tower_depth = depth; }
|
|
void set_wipe_tower_bbx(const BoundingBoxf & bbx) { m_wipe_tower_bbx = bbx; }
|
|
void set_rib_offset(const Vec2f &rib_offset) { m_rib_offset = rib_offset; }
|
|
|
|
private:
|
|
WipeTowerIntegration& operator=(const WipeTowerIntegration&);
|
|
std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;
|
|
Polyline generate_path_to_wipe_tower(const Point &start_pos, const Point &end_pos, const BoundingBox &avoid_polygon, const Polygons &bed_polygons) const;
|
|
std::string append_tcr2(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;
|
|
std::string travel_to_tower_gap(GCode &gcodegen, const Point &route_start, const Point &start_wipe_pos) const;
|
|
Vec2f transform_wt2_pt(const Vec2f &pt) const;
|
|
Polygons shared_printable_area(GCode &gcodegen) const;
|
|
|
|
// Postprocesses gcode: rotates and moves G1 extrusions and returns result
|
|
std::string post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const;
|
|
// Left / right edges of the wipe tower, for the planning of wipe moves.
|
|
const float m_left;
|
|
const float m_right;
|
|
const Vec2f m_wipe_tower_pos;
|
|
const float m_wipe_tower_rotation;
|
|
std::vector<Vec2d> m_extruder_offsets;
|
|
|
|
// Reference to cached values at the Printer class.
|
|
const std::vector<WipeTower::ToolChangeResult> &m_priming;
|
|
const std::vector<std::vector<WipeTower::ToolChangeResult>> &m_tool_changes;
|
|
const WipeTower::ToolChangeResult &m_final_purge;
|
|
// Current layer index.
|
|
int m_layer_idx;
|
|
int m_tool_change_idx;
|
|
double m_last_wipe_tower_print_z;
|
|
|
|
// BBS
|
|
Vec3d m_plate_origin;
|
|
bool m_single_extruder_multi_material;
|
|
bool m_enable_timelapse_print;
|
|
bool m_enable_wrapping_detection;
|
|
bool m_is_first_print;
|
|
const PrintConfig * m_print_config;
|
|
float m_wipe_tower_depth;
|
|
BoundingBoxf m_wipe_tower_bbx;
|
|
Vec2f m_rib_offset{Vec2f(0, 0)};
|
|
};
|
|
|
|
class ColorPrintColors
|
|
{
|
|
static const std::vector<std::string> Colors;
|
|
public:
|
|
static const std::vector<std::string>& get() { return Colors; }
|
|
};
|
|
|
|
struct LayerResult {
|
|
std::string gcode;
|
|
size_t layer_id;
|
|
// Is spiral vase post processing enabled for this layer?
|
|
bool spiral_vase_enable { false };
|
|
// Should the cooling buffer content be flushed at the end of this layer?
|
|
bool cooling_buffer_flush { false };
|
|
// Is indicating if this LayerResult should be processed, or it is just inserted artificial LayerResult.
|
|
// It is used for the pressure equalizer because it needs to buffer one layer back.
|
|
bool nop_layer_result { false };
|
|
|
|
static LayerResult make_nop_layer_result() { return {"", std::numeric_limits<size_t>::max(), false, false, true}; }
|
|
};
|
|
|
|
class GCode {
|
|
|
|
public:
|
|
GCode() :
|
|
m_origin(Vec2d::Zero()),
|
|
m_enable_loop_clipping(true),
|
|
m_resonance_avoidance(true),
|
|
m_enable_cooling_markers(false),
|
|
m_enable_extrusion_role_markers(false),
|
|
m_last_processor_extrusion_role(erNone),
|
|
m_layer_count(0),
|
|
m_layer_index(-1),
|
|
m_layer(nullptr),
|
|
m_object_layer_over_raft(false),
|
|
//m_volumetric_speed(0),
|
|
m_last_pos_defined(false),
|
|
m_last_extrusion_role(erNone),
|
|
m_last_width(0.0f),
|
|
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
|
m_last_mm3_per_mm(0.0),
|
|
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
|
m_brim_done(false),
|
|
m_second_layer_things_done(false),
|
|
m_silent_time_estimator_enabled(false),
|
|
m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max())),
|
|
// BBS
|
|
m_toolchange_count(0),
|
|
m_nominal_z(0.),
|
|
m_writer(std::make_unique<GCodeWriter>())
|
|
{}
|
|
virtual ~GCode() = default;
|
|
|
|
public:
|
|
// throws std::runtime_exception on error,
|
|
// throws CanceledException through print->throw_if_canceled().
|
|
void do_export(Print* print, const char* path, GCodeProcessorResult* result = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
|
void export_layer_filaments(GCodeProcessorResult* result);
|
|
//BBS: set offset for gcode writer
|
|
void set_gcode_offset(double x, double y) { m_gcode_offset = Vec2d(x, y); m_writer->set_xy_offset(x, y); m_processor.set_xy_offset(x, y);}
|
|
|
|
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
|
const Vec2d& origin() const { return m_origin; }
|
|
void set_origin(const Vec2d &pointf);
|
|
void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); }
|
|
Point last_pos() const { return m_last_pos.to_point(); }
|
|
Vec2d point_to_gcode(const Point &point) const;
|
|
Vec3d point_to_gcode(const Point3& point) const;
|
|
Point gcode_to_point(const Vec2d &point) const;
|
|
Vec2d point_to_gcode_quantized(const Point& point) const;
|
|
Vec3d point_to_gcode_quantized(const Point3& point) const;
|
|
const FullPrintConfig &config() const { return m_config; }
|
|
const Layer* layer() const { return m_layer; }
|
|
GCodeWriter& writer() { return *m_writer; }
|
|
const GCodeWriter& writer() const { return *m_writer; }
|
|
PlaceholderParser& placeholder_parser() { return m_placeholder_parser_integration.parser; }
|
|
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser_integration.parser; }
|
|
// Process a template through the placeholder parser, collect error messages to be reported
|
|
// inside the generated string and after the G-code export finishes.
|
|
std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_filament_id, const DynamicConfig *config_override = nullptr);
|
|
bool enable_cooling_markers() const { return m_enable_cooling_markers; }
|
|
std::string extrusion_role_to_string_for_parser(const ExtrusionRole &);
|
|
|
|
// Calculate the interpolated value for the current layer between start_value and end_value.
|
|
// Step will create equal layers steps from first to last value.
|
|
// Step = 0 means gradual interpolation finishing at last value.
|
|
float interpolate_value_across_layers(float start_value, float end_value, float step = 0.0f) const;
|
|
|
|
// For Perl bindings, to be used exclusively by unit tests.
|
|
unsigned int layer_count() const { return m_layer_count; }
|
|
void set_layer_count(unsigned int value) { m_layer_count = value; }
|
|
void apply_print_config(const PrintConfig &print_config);
|
|
|
|
std::string travel_to(const Point& point, ExtrusionRole role, std::string comment, double z = DBL_MAX);
|
|
bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type);
|
|
std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift, bool apply_instantly = false, ExtrusionRole role = erNone);
|
|
// extra_retract forwards a PETG pre-extrusion over-extrusion; default 0 -> identical to the plain deretract.
|
|
std::string unretract(float extra_retract = 0.f) { return m_writer->unlift() + m_writer->unretract(extra_retract); }
|
|
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1, bool defer_temp_wait = false);
|
|
bool is_BBL_Printer();
|
|
WipeTowerType wipe_tower_type();
|
|
|
|
// SoftFever
|
|
std::string set_object_info(Print* print);
|
|
|
|
// append full config to the given string
|
|
static void append_full_config(const Print& print, std::string& str);
|
|
|
|
// Per-filament config-slot resolvers for the current layer (m_cur_layer_idx): the filament
|
|
// resolver keys filament-indexed arrays, the nozzle resolver keys (extruder x volume-type)
|
|
// slot arrays. Both degenerate to filament_id / extruder index on single-volume printers.
|
|
size_t get_filament_config_index(int filament_id) const;
|
|
size_t get_nozzle_config_index(int filament_id) const;
|
|
|
|
// Object and support extrusions of the same PrintObject at the same print_z.
|
|
// public, so that it could be accessed by free helper functions from GCode.cpp
|
|
struct LayerToPrint
|
|
{
|
|
LayerToPrint() : object_layer(nullptr), support_layer(nullptr), original_object(nullptr) {}
|
|
const Layer* object_layer;
|
|
const SupportLayer* support_layer;
|
|
const PrintObject* original_object; //BBS: used for shared object logic
|
|
// Belt printers only: an apron band that prints BELOW the object's first
|
|
// layer, so it has no object or support layer of its own. Deliberately
|
|
// not a Layer, so it cannot leak Layer::id() semantics into initial-layer
|
|
// temperature, spiral vase, cooling or interpolation logic. When this is
|
|
// the only thing set, layer() is null and process_layer() takes its
|
|
// dedicated brim-only branch.
|
|
const BeltBrimBand* belt_brim_band { nullptr };
|
|
const Layer* layer() const
|
|
{
|
|
if (object_layer != nullptr)
|
|
return object_layer;
|
|
|
|
if (support_layer != nullptr)
|
|
return support_layer;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const PrintObject* object() const
|
|
{
|
|
return (this->layer() != nullptr) ? this->layer()->object() : nullptr;
|
|
}
|
|
coordf_t print_z() const
|
|
{
|
|
coordf_t sum_z = 0.;
|
|
size_t count = 0;
|
|
if (object_layer != nullptr) {
|
|
sum_z += object_layer->print_z;
|
|
count++;
|
|
}
|
|
|
|
if (support_layer != nullptr) {
|
|
sum_z += support_layer->print_z;
|
|
count++;
|
|
}
|
|
|
|
// A brim-only apron band contributes no object/support layer, and
|
|
// averaging zero terms would yield NaN. Never folded into the
|
|
// average, so the non-belt result is bit-identical.
|
|
if (count == 0 && belt_brim_band != nullptr)
|
|
return belt_brim_band->print_z;
|
|
|
|
return sum_z / count;
|
|
}
|
|
};
|
|
|
|
// Public accessor for the first-layer plane evaluator. Used by
|
|
// CoolingBuffer (which is constructed with a GCode reference and needs
|
|
// to read the plane for per-segment fan re-evaluation). All other
|
|
// first-layer-plane access points (on_first_layer overload, effective
|
|
// index helper) are in the protected section since they're called from
|
|
// GCode internals only.
|
|
const FirstLayerPlane *first_layer_plane() const { return m_first_layer_plane.get(); }
|
|
|
|
protected:
|
|
class GCodeOutputStream {
|
|
public:
|
|
GCodeOutputStream(FILE *f, GCodeProcessor &processor) : f(f), m_processor(processor) {}
|
|
~GCodeOutputStream() { this->close(); }
|
|
|
|
bool is_open() const { return f; }
|
|
bool is_error() const;
|
|
|
|
void flush();
|
|
void close();
|
|
|
|
// Write a string into a file.
|
|
void write(const std::string& what) { this->write(what.c_str()); }
|
|
void write(const char* what);
|
|
|
|
// Write a string into a file.
|
|
// Add a newline, if the string does not end with a newline already.
|
|
// Used to export a custom G-code section processed by the PlaceholderParser.
|
|
void writeln(const std::string& what);
|
|
|
|
// Formats and write into a file the given data.
|
|
void write_format(const char* format, ...);
|
|
|
|
private:
|
|
FILE *f = nullptr;
|
|
GCodeProcessor &m_processor;
|
|
};
|
|
|
|
// Virtual hooks for belt printer subclass (BeltGCode).
|
|
// No-ops in base GCode; overridden in BeltGCode.
|
|
virtual void init_belt_writer(Print &print) {}
|
|
virtual void write_belt_header(GCodeOutputStream &file, const Print &print) {}
|
|
virtual void on_set_origin(const PrintObject *obj, const Point &inst_shift) {}
|
|
// Arc fitting is suppressed whenever the writer's machine mapping cannot
|
|
// represent a G2/G3 arc. Belt printers get this through BeltKinematics
|
|
// rather than through an override of their own.
|
|
virtual bool should_disable_arc_fitting() const
|
|
{ return ! m_writer->kinematics().supports_arc_moves(); }
|
|
|
|
void _do_export(Print &print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb);
|
|
|
|
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object, bool skip_empty_first_layer = false);
|
|
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
|
|
|
std::string generate_skirt(const Print &print,
|
|
const ExtrusionEntityCollection &skirt,
|
|
const Point& offset,
|
|
const float skirt_start_angle,
|
|
const LayerTools &layer_tools,
|
|
const Layer& layer,
|
|
unsigned int extruder_id,
|
|
std::vector<coordf_t> &skirt_done);
|
|
std::string generate_object_skirt_group(const Print &print,
|
|
const PrintObject &object,
|
|
size_t instance_id,
|
|
const LayerTools &layer_tools,
|
|
const Layer& layer,
|
|
unsigned int extruder_id);
|
|
std::string generate_object_brim(const Print &print,
|
|
const PrintObject &object,
|
|
size_t instance_id,
|
|
bool first_layer,
|
|
const Layer *object_layer);
|
|
|
|
// Belt printers: emit one brim-only apron layer. These print below the
|
|
// object's first layer, so there is no object or support layer for the normal
|
|
// process_layer() machinery to work from. Kept to the minimum a layer needs -
|
|
// tool, Z move, extrusions - so that nothing here can perturb the
|
|
// Layer::id()-based logic the ordinary path relies on.
|
|
LayerResult process_belt_brim_layer(
|
|
const Print &print,
|
|
const std::vector<LayerToPrint> &layers,
|
|
const LayerTools &layer_tools,
|
|
const bool last_layer,
|
|
const size_t single_object_instance_idx);
|
|
|
|
// Emit the apron bands carried by these layers whose brim filament is extruder_id
|
|
// (0-based). Called from both the brim-only branch and the ordinary path, since a
|
|
// band's print_z can coincide with another object's layer on a multi-object belt.
|
|
std::string emit_belt_brim_bands(
|
|
const Print &print,
|
|
const std::vector<LayerToPrint> &layers,
|
|
const size_t single_object_instance_idx,
|
|
const unsigned int extruder_id);
|
|
|
|
LayerResult process_layer(
|
|
const Print &print,
|
|
// Set of object & print layers of the same PrintObject and with the same print_z.
|
|
const std::vector<LayerToPrint> &layers,
|
|
const LayerTools &layer_tools,
|
|
const bool last_layer,
|
|
// Pairs of PrintObject index and its instance index.
|
|
const std::vector<const PrintInstance*> *ordering,
|
|
// idientiy timelapse pos
|
|
const int most_used_extruder,
|
|
// If set to size_t(-1), then print all copies of all objects.
|
|
// Otherwise print a single copy of a single object.
|
|
const size_t single_object_idx = size_t(-1),
|
|
// BBS
|
|
const bool prime_extruder = false);
|
|
// Process all layers of all objects (non-sequential mode) with a parallel pipeline:
|
|
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
|
// and export G-code into file.
|
|
void process_layers(
|
|
const Print &print,
|
|
const ToolOrdering &tool_ordering,
|
|
const std::vector<const PrintInstance*> &print_object_instances_ordering,
|
|
const std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> &layers_to_print,
|
|
GCodeOutputStream &output_stream);
|
|
// Process all layers of a single object instance (sequential mode) with a parallel pipeline:
|
|
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
|
// and export G-code into file.
|
|
void process_layers(
|
|
const Print &print,
|
|
const ToolOrdering &tool_ordering,
|
|
std::vector<LayerToPrint> layers_to_print,
|
|
const size_t single_object_idx,
|
|
GCodeOutputStream &output_stream,
|
|
// BBS
|
|
const bool prime_extruder = false);
|
|
|
|
//BBS
|
|
void check_placeholder_parser_failed();
|
|
size_t cur_extruder_index() const;
|
|
size_t get_extruder_id(unsigned int filament_id) const;
|
|
void update_placeholder_parser_with_variant_params();
|
|
|
|
void set_last_pos(const Point &pos) { m_last_pos = Point3(pos, 0); m_last_pos_defined = true; }
|
|
void set_last_pos(const Point3 &pos) { m_last_pos = pos; m_last_pos_defined = true; }
|
|
bool last_pos_defined() const { return m_last_pos_defined; }
|
|
void set_extruders(const std::vector<unsigned int> &extruder_ids);
|
|
std::string preamble();
|
|
// BBS
|
|
std::string change_layer(coordf_t print_z);
|
|
// Bedslinger model: derive the Y-axis acceleration limit from the machine force/bed-mass config
|
|
// and the mass already printed. Yields the min machine Y acceleration when the A2L config keys are
|
|
// unset (i.e. every existing printer), so it is inert for them.
|
|
void mass_load_limited_machine_acceleration(const PrintStatistics &curr_print_statistics, const Print &print,
|
|
double &y_acceleration_limit_res, double &accumulated_mass_res);
|
|
// Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop
|
|
// should be executed
|
|
std::string extrude_entity(const ExtrusionEntity& entity,
|
|
const std::string& description = "",
|
|
double speed = -1.,
|
|
const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr());
|
|
// Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop
|
|
// should be executed
|
|
std::string extrude_loop(const ExtrusionLoop& loop,
|
|
const std::string& description,
|
|
double speed = -1.,
|
|
const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr(),
|
|
const Point* start_point = nullptr);
|
|
std::string extrude_multi_path(const ExtrusionMultiPath& multipath, const std::string& description = "", double speed = -1.);
|
|
std::string extrude_path(const ExtrusionPath& path, const std::string& description = "", double speed = -1.);
|
|
|
|
// Orca: Adaptive PA variables
|
|
// Used for adaptive PA when extruding paths with multiple, varying flow segments.
|
|
// This contains the sum of the mm3_per_mm values weighted by the length of each path segment.
|
|
// The m_multi_flow_segment_path_pa_set constrains the PA change request to the first extrusion segment.
|
|
// It sets the mm3_mm value for the adaptive PA post processor to be the average of that path
|
|
// as calculated and stored in the m_multi_segment_path_average_mm3_per_mm value
|
|
double m_multi_flow_segment_path_average_mm3_per_mm = 0;
|
|
bool m_multi_flow_segment_path_pa_set = false;
|
|
// Adaptive PA last set flow to enable issuing of PA change commands when adaptive PA for overhangs
|
|
// is enabled
|
|
double m_last_mm3_mm = 0;
|
|
// Orca: Adaptive PA code segment end
|
|
|
|
// Extruding multiple objects with soluble / non-soluble / combined supports
|
|
// on a multi-material printer, trying to minimize tool switches.
|
|
// Following structures sort extrusions by the extruder ID, by an order of objects and object islands.
|
|
struct ObjectByExtruder
|
|
{
|
|
ObjectByExtruder() : support(nullptr), support_extrusion_role(erNone) {}
|
|
const ExtrusionEntityCollection *support;
|
|
// erSupportMaterial / erSupportMaterialInterface / erSupportTransition or erMixed.
|
|
ExtrusionRole support_extrusion_role;
|
|
|
|
struct Island
|
|
{
|
|
struct Region {
|
|
// Non-owned references to LayerRegion::perimeters::entities
|
|
// std::vector<const ExtrusionEntity*> would be better here, but there is no way in C++ to convert from std::vector<T*> std::vector<const T*> without copying.
|
|
ExtrusionEntitiesPtr perimeters;
|
|
// Non-owned references to LayerRegion::fills::entities
|
|
ExtrusionEntitiesPtr infills;
|
|
|
|
std::vector<const WipingExtrusions::ExtruderPerCopy*> infills_overrides;
|
|
std::vector<const WipingExtrusions::ExtruderPerCopy*> perimeters_overrides;
|
|
|
|
enum Type {
|
|
PERIMETERS,
|
|
INFILL,
|
|
};
|
|
|
|
// Appends perimeter/infill entities and writes don't indices of those that are not to be extruder as part of perimeter/infill wiping
|
|
void append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copy_extruders);
|
|
};
|
|
|
|
|
|
std::vector<Region> by_region; // all extrusions for this island, grouped by regions
|
|
|
|
// Fills in by_region_per_copy_cache and returns its reference.
|
|
const std::vector<Region>& by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, unsigned int extruder, bool wiping_entities = false) const;
|
|
};
|
|
std::vector<Island> islands;
|
|
};
|
|
|
|
struct InstanceToPrint
|
|
{
|
|
InstanceToPrint(ObjectByExtruder &object_by_extruder, size_t layer_id, const PrintObject &print_object, size_t instance_id, size_t label_object_id) :
|
|
object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id), label_object_id(label_object_id) {}
|
|
|
|
// Repository
|
|
ObjectByExtruder &object_by_extruder;
|
|
// Index into std::vector<LayerToPrint>, which contains Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
|
|
const size_t layer_id;
|
|
const PrintObject &print_object;
|
|
// Instance idx of the copy of a print object.
|
|
const size_t instance_id;
|
|
//BBS: Unique id to label object to support skiping during printing
|
|
const size_t label_object_id;
|
|
};
|
|
|
|
std::vector<InstanceToPrint> sort_print_object_instances(
|
|
std::vector<ObjectByExtruder> &objects_by_extruder,
|
|
// Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
|
|
const std::vector<LayerToPrint> &layers,
|
|
// Ordering must be defined for normal (non-sequential print).
|
|
const std::vector<const PrintInstance*> *ordering,
|
|
// For sequential print, the instance of the object to be printing has to be defined.
|
|
const size_t single_object_instance_idx);
|
|
|
|
std::string extrude_perimeters(const Print& print, const std::vector<ObjectByExtruder::Island::Region>& by_region, bool is_first_layer, bool is_infill_first);
|
|
std::string extrude_infill(const Print& print, const std::vector<ObjectByExtruder::Island::Region>& by_region, bool ironing);
|
|
std::string extrude_support(const ExtrusionEntityCollection& support_fills, const ExtrusionRole support_extrusion_role);
|
|
|
|
// Farthest-point timelapse: find the extrusion point farthest from camera (0,0)
|
|
void compute_farthest_point(const std::vector<LayerToPrint> &layers, int most_used_extruder,
|
|
const std::map<std::pair<const SupportLayer *, ExtrusionRole>, unsigned int> &support_filaments);
|
|
// Build the per-layer timelapse snapshot g-code (safe-position or, when skip_pos_pick,
|
|
// an inline photo at the current head position). Extracted from the former process_layer lambda so the
|
|
// per-extrusion farthest-point hook (_extrude) can call it too. Identical to the old lambda when the
|
|
// farthest-point subsystem is disabled (skip_pos_pick=false, m_farthest_point_timelapse.enabled=false).
|
|
std::string generate_timelapse_gcode(const Print &print, coordf_t print_z, int most_used_extruder,
|
|
const std::set<size_t> *layer_object_label_ids,
|
|
const std::vector<const PrintObject*> *printed_objects,
|
|
bool skip_pos_pick = false);
|
|
|
|
// BBS
|
|
LiftType to_lift_type(ZHopType z_hop_types);
|
|
|
|
std::set<ObjectInstanceID> m_objsWithBrim; // indicates the object instances with brim
|
|
// Cache for custom seam enforcers/blockers for each layer.
|
|
SeamPlacer m_seam_placer;
|
|
|
|
// One stop of the island-level tour: consecutive islands of a single instance. An instance
|
|
// can have several visits per layer when its islands are toured non-consecutively.
|
|
struct InstanceVisit
|
|
{
|
|
// Index into the per-filament InstanceToPrint vector.
|
|
size_t instance_idx;
|
|
// Islands to print, in order (indices into ObjectByExtruder::islands). Empty: print all
|
|
// islands, ordered at extrusion time.
|
|
std::vector<size_t> islands;
|
|
// First visit of this instance this layer; skirt, brim and support are emitted here.
|
|
bool first_visit;
|
|
};
|
|
|
|
// One node of the island-level tour, also used as cache key: identity plus quantized position.
|
|
struct IslandOrderNode
|
|
{
|
|
ObjectID object_id;
|
|
size_t instance_id;
|
|
// Index into ObjectByExtruder::islands, or size_t(-1) for an instance without chainable
|
|
// islands (e.g. support only), which is toured as a single stop.
|
|
size_t island_idx;
|
|
// Island centroid in G-code coordinates, quantized to 1 mm for cache stability.
|
|
Point pos;
|
|
bool operator==(const IslandOrderNode &rhs) const {
|
|
return object_id == rhs.object_id && instance_id == rhs.instance_id &&
|
|
island_idx == rhs.island_idx && pos == rhs.pos;
|
|
}
|
|
};
|
|
|
|
// Cache the per-filament island tour to avoid recomputing while the layer's island layout is
|
|
// unchanged. Key: filament_id. Value: the nodes the tour was computed from, the per-instance
|
|
// island layout (count and whether the trailing catch-all island has anything to print), and
|
|
// the resulting visits.
|
|
// The layout is part of the key. Nodes only cover the chainable islands, so two
|
|
// layers with the same centroids but a different number of islands (thin walls, negative
|
|
// volumes come and go) matched the cache and the visit's catch-all index -- islands.size() - 1
|
|
// of the OLD layer -- ran past the new layer's islands (found by fuzzing: segfault in
|
|
// extrude_perimeters on multi-part objects).
|
|
struct IslandOrderCacheEntry
|
|
{
|
|
std::vector<IslandOrderNode> nodes;
|
|
std::vector<std::pair<size_t, bool>> layout;
|
|
std::vector<InstanceVisit> visits;
|
|
};
|
|
std::map<unsigned int, IslandOrderCacheEntry> m_ordering_cache;
|
|
|
|
ExtrusionQualityEstimator m_extrusion_quality_estimator;
|
|
|
|
|
|
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
|
This affects the input arguments supplied to the extrude*() and travel_to()
|
|
methods. */
|
|
Vec2d m_origin;
|
|
FullPrintConfig m_config;
|
|
DynamicConfig m_calib_config;
|
|
// scaled G-code resolution
|
|
double m_scaled_resolution;
|
|
std::unique_ptr<GCodeWriter> m_writer;
|
|
|
|
struct PlaceholderParserIntegration {
|
|
void reset();
|
|
void init(const GCodeWriter &config);
|
|
void update_from_gcodewriter(const GCodeWriter &writer);
|
|
void validate_output_vector_variables();
|
|
|
|
PlaceholderParser parser;
|
|
// For random number generator etc.
|
|
PlaceholderParser::ContextData context;
|
|
// Collection of templates, on which the placeholder substitution failed.
|
|
std::map<std::string, std::string> failed_templates;
|
|
// Input/output from/to custom G-code block, for returning position, retraction etc.
|
|
DynamicConfig output_config;
|
|
ConfigOptionFloats *opt_position { nullptr };
|
|
ConfigOptionFloat *opt_zhop { nullptr };
|
|
ConfigOptionFloats *opt_e_position { nullptr };
|
|
ConfigOptionFloats *opt_e_retracted { nullptr };
|
|
ConfigOptionFloats *opt_e_restart_extra { nullptr };
|
|
ConfigOptionFloats *opt_extruded_volume { nullptr };
|
|
ConfigOptionFloats *opt_extruded_weight { nullptr };
|
|
ConfigOptionFloat *opt_extruded_volume_total { nullptr };
|
|
ConfigOptionFloat *opt_extruded_weight_total { nullptr };
|
|
// Caches of the data passed to the script.
|
|
size_t num_extruders;
|
|
std::vector<double> position;
|
|
std::vector<double> e_position;
|
|
std::vector<double> e_retracted;
|
|
std::vector<double> e_restart_extra;
|
|
} m_placeholder_parser_integration;
|
|
|
|
OozePrevention m_ooze_prevention;
|
|
Wipe m_wipe;
|
|
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
|
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters;
|
|
TimelapsePosPicker m_timelapse_pos_picker;
|
|
|
|
// Farthest-point timelapse context. Corexy-only refinement layered on top of the existing
|
|
// timelapse_type. All fields default to the inert state; `enabled` is (re)computed each layer in
|
|
// process_layer and is false whenever the farthest_point_timelapse config toggle is off, the printer
|
|
// is i3 (psI3), or timelapse_type is not traditional — so every shipping printer that does not set the
|
|
// toggle is identical to the previous path.
|
|
struct FarthestPointTimelapseContext {
|
|
// Whether farthest-point timelapse is active for this layer
|
|
bool enabled{false};
|
|
// The farthest extrusion point from camera (0,0) in global scaled coordinates (includes plate origin + inst.shift)
|
|
Point farthest_point;
|
|
// farthest_point converted to mm (gcode coordinate space, includes plate origin)
|
|
Vec2d farthest_gcode_pos{0, 0};
|
|
// Extruder index (0-based) that prints the farthest point
|
|
int farthest_extruder_id{0};
|
|
// Whether the farthest point is printed by the photo head (most_used_extruder)
|
|
bool farthest_is_photo_head{false};
|
|
// Whether inline timelapse gcode has already been inserted on this layer
|
|
bool inserted_this_layer{false};
|
|
// The extruder used most on this layer, chosen as the photo head
|
|
int most_used_extruder{0};
|
|
// Object labels for the current layer, used when inline timelapse is inserted from extrusion code.
|
|
std::set<size_t> layer_object_label_ids;
|
|
};
|
|
FarthestPointTimelapseContext m_farthest_point_timelapse;
|
|
|
|
bool m_enable_loop_clipping;
|
|
//resonance avoidance
|
|
bool m_resonance_avoidance;
|
|
// If enabled, the G-code generator will put following comments at the ends
|
|
// of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _OVERHANG_FAN_START, _OVERHANG_FAN_END
|
|
// Those comments are received and consumed (removed from the G-code) by the CoolingBuffer.pm Perl module.
|
|
bool m_enable_cooling_markers;
|
|
|
|
bool m_enable_exclude_object;
|
|
std::vector<size_t> m_label_objects_ids;
|
|
std::string _encode_label_ids_to_base64(std::vector<size_t> ids);
|
|
// ORCA: Add support for role based fan speed control
|
|
std::array<bool, ExtrusionRole::erCount> m_is_role_based_fan_on;
|
|
std::array<int, ExtrusionRole::erCount> m_role_based_fan_marker_layer;
|
|
// Markers for the Pressure Equalizer to recognize the extrusion type.
|
|
// The Pressure Equalizer removes the markers from the final G-code.
|
|
bool m_enable_extrusion_role_markers;
|
|
// Keeps track of the last extrusion role passed to the processor
|
|
ExtrusionRole m_last_processor_extrusion_role;
|
|
// How many times will change_layer() be called?
|
|
// change_layer() will update the progress bar.
|
|
unsigned int m_layer_count;
|
|
// Progress bar indicator. Increments from -1 up to layer_count.
|
|
int m_layer_index;
|
|
// Current layer processed. In sequential printing mode, only a single copy will be printed.
|
|
// In non-sequential mode, all its copies will be printed.
|
|
const Layer* m_layer;
|
|
// m_layer is an object layer and it is being printed over raft surface.
|
|
bool m_object_layer_over_raft;
|
|
//double m_volumetric_speed;
|
|
// Support for the extrusion role markers. Which marker is active?
|
|
ExtrusionRole m_last_extrusion_role;
|
|
// To ignore gapfill role for retract_lift_enforce
|
|
ExtrusionRole m_last_notgapfill_extrusion_role;
|
|
// Support for G-Code Processor
|
|
float m_last_height{ 0.0f };
|
|
float m_last_layer_z{ 0.0f };
|
|
float m_max_layer_z{ 0.0f };
|
|
float m_last_width{ 0.0f };
|
|
// Bedslinger mass model: cumulative printed mass at the previous layer, used to derive
|
|
// the current layer mass for the per-layer Y acceleration limit (curr_y_acceleration_limit).
|
|
double m_last_layer_accumulated_mass{ 0.0 };
|
|
|
|
// Always check gcode placeholders when building in debug mode.
|
|
#if !defined(NDEBUG)
|
|
#define ORCA_CHECK_GCODE_PLACEHOLDERS 1
|
|
#endif
|
|
|
|
#if ORCA_CHECK_GCODE_PLACEHOLDERS
|
|
std::map<std::string, std::vector<std::string>> m_placeholder_error_messages;
|
|
#endif
|
|
|
|
Point3 m_last_pos;
|
|
bool m_last_pos_defined;
|
|
|
|
std::unique_ptr<CoolingBuffer> m_cooling_buffer;
|
|
std::unique_ptr<SpiralVase> m_spiral_vase;
|
|
// First-layer plane evaluator. Constructed once per print from the
|
|
// PrintConfig. is_active() == false on non-belt printers and on belt
|
|
// printers without a Z-axis shear; in that case all per-path plane
|
|
// checks short-circuit to the legacy Layer::id() == 0 path.
|
|
std::unique_ptr<FirstLayerPlane> m_first_layer_plane;
|
|
// Plate origin, kept so a writer replaced during export can be given it again.
|
|
Vec2d m_gcode_offset{ Vec2d::Zero() };
|
|
|
|
std::unique_ptr<PressureEqualizer> m_pressure_equalizer;
|
|
|
|
std::unique_ptr<AdaptivePAProcessor> m_pa_processor;
|
|
|
|
std::unique_ptr<WipeTowerIntegration> m_wipe_tower;
|
|
|
|
std::unique_ptr<SmallAreaInfillFlowCompensator> m_small_area_infill_flow_compensator;
|
|
|
|
// Heights (print_z) at which each grouped skirt has already been extruded.
|
|
std::vector<std::vector<coordf_t>> m_skirt_group_done;
|
|
// Has the brim been extruded already? Brim is being extruded only for the first object of a multi-object print.
|
|
bool m_brim_done;
|
|
// Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
|
|
bool m_second_layer_things_done;
|
|
// Index of a last object copy extruded.
|
|
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
|
|
|
// 1 << 0: A1 series cannot supprot traditional timelapse when printing by object (cannot turn on timelapse)
|
|
// 1 << 1: A1 series cannot supprot traditional timelapse with spiral vase mode (cannot turn on timelapse)
|
|
// 1 << 2: Timelapse in smooth mode without wipe tower (turn on with prompt)
|
|
int m_timelapse_warning_code = 0;
|
|
bool m_support_traditional_timelapse = true;
|
|
|
|
bool m_silent_time_estimator_enabled;
|
|
|
|
Print *m_print{nullptr};
|
|
|
|
std::vector<const PrintObject*> m_printed_objects;
|
|
|
|
// Processor
|
|
GCodeProcessor m_processor;
|
|
|
|
//some post-processing on the file, with their data class
|
|
std::unique_ptr<FanMover> m_fan_mover;
|
|
|
|
// BBS
|
|
Print* m_curr_print = nullptr;
|
|
unsigned int m_toolchange_count;
|
|
coordf_t m_nominal_z;
|
|
// Mixed-color sublayer state. Non-zero only while emitting a mixed slot's sub-layer:
|
|
// scales extrusion flow to the sub-layer's share of the nominal layer height, and
|
|
// reports that sub-height as the effective extrusion height. Reset to 0 afterwards.
|
|
double m_sub_layer_flow_ratio = 0.0;
|
|
double m_sub_layer_height = 0.0;
|
|
bool m_need_change_layer_lift_z = false;
|
|
int m_start_gcode_filament = -1;
|
|
std::string m_filament_instances_code;
|
|
|
|
// Object layer id of the layer being generated; keys the per-filament config-slot
|
|
// resolvers. Distinct from m_layer_index (an export progress counter starting at -1).
|
|
size_t m_cur_layer_idx{0};
|
|
|
|
// Belt brim apron layers only. They have no Layer, so the print_z that
|
|
// _extrude() needs for the first-layer-plane probe is published here instead.
|
|
// Scoped by BeltBrimZGuard in process_belt_brim_layer(), never left set.
|
|
std::optional<coordf_t> m_belt_brim_z;
|
|
// Belt brim only. Brim and coincident apron bands are emitted before m_layer
|
|
// is switched to their object, so belt_height_above_floor() would otherwise
|
|
// read the previously visited object's belt description -- making a brim's
|
|
// classification depend on plate visiting order. Those paths publish the
|
|
// owner here for the duration of the emission. Never left set.
|
|
const PrintObject *m_belt_floor_object{nullptr};
|
|
struct BeltFloorObjectGuard {
|
|
const PrintObject *&slot;
|
|
BeltFloorObjectGuard(const PrintObject *&s, const PrintObject *o) : slot(s) { slot = o; }
|
|
~BeltFloorObjectGuard() { slot = nullptr; }
|
|
};
|
|
|
|
std::set<unsigned int> m_initial_layer_extruders;
|
|
std::vector<std::vector<unsigned int>> m_sorted_layer_filaments;
|
|
// BBS
|
|
int get_bed_temperature(const int extruder_id, const bool is_first_layer, const BedType bed_type) const;
|
|
int get_highest_bed_temperature(const bool is_first_layer,const Print &print) const;
|
|
|
|
void update_layer_related_config(int layer_id);
|
|
|
|
double calc_max_volumetric_speed(const double layer_height, const double line_width, const std::string co_str);
|
|
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
|
bool _needSAFC(const ExtrusionPath &path);
|
|
void print_machine_envelope(GCodeOutputStream& file, Print& print);
|
|
void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
|
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
|
// On the first printing layer. This flag triggers first layer speeds.
|
|
//BBS
|
|
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0 && abs(m_layer->bottom_z()) < EPSILON; }
|
|
// Per-point first-layer test. When the FirstLayerPlane evaluator is
|
|
// active, the result depends on the supplied slicing-frame point;
|
|
// otherwise we delegate to the legacy per-layer test. This is the
|
|
// entry point used by per-path call sites in _extrude.
|
|
bool on_first_layer(const Vec3d &point_slicing_mm) const {
|
|
// Belt printers: measure height above the belt surface itself, in the
|
|
// slicing frame. See belt_height_above_floor() for why this does not go
|
|
// through FirstLayerPlane.
|
|
double h;
|
|
if (this->belt_height_above_floor(point_slicing_mm, h))
|
|
return h <= m_config.initial_layer_print_height.value + EPSILON;
|
|
if (m_first_layer_plane && m_first_layer_plane->is_active())
|
|
return m_first_layer_plane->is_first_layer(
|
|
point_slicing_mm, m_config.initial_layer_print_height.value);
|
|
return on_first_layer();
|
|
}
|
|
// "Effective layer index" used to drive layer-count thresholds like
|
|
// slow_down_layers. When the evaluator is active this returns the
|
|
// perpendicular distance to the plane in band_thickness_mm units;
|
|
// otherwise it returns the legacy slicing layer index.
|
|
int effective_layer_index_for_point(const Vec3d &point_slicing_mm) const {
|
|
double h;
|
|
if (this->belt_height_above_floor(point_slicing_mm, h)) {
|
|
const double lh = this->first_layer_band_mm();
|
|
return h <= 0. ? 0 : int(std::floor(h / lh));
|
|
}
|
|
if (m_first_layer_plane && m_first_layer_plane->is_active())
|
|
return m_first_layer_plane->effective_layer_index(point_slicing_mm);
|
|
return on_first_layer() ? 0 : layer_id();
|
|
}
|
|
|
|
// Band thickness for the *effective layer index* only. FirstLayerPlane keeps
|
|
// two separate thresholds and so must this path: is_first_layer() tests
|
|
// against initial_layer_print_height, while effective_layer_index() counts
|
|
// bands of first_layer_plane_thickness. Conflating them would apply
|
|
// first-layer treatment through a whole 1mm band on a 0.2mm first layer.
|
|
double first_layer_band_mm() const {
|
|
double band = m_config.first_layer_plane_thickness.value;
|
|
if (band <= 0.) band = m_config.initial_layer_print_height.value;
|
|
return band > 0. ? band : 0.2;
|
|
}
|
|
|
|
// Height of a slicing-frame point above the belt surface, or false when this
|
|
// is not a belt print.
|
|
//
|
|
// The belt surface is known exactly in the slicing frame from the slicing
|
|
// parameters (belt_floor_shear_factor / _from_axis / _z_shift) -- the same
|
|
// description the support generator uses. FirstLayerPlane instead derives its
|
|
// plane by composing gcode_remap_* with the g-code back-transform, so its
|
|
// answer changes with the machine's *output* axis convention: on a printer
|
|
// with a non-identity remap it reported ~86mm of clearance for geometry
|
|
// sitting directly on the belt, and no extrusion was ever classified as
|
|
// first-layer. Measuring against the belt itself is independent of every
|
|
// remap and back-transform.
|
|
bool belt_height_above_floor(const Vec3d &point_slicing_mm, double &height_mm) const;
|
|
int layer_id() const {
|
|
if (m_layer == nullptr)
|
|
return -1;
|
|
return m_layer->id();
|
|
}
|
|
// To control print speed of 1st object layer over raft interface.
|
|
bool object_layer_over_raft() const { return m_object_layer_over_raft; }
|
|
|
|
friend ObjectByExtruder& object_by_extruder(
|
|
std::map<unsigned int, std::vector<ObjectByExtruder>> &by_extruder,
|
|
unsigned int extruder_id,
|
|
size_t object_idx,
|
|
size_t num_objects);
|
|
friend std::vector<ObjectByExtruder::Island>& object_islands_by_extruder(
|
|
std::map<unsigned int, std::vector<ObjectByExtruder>> &by_extruder,
|
|
unsigned int extruder_id,
|
|
size_t object_idx,
|
|
size_t num_objects,
|
|
size_t num_islands);
|
|
|
|
friend class Wipe;
|
|
friend class WipeTowerIntegration;
|
|
friend class PressureEqualizer;
|
|
friend class Print;
|
|
friend class SmallAreaInfillFlowCompensator;
|
|
};
|
|
|
|
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print, bool init_order = false);
|
|
|
|
}
|
|
|
|
#endif
|