ENH: Add gcode check for multi_extruder
jira: none Change-Id: Iebc43e608c4509eb62b280af2d401fa9e0e089ba
This commit is contained in:
parent
c53a35856d
commit
c75c10e312
|
@ -1305,6 +1305,20 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||||
m_processor.result().filament_printable_reuslt = FilamentPrintableResult(conflict_filament, bed_type_to_gcode_string(m_config.curr_bed_type));
|
m_processor.result().filament_printable_reuslt = FilamentPrintableResult(conflict_filament, bed_type_to_gcode_string(m_config.curr_bed_type));
|
||||||
}
|
}
|
||||||
m_processor.set_filaments(m_writer.extruders());
|
m_processor.set_filaments(m_writer.extruders());
|
||||||
|
// check gcode is valid in multi_extruder printabele area
|
||||||
|
int extruder_size = m_print->config().nozzle_diameter.values.size();
|
||||||
|
if (extruder_size > 1) {
|
||||||
|
std::vector<Vec2d> printable_area = m_print->get_printable_area();
|
||||||
|
Polygon printable_poly = Polygon::new_scale(printable_area);
|
||||||
|
std::vector<std::vector<Vec2d>> extruder_printable_areas = m_print->get_extruder_printable_area();
|
||||||
|
std::vector<Polygons> extruder_unprintable_polys;
|
||||||
|
for (const auto &e_printable_area : extruder_printable_areas) {
|
||||||
|
Polygons ploys = diff(printable_poly, Polygon::new_scale(e_printable_area));
|
||||||
|
extruder_unprintable_polys.emplace_back(ploys);
|
||||||
|
}
|
||||||
|
m_processor.check_multi_extruder_gcode_valid(extruder_unprintable_polys, m_print->get_filament_maps());
|
||||||
|
}
|
||||||
|
|
||||||
m_processor.finalize(true);
|
m_processor.finalize(true);
|
||||||
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
|
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
|
||||||
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics);
|
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics);
|
||||||
|
|
|
@ -1070,6 +1070,59 @@ GCodeProcessor::GCodeProcessor()
|
||||||
m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].line_m73_stop_mask = "M73 D%s\n";
|
m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].line_m73_stop_mask = "M73 D%s\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GCodeProcessor::check_multi_extruder_gcode_valid(const std::vector<Polygons> &unprintable_areas, const std::vector<int> &filament_map)
|
||||||
|
{
|
||||||
|
m_result.gcode_check_result.reset();
|
||||||
|
|
||||||
|
auto to_2d = [](const Vec3d &pos) -> Point {
|
||||||
|
Point ps(scale_(pos.x()), scale_(pos.y()));
|
||||||
|
return ps;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<int, Points> gcode_path_pos;
|
||||||
|
for (const GCodeProcessorResult::MoveVertex &move : m_result.moves) {
|
||||||
|
if (move.type == EMoveType::Extrude/* || move.type == EMoveType::Travel*/) {
|
||||||
|
if (move.is_arc_move_with_interpolation_points()) {
|
||||||
|
for (int i = 0; i < move.interpolation_points.size(); i++) {
|
||||||
|
gcode_path_pos[int(move.extruder_id)].emplace_back(to_2d(move.interpolation_points[i].cast<double>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gcode_path_pos[int(move.extruder_id)].emplace_back(to_2d(move.position.cast<double>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid = true;
|
||||||
|
for (auto iter = gcode_path_pos.begin(); iter != gcode_path_pos.end(); ++iter) {
|
||||||
|
int extruder_id = filament_map[iter->first] - 1;
|
||||||
|
Polygon path_poly(iter->second);
|
||||||
|
BoundingBox bbox = path_poly.bounding_box();
|
||||||
|
|
||||||
|
// Simplified use bounding_box, Accurate calculation is not efficient
|
||||||
|
for (const Polygon &poly : unprintable_areas[extruder_id]) {
|
||||||
|
if (poly.bounding_box().overlap(bbox)) {
|
||||||
|
m_result.gcode_check_result.error_code = 1;
|
||||||
|
m_result.gcode_check_result.error_infos[extruder_id].push_back(iter->first);
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Accurate calculation is not efficient
|
||||||
|
for (const Polygon& poly : unprintable_areas[extruder_id]) {
|
||||||
|
if (poly.overlaps({path_poly})) {
|
||||||
|
m_result.gcode_check_result.error_code = 1;
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
void GCodeProcessor::apply_config(const PrintConfig& config)
|
void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||||
{
|
{
|
||||||
m_parser.apply_config(config);
|
m_parser.apply_config(config);
|
||||||
|
|
|
@ -132,9 +132,23 @@ namespace Slic3r {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ConflictResultOpt = std::optional<ConflictResult>;
|
||||||
|
|
||||||
|
struct GCodeCheckResult
|
||||||
|
{
|
||||||
|
int error_code = 0; // 0 means succeed
|
||||||
|
std::map<int, std::vector<int>> error_infos; // extruder_id to filament_ids
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
error_code = 0;
|
||||||
|
error_infos.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct GCodeProcessorResult
|
struct GCodeProcessorResult
|
||||||
{
|
{
|
||||||
ConflictResultOpt conflict_result;
|
ConflictResultOpt conflict_result;
|
||||||
|
GCodeCheckResult gcode_check_result;
|
||||||
FilamentPrintableResult filament_printable_reuslt;
|
FilamentPrintableResult filament_printable_reuslt;
|
||||||
|
|
||||||
struct SettingsIds
|
struct SettingsIds
|
||||||
|
@ -256,6 +270,7 @@ namespace Slic3r {
|
||||||
spiral_vase_layers = other.spiral_vase_layers;
|
spiral_vase_layers = other.spiral_vase_layers;
|
||||||
warnings = other.warnings;
|
warnings = other.warnings;
|
||||||
bed_type = other.bed_type;
|
bed_type = other.bed_type;
|
||||||
|
gcode_check_result = other.gcode_check_result;
|
||||||
filament_printable_reuslt = other.filament_printable_reuslt;
|
filament_printable_reuslt = other.filament_printable_reuslt;
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
time = other.time;
|
time = other.time;
|
||||||
|
@ -820,6 +835,8 @@ namespace Slic3r {
|
||||||
public:
|
public:
|
||||||
GCodeProcessor();
|
GCodeProcessor();
|
||||||
|
|
||||||
|
// check whether the gcode path meets the filament_map grouping requirements
|
||||||
|
bool check_multi_extruder_gcode_valid(const std::vector<Polygons> &unprintable_areas, const std::vector<int>& filament_map);
|
||||||
void apply_config(const PrintConfig& config);
|
void apply_config(const PrintConfig& config);
|
||||||
|
|
||||||
void set_filaments(const std::vector<Extruder>&filament_lists) { m_filament_lists=filament_lists;}
|
void set_filaments(const std::vector<Extruder>&filament_lists) { m_filament_lists=filament_lists;}
|
||||||
|
|
|
@ -2370,6 +2370,16 @@ FilamentMapMode Print::get_filament_map_mode() const
|
||||||
return m_config.filament_map_mode;
|
return m_config.filament_map_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Vec2d> Print::get_printable_area()
|
||||||
|
{
|
||||||
|
return m_config.printable_area.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<Vec2d>> Print::get_extruder_printable_area()
|
||||||
|
{
|
||||||
|
return m_config.extruder_printable_area.values;
|
||||||
|
}
|
||||||
|
|
||||||
size_t Print::get_extruder_id(unsigned int filament_id) const
|
size_t Print::get_extruder_id(unsigned int filament_id) const
|
||||||
{
|
{
|
||||||
std::vector<int> filament_map = get_filament_maps();
|
std::vector<int> filament_map = get_filament_maps();
|
||||||
|
|
|
@ -827,7 +827,6 @@ public:
|
||||||
// get the group label of filament
|
// get the group label of filament
|
||||||
size_t get_extruder_id(unsigned int filament_id) const;
|
size_t get_extruder_id(unsigned int filament_id) const;
|
||||||
|
|
||||||
// 1 based ids
|
|
||||||
const std::vector<std::vector<int>>& get_unprintable_filament_ids() const { return m_unprintable_filament_ids; }
|
const std::vector<std::vector<int>>& get_unprintable_filament_ids() const { return m_unprintable_filament_ids; }
|
||||||
void set_unprintable_filament_ids(const std::vector<std::vector<int>> &filament_ids) { m_unprintable_filament_ids = filament_ids; }
|
void set_unprintable_filament_ids(const std::vector<std::vector<int>> &filament_ids) { m_unprintable_filament_ids = filament_ids; }
|
||||||
|
|
||||||
|
@ -954,6 +953,8 @@ private:
|
||||||
FakeWipeTower m_fake_wipe_tower;
|
FakeWipeTower m_fake_wipe_tower;
|
||||||
bool m_has_auto_filament_map_result{false};
|
bool m_has_auto_filament_map_result{false};
|
||||||
|
|
||||||
|
std::vector<std::vector<int>> m_unprintable_filament_ids;
|
||||||
|
|
||||||
// OrcaSlicer: calibration
|
// OrcaSlicer: calibration
|
||||||
Calib_Params m_calib_params;
|
Calib_Params m_calib_params;
|
||||||
|
|
||||||
|
|
|
@ -1720,6 +1720,7 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
|
||||||
BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height(), build_volume.extruder_areas());
|
BuildVolume plate_build_volume(pp_bed_shape, build_volume.printable_height(), build_volume.extruder_areas());
|
||||||
const std::vector<BoundingBoxf3>& exclude_areas = curr_plate->get_exclude_areas();
|
const std::vector<BoundingBoxf3>& exclude_areas = curr_plate->get_exclude_areas();
|
||||||
|
|
||||||
|
curr_plate->clear_unprintable_filament_ids();
|
||||||
for (GLVolume* volume : this->volumes)
|
for (GLVolume* volume : this->volumes)
|
||||||
{
|
{
|
||||||
if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) {
|
if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) {
|
||||||
|
@ -1736,6 +1737,17 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
|
||||||
{
|
{
|
||||||
std::vector<bool> inside_extruders;
|
std::vector<bool> inside_extruders;
|
||||||
state = plate_build_volume.check_volume_bbox_state_with_extruder_areas(bb, inside_extruders);
|
state = plate_build_volume.check_volume_bbox_state_with_extruder_areas(bb, inside_extruders);
|
||||||
|
if (state == BuildVolume::ObjectState::Limited) {
|
||||||
|
const ModelObjectPtrs &model_objects = model.objects;
|
||||||
|
ModelObject *model_object = model_objects[volume->object_idx()];
|
||||||
|
ModelVolume *model_volume = model_object->volumes[volume->volume_idx()];
|
||||||
|
for (size_t i = 0; i < inside_extruders.size(); ++i) {
|
||||||
|
if (!inside_extruders[i]) {
|
||||||
|
std::vector<int> extruders = model_volume->get_extruders();
|
||||||
|
curr_plate->append_unprintable_filament_ids(i, extruders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BuildVolume::Type::Circle:
|
case BuildVolume::Type::Circle:
|
||||||
|
|
|
@ -1147,6 +1147,8 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
|
||||||
m_conflict_result = gcode_result.conflict_result;
|
m_conflict_result = gcode_result.conflict_result;
|
||||||
if (m_conflict_result) { m_conflict_result.value().layer = m_layers.get_l_at(m_conflict_result.value()._height); }
|
if (m_conflict_result) { m_conflict_result.value().layer = m_layers.get_l_at(m_conflict_result.value()._height); }
|
||||||
|
|
||||||
|
m_gcode_check_result = gcode_result.gcode_check_result;
|
||||||
|
|
||||||
filament_printable_reuslt = gcode_result.filament_printable_reuslt;
|
filament_printable_reuslt = gcode_result.filament_printable_reuslt;
|
||||||
//BBS: add mutex for protection of gcode result
|
//BBS: add mutex for protection of gcode result
|
||||||
gcode_result.unlock();
|
gcode_result.unlock();
|
||||||
|
|
|
@ -746,6 +746,7 @@ public:
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
ConflictResultOpt m_conflict_result;
|
ConflictResultOpt m_conflict_result;
|
||||||
|
GCodeCheckResult m_gcode_check_result;
|
||||||
FilamentPrintableResult filament_printable_reuslt;
|
FilamentPrintableResult filament_printable_reuslt;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -2901,6 +2901,7 @@ void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, co
|
||||||
_set_warning_notification_if_needed(EWarning::ToolHeightOutside);
|
_set_warning_notification_if_needed(EWarning::ToolHeightOutside);
|
||||||
_set_warning_notification_if_needed(EWarning::ToolpathOutside);
|
_set_warning_notification_if_needed(EWarning::ToolpathOutside);
|
||||||
_set_warning_notification_if_needed(EWarning::GCodeConflict);
|
_set_warning_notification_if_needed(EWarning::GCodeConflict);
|
||||||
|
_set_warning_notification_if_needed(EWarning::MultiExtruderPrintableError);
|
||||||
_set_warning_notification_if_needed(EWarning::FilamentUnPrintableOnFirstLayer);
|
_set_warning_notification_if_needed(EWarning::FilamentUnPrintableOnFirstLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9548,6 +9549,8 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
|
||||||
(m_gcode_viewer.get_max_print_height() - m_gcode_viewer.get_layers_zs()[max_z_layer] >= 1e-6);
|
(m_gcode_viewer.get_max_print_height() - m_gcode_viewer.get_layers_zs()[max_z_layer] >= 1e-6);
|
||||||
} else if (warning == EWarning::GCodeConflict)
|
} else if (warning == EWarning::GCodeConflict)
|
||||||
show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.m_conflict_result.has_value();
|
show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.m_conflict_result.has_value();
|
||||||
|
else if (warning == EWarning::MultiExtruderPrintableError)
|
||||||
|
show = m_gcode_viewer.has_data() && m_gcode_viewer.m_gcode_check_result.error_code != 0;
|
||||||
else if (warning == EWarning::FilamentUnPrintableOnFirstLayer)
|
else if (warning == EWarning::FilamentUnPrintableOnFirstLayer)
|
||||||
show = m_gcode_viewer.has_data() && m_gcode_viewer.filament_printable_reuslt.has_value();
|
show = m_gcode_viewer.has_data() && m_gcode_viewer.filament_printable_reuslt.has_value();
|
||||||
}
|
}
|
||||||
|
@ -9616,6 +9619,25 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||||
case EWarning::ObjectOutside: text = _u8L("An object is layed over the boundary of plate."); break;
|
case EWarning::ObjectOutside: text = _u8L("An object is layed over the boundary of plate."); break;
|
||||||
case EWarning::ToolHeightOutside: text = _u8L("A G-code path goes beyond the max print height."); error = ErrorType::SLICING_ERROR; break;
|
case EWarning::ToolHeightOutside: text = _u8L("A G-code path goes beyond the max print height."); error = ErrorType::SLICING_ERROR; break;
|
||||||
case EWarning::ToolpathOutside: text = _u8L("A G-code path goes beyond the boundary of plate."); error = ErrorType::SLICING_ERROR; break;
|
case EWarning::ToolpathOutside: text = _u8L("A G-code path goes beyond the boundary of plate."); error = ErrorType::SLICING_ERROR; break;
|
||||||
|
case EWarning::MultiExtruderPrintableError: {
|
||||||
|
text.clear();
|
||||||
|
for (auto error_iter = m_gcode_viewer.m_gcode_check_result.error_infos.begin(); error_iter != m_gcode_viewer.m_gcode_check_result.error_infos.end(); ++error_iter) {
|
||||||
|
if (error_iter != m_gcode_viewer.m_gcode_check_result.error_infos.begin()) {
|
||||||
|
text += "\n";
|
||||||
|
}
|
||||||
|
int extruder_id = error_iter->first + 1;
|
||||||
|
std::string filaments;
|
||||||
|
for (size_t i = 0; i < error_iter->second.size(); ++i) {
|
||||||
|
if (i > 0) {
|
||||||
|
filaments += ", ";
|
||||||
|
}
|
||||||
|
filaments += std::to_string(error_iter->second[i] + 1);
|
||||||
|
}
|
||||||
|
text += (boost::format(_u8L("Extruder %d conflicts with filaments: %s.")) %extruder_id %filaments).str();
|
||||||
|
}
|
||||||
|
error = ErrorType::SLICING_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
// BBS: remove _u8L() for SLA
|
// BBS: remove _u8L() for SLA
|
||||||
case EWarning::SlaSupportsOutside: text = ("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
|
case EWarning::SlaSupportsOutside: text = ("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
|
||||||
case EWarning::SomethingNotShown: text = _u8L("Only the object being edited is visible."); break;
|
case EWarning::SomethingNotShown: text = _u8L("Only the object being edited is visible."); break;
|
||||||
|
|
|
@ -379,6 +379,7 @@ class GLCanvas3D
|
||||||
ObjectLimited,
|
ObjectLimited,
|
||||||
GCodeConflict,
|
GCodeConflict,
|
||||||
ToolHeightOutside,
|
ToolHeightOutside,
|
||||||
|
MultiExtruderPrintableError, // after slice
|
||||||
FilamentUnPrintableOnFirstLayer
|
FilamentUnPrintableOnFirstLayer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2581,6 +2581,7 @@ void PartPlate::update_slice_context(BackgroundSlicingProcess & process)
|
||||||
process.select_technology(this->printer_technology);
|
process.select_technology(this->printer_technology);
|
||||||
process.set_current_plate(this);
|
process.set_current_plate(this);
|
||||||
m_print->set_status_callback(statuscb);
|
m_print->set_status_callback(statuscb);
|
||||||
|
m_print->set_unprintable_filament_ids(m_unprintable_filament_ids);
|
||||||
process.switch_print_preprocess();
|
process.switch_print_preprocess();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -2940,6 +2941,14 @@ std::vector<int> PartPlate::get_filament_maps()
|
||||||
return filament_maps;
|
return filament_maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartPlate::append_unprintable_filament_ids(int extruder_id, const std::vector<int> &filament_ids)
|
||||||
|
{
|
||||||
|
if (extruder_id > m_unprintable_filament_ids.size()) {
|
||||||
|
m_unprintable_filament_ids.resize(extruder_id + 1);
|
||||||
|
}
|
||||||
|
m_unprintable_filament_ids[extruder_id].insert(m_unprintable_filament_ids[extruder_id].end(), filament_ids.begin(), filament_ids.end());
|
||||||
|
}
|
||||||
|
|
||||||
void PartPlate::set_filament_maps(const std::vector<int>& f_maps)
|
void PartPlate::set_filament_maps(const std::vector<int>& f_maps)
|
||||||
{
|
{
|
||||||
std::vector<int>& filament_maps = m_config.option<ConfigOptionInts>("filament_map", true)->values;
|
std::vector<int>& filament_maps = m_config.option<ConfigOptionInts>("filament_map", true)->values;
|
||||||
|
|
|
@ -111,6 +111,9 @@ private:
|
||||||
std::vector<FilamentInfo> slice_filaments_info;
|
std::vector<FilamentInfo> slice_filaments_info;
|
||||||
int m_print_index;
|
int m_print_index;
|
||||||
|
|
||||||
|
// filament ids of extruder
|
||||||
|
std::vector<std::vector<int>> m_unprintable_filament_ids;
|
||||||
|
|
||||||
std::string m_tmp_gcode_path; //use a temp path to store the gcode
|
std::string m_tmp_gcode_path; //use a temp path to store the gcode
|
||||||
std::string m_temp_config_3mf_path; //use a temp path to store the config 3mf
|
std::string m_temp_config_3mf_path; //use a temp path to store the config 3mf
|
||||||
std::string m_gcode_path_from_3mf; //use a path to store the gcode loaded from 3mf
|
std::string m_gcode_path_from_3mf; //use a path to store the gcode loaded from 3mf
|
||||||
|
@ -490,6 +493,11 @@ public:
|
||||||
std::vector<int> get_filament_maps();
|
std::vector<int> get_filament_maps();
|
||||||
void set_filament_maps(const std::vector<int>& f_maps);
|
void set_filament_maps(const std::vector<int>& f_maps);
|
||||||
|
|
||||||
|
const std::vector<std::vector<int>> &get_unprintable_filament_ids() const { return m_unprintable_filament_ids; }
|
||||||
|
void set_unprintable_filament_ids(const std::vector<std::vector<int>> &filament_ids) { m_unprintable_filament_ids = filament_ids; }
|
||||||
|
void clear_unprintable_filament_ids() { m_unprintable_filament_ids.clear(); }
|
||||||
|
void append_unprintable_filament_ids(int extruder_id, const std::vector<int> &filament_ids);
|
||||||
|
|
||||||
void on_extruder_count_changed(int extruder_count);
|
void on_extruder_count_changed(int extruder_count);
|
||||||
void set_filament_count(int filament_count);
|
void set_filament_count(int filament_count);
|
||||||
void on_filament_added();
|
void on_filament_added();
|
||||||
|
|
Loading…
Reference in New Issue