ENH: seperate skippable part time

jira: NONE

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I8d2117c7a7114298e966d3e043604d738847a72b
This commit is contained in:
xun.zhang 2025-02-08 15:59:38 +08:00 committed by lane.wei
parent f8369e8796
commit 9a9f634e31
2 changed files with 115 additions and 35 deletions

View File

@ -46,7 +46,7 @@ static const Slic3r::Vec3f DEFAULT_EXTRUDER_OFFSET = Slic3r::Vec3f::Zero();
namespace Slic3r { namespace Slic3r {
const std::vector<std::string> GCodeProcessor::Reserved_Tags = { const std::vector<std::string> GCodeProcessor::ReservedTags = {
" FEATURE: ", " FEATURE: ",
" WIPE_START", " WIPE_START",
" WIPE_END", " WIPE_END",
@ -71,10 +71,15 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
" NOZZLE_CHANGE_END" " NOZZLE_CHANGE_END"
}; };
const std::string GCodeProcessor::Flush_Start_Tag = " FLUSH_START"; const std::vector<std::string> GCodeProcessor::CustomTags = {
const std::string GCodeProcessor::Flush_End_Tag = " FLUSH_END"; " FLUSH_START",
const std::string GCodeProcessor::VFlush_Start_Tag = " VFLUSH_START"; " FLUSH_END",
const std::string GCodeProcessor::VFlush_End_Tag = " VFLUSH_END"; " VFLUSH_START",
" VFLUSH_END",
" SKIPPABLE_START",
" SKIPPABLE_END",
" SKIPTYPE: "
};
const float GCodeProcessor::Wipe_Width = 0.05f; const float GCodeProcessor::Wipe_Width = 0.05f;
@ -392,6 +397,13 @@ static void recalculate_trapezoids(std::vector<GCodeProcessor::TimeBlock>& block
} }
} }
void GCodeProcessor::TimeMachine::handle_time_block(const TimeBlock& block, float time, int activate_machine_idx, GCodeProcessorResult& result)
{
if (block.skippable_type != SkipType::stNone)
result.skippable_part_time[block.skippable_type] += block.time();
result.moves[block.move_id].time[activate_machine_idx] = time;
}
void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, float additional_time, ExtrusionRole target_role, block_handler_t block_handler) void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, float additional_time, ExtrusionRole target_role, block_handler_t block_handler)
{ {
if (!enabled || blocks.size() < 2) if (!enabled || blocks.size() < 2)
@ -1332,6 +1344,7 @@ void GCodeProcessorResult::reset() {
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>(); spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
layer_filaments.clear(); layer_filaments.clear();
filament_change_count_map.clear(); filament_change_count_map.clear();
skippable_part_time.clear();
warnings.clear(); warnings.clear();
//BBS: add mutex for protection of gcode result //BBS: add mutex for protection of gcode result
@ -1367,7 +1380,7 @@ bool GCodeProcessor::contains_reserved_tag(const std::string& gcode, std::string
std::string comment = line.raw(); std::string comment = line.raw();
if (comment.length() > 2 && comment.front() == ';') { if (comment.length() > 2 && comment.front() == ';') {
comment = comment.substr(1); comment = comment.substr(1);
for (const std::string& s : Reserved_Tags) { for (const std::string& s : ReservedTags) {
if (boost::starts_with(comment, s)) { if (boost::starts_with(comment, s)) {
ret = true; ret = true;
found_tag = comment; found_tag = comment;
@ -1394,7 +1407,7 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i
std::string comment = line.raw(); std::string comment = line.raw();
if (comment.length() > 2 && comment.front() == ';') { if (comment.length() > 2 && comment.front() == ';') {
comment = comment.substr(1); comment = comment.substr(1);
for (const std::string& s : Reserved_Tags) { for (const std::string& s : ReservedTags) {
if (boost::starts_with(comment, s)) { if (boost::starts_with(comment, s)) {
ret = true; ret = true;
found_tag.push_back(comment); found_tag.push_back(comment);
@ -2053,6 +2066,8 @@ void GCodeProcessor::reset()
m_wiping = false; m_wiping = false;
m_flushing = false; m_flushing = false;
m_virtual_flushing = false; m_virtual_flushing = false;
m_skippable = false;
m_skippable_type = SkipType::stNone;
m_wipe_tower = false; m_wipe_tower = false;
m_remaining_volume = { 0.f,0.f }; m_remaining_volume = { 0.f,0.f };
// BBS: arc move related data // BBS: arc move related data
@ -2236,9 +2251,9 @@ void GCodeProcessor::finalize(bool post_process)
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) { for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
TimeMachine& machine = m_time_processor.machines[i]; TimeMachine& machine = m_time_processor.machines[i];
TimeMachine::CustomGCodeTime& gcode_time = machine.gcode_time; TimeMachine::CustomGCodeTime& gcode_time = machine.gcode_time;
machine.calculate_time(0, 0, ExtrusionRole::erNone, [&moves = m_result.moves, i](const TimeBlock& block, int time) { machine.calculate_time(0, 0, ExtrusionRole::erNone, [&result=m_result, i,&machine](const TimeBlock& block, int time) {
moves[block.move_id].time[i] = time; machine.handle_time_block(block,time,i,result);
}); });
if (gcode_time.needed && gcode_time.cache != 0.0f) if (gcode_time.needed && gcode_time.cache != 0.0f)
gcode_time.times.push_back({ CustomGCode::ColorChange, gcode_time.cache }); gcode_time.times.push_back({ CustomGCode::ColorChange, gcode_time.cache });
} }
@ -2808,8 +2823,27 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
return; return;
} }
if (boost::starts_with(comment, custom_tags(CustomETags::SKIPPABLE_START))) {
m_skippable = true;
return;
}
if (boost::starts_with(comment, custom_tags(CustomETags::SKIPPABLE_END))) {
m_skippable = false;
m_skippable_type = SkipType::stNone;
return;
}
// skippable type
if (boost::starts_with(comment, custom_tags(CustomETags::SKIPPABLE_TYPE))) {
std::string_view type =comment.substr(custom_tags(CustomETags::SKIPPABLE_TYPE).length());
set_skippable_type(type);
return;
}
//BBS: flush start tag //BBS: flush start tag
if (boost::starts_with(comment, GCodeProcessor::Flush_Start_Tag)) { if (boost::starts_with(comment, custom_tags(CustomETags::FLUSH_START))) {
prev_role = m_extrusion_role; prev_role = m_extrusion_role;
set_extrusion_role(erFlush); set_extrusion_role(erFlush);
m_flushing = true; m_flushing = true;
@ -2817,20 +2851,20 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
} }
//BBS: flush end tag //BBS: flush end tag
if (boost::starts_with(comment, GCodeProcessor::Flush_End_Tag)) { if (boost::starts_with(comment, custom_tags(CustomETags::FLUSH_END))) {
set_extrusion_role(prev_role); set_extrusion_role(prev_role);
m_flushing = false; m_flushing = false;
return; return;
} }
if (boost::starts_with(comment, GCodeProcessor::VFlush_Start_Tag)) { if (boost::starts_with(comment, custom_tags(CustomETags::VFLUSH_START))) {
prev_role = m_extrusion_role; prev_role = m_extrusion_role;
set_extrusion_role(erFlush); set_extrusion_role(erFlush);
m_virtual_flushing = true; m_virtual_flushing = true;
return; return;
} }
if (boost::starts_with(comment, GCodeProcessor::VFlush_End_Tag)) { if (boost::starts_with(comment, custom_tags(CustomETags::VFLUSH_END))) {
set_extrusion_role(prev_role); set_extrusion_role(prev_role);
m_virtual_flushing = false; m_virtual_flushing = false;
return; return;
@ -3624,6 +3658,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
TimeBlock block; TimeBlock block;
block.move_type = type; block.move_type = type;
block.skippable_type = m_skippable_type;
//BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode. //BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode.
block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone; block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone;
block.distance = distance; block.distance = distance;
@ -3810,9 +3845,9 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
blocks.push_back(block); blocks.push_back(block);
if (blocks.size() > TimeProcessor::Planner::refresh_threshold) { if (blocks.size() > TimeProcessor::Planner::refresh_threshold) {
machine.calculate_time(TimeProcessor::Planner::queue_size, 0, erNone,[&moves = m_result.moves, i](const TimeBlock& block, int time) { machine.calculate_time(TimeProcessor::Planner::queue_size, 0, erNone, [&result=m_result, i,&machine](const TimeBlock& block, int time) {
moves[block.move_id].time[i] = time; machine.handle_time_block(block,time,i,result);
}); });
} }
} }
@ -4062,6 +4097,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
TimeBlock block; TimeBlock block;
block.move_type = type; block.move_type = type;
block.skippable_type = m_skippable_type;
//BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode. //BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode.
block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone; block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone;
block.distance = distance; block.distance = distance;
@ -4248,9 +4284,9 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
blocks.push_back(block); blocks.push_back(block);
if (blocks.size() > TimeProcessor::Planner::refresh_threshold) { if (blocks.size() > TimeProcessor::Planner::refresh_threshold) {
machine.calculate_time(TimeProcessor::Planner::queue_size, 0, erNone, [&move = this->m_result.moves,i](const TimeBlock& block, int time) { machine.calculate_time(TimeProcessor::Planner::queue_size, 0, erNone, [&result=m_result, i,&machine](const TimeBlock& block, int time) {
move[block.move_id].time[i] = time; machine.handle_time_block(block,time,i,result);
}); });
} }
} }
@ -4463,6 +4499,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
TimeBlock block; TimeBlock block;
block.move_type = type; block.move_type = type;
block.skippable_type = m_skippable_type;
//BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode. //BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode.
block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone; block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone;
block.distance = delta_xyz; block.distance = delta_xyz;
@ -4630,9 +4667,9 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
blocks.push_back(block); blocks.push_back(block);
if (blocks.size() > TimeProcessor::Planner::refresh_threshold) { if (blocks.size() > TimeProcessor::Planner::refresh_threshold) {
machine.calculate_time(TimeProcessor::Planner::queue_size, 0, erNone, [&moves = m_result.moves, i](const TimeBlock& block, int time) { machine.calculate_time(TimeProcessor::Planner::queue_size, 0, erNone, [&result=m_result, i,&machine](const TimeBlock& block, int time) {
moves[block.move_id].time[i] = time; machine.handle_time_block(block,time,i,result);
}); });
} }
} }
@ -5346,6 +5383,7 @@ void GCodeProcessor::process_filament_change(int id)
if (!machine.enabled) if (!machine.enabled)
continue; continue;
TimeBlock block; TimeBlock block;
block.skippable_type = m_skippable_type;
block.move_id = m_result.moves.size() - 1; block.move_id = m_result.moves.size() - 1;
block.role = erFlush; block.role = erFlush;
block.move_type = EMoveType::Tool_change; block.move_type = EMoveType::Tool_change;
@ -5427,6 +5465,20 @@ void GCodeProcessor::set_extrusion_role(ExtrusionRole role)
m_extrusion_role = role; m_extrusion_role = role;
} }
void GCodeProcessor::set_skippable_type(const std::string_view type)
{
if (!m_skippable){
m_skippable_type = SkipType::stNone;
return;
}
auto iter = skip_type_map.find(type);
if(iter!=skip_type_map.end()) {
m_skippable_type = iter->second;
} else {
m_skippable_type = SkipType::stOther;
}
}
float GCodeProcessor::minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const float GCodeProcessor::minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const
{ {
if (m_time_processor.machine_limits.machine_min_extruding_rate.empty()) if (m_time_processor.machine_limits.machine_min_extruding_rate.empty())
@ -5574,9 +5626,9 @@ void GCodeProcessor::process_custom_gcode_time(CustomGCode::Type code)
gcode_time.needed = true; gcode_time.needed = true;
//FIXME this simulates st_synchronize! is it correct? //FIXME this simulates st_synchronize! is it correct?
// The estimated time may be longer than the real print time. // The estimated time may be longer than the real print time.
machine.simulate_st_synchronize(0, erNone, [&moves = m_result.moves, i](const TimeBlock& block, int time) { machine.simulate_st_synchronize(0, erNone, [&result=m_result, i,&machine](const TimeBlock& block, int time) {
moves[block.move_id].time[i] = time; machine.handle_time_block(block,time,i,result);
}); });
if (gcode_time.cache != 0.0f) { if (gcode_time.cache != 0.0f) {
gcode_time.times.push_back({ code, gcode_time.cache }); gcode_time.times.push_back({ code, gcode_time.cache });
gcode_time.cache = 0.0f; gcode_time.cache = 0.0f;
@ -5606,9 +5658,9 @@ void GCodeProcessor::simulate_st_synchronize(float additional_time, ExtrusionRol
if (!machine.enabled) if (!machine.enabled)
continue; continue;
machine.simulate_st_synchronize(additional_time, target_role, [&moves = m_result.moves, i](const TimeBlock& block, int time) { machine.simulate_st_synchronize(additional_time, target_role, [&result=m_result, i,&machine](const TimeBlock& block, int time) {
moves[block.move_id].time[i] = time; machine.handle_time_block(block,time,i,result);
}); });
} }
} }

View File

@ -42,6 +42,16 @@ namespace Slic3r {
Count Count
}; };
enum SkipType
{
stTimelapse,
stOther,
stNone
};
const std::unordered_map<std::string_view, SkipType> skip_type_map {
{"timelapse", SkipType::stTimelapse}
};
struct PrintEstimatedStatistics struct PrintEstimatedStatistics
{ {
enum class ETimeMode : unsigned char enum class ETimeMode : unsigned char
@ -257,6 +267,8 @@ namespace Slic3r {
// first key stores `from` filament, second keys stores the `to` filament // first key stores `from` filament, second keys stores the `to` filament
std::map<std::pair<int,int>, int > filament_change_count_map; std::map<std::pair<int,int>, int > filament_change_count_map;
std::unordered_map<SkipType, float> skippable_part_time;
BedType bed_type = BedType::btCount; BedType bed_type = BedType::btCount;
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
int64_t time{ 0 }; int64_t time{ 0 };
@ -294,6 +306,7 @@ namespace Slic3r {
filament_printable_reuslt = other.filament_printable_reuslt; filament_printable_reuslt = other.filament_printable_reuslt;
layer_filaments = other.layer_filaments; layer_filaments = other.layer_filaments;
filament_change_count_map = other.filament_change_count_map; filament_change_count_map = other.filament_change_count_map;
skippable_part_time = other.skippable_part_time;
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
time = other.time; time = other.time;
#endif #endif
@ -381,11 +394,8 @@ namespace Slic3r {
class GCodeProcessor class GCodeProcessor
{ {
static const std::vector<std::string> Reserved_Tags; static const std::vector<std::string> ReservedTags;
static const std::string Flush_Start_Tag; static const std::vector<std::string> CustomTags;
static const std::string Flush_End_Tag;
static const std::string VFlush_Start_Tag;
static const std::string VFlush_End_Tag;
public: public:
enum class ETags : unsigned char enum class ETags : unsigned char
{ {
@ -413,7 +423,19 @@ namespace Slic3r {
NozzleChangeEnd NozzleChangeEnd
}; };
static const std::string& reserved_tag(ETags tag) { return Reserved_Tags[static_cast<unsigned char>(tag)]; } enum class CustomETags : unsigned char
{
FLUSH_START,
FLUSH_END,
VFLUSH_START,
VFLUSH_END,
SKIPPABLE_START,
SKIPPABLE_END,
SKIPPABLE_TYPE
};
static const std::string& reserved_tag(ETags tag) { return ReservedTags[static_cast<unsigned char>(tag)]; }
static const std::string& custom_tags(CustomETags tag) { return CustomTags[static_cast<unsigned char>(tag)]; }
// checks the given gcode for reserved tags and returns true when finding the 1st (which is returned into found_tag) // checks the given gcode for reserved tags and returns true when finding the 1st (which is returned into found_tag)
static bool contains_reserved_tag(const std::string& gcode, std::string& found_tag); static bool contains_reserved_tag(const std::string& gcode, std::string& found_tag);
// checks the given gcode for reserved tags and returns true when finding any // checks the given gcode for reserved tags and returns true when finding any
@ -497,6 +519,7 @@ namespace Slic3r {
EMoveType move_type{ EMoveType::Noop }; EMoveType move_type{ EMoveType::Noop };
ExtrusionRole role{ erNone }; ExtrusionRole role{ erNone };
SkipType skippable_type{ SkipType::stNone };
unsigned int move_id{ 0 }; // index of the related move vertex, will be assigned duraing gcode process unsigned int move_id{ 0 }; // index of the related move vertex, will be assigned duraing gcode process
unsigned int g1_line_id{ 0 }; unsigned int g1_line_id{ 0 };
unsigned int layer_id{ 0 }; unsigned int layer_id{ 0 };
@ -610,6 +633,8 @@ namespace Slic3r {
* @param block_handler Handler to set the processing logic for each block and its corresponding time. * @param block_handler Handler to set the processing logic for each block and its corresponding time.
*/ */
void calculate_time(size_t keep_last_n_blocks = 0, float additional_time = 0.0f, ExtrusionRole target_role = ExtrusionRole::erNone, block_handler_t block_handler = block_handler_t()); void calculate_time(size_t keep_last_n_blocks = 0, float additional_time = 0.0f, ExtrusionRole target_role = ExtrusionRole::erNone, block_handler_t block_handler = block_handler_t());
void handle_time_block(const TimeBlock& block, float time, int activate_machine_idx, GCodeProcessorResult& result);
}; };
struct UsedFilaments // filaments per ColorChange struct UsedFilaments // filaments per ColorChange
@ -963,6 +988,8 @@ namespace Slic3r {
bool m_flushing; // mark a section with real flush bool m_flushing; // mark a section with real flush
bool m_virtual_flushing; // mark a section with virtual flush, only for statistics bool m_virtual_flushing; // mark a section with virtual flush, only for statistics
bool m_wipe_tower; bool m_wipe_tower;
bool m_skippable;
SkipType m_skippable_type;
int m_object_label_id{-1}; int m_object_label_id{-1};
float m_print_z{0.0f}; float m_print_z{0.0f};
std::vector<float> m_remaining_volume; std::vector<float> m_remaining_volume;
@ -1244,6 +1271,7 @@ namespace Slic3r {
void store_move_vertex(EMoveType type, EMovePathType path_type = EMovePathType::Noop_move); void store_move_vertex(EMoveType type, EMovePathType path_type = EMovePathType::Noop_move);
void set_extrusion_role(ExtrusionRole role); void set_extrusion_role(ExtrusionRole role);
void set_skippable_type(const std::string_view type);
float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const; float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;
float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const; float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;