mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-29 12:11:59 +08:00
720 lines
24 KiB
C++
720 lines
24 KiB
C++
///|/ Copyright (c) Prusa Research 2020 - 2023 Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966
|
|
///|/
|
|
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
|
///|/
|
|
#include "TickCodesManager.hpp"
|
|
|
|
#include <math.h>
|
|
#include <algorithm>
|
|
#include <random>
|
|
|
|
#include "I18N.hpp"
|
|
#include "libslic3r/Print.hpp"
|
|
#include "libslic3r/Color.hpp"
|
|
#include "libslic3r/ExPolygon.hpp"
|
|
#include "libslic3r/GCode/ToolOrdering.hpp"
|
|
#include "libslic3r/Layer.hpp"
|
|
#include "libslic3r/PrintConfig.hpp"
|
|
#include "libslic3r/libslic3r.h"
|
|
|
|
using namespace Slic3r;
|
|
using namespace CustomGCode;
|
|
|
|
namespace DoubleSlider {
|
|
|
|
constexpr double min_delta_area = scale_(scale_(25)); // equal to 25 mm2
|
|
constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2
|
|
|
|
static const int YES = 0x00000002; // an analogue of wxYES
|
|
static const int NO = 0x00000008; // an analogue of wxNO
|
|
static const int CANCEL = 0x00000010; // an analogue of wxCANCEL
|
|
|
|
bool equivalent_areas(const double& bottom_area, const double& top_area)
|
|
{
|
|
return fabs(bottom_area - top_area) <= miscalculation;
|
|
}
|
|
|
|
TickCodeManager::TickCodeManager()
|
|
{
|
|
m_pause_print_msg = _u8L("Place bearings in slots and resume printing");
|
|
}
|
|
|
|
std::string TickCodeManager::gcode(CustomGCode::Type type)
|
|
{
|
|
if (m_print) {
|
|
const Slic3r::PrintConfig& config = m_print->config();
|
|
switch (type) {
|
|
case CustomGCode::ColorChange: return config.color_change_gcode;
|
|
case CustomGCode::PausePrint: return config.pause_print_gcode;
|
|
case CustomGCode::Template: return config.template_custom_gcode;
|
|
default: return std::string();
|
|
}
|
|
}
|
|
return std::string();
|
|
}
|
|
|
|
int TickCodeManager::get_tick_from_value(double value, bool force_lower_bound/* = false*/)
|
|
{
|
|
if (!m_values)
|
|
return -1;
|
|
std::vector<double>::const_iterator it;
|
|
if (is_wipe_tower && !force_lower_bound)
|
|
it = std::find_if(m_values->begin(), m_values->end(),
|
|
[value](const double & val) { return fabs(value - val) <= epsilon(); });
|
|
else
|
|
it = std::lower_bound(m_values->begin(), m_values->end(), value - epsilon());
|
|
|
|
if (it == m_values->end())
|
|
return -1;
|
|
return int(it - m_values->begin());
|
|
}
|
|
|
|
void TickCodeManager::set_ticks(const Info& custom_gcode_per_print_z)
|
|
{
|
|
ticks.clear();
|
|
|
|
const std::vector<CustomGCode::Item>& heights = custom_gcode_per_print_z.gcodes;
|
|
for (auto h : heights) {
|
|
int tick = get_tick_from_value(h.print_z);
|
|
if (tick >=0)
|
|
ticks.emplace(TickCode{ tick, h.type, h.extruder, h.color, h.extra });
|
|
}
|
|
|
|
if (custom_gcode_per_print_z.mode && !custom_gcode_per_print_z.gcodes.empty())
|
|
mode = custom_gcode_per_print_z.mode;
|
|
}
|
|
|
|
// Get active extruders for tick.
|
|
// Means one current extruder for not existing tick OR
|
|
// 2 extruders - for existing tick (extruder before ToolChange and extruder of current existing tick)
|
|
// Use those values to disable selection of active extruders
|
|
std::array<int, 2> TickCodeManager::get_active_extruders_for_tick(int tick, Mode main_mode) const
|
|
{
|
|
int default_initial_extruder = main_mode == MultiAsSingle ? std::max<int>(1, only_extruder_id) : 1;
|
|
std::array<int, 2> extruders = { default_initial_extruder, -1 };
|
|
if (empty())
|
|
return extruders;
|
|
|
|
auto it = ticks.lower_bound(TickCode{tick});
|
|
|
|
if (it != ticks.end() && it->tick == tick) // current tick exists
|
|
extruders[1] = it->extruder;
|
|
|
|
while (it != ticks.begin()) {
|
|
--it;
|
|
if(it->type == ToolChange) {
|
|
extruders[0] = it->extruder;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return extruders;
|
|
}
|
|
|
|
bool check_color_change(const PrintObject* object, size_t frst_layer_id, size_t layers_cnt, bool check_overhangs, std::function<bool(const Layer*)> break_condition)
|
|
{
|
|
double prev_area = area(object->get_layer(frst_layer_id)->lslices);
|
|
|
|
bool detected = false;
|
|
for (size_t i = frst_layer_id+1; i < layers_cnt; i++) {
|
|
const Layer* layer = object->get_layer(i);
|
|
double cur_area = area(layer->lslices);
|
|
|
|
// check for overhangs
|
|
if (check_overhangs && cur_area > prev_area && !equivalent_areas(prev_area, cur_area))
|
|
break;
|
|
|
|
// Check percent of the area decrease.
|
|
// This value have to be more than min_delta_area and more then 10%
|
|
if ((prev_area - cur_area > min_delta_area) && (cur_area / prev_area < 0.9)) {
|
|
detected = true;
|
|
if (break_condition(layer))
|
|
break;
|
|
}
|
|
|
|
prev_area = cur_area;
|
|
}
|
|
return detected;
|
|
}
|
|
|
|
bool TickCodeManager::auto_color_change(Mode main_mode)
|
|
{
|
|
if (!m_print)
|
|
return false;
|
|
|
|
if (!empty()) {
|
|
if (m_cb_show_warning_msg) {
|
|
std::string msg_text = _u8L("This action will cause deletion of all ticks on vertical slider.") + "\n\n" +
|
|
_u8L("This action is not revertible.\nDo you want to proceed?");
|
|
if (m_cb_show_warning_msg(msg_text, YES | NO) == NO)
|
|
return false;
|
|
}
|
|
ticks.clear();
|
|
}
|
|
|
|
int extruders_cnt = m_cb_get_extruders_cnt ? m_cb_get_extruders_cnt() : 0;
|
|
|
|
for (auto object : m_print->objects()) {
|
|
// An object should to have at least 2 layers to apply an auto color change
|
|
if (object->layer_count() < 2)
|
|
continue;
|
|
|
|
check_color_change(object, 1, object->layers().size(), false, [this, extruders_cnt, main_mode](const Layer* layer)
|
|
{
|
|
int tick = get_tick_from_value(layer->print_z);
|
|
if (tick >= 0 && !has_tick(tick)) {
|
|
if (main_mode == SingleExtruder) {
|
|
set_default_colors(true);
|
|
add_tick(tick, ColorChange, 1, layer->print_z);
|
|
}
|
|
else {
|
|
int extruder = 2;
|
|
if (!empty()) {
|
|
auto it = ticks.end();
|
|
it--;
|
|
extruder = it->extruder + 1;
|
|
if (extruder > extruders_cnt)
|
|
extruder = 1;
|
|
}
|
|
add_tick(tick, ToolChange, extruder, layer->print_z);
|
|
}
|
|
}
|
|
// allow max 3 auto color changes
|
|
return ticks.size() > 2;
|
|
});
|
|
}
|
|
|
|
if (empty() && m_cb_notify_empty_color_change)
|
|
m_cb_notify_empty_color_change();
|
|
|
|
return true;
|
|
}
|
|
|
|
std::string TickCodeManager::get_new_color(const std::string& color)
|
|
{
|
|
if (m_cb_get_new_color)
|
|
return m_cb_get_new_color(color);
|
|
return std::string();
|
|
}
|
|
|
|
std::string TickCodeManager::get_custom_code(const std::string& code_in, double height)
|
|
{
|
|
if (m_cb_get_custom_code)
|
|
return m_cb_get_custom_code(code_in, height);
|
|
return std::string();
|
|
}
|
|
|
|
std::string TickCodeManager::get_pause_print_msg(const std::string& msg_in, double height)
|
|
{
|
|
if (m_cb_get_pause_print_msg)
|
|
return m_cb_get_pause_print_msg(msg_in, height);
|
|
return std::string();
|
|
}
|
|
|
|
bool TickCodeManager::edit_extruder_sequence(const int max_tick, Mode main_mode)
|
|
{
|
|
if (!check_ticks_changed_event(ToolChange, main_mode) || !m_cb_get_extruders_sequence)
|
|
return false;
|
|
|
|
// init extruder sequence in respect to the extruders count
|
|
if (empty())
|
|
m_extruders_sequence.init(colors.size());
|
|
|
|
if(!m_cb_get_extruders_sequence(m_extruders_sequence))
|
|
return false;
|
|
|
|
erase_all_ticks_with_code(ToolChange);
|
|
|
|
const int extr_cnt = m_extruders_sequence.extruders.size();
|
|
if (extr_cnt == 1)
|
|
return true;
|
|
|
|
int tick = 0;
|
|
double value = 0.0;
|
|
int extruder = -1;
|
|
|
|
std::random_device rd; //Will be used to obtain a seed for the random number engine
|
|
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
|
|
std::uniform_int_distribution<> distrib(0, extr_cnt-1);
|
|
|
|
while (tick <= max_tick)
|
|
{
|
|
bool color_repetition = false;
|
|
if (m_extruders_sequence.random_sequence) {
|
|
int rand_extr = distrib(gen);
|
|
if (m_extruders_sequence.color_repetition)
|
|
color_repetition = rand_extr == extruder;
|
|
else
|
|
while (rand_extr == extruder)
|
|
rand_extr = distrib(gen);
|
|
extruder = rand_extr;
|
|
}
|
|
else {
|
|
extruder++;
|
|
if (extruder == extr_cnt)
|
|
extruder = 0;
|
|
}
|
|
|
|
const int cur_extruder = m_extruders_sequence.extruders[extruder];
|
|
|
|
bool meaningless_tick = tick == 0.0 && cur_extruder == extruder;
|
|
if (!meaningless_tick && !color_repetition)
|
|
ticks.emplace(TickCode{tick, ToolChange,cur_extruder + 1, colors[cur_extruder]});
|
|
|
|
if (m_extruders_sequence.is_mm_intervals) {
|
|
value += m_extruders_sequence.interval_by_mm;
|
|
tick = get_tick_from_value(value, true);
|
|
if (tick < 0)
|
|
break;
|
|
}
|
|
else
|
|
tick += m_extruders_sequence.interval_by_layers;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TickCodeManager::check_ticks_changed_event(Type type, Mode main_mode)
|
|
{
|
|
if ( mode == main_mode ||
|
|
(type != ColorChange && type != ToolChange) ||
|
|
(mode == SingleExtruder && main_mode == MultiAsSingle) || // All ColorChanges will be applied for 1st extruder
|
|
(mode == MultiExtruder && main_mode == MultiAsSingle) ) // Just mark ColorChanges for all unused extruders
|
|
return true;
|
|
|
|
if ((mode == SingleExtruder && main_mode == MultiExtruder ) ||
|
|
(mode == MultiExtruder && main_mode == SingleExtruder) )
|
|
{
|
|
if (!has_tick_with_code(ColorChange))
|
|
return true;
|
|
|
|
if (m_cb_show_info_msg) {
|
|
std::string message = (mode == SingleExtruder ?
|
|
_u8L("The last color change data was saved for a single extruder printing.") :
|
|
_u8L("The last color change data was saved for a multi extruder printing.")
|
|
) + "\n" +
|
|
_u8L("Your current changes will delete all saved color changes.") + "\n\n\t" +
|
|
_u8L("Are you sure you want to continue?");
|
|
|
|
if ( m_cb_show_info_msg(message, YES | NO) == YES)
|
|
erase_all_ticks_with_code(ColorChange);
|
|
}
|
|
return false;
|
|
}
|
|
// m_ticks_mode == MultiAsSingle
|
|
if( has_tick_with_code(ToolChange) ) {
|
|
if (m_cb_show_info_msg) {
|
|
std::string message = main_mode == SingleExtruder ? (
|
|
_u8L("The last color change data was saved for a multi extruder printing.") + "\n\n" +
|
|
_u8L("Select YES if you want to delete all saved tool changes, \n"
|
|
"NO if you want all tool changes switch to color changes, \n"
|
|
"or CANCEL to leave it unchanged.") + "\n\n\t" +
|
|
_u8L("Do you want to delete all saved tool changes?")
|
|
): ( // MultiExtruder
|
|
_u8L("The last color change data was saved for a multi extruder printing with tool changes for whole print.") + "\n\n" +
|
|
_u8L("Your current changes will delete all saved extruder (tool) changes.") + "\n\n\t" +
|
|
_u8L("Are you sure you want to continue?") ) ;
|
|
|
|
const int answer = m_cb_show_info_msg(message, YES | NO | (main_mode == SingleExtruder ? CANCEL : 0));
|
|
if (answer == YES) {
|
|
erase_all_ticks_with_code(ToolChange);
|
|
}
|
|
else if (main_mode == SingleExtruder && answer == NO) {
|
|
switch_code(ToolChange, ColorChange);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (m_cb_check_gcode_and_notify)
|
|
m_cb_check_gcode_and_notify(type);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get used extruders for tick.
|
|
// Means all extruders(tools) which will be used during printing from current tick to the end
|
|
std::set<int> TickCodeManager::get_used_extruders_for_tick(int tick, double print_z, Mode force_mode/* = Undef*/) const
|
|
{
|
|
if (!m_print)
|
|
return {};
|
|
|
|
Mode e_mode = !force_mode ? mode : force_mode;
|
|
|
|
if (e_mode == MultiExtruder) {
|
|
const ToolOrdering& tool_ordering = m_print->get_tool_ordering();
|
|
|
|
if (tool_ordering.empty())
|
|
return {};
|
|
|
|
std::set<int> used_extruders;
|
|
|
|
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), print_z, [](const LayerTools& lhs, double rhs) { return lhs.print_z < rhs; });
|
|
for (; it_layer_tools != tool_ordering.end(); ++it_layer_tools) {
|
|
const std::vector<unsigned>& extruders = it_layer_tools->extruders;
|
|
for (const auto& extruder : extruders)
|
|
used_extruders.emplace(extruder + 1);
|
|
}
|
|
|
|
return used_extruders;
|
|
}
|
|
|
|
const int default_initial_extruder = e_mode == MultiAsSingle ? std::max(only_extruder_id, 1) : 1;
|
|
if (ticks.empty() || e_mode == SingleExtruder)
|
|
return { default_initial_extruder };
|
|
|
|
std::set<int> used_extruders;
|
|
|
|
auto it_start = ticks.lower_bound(TickCode{ tick });
|
|
auto it = it_start;
|
|
if (it == ticks.begin() && it->type == ToolChange &&
|
|
tick != it->tick) // In case of switch of ToolChange to ColorChange, when tick exists,
|
|
// we shouldn't change color for extruder, which will be deleted
|
|
{
|
|
used_extruders.emplace(it->extruder);
|
|
if (tick < it->tick)
|
|
used_extruders.emplace(default_initial_extruder);
|
|
}
|
|
|
|
while (it != ticks.begin()) {
|
|
--it;
|
|
if (it->type == ToolChange && tick != it->tick) {
|
|
used_extruders.emplace(it->extruder);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (it == ticks.begin() && used_extruders.empty())
|
|
used_extruders.emplace(default_initial_extruder);
|
|
|
|
for (it = it_start; it != ticks.end(); ++it)
|
|
if (it->type == ToolChange && tick != it->tick)
|
|
used_extruders.emplace(it->extruder);
|
|
|
|
return used_extruders;
|
|
}
|
|
|
|
std::string TickCodeManager::get_color_for_tick(TickCode tick, Type type, const int extruder)
|
|
{
|
|
auto opposite_one_color = [](const std::string& color) {
|
|
ColorRGB rgb;
|
|
decode_color(color, rgb);
|
|
return encode_color(opposite(rgb));
|
|
};
|
|
auto opposite_two_colors = [](const std::string& a, const std::string& b) {
|
|
ColorRGB rgb1; decode_color(a, rgb1);
|
|
ColorRGB rgb2; decode_color(b, rgb2);
|
|
return encode_color(opposite(rgb1, rgb2));
|
|
};
|
|
|
|
if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) {
|
|
|
|
if (ticks.empty())
|
|
return opposite_one_color(colors[0]);
|
|
|
|
auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick);
|
|
if (before_tick_it == ticks.end()) {
|
|
while (before_tick_it != ticks.begin())
|
|
if (--before_tick_it; before_tick_it->type == ColorChange)
|
|
break;
|
|
if (before_tick_it->type == ColorChange)
|
|
return opposite_one_color(before_tick_it->color);
|
|
|
|
return opposite_one_color(colors[0]);
|
|
}
|
|
|
|
if (before_tick_it == ticks.begin()) {
|
|
const std::string& frst_color = colors[0];
|
|
if (before_tick_it->type == ColorChange)
|
|
return opposite_two_colors(frst_color, before_tick_it->color);
|
|
|
|
auto next_tick_it = before_tick_it;
|
|
while (next_tick_it != ticks.end())
|
|
if (++next_tick_it; next_tick_it != ticks.end() && next_tick_it->type == ColorChange)
|
|
break;
|
|
if (next_tick_it != ticks.end() && next_tick_it->type == ColorChange)
|
|
return opposite_two_colors(frst_color, next_tick_it->color);
|
|
|
|
return opposite_one_color(frst_color);
|
|
}
|
|
|
|
std::string frst_color = "";
|
|
if (before_tick_it->type == ColorChange)
|
|
frst_color = before_tick_it->color;
|
|
else {
|
|
auto next_tick_it = before_tick_it;
|
|
while (next_tick_it != ticks.end())
|
|
if (++next_tick_it; next_tick_it != ticks.end() && next_tick_it->type == ColorChange) {
|
|
frst_color = next_tick_it->color;
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (before_tick_it != ticks.begin())
|
|
if (--before_tick_it; before_tick_it->type == ColorChange)
|
|
break;
|
|
|
|
if (before_tick_it->type == ColorChange) {
|
|
if (frst_color.empty())
|
|
return opposite_one_color(before_tick_it->color);
|
|
|
|
return opposite_two_colors(before_tick_it->color, frst_color);
|
|
}
|
|
|
|
if (frst_color.empty())
|
|
return opposite_one_color(colors[0]);
|
|
|
|
return opposite_two_colors(colors[0], frst_color);
|
|
}
|
|
|
|
std::string color = colors[extruder - 1];
|
|
|
|
if (type == ColorChange) {
|
|
if (!ticks.empty()) {
|
|
auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick );
|
|
while (before_tick_it != ticks.begin()) {
|
|
--before_tick_it;
|
|
if (before_tick_it->type == ColorChange && before_tick_it->extruder == extruder) {
|
|
color = before_tick_it->color;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
color = get_new_color(color);
|
|
}
|
|
return color;
|
|
}
|
|
|
|
bool TickCodeManager::add_tick(const int tick, Type type, const int extruder, double print_z)
|
|
{
|
|
std::string color;
|
|
std::string extra;
|
|
if (type == Custom) // custom Gcode
|
|
{
|
|
extra = get_custom_code(m_custom_gcode, print_z);
|
|
if (extra.empty())
|
|
return false;
|
|
m_custom_gcode = extra;
|
|
}
|
|
else if (type == PausePrint) {
|
|
extra = get_pause_print_msg(m_pause_print_msg, print_z);
|
|
if (extra.empty())
|
|
return false;
|
|
m_pause_print_msg = extra;
|
|
}
|
|
else {
|
|
color = get_color_for_tick(TickCode{ tick }, type, extruder);
|
|
if (color.empty())
|
|
return false;
|
|
}
|
|
|
|
ticks.emplace(TickCode{ tick, type, extruder, color, extra });
|
|
return true;
|
|
}
|
|
|
|
bool TickCodeManager::edit_tick(std::set<TickCode>::iterator it, double print_z)
|
|
{
|
|
// Save previously value of the tick before the call a Dialog from get_... functions,
|
|
// otherwise a background process can change ticks values and current iterator wouldn't be valid for the moment of a Dialog close
|
|
// and PS will crash (see https://github.com/prusa3d/PrusaSlicer/issues/10941)
|
|
TickCode changed_tick = *it;
|
|
|
|
std::string edited_value;
|
|
if (it->type == ColorChange)
|
|
edited_value = get_new_color(it->color);
|
|
else if (it->type == PausePrint)
|
|
edited_value = get_pause_print_msg(it->extra, print_z);
|
|
else
|
|
edited_value = get_custom_code(it->type == Template ? gcode(Template) : it->extra, print_z);
|
|
|
|
if (edited_value.empty())
|
|
return false;
|
|
|
|
// Update iterator. For this moment its value can be invalid
|
|
if (it = ticks.find(changed_tick); it == ticks.end())
|
|
return false;
|
|
|
|
if (it->type == ColorChange) {
|
|
if (it->color == edited_value)
|
|
return false;
|
|
changed_tick.color = edited_value;
|
|
}
|
|
else if (it->type == Template) {
|
|
if (gcode(Template) == edited_value)
|
|
return false;
|
|
changed_tick.extra = edited_value;
|
|
changed_tick.type = Custom;
|
|
}
|
|
else if (it->type == Custom || it->type == PausePrint) {
|
|
if (it->extra == edited_value)
|
|
return false;
|
|
changed_tick.extra = edited_value;
|
|
if (it->type == Template)
|
|
changed_tick.type = Custom;
|
|
}
|
|
|
|
ticks.erase(it);
|
|
ticks.emplace(changed_tick);
|
|
|
|
return true;
|
|
}
|
|
|
|
void TickCodeManager::switch_code(Type type_from, Type type_to)
|
|
{
|
|
for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; )
|
|
if (it->type == type_from) {
|
|
TickCode tick = *it;
|
|
tick.type = type_to;
|
|
tick.extruder = 1;
|
|
ticks.erase(it);
|
|
it = ticks.emplace(tick).first;
|
|
}
|
|
else
|
|
++it;
|
|
}
|
|
|
|
bool TickCodeManager::switch_code_for_tick(std::set<TickCode>::iterator it, Type type_to, const int extruder)
|
|
{
|
|
const std::string color = get_color_for_tick(*it, type_to, extruder);
|
|
if (color.empty())
|
|
return false;
|
|
|
|
TickCode changed_tick = *it;
|
|
changed_tick.type = type_to;
|
|
changed_tick.extruder = extruder;
|
|
changed_tick.color = color;
|
|
|
|
ticks.erase(it);
|
|
ticks.emplace(changed_tick);
|
|
|
|
return true;
|
|
}
|
|
|
|
void TickCodeManager::erase_all_ticks_with_code(Type type)
|
|
{
|
|
for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; ) {
|
|
if (it->type == type)
|
|
it = ticks.erase(it);
|
|
else
|
|
++it;
|
|
}
|
|
}
|
|
|
|
bool TickCodeManager::has_tick_with_code(Type type)
|
|
{
|
|
for (const TickCode& tick : ticks)
|
|
if (tick.type == type)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TickCodeManager::has_tick(int tick)
|
|
{
|
|
return ticks.find(TickCode{ tick }) != ticks.end();
|
|
}
|
|
|
|
ConflictType TickCodeManager::is_conflict_tick(const TickCode& tick, Mode main_mode, double print_z)
|
|
{
|
|
if ((tick.type == ColorChange && (
|
|
(mode == SingleExtruder && main_mode == MultiExtruder ) ||
|
|
(mode == MultiExtruder && main_mode == SingleExtruder) )) ||
|
|
(tick.type == ToolChange &&
|
|
(mode == MultiAsSingle && main_mode != MultiAsSingle)) )
|
|
return ctModeConflict;
|
|
|
|
// check ColorChange tick
|
|
if (tick.type == ColorChange) {
|
|
// We should mark a tick as a "MeaninglessColorChange",
|
|
// if it has a ColorChange for unused extruder from current print to end of the print
|
|
std::set<int> used_extruders_for_tick = get_used_extruders_for_tick(tick.tick, print_z, main_mode);
|
|
|
|
if (used_extruders_for_tick.find(tick.extruder) == used_extruders_for_tick.end())
|
|
return ctMeaninglessColorChange;
|
|
|
|
// We should mark a tick as a "Redundant",
|
|
// if it has a ColorChange for extruder that has not been used before
|
|
if (mode == MultiAsSingle && tick.extruder != std::max<int>(only_extruder_id, 1) )
|
|
{
|
|
auto it = ticks.lower_bound( tick );
|
|
if (it == ticks.begin() && it->type == ToolChange && tick.extruder == it->extruder)
|
|
return ctNone;
|
|
|
|
while (it != ticks.begin()) {
|
|
--it;
|
|
if (it->type == ToolChange && tick.extruder == it->extruder)
|
|
return ctNone;
|
|
}
|
|
|
|
return ctRedundant;
|
|
}
|
|
}
|
|
|
|
// check ToolChange tick
|
|
if (mode == MultiAsSingle && tick.type == ToolChange) {
|
|
// We should mark a tick as a "MeaninglessToolChange",
|
|
// if it has a ToolChange to the same extruder
|
|
auto it = ticks.find(tick);
|
|
if (it->extruder > colors.size())
|
|
return ctNotPossibleToolChange;
|
|
|
|
if (it == ticks.begin())
|
|
return tick.extruder == std::max<int>(only_extruder_id, 1) ? ctMeaninglessToolChange : ctNone;
|
|
|
|
while (it != ticks.begin()) {
|
|
--it;
|
|
if (it->type == ToolChange)
|
|
return tick.extruder == it->extruder ? ctMeaninglessToolChange : ctNone;
|
|
}
|
|
}
|
|
|
|
return ctNone;
|
|
}
|
|
|
|
std::string TickCodeManager::get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const
|
|
{
|
|
const int current_extruder = it->extruder == 0 ? std::max<int>(only_extruder_id, 1) : it->extruder;
|
|
|
|
if (current_extruder > colors.size())
|
|
return it->color;
|
|
|
|
auto it_n = it;
|
|
while (it_n != ticks.begin()) {
|
|
--it_n;
|
|
if (it_n->type == ColorChange && it_n->extruder == current_extruder)
|
|
return it_n->color;
|
|
}
|
|
|
|
return colors[current_extruder-1]; // return a color for a specific extruder from the colors list
|
|
}
|
|
|
|
std::string TickCodeManager::get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const
|
|
{
|
|
const int def_extruder = std::max<int>(1, only_extruder_id);
|
|
auto it_n = it;
|
|
bool is_tool_change = false;
|
|
while (it_n != ticks.begin()) {
|
|
--it_n;
|
|
if (it_n->type == ToolChange) {
|
|
is_tool_change = true;
|
|
if (it_n->extruder == it->extruder)
|
|
return it->color;
|
|
break;
|
|
}
|
|
if (it_n->type == ColorChange && it_n->extruder == it->extruder)
|
|
return it->color;
|
|
}
|
|
if (!is_tool_change && it->extruder == def_extruder)
|
|
return it->color;
|
|
|
|
return "";
|
|
}
|
|
|
|
} // DoubleSlider
|
|
|
|
|