From 7ece35931e580cf65395f2a675402c0b77355537 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 8 Aug 2023 00:13:33 +0800 Subject: [PATCH] Merge some BS1.7 changes: Port object canceling for BL X1 from BS. Todo: refactor --- src/libslic3r/Exception.hpp | 11 ++ src/libslic3r/GCode.cpp | 234 ++++++++++++++++++++----- src/libslic3r/GCode.hpp | 13 +- src/libslic3r/GCode/GCodeProcessor.cpp | 30 +++- src/libslic3r/GCode/GCodeProcessor.hpp | 9 +- src/libslic3r/GCodeWriter.cpp | 54 ++++-- src/libslic3r/GCodeWriter.hpp | 15 +- src/libslic3r/Layer.hpp | 42 ++++- src/libslic3r/LayerRegion.cpp | 7 - src/libslic3r/Model.hpp | 9 + src/libslic3r/Print.cpp | 213 +++++++++++++++------- src/libslic3r/Print.hpp | 13 +- src/libslic3r/PrintBase.hpp | 3 + src/libslic3r/PrintObject.cpp | 57 +++++- src/slic3r/GUI/Tab.cpp | 9 +- 15 files changed, 557 insertions(+), 162 deletions(-) diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp index e796e3cc19..d271a25052 100644 --- a/src/libslic3r/Exception.hpp +++ b/src/libslic3r/Exception.hpp @@ -2,6 +2,7 @@ #define _libslic3r_Exception_h_ #include +#include namespace Slic3r { @@ -35,6 +36,16 @@ public: private: size_t objectId_ = 0; }; + +class SlicingErrors : public Exception +{ +public: + using Exception::Exception; + SlicingErrors(const std::vector &errors) : Exception("Errors"), errors_(errors) {} + + std::vector errors_; +}; + #undef SLIC3R_DERIVE_EXCEPTION } // namespace Slic3r diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index caab3a4ffd..844a8fc384 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -11,6 +11,7 @@ #include "Print.hpp" #include "Utils.hpp" #include "ClipperUtils.hpp" +#include "libslic3r.h" #include "LocalesUtils.hpp" #include "libslic3r/format.hpp" #include "Time.hpp" @@ -78,6 +79,7 @@ namespace Slic3r { static const float g_min_purge_volume = 100.f; static const float g_purge_volume_one_time = 135.f; static const int g_max_flush_count = 4; +static const size_t g_max_label_object = 64; Vec2d travel_point_1; Vec2d travel_point_2; @@ -420,6 +422,9 @@ static std::vector get_path_of_change_filament(const Print& print) gcode += gcodegen.unretract(); } + //BBS: if needed, write the gcode_label_objects_end then priming tower, if the retract, didn't did it. + gcodegen.m_writer.add_object_end_labels(gcode); + double current_z = gcodegen.writer().get_position().z(); if (z == -1.) // in case no specific z was provided, print at current_z pos z = current_z; @@ -484,6 +489,7 @@ static std::vector get_path_of_change_filament(const Print& print) new_filament_e_feedrate = new_filament_e_feedrate == 0 ? 100 : new_filament_e_feedrate; config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z)); + config.set_key_value("relative_e_axis", new ConfigOptionBool(full_config.use_relative_e_distances)); config.set_key_value("toolchange_count", new ConfigOptionInt((int)gcodegen.m_toolchange_count)); //BBS: fan speed is useless placeholer now, but we don't remove it to avoid //slicing error in old change_filament_gcode in old 3MF @@ -834,6 +840,10 @@ std::vector GCode::collect_layers_to_print(const PrintObjec double extra_gap = (layer_to_print.support_layer ? bottom_cd : top_cd); + // raft contact distance should not trigger any warning + if(last_extrusion_layer && last_extrusion_layer->support_layer) + extra_gap = std::max(extra_gap, object.config().raft_contact_distance.value); + double maximal_print_z = (last_extrusion_layer ? last_extrusion_layer->print_z() : 0.) + layer_to_print.layer()->height + std::max(0., extra_gap); @@ -876,8 +886,16 @@ std::vector>> GCode::collec std::vector> per_object(print.objects().size(), std::vector()); std::vector ordering; + + std::vector errors; + for (size_t i = 0; i < print.objects().size(); ++i) { - per_object[i] = collect_layers_to_print(*print.objects()[i]); + try { + per_object[i] = collect_layers_to_print(*print.objects()[i]); + } catch (const Slic3r::SlicingError &e) { + errors.push_back(e); + continue; + } OrderingItem ordering_item; ordering_item.object_idx = i; ordering.reserve(ordering.size() + per_object[i].size()); @@ -889,6 +907,8 @@ std::vector>> GCode::collec } } + if (!errors.empty()) { throw Slic3r::SlicingErrors(errors); } + std::sort(ordering.begin(), ordering.end(), [](const OrderingItem& oi1, const OrderingItem& oi2) { return oi1.print_z < oi2.print_z; }); std::vector>> layers_to_print; @@ -1037,6 +1057,13 @@ namespace DoExport { } } // namespace DoExport +bool GCode::is_BBL_Printer() +{ + if (m_curr_print) + return m_curr_print->is_BBL_printer(); + return false; +} + void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb) { PROFILE_CLEAR(); @@ -1143,6 +1170,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info(); print->set_done(psGCodeExport); + // Used by BBL only + result->label_object_enabled = m_enable_label_object; // Write the profiler measurements to file PROFILE_UPDATE(); @@ -1455,13 +1484,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato if (print.config().print_sequence == PrintSequence::ByObject) { // Add each of the object's layers separately. for (auto object : print.objects()) { - //BBS: fix the issue that total layer is not right - std::vector zs; + std::vector zs; zs.reserve(object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) - zs.push_back((coord_t)(layer->print_z / EPSILON)); + zs.push_back(layer->print_z); for (auto layer : object->support_layers()) - zs.push_back((coord_t)(layer->print_z / EPSILON)); + zs.push_back(layer->print_z); std::sort(zs.begin(), zs.end()); //BBS: merge numerically very close Z values. auto end_it = std::unique(zs.begin(), zs.end()); @@ -1474,22 +1502,24 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato } } else { // Print all objects with the same print_z together. - //BBS: fix the issue that total layer is not right - std::vector zs; + std::vector zs; for (auto object : print.objects()) { zs.reserve(zs.size() + object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) - zs.push_back((coord_t)(layer->print_z / EPSILON)); + zs.push_back(layer->print_z); for (auto layer : object->support_layers()) - zs.push_back((coord_t)(layer->print_z / EPSILON)); + zs.push_back(layer->print_z); } - std::sort(zs.begin(), zs.end()); - //BBS: merge numerically very close Z values. - auto end_it = std::unique(zs.begin(), zs.end()); - m_layer_count = (unsigned int)(end_it - zs.begin()); - for (auto it = zs.begin(); it != end_it - 1; it++) { - if (abs(*it - *(it + 1)) < EPSILON) - m_layer_count--; + if (!zs.empty()) + { + std::sort(zs.begin(), zs.end()); + //BBS: merge numerically very close Z values. + auto end_it = std::unique(zs.begin(), zs.end()); + m_layer_count = (unsigned int)(end_it - zs.begin()); + for (auto it = zs.begin(); it != end_it - 1; it++) { + if (abs(*it - *(it + 1)) < EPSILON) + m_layer_count--; + } } } print.throw_if_canceled(); @@ -1518,6 +1548,29 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str()); //BBS: total layer number file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Total_Layer_Number_Placeholder).c_str()); + //BBS: judge whether support skipping, if yes, list all label_object_id with sorted order here + if (print.extruders(true).size() == 1 && //Don't support multi-color + print.num_object_instances() <= g_max_label_object && //Don't support too many objects on one plate + print.calib_params().mode == CalibMode::Calib_None) { //Don't support skipping in cali mode + m_enable_label_object = true; + m_label_objects_ids.clear(); + m_label_objects_ids.reserve(print.num_object_instances()); + for (const PrintObject* print_object : print.objects()) + for (const PrintInstance& print_instance : print_object->instances()) + m_label_objects_ids.push_back(print_instance.model_instance->get_labeled_id()); + + std::sort(m_label_objects_ids.begin(), m_label_objects_ids.end()); + + std::string objects_id_list = "; model label id: "; + for (auto it = m_label_objects_ids.begin(); it != m_label_objects_ids.end(); it++) + objects_id_list += (std::to_string(*it) + (it != m_label_objects_ids.end() - 1 ? "," : "\n")); + file.writeln(objects_id_list); + } + else { + m_enable_label_object = false; + m_label_objects_ids.clear(); + } + file.write_format("; HEADER_BLOCK_END\n\n"); @@ -2058,6 +2111,14 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato //BBS: the last retraction // Write end commands to file. file.write(this->retract(false, true)); + + // if needed, write the gcode_label_objects_end + { + std::string gcode; + m_writer.add_object_change_labels(gcode); + file.write(gcode); + } + file.write(m_writer.set_fan(0)); //BBS: make sure the additional fan is closed when end if(m_config.auxiliary_fan.value) @@ -2539,7 +2600,7 @@ std::vector GCode::sort_print_object_instances( const PrintObject *print_object = layers[layer_id].original_object; //const PrintObject *print_object = layers[layer_id].object(); if (print_object) - out.emplace_back(object_by_extruder, layer_id, *print_object, single_object_instance_idx); + out.emplace_back(object_by_extruder, layer_id, *print_object, single_object_instance_idx, print_object->instances()[single_object_instance_idx].model_instance->get_labeled_id()); } } else { // Create mapping from PrintObject* to ObjectByExtruder*. @@ -2567,7 +2628,7 @@ std::vector GCode::sort_print_object_instances( auto it = std::lower_bound(sorted.begin(), sorted.end(), key); if (it != sorted.end() && it->first == &print_object) // ObjectByExtruder for this PrintObject was found. - out.emplace_back(*it->second, it->second - objects_by_extruder.data(), print_object, instance - print_object.instances().data()); + out.emplace_back(*it->second, it->second - objects_by_extruder.data(), print_object, instance - print_object.instances().data(), instance->model_instance->get_labeled_id()); } } } @@ -2721,7 +2782,6 @@ namespace Skirt { #if 0 // Prime just the first printing extruder. This is original Slic3r's implementation. skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair(0, print.config().skirt_loops.value); - skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair(0, print.config().skirt_loops.value); #else // Prime all extruders planned for this layer, see skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); @@ -3264,6 +3324,16 @@ GCode::LayerResult GCode::process_layer( m_object_layer_over_raft = object_layer_over_raft; if (m_config.reduce_crossing_wall) m_avoid_crossing_perimeters.init_layer(*m_layer); + + // Skip objects + if (m_enable_label_object) { + std::string start_str = std::string("; start printing object, unique label id: ") + std::to_string(instance_to_print.label_object_id) + "\n"; + if (print.is_BBL_printer()) { + start_str += ("M624 " + _encode_label_ids_to_base64({ instance_to_print.label_object_id })); + start_str += "\n"; + } + m_writer.set_object_start_str(start_str); + } bool reset_e = false; if (this->config().gcode_label_objects) { gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.print_object.get_id()) + " copy " + std::to_string(inst.id) + "\n"; @@ -3282,7 +3352,7 @@ GCode::LayerResult GCode::process_layer( m_extrusion_quality_estimator.set_current_object(&instance_to_print.print_object); // When starting a new object, use the external motion planner for the first travel move. - const Point &offset = inst.shift; + const Point &offset = instance_to_print.print_object.instances()[instance_to_print.instance_id].shift; std::pair this_object_copy(&instance_to_print.print_object, offset); if (m_last_obj_copy != this_object_copy) m_avoid_crossing_perimeters.use_external_mp_once(); @@ -3365,6 +3435,15 @@ GCode::LayerResult GCode::process_layer( } // ironing gcode += this->extrude_infill(print,by_region_specific, true); + } + // Don't set m_gcode_label_objects_end if you don't had to write the m_gcode_label_objects_start. + if (!m_writer.empty_object_start_str()) { + m_writer.set_object_start_str(""); + } else if (m_enable_label_object) { + std::string end_str = std::string("; stop printing object, unique label id: ") + std::to_string(instance_to_print.label_object_id) + "\n"; + if (print.is_BBL_printer()) + end_str += "M625\n"; + m_writer.set_object_end_str(end_str); } if (this->config().gcode_label_objects) { gcode += std::string("; stop printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.print_object.get_id()) + " copy " + std::to_string(inst.id) + "\n"; @@ -3501,6 +3580,8 @@ std::string GCode::change_layer(coordf_t print_z, bool lazy_raise) //BBS: force to use SpiralLift when change layer if lift type is auto gcode += this->retract(false, false, ZHopType(EXTRUDER_CONFIG(z_hop_types)) == ZHopType::zhtAuto ? LiftType::SpiralLift : lift_type); } + + m_writer.add_object_change_labels(gcode); if (!lazy_raise) { std::ostringstream comment; @@ -3511,7 +3592,6 @@ std::string GCode::change_layer(coordf_t print_z, bool lazy_raise) m_need_change_layer_lift_z = true; } - // BBS m_nominal_z = print_z; // forget last wiping path as wiping after raising Z is pointless @@ -3882,6 +3962,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, m_need_change_layer_lift_z = false; } + // if needed, write the gcode_label_objects_end then gcode_label_objects_start + // should be already done by travel_to, but just in case + m_writer.add_object_change_labels(gcode); + // compensate retraction gcode += this->unretract(); m_config.apply(m_calib_config); @@ -4296,6 +4380,37 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, return gcode; } +std::string encodeBase64(uint64_t value) +{ + //Always use big endian mode + uint8_t src[8]; + for (size_t i = 0; i < 8; i++) + src[i] = (value >> (8 * i)) & 0xff; + + std::string dest; + dest.resize(boost::beast::detail::base64::encoded_size(sizeof(src))); + dest.resize(boost::beast::detail::base64::encode(&dest[0], src, sizeof(src))); + return dest; +} + +std::string GCode::_encode_label_ids_to_base64(std::vector ids) +{ + assert(m_label_objects_ids.size() < 64); + + uint64_t bitset = 0; + for (size_t id : ids) { + auto index = std::lower_bound(m_label_objects_ids.begin(), m_label_objects_ids.end(), id); + if (index != m_label_objects_ids.end() && *index == id) + bitset |= (1ull << (index - m_label_objects_ids.begin())); + else + throw Slic3r::LogicError("Unknown label object id!"); + } + if (bitset == 0) + throw Slic3r::LogicError("Label object id error!"); + + return encodeBase64(bitset); +} + // This method accepts &point in print coordinates. std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string comment) { @@ -4369,6 +4484,9 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string // Reset the wipe path when traveling, so one would not wipe along an old path. m_wipe.reset_path(); + // if needed, write the gcode_label_objects_end then gcode_label_objects_start + m_writer.add_object_change_labels(gcode); + // use G1 because we rely on paths being straight (G0 may make round paths) if (travel.size() >= 2) { for (size_t i = 1; i < travel.size(); ++ i) { @@ -4410,32 +4528,60 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role, LiftTyp return false; } + //BBS: input travel polyline must be in current plate coordinate system auto is_through_overhang = [this](const Polyline& travel) { + BoundingBox travel_bbox = get_extents(travel); + travel_bbox.inflated(1); + travel_bbox.defined = true; + const float protect_z_scaled = scale_(0.4); std::pair z_range; z_range.second = m_layer ? m_layer->print_z : 0.f; z_range.first = std::max(0.f, z_range.second - protect_z_scaled); - for (auto object : m_curr_print->objects()) { - BoundingBox obj_bbox = object->bounding_box(); - BoundingBox travel_bbox = get_extents(travel); - obj_bbox.offset(scale_(EPSILON)); - if (!obj_bbox.overlap(travel_bbox)) - continue; + std::vector layers_of_objects; + std::vector boundingBox_for_objects; + std::vector objects_instances_shift; + std::vector idx_of_object_sorted = m_curr_print->layers_sorted_for_object(z_range.first, z_range.second, layers_of_objects, boundingBox_for_objects, objects_instances_shift); - for (auto layer : object->layers()) { - if (layer->print_z < z_range.first) + std::vector is_layers_of_objects_sorted(layers_of_objects.size(), false); + + for (size_t idx : idx_of_object_sorted) { + for (const Point & instance_shift : objects_instances_shift[idx]) { + BoundingBox instance_bbox = boundingBox_for_objects[idx]; + if (!instance_bbox.defined) //BBS: Don't need to check when bounding box of overhang area is empty(undefined) continue; - if (layer->print_z > z_range.second + EPSILON) - break; + instance_bbox.offset(scale_(EPSILON)); + instance_bbox.translate(instance_shift.x(), instance_shift.y()); + if (!instance_bbox.overlap(travel_bbox)) + continue; + + Polygons temp; + temp.emplace_back(std::move(instance_bbox.polygon())); + if (intersection_pl(travel, temp).empty()) + continue; + + if (!is_layers_of_objects_sorted[idx]) { + std::sort(layers_of_objects[idx].begin(), layers_of_objects[idx].end(), [](auto left, auto right) { return left->loverhangs_bbox.area() > right->loverhangs_bbox.area();}); + is_layers_of_objects_sorted[idx] = true; + } + + for (const auto& layer : layers_of_objects[idx]) { + for (ExPolygon overhang : layer->loverhangs) { + overhang.translate(instance_shift); + BoundingBox bbox1 = get_extents(overhang); + + if (!bbox1.overlap(travel_bbox)) + continue; + + if (intersection_pl(travel, overhang).empty()) + continue; - for (ExPolygon& overhang : layer->loverhangs) { - if (overhang.contains(travel)) return true; + } } } } - return false; }; @@ -4445,17 +4591,12 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role, LiftTyp float travel_len_thresh = max_z_hop / tan(GCodeWriter::slope_threshold); float accum_len = 0.f; Polyline clipped_travel; - for (auto line : travel.lines()) { - if (accum_len + line.length() > travel_len_thresh + EPSILON) { - Point end_pnt = line.a + line.normal() * (travel_len_thresh - accum_len); - clipped_travel.append(Polyline(line.a, end_pnt)); - break; - } - else { - clipped_travel.append(Polyline(line.a, line.b)); - accum_len += line.length(); - } - } + + clipped_travel.append(Polyline(travel.points[0], travel.points[1])); + if (clipped_travel.length() > travel_len_thresh) + clipped_travel.points.back() = clipped_travel.points.front()+(clipped_travel.points.back() - clipped_travel.points.front()) * (travel_len_thresh / clipped_travel.length()); + //BBS: translate to current plate coordinate system + clipped_travel.translate(Point::new_scale(double(m_origin.x() - m_writer.get_xy_offset().x()), double(m_origin.y() - m_writer.get_xy_offset().y()))); //BBS: force to retract when leave from external perimeter for a long travel //Better way is judging whether the travel move direction is same with last extrusion move. @@ -4549,9 +4690,7 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li can_lift = false; } - //BBS if (needs_lift && can_lift) { - // BBS: don't do lazy_lift when enable spiral vase size_t extruder_id = m_writer.extruder()->id(); gcode += m_writer.lift(!m_spiral_vase ? lift_type : LiftType::NormalLift); } @@ -4660,6 +4799,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) dyn_config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); dyn_config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); dyn_config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); + dyn_config.set_key_value("relative_e_axis", new ConfigOptionBool(m_config.use_relative_e_distances)); dyn_config.set_key_value("toolchange_count", new ConfigOptionInt((int)m_toolchange_count)); //BBS: fan speed is useless placeholer now, but we don't remove it to avoid //slicing error in old change_filament_gcode in old 3MF diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index b979f542f5..f8acc85b81 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -203,6 +203,7 @@ public: std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::SpiralLift); std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } std::string set_extruder(unsigned int extruder_id, double print_z); + bool is_BBL_Printer(); // SoftFever std::string set_object_info(Print* print); @@ -382,8 +383,8 @@ private: struct InstanceToPrint { - InstanceToPrint(ObjectByExtruder &object_by_extruder, size_t layer_id, const PrintObject &print_object, size_t instance_id) : - object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id) {} + 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; @@ -392,6 +393,8 @@ private: 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 sort_print_object_instances( @@ -441,7 +444,11 @@ private: // 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; - + + // for bbl printer + bool m_enable_label_object; + std::vector m_label_objects_ids; + std::string _encode_label_ids_to_base64(std::vector ids); // Orca bool m_is_overhang_fan_on; bool m_is_supp_interface_fan_on; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index bbd23f4a1e..6621ca7997 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -81,6 +81,13 @@ const std::vector GCodeProcessor::Reserved_Tags_compatible = { const std::string GCodeProcessor::Flush_Start_Tag = " FLUSH_START"; const std::string GCodeProcessor::Flush_End_Tag = " FLUSH_END"; +const std::map GCodeProcessor::Nozzle_Type_To_HRC={ + {NozzleType::ntStainlessSteel,20}, + {NozzleType::ntHardenedSteel,55}, + {NozzleType::ntBrass,2}, + {NozzleType::ntUndefine,0} +}; + const float GCodeProcessor::Wipe_Width = 0.05f; const float GCodeProcessor::Wipe_Height = 0.05f; @@ -792,6 +799,8 @@ void GCodeProcessorResult::reset() { bed_exclude_area = Pointfs(); //BBS: add toolpath_outside toolpath_outside = false; + //BBS: add label_object_enabled + label_object_enabled = false; printable_height = 0.0f; settings_ids.reset(); extruders_count = 0; @@ -817,6 +826,8 @@ void GCodeProcessorResult::reset() { bed_exclude_area = Pointfs(); //BBS: add toolpath_outside toolpath_outside = false; + //BBS: add label_object_enabled + label_object_enabled = false; printable_height = 0.0f; settings_ids.reset(); extruders_count = 0; @@ -936,7 +947,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_result.filament_vitrification_temperature.resize(extruders_count); m_extruder_temps.resize(extruders_count); m_result.nozzle_hrc = static_cast(config.nozzle_hrc.getInt()); - + m_result.nozzle_type = config.nozzle_type; for (size_t i = 0; i < extruders_count; ++ i) { m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast().eval(), 0.f); m_extruder_colors[i] = static_cast(i); @@ -1000,6 +1011,10 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) const ConfigOptionInt *nozzle_HRC = config.option("nozzle_hrc"); if (nozzle_HRC != nullptr) m_result.nozzle_hrc = nozzle_HRC->value; + const ConfigOptionEnum* nozzle_type = config.option>("nozzle_type"); + if (nozzle_type != nullptr) + m_result.nozzle_type=nozzle_type->value; + const ConfigOptionEnum* gcode_flavor = config.option>("gcode_flavor"); if (gcode_flavor != nullptr) m_flavor = gcode_flavor->value; @@ -1252,6 +1267,11 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) const ConfigOptionBool* spiral_vase = config.option("spiral_mode"); if (spiral_vase != nullptr) m_spiral_vase_active = spiral_vase->value; + + const ConfigOptionEnumGeneric *bed_type = config.option("curr_bed_type"); + if (bed_type != nullptr) + m_result.bed_type = (BedType)bed_type->value; + } void GCodeProcessor::enable_stealth_time_estimator(bool enabled) @@ -4305,12 +4325,16 @@ void GCodeProcessor::update_slice_warnings() //bbs:HRC checker warning.params.clear(); warning.level=1; - if (m_result.nozzle_hrc!=0) { + + int nozzle_hrc = m_result.nozzle_hrc; + if(nozzle_hrc <= 0) + nozzle_hrc = Nozzle_Type_To_HRC.find(m_result.nozzle_type)->second; + if (nozzle_hrc!=0) { for (size_t i = 0; i < used_extruders.size(); i++) { int HRC=0; if (used_extruders[i] < m_result.required_nozzle_HRC.size()) HRC = m_result.required_nozzle_HRC[used_extruders[i]]; - if (HRC != 0 && (m_result.nozzle_hrc warnings; int nozzle_hrc; - + NozzleType nozzle_type; + BedType bed_type = BedType::btCount; #if ENABLE_GCODE_VIEWER_STATISTICS int64_t time{ 0 }; #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -208,6 +211,7 @@ namespace Slic3r { printable_area = other.printable_area; bed_exclude_area = other.bed_exclude_area; toolpath_outside = other.toolpath_outside; + label_object_enabled = other.label_object_enabled; printable_height = other.printable_height; settings_ids = other.settings_ids; extruders_count = other.extruders_count; @@ -218,6 +222,7 @@ namespace Slic3r { custom_gcode_per_print_z = other.custom_gcode_per_print_z; spiral_vase_layers = other.spiral_vase_layers; warnings = other.warnings; + bed_type = other.bed_type; #if ENABLE_GCODE_VIEWER_STATISTICS time = other.time; #endif @@ -234,7 +239,7 @@ namespace Slic3r { static const std::vector Reserved_Tags_compatible; static const std::string Flush_Start_Tag; static const std::string Flush_End_Tag; - + static const std::mapNozzle_Type_To_HRC; public: enum class ETags : unsigned char { diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 77dbb6f454..de9567fb23 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -377,22 +377,21 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co Vec3d target = { dest_point(0) - m_x_offset, dest_point(1) - m_y_offset, dest_point(2) }; Vec3d delta = target - source; Vec2d delta_no_z = { delta(0), delta(1) }; - - - //BBS: don'need slope travel because we don't know where is the source position the first time //BBS: Also don't need to do slope move or spiral lift if x-y distance is absolute zero - if (this->is_current_position_clear() && delta(2) > 0 && delta_no_z.norm() != 0.0f) { - double radius = delta(2) / (2 * PI * atan(GCodeWriter::slope_threshold)); - Vec2d ij_offset = radius * delta_no_z.normalized(); - ij_offset = { -ij_offset(1), ij_offset(0) }; + if (delta(2) > 0 && delta_no_z.norm() != 0.0f) { //BBS: SpiralLift - if (m_to_lift_type == LiftType::SpiralLift) { + if (m_to_lift_type == LiftType::SpiralLift && this->is_current_position_clear()) { //BBS: todo: check the arc move all in bed area, if not, then use lazy lift + double radius = delta(2) / (2 * PI * atan(GCodeWriter::slope_threshold)); + Vec2d ij_offset = radius * delta_no_z.normalized(); + ij_offset = { -ij_offset(1), ij_offset(0) }; slop_move = this->_spiral_travel_to_z(target(2), ij_offset, "spiral lift Z"); } //BBS: LazyLift - else if (atan2(delta(2), delta_no_z.norm()) < GCodeWriter::slope_threshold) { + else if (m_to_lift_type == LiftType::LazyLift && + this->is_current_position_clear() && + atan2(delta(2), delta_no_z.norm()) < GCodeWriter::slope_threshold) { //BBS: check whether we can make a travel like // _____ // / to make the z list early to avoid to hit some warping place when travel is long. @@ -405,6 +404,9 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co w0.emit_comment(GCodeWriter::full_gcode_comment, comment); slop_move = w0.string(); } + else if (m_to_lift_type == LiftType::NormalLift) { + slop_move = _travel_to_z(target.z(), "normal lift Z"); + } } std::string xy_z_move; @@ -687,12 +689,11 @@ std::string GCodeWriter::unretract() /* If this method is called more than once before calling unlift(), it will not perform subsequent lifts, even if Z was raised manually (i.e. with travel_to_z()) and thus _lifted was reduced. */ -std::string GCodeWriter::lift(LiftType lift_type) +std::string GCodeWriter::lift(LiftType lift_type, bool spiral_vase) { // check whether the above/below conditions are met double target_lift = 0; { - //BBS double above = this->config.retract_lift_above.get_at(m_extruder->id()); double below = this->config.retract_lift_below.get_at(m_extruder->id()); if (m_pos(2) >= above && (below == 0 || m_pos(2) <= below)) @@ -700,13 +701,14 @@ std::string GCodeWriter::lift(LiftType lift_type) } // BBS if (m_lifted == 0 && m_to_lift == 0 && target_lift > 0) { - if (lift_type == LiftType::LazyLift || lift_type == LiftType::SpiralLift) { - m_to_lift = target_lift; - m_to_lift_type = lift_type; - } else { + if (spiral_vase) { m_lifted = target_lift; return this->_travel_to_z(m_pos(2) + target_lift, "lift Z"); } + else { + m_to_lift = target_lift; + m_to_lift_type = lift_type; + } } return ""; } @@ -778,6 +780,28 @@ std::string GCodeWriter::set_additional_fan(unsigned int speed) return gcode.str(); } +void GCodeWriter::add_object_start_labels(std::string& gcode) +{ + if (!m_gcode_label_objects_start.empty()) { + gcode += m_gcode_label_objects_start; + m_gcode_label_objects_start = ""; + } +} + +void GCodeWriter::add_object_end_labels(std::string& gcode) +{ + if (!m_gcode_label_objects_end.empty()) { + gcode += m_gcode_label_objects_end; + m_gcode_label_objects_end = ""; + } +} + +void GCodeWriter::add_object_change_labels(std::string& gcode) +{ + add_object_end_labels(gcode); + add_object_start_labels(gcode); +} + void GCodeFormatter::emit_axis(const char axis, const double v, size_t digits) { assert(digits <= 9); static constexpr const std::array pow_10{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 2ae602aa2f..e4a59dec82 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -73,7 +73,7 @@ public: std::string retract(bool before_wipe = false); std::string retract_for_toolchange(bool before_wipe = false); std::string unretract(); - std::string lift(LiftType lift_type = LiftType::NormalLift); + std::string lift(LiftType lift_type = LiftType::NormalLift, bool spiral_vase = false); std::string unlift(); Vec3d get_position() const { return m_pos; } void set_position(Vec3d& in) { m_pos = in; } @@ -88,6 +88,14 @@ public: std::string set_fan(unsigned int speed) const; //BBS: set additional fan speed for BBS machine only static std::string set_additional_fan(unsigned int speed); + //BBS + void set_object_start_str(std::string start_string) { m_gcode_label_objects_start = start_string; } + bool empty_object_start_str() { return m_gcode_label_objects_start.empty(); } + void set_object_end_str(std::string end_string) { m_gcode_label_objects_end = end_string; } + bool empty_object_end_str() { return m_gcode_label_objects_end.empty(); } + void add_object_start_labels(std::string& gcode); + void add_object_end_labels(std::string& gcode); + void add_object_change_labels(std::string& gcode); //BBS: void set_current_position_clear(bool clear) { m_is_current_pos_clear = clear; }; @@ -136,12 +144,15 @@ private: //BBS: x, y offset for gcode generated double m_x_offset{ 0 }; double m_y_offset{ 0 }; + + std::string m_gcode_label_objects_start; + std::string m_gcode_label_objects_end; //SoftFever bool m_is_bbl_printers = false; double m_current_speed; bool m_is_first_layer = true; - + std::string _travel_to_z(double z, const std::string &comment); std::string _spiral_travel_to_z(double z, const Vec2d &ij_offset, const std::string &comment); std::string _retract(double length, double restart_extra, const std::string &comment); diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 47b0b78177..ac3e054e77 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -95,7 +95,8 @@ public: // Is there any valid extrusion assigned to this LayerRegion? bool has_extrusions() const { return ! this->perimeters.entities.empty() || ! this->fills.entities.empty(); } //BBS - void simplify_extrusion_entity(); + void simplify_infill_extrusion_entity() { simplify_entity_collection(&fills); } + void simplify_wall_extrusion_entity() { simplify_entity_collection(&perimeters); } private: void simplify_entity_collection(ExtrusionEntityCollection* entity_collection); void simplify_path(ExtrusionPath* path); @@ -149,7 +150,7 @@ public: // BBS ExPolygons loverhangs; - + BoundingBox loverhangs_bbox; size_t region_count() const { return m_regions.size(); } const LayerRegion* get_region(int idx) const { return m_regions[idx]; } LayerRegion* get_region(int idx) { return m_regions[idx]; } @@ -190,10 +191,45 @@ public: virtual bool has_extrusions() const { for (auto layerm : m_regions) if (layerm->has_extrusions()) return true; return false; } //BBS - void simplify_extrusion_path() { for (auto layerm : m_regions) layerm->simplify_extrusion_entity();} + void simplify_wall_extrusion_path() { for (auto layerm : m_regions) layerm->simplify_wall_extrusion_entity();} + void simplify_infill_extrusion_path() { for (auto layerm : m_regions) layerm->simplify_infill_extrusion_entity(); } //BBS: this function calculate the maximum void grid area of sparse infill of this layer. Just estimated value coordf_t get_sparse_infill_max_void_area(); + // FN_HIGHER_EQUAL: the provided object pointer has a Z value >= of an internal threshold. + // Find the first item with Z value >= of an internal threshold of fn_higher_equal. + // If no vec item with Z value >= of an internal threshold of fn_higher_equal is found, return vec.size() + // If the initial idx is size_t(-1), then use binary search. + // Otherwise search linearly upwards. + template + static IndexType idx_higher_or_equal(IteratorType begin, IteratorType end, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal) + { + auto size = int(end - begin); + if (size == 0) { + idx = 0; + } + else if (idx == IndexType(-1)) { + // First of the batch of layers per thread pool invocation. Use binary search. + int idx_low = 0; + int idx_high = std::max(0, size - 1); + while (idx_low + 1 < idx_high) { + int idx_mid = (idx_low + idx_high) / 2; + if (fn_higher_equal(begin[idx_mid])) + idx_high = idx_mid; + else + idx_low = idx_mid; + } + idx = fn_higher_equal(begin[idx_low]) ? idx_low : + (fn_higher_equal(begin[idx_high]) ? idx_high : size); + } + else { + // For the other layers of this batch of layers, search incrementally, which is cheaper than the binary search. + while (int(idx) < size && !fn_higher_equal(begin[idx])) + ++idx; + } + return idx; + } + protected: friend class PrintObject; friend std::vector new_layers(PrintObject*, const std::vector&); diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 61eef17801..7bfbf91597 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -533,13 +533,6 @@ void LayerRegion::export_region_fill_surfaces_to_svg_debug(const char *name) con this->export_region_fill_surfaces_to_svg(debug_out_path("LayerRegion-fill_surfaces-%s-%d.svg", name, idx ++).c_str()); } -//BBS -void LayerRegion::simplify_extrusion_entity() -{ - simplify_entity_collection(&perimeters); - simplify_entity_collection(&fills); -} - void LayerRegion::simplify_entity_collection(ExtrusionEntityCollection* entity_collection) { for (size_t i = 0; i < entity_collection->entities.size(); i++) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 6e66ce2289..9094bdd900 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1220,9 +1220,18 @@ public: ModelInstanceEPrintVolumeState print_volume_state; // Whether or not this instance is printable bool printable; + bool use_loaded_id_for_label {false}; int arrange_order = 0; // BBS size_t loaded_id = 0; // BBS + size_t get_labeled_id() const + { + if (use_loaded_id_for_label && (loaded_id > 0)) + return loaded_id; + else + return id().id; + } + ModelObject* get_object() const { return this->object; } const Geometry::Transformation& get_transformation() const { return m_transformation; } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 05b42ec7cc..7720c308db 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -260,7 +260,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n osteps.emplace_back(posPerimeters); osteps.emplace_back(posInfill); osteps.emplace_back(posSupportMaterial); - osteps.emplace_back(posSimplifyPath); + osteps.emplace_back(posSimplifyPath); + osteps.emplace_back(posSimplifyInfill); osteps.emplace_back(posSimplifySupportPath); steps.emplace_back(psSkirtBrim); } @@ -332,6 +333,18 @@ std::vector Print::object_extruders() const extruders.push_back(extruder - 1); } } + + // layer range + for (auto layer_range : mo->layer_config_ranges) { + if (layer_range.second.has("extruder")) { + //BBS: actually when user doesn't change filament by height range(value is default 0), height range should not save key "extruder". + //Don't know why height range always save key "extruder" because of no change(should only save difference)... + //Add protection here to avoid overflow + auto value = layer_range.second.option("extruder")->getInt(); + if (value > 0) + extruders.push_back(value - 1); + } + } } #endif sort_remove_duplicates(extruders); @@ -436,6 +449,25 @@ bool Print::has_brim() const } //BBS +std::vector Print::layers_sorted_for_object(float start, float end, std::vector &layers_of_objects, std::vector &boundingBox_for_objects, std::vector &objects_instances_shift) +{ + std::vector idx_of_object_sorted; + size_t idx = 0; + for (const auto &object : m_objects) { + idx_of_object_sorted.push_back(idx++); + object->get_certain_layers(start, end, layers_of_objects, boundingBox_for_objects); + } + std::sort(idx_of_object_sorted.begin(), idx_of_object_sorted.end(), + [boundingBox_for_objects](auto left, auto right) { return boundingBox_for_objects[left].area() > boundingBox_for_objects[right].area(); }); + + objects_instances_shift.clear(); + objects_instances_shift.reserve(m_objects.size()); + for (const auto& object : m_objects) + objects_instances_shift.emplace_back(object->get_instances_shift_without_plate_offset()); + + return idx_of_object_sorted; +}; + StringObjectException Print::sequential_print_clearance_valid(const Print &print, Polygons *polygons, std::vector>* height_polygons) { StringObjectException single_object_exception; @@ -534,19 +566,24 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print // if output needed, collect indices (inside convex_hulls_other) of intersecting hulls for (size_t i = 0; i < convex_hulls_other.size(); ++i) { if (! intersection(convex_hulls_other[i], convex_hull).empty()) { + bool has_exception = false; if (single_object_exception.string.empty()) { single_object_exception.string = (boost::format(L("%1% is too close to others, and collisions may be caused.")) %instance.model_instance->get_object()->name).str(); single_object_exception.object = instance.model_instance->get_object(); + has_exception = true; } else { single_object_exception.string += "\n"+(boost::format(L("%1% is too close to others, and collisions may be caused.")) %instance.model_instance->get_object()->name).str(); single_object_exception.object = nullptr; + has_exception = true; } if (polygons) { intersecting_idxs.emplace_back(i); intersecting_idxs.emplace_back(convex_hulls_other.size()); } + + if (has_exception) break; } } struct print_instance_info print_info {&instance, convex_hull.bounding_box(), convex_hull}; @@ -865,40 +902,51 @@ static StringObjectException layered_print_cleareance_valid(const Print &print, return {}; } -//BBS -static std::map filament_is_high_temp { - {"PLA", false}, - {"PLA-CF", false}, - //{"PETG", true}, - {"ABS", true}, - {"TPU", false}, - {"PA", true}, - {"PA-CF", true}, - {"PET-CF", true}, - {"PC", true}, - {"ASA", true} -}; - -//BBS: this function is used to check whether multi filament can be printed -StringObjectException Print::check_multi_filament_valid(const Print& print) +bool Print::check_multi_filaments_compatibility(const std::vector& filament_types) { + static std::map filament_is_high_temp{ + {"PLA", false}, + {"PLA-CF", false}, + //{"PETG", true}, + {"ABS", true}, + {"TPU", false}, + {"PA", true}, + {"PA-CF", true}, + {"PET-CF", true}, + {"PC", true}, + {"ASA", true}, + {"HIPS", true} + }; + bool has_high_temperature_filament = false; bool has_low_temperature_filament = false; - auto print_config = print.config(); - std::vector extruders = print.extruders(); - - for (const auto& extruder_idx : extruders) { - std::string filament_type = print_config.filament_type.get_at(extruder_idx); - if (filament_is_high_temp.find(filament_type) != filament_is_high_temp.end()) { - if (filament_is_high_temp[filament_type]) + for (const auto& type : filament_types) + if (filament_is_high_temp.find(type) != filament_is_high_temp.end()) { + if (filament_is_high_temp[type]) has_high_temperature_filament = true; else has_low_temperature_filament = true; } - } if (has_high_temperature_filament && has_low_temperature_filament) + return false; + + return true; +} + +//BBS: this function is used to check whether multi filament can be printed +StringObjectException Print::check_multi_filament_valid(const Print& print) +{ + auto print_config = print.config(); + std::vector extruders = print.extruders(); + std::vector filament_types; + filament_types.reserve(extruders.size()); + + for (const auto& extruder_idx : extruders) + filament_types.push_back(print_config.filament_type.get_at(extruder_idx)); + + if (!check_multi_filaments_compatibility(filament_types)) return { L("Can not print multiple filaments which have large difference of temperature together. Otherwise, the extruder and nozzle may be blocked or damaged during printing") }; return {std::string()}; @@ -917,28 +965,11 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* return { L("No extrusions under current settings.") }; if (extruders.size() > 1 && m_config.print_sequence != PrintSequence::ByObject) { - if (m_config.single_extruder_multi_material) { - auto ret = check_multi_filament_valid(*this); - if (!ret.string.empty()) - return ret; - } - - if (warning) { - for (unsigned int extruder_a: extruders) { - const ConfigOptionInts* bed_temp_opt = m_config.option(get_bed_temp_key(m_config.curr_bed_type)); - const ConfigOptionInts* bed_temp_1st_opt = m_config.option(get_bed_temp_1st_layer_key(m_config.curr_bed_type)); - int bed_temp_a = bed_temp_opt->get_at(extruder_a); - int bed_temp_1st_a = bed_temp_1st_opt->get_at(extruder_a); - for (unsigned int extruder_b: extruders) { - int bed_temp_b = bed_temp_opt->get_at(extruder_b); - int bed_temp_1st_b = bed_temp_1st_opt->get_at(extruder_b); - if (std::abs(bed_temp_a - bed_temp_b) > 15 || std::abs(bed_temp_1st_a - bed_temp_1st_b) > 15) { - warning->string = L("Bed temperatures for the used filaments differ significantly."); - goto DONE; - } - } - } - DONE:; + auto ret = check_multi_filament_valid(*this); + if (!ret.string.empty()) + { + ret.type = STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMP; + return ret; } } @@ -948,13 +979,16 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* //BBS: refine seq-print validation logic auto ret = sequential_print_clearance_valid(*this, collison_polygons, height_polygons); - if (!ret.string.empty()) + if (!ret.string.empty()) { + ret.type = STRING_EXCEPT_OBJECT_COLLISION_IN_SEQ_PRINT; return ret; + } } else { //BBS auto ret = layered_print_cleareance_valid(*this, warning); if (!ret.string.empty()) { + ret.type = STRING_EXCEPT_OBJECT_COLLISION_IN_LAYER_PRINT; return ret; } } @@ -984,10 +1018,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* // BBS: remove L() return { ("Different nozzle diameters and different filament diameters is not allowed when prime tower is enabled.") }; } - + if (! m_config.use_relative_e_distances) return { ("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") }; - if (m_config.ooze_prevention) return { ("Ooze prevention is currently not supported with the prime tower enabled.") }; @@ -1393,6 +1426,20 @@ void PrintObject::copy_layers_from_shared_object() } } +void PrintObject::copy_layers_overhang_from_shared_object() +{ + if (m_shared_object) { + for (size_t index = 0; index < m_layers.size() && index < m_shared_object->m_layers.size(); index++) + { + Layer* layer_src = m_layers[index]; + layer_src->loverhangs = m_shared_object->m_layers[index]->loverhangs; + layer_src->loverhangs_bbox = m_shared_object->m_layers[index]->loverhangs_bbox; + } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, copied layer overhang from object %2%")%this%m_shared_object; + } +} + + // BBS BoundingBox PrintObject::get_first_layer_bbox(float& a, float& layer_height, std::string& name) { @@ -1403,7 +1450,7 @@ BoundingBox PrintObject::get_first_layer_bbox(float& a, float& layer_height, std auto layer = get_layer(0); layer_height = layer->height; // only work for object with single instance - auto shift = instances()[0].shift; + auto shift = instances()[0].shift_without_plate_offset(); for (auto bb : layer->lslices_bboxes) { bb.translate(shift.x(), shift.y()); @@ -1494,6 +1541,7 @@ void Print::process(bool use_cache) }; int object_count = m_objects.size(); std::set need_slicing_objects; + std::set re_slicing_objects; if (!use_cache) { for (int index = 0; index < object_count; index++) { @@ -1530,8 +1578,12 @@ void Print::process(bool use_cache) } } if (!found_shared) { - BOOST_LOG_TRIVIAL(error) << boost::format("Also can not find the shared object, identify_id %1%")%obj->model_object()->instances[0]->loaded_id; - throw Slic3r::SlicingError("Can not find the cached data."); + BOOST_LOG_TRIVIAL(warning) << boost::format("Also can not find the shared object, identify_id %1%, maybe shared object is skipped")%obj->model_object()->instances[0]->loaded_id; + //throw Slic3r::SlicingError("Can not find the cached data."); + //don't report errot, set use_cache to false, and reslice these objects + need_slicing_objects.insert(obj); + re_slicing_objects.insert(obj); + //use_cache = false; } } } @@ -1589,18 +1641,26 @@ void Print::process(bool use_cache) } else { for (PrintObject *obj : m_objects) { - if (obj->set_started(posSlice)) - obj->set_done(posSlice); - if (obj->set_started(posPerimeters)) - obj->set_done(posPerimeters); - if (obj->set_started(posPrepareInfill)) - obj->set_done(posPrepareInfill); - if (obj->set_started(posInfill)) - obj->set_done(posInfill); - if (obj->set_started(posIroning)) - obj->set_done(posIroning); - if (obj->set_started(posSupportMaterial)) - obj->set_done(posSupportMaterial); + if (re_slicing_objects.count(obj) == 0) { + if (obj->set_started(posSlice)) + obj->set_done(posSlice); + if (obj->set_started(posPerimeters)) + obj->set_done(posPerimeters); + if (obj->set_started(posPrepareInfill)) + obj->set_done(posPrepareInfill); + if (obj->set_started(posInfill)) + obj->set_done(posInfill); + if (obj->set_started(posIroning)) + obj->set_done(posIroning); + if (obj->set_started(posSupportMaterial)) + obj->set_done(posSupportMaterial); + } + else { + obj->make_perimeters(); + obj->infill(); + obj->ironing(); + obj->generate_support_material(); + } } } @@ -1713,12 +1773,15 @@ void Print::process(bool use_cache) } //BBS for (PrintObject *obj : m_objects) { - if ((!use_cache)&&(need_slicing_objects.count(obj) != 0)) { + if (((!use_cache)&&(need_slicing_objects.count(obj) != 0)) + || (use_cache &&(re_slicing_objects.count(obj) != 0))){ obj->simplify_extrusion_path(); } else { if (obj->set_started(posSimplifyPath)) obj->set_done(posSimplifyPath); + if (obj->set_started(posSimplifyInfill)) + obj->set_done(posSimplifyInfill); if (obj->set_started(posSimplifySupportPath)) obj->set_done(posSimplifySupportPath); } @@ -1730,6 +1793,7 @@ void Print::process(bool use_cache) obj->detect_overhangs_for_lift(); } else { + obj->copy_layers_overhang_from_shared_object(); if (obj->set_started(posDetectOverhangsForLift)) obj->set_done(posDetectOverhangsForLift); } @@ -3094,7 +3158,14 @@ int Print::export_cached_data(const std::string& directory, bool with_space) if (fs::exists(directory_path)) { fs::remove_all(directory_path); } - if (!fs::create_directory(directory_path)) { + try { + if (!fs::create_directory(directory_path)) { + BOOST_LOG_TRIVIAL(error) << boost::format("create directory %1% failed")%directory; + return CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED; + } + } + catch (...) + { BOOST_LOG_TRIVIAL(error) << boost::format("create directory %1% failed")%directory; return CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED; } @@ -3528,4 +3599,12 @@ Polygon PrintInstance::get_convex_hull_2d() { return poly; } +//BBS: instance_shift is too large because of multi-plate, apply without plate offset. +Point PrintInstance::shift_without_plate_offset() const +{ + const Print* print = print_object->print(); + const Vec3d plate_offset = print->get_plate_origin(); + return shift - Point(scaled(plate_offset.x()), scaled(plate_offset.y())); +} + } // namespace Slic3r diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 2b3775f3a0..83ccfbaa6d 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -89,6 +89,7 @@ enum PrintObjectStep { posSlice, posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportMaterial, posSimplifyPath, posSimplifySupportPath, // BBS + posSimplifyInfill, posDetectOverhangsForLift, posCount, }; @@ -200,6 +201,9 @@ struct PrintInstance // // instance id size_t id; + + //BBS: instance_shift is too large because of multi-plate, apply without plate offset. + Point shift_without_plate_offset() const; }; typedef std::vector PrintInstances; @@ -419,11 +423,13 @@ public: //BBS BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name); - + void get_certain_layers(float start, float end, std::vector &out, std::vector &boundingbox_objects); + std::vector get_instances_shift_without_plate_offset(); PrintObject* get_shared_object() const { return m_shared_object; } void set_shared_object(PrintObject *object); void clear_shared_object(); void copy_layers_from_shared_object(); + void copy_layers_overhang_from_shared_object(); // BBS: Boundingbox of the first layer BoundingBox firstLayerObjectBrimBoundingBox; @@ -755,7 +761,7 @@ public: // For Perl bindings. PrintObjectPtrs& objects_mutable() { return m_objects; } PrintRegionPtrs& print_regions_mutable() { return m_print_regions; } - + std::vector layers_sorted_for_object(float start, float end, std::vector &layers_of_objects, std::vector &boundingBox_for_objects, std::vector& objects_instances_shift); const ExtrusionEntityCollection& skirt() const { return m_skirt; } // Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line. // It encompasses the object extrusions, support extrusions, skirt, brim, wipe tower. @@ -818,6 +824,9 @@ public: Vec2d translate_to_print_space(const Vec2d &point) const; // scaled point Vec2d translate_to_print_space(const Point &point) const; + + static bool check_multi_filaments_compatibility(const std::vector& filament_types); + protected: // Invalidates the step, and its depending steps in Print. bool invalidate_step(PrintStep step); diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 1fd296c689..e70d52e2c5 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -19,6 +19,9 @@ namespace Slic3r { enum StringExceptionType { STRING_EXCEPT_NOT_DEFINED = 0, STRING_EXCEPT_FILAMENT_NOT_MATCH_BED_TYPE = 1, + STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMP = 2, + STRING_EXCEPT_OBJECT_COLLISION_IN_SEQ_PRINT = 3, + STRING_EXCEPT_OBJECT_COLLISION_IN_LAYER_PRINT = 4, STRING_EXCEPT_COUNT }; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 03d2935617..82acc37825 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -444,6 +444,7 @@ void PrintObject::detect_overhangs_for_lift() ExPolygons overhangs = diff_ex(layer.lslices, offset_ex(lower_layer.lslices, scale_(min_overlap))); layer.loverhangs = std::move(offset2_ex(overhangs, -0.1f * scale_(line_width), 0.1f * scale_(line_width))); + layer.loverhangs_bbox = get_extents(layer.loverhangs); } }); @@ -507,15 +508,33 @@ void PrintObject::simplify_extrusion_path() [this](const tbb::blocked_range& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { m_print->throw_if_canceled(); - m_layers[layer_idx]->simplify_extrusion_path(); + m_layers[layer_idx]->simplify_wall_extrusion_path(); } } ); m_print->throw_if_canceled(); - BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of object in parallel - end"; + BOOST_LOG_TRIVIAL(debug) << "Simplify wall extrusion path of object in parallel - end"; this->set_done(posSimplifyPath); } + if (this->set_started(posSimplifyInfill)) { + m_print->set_status(75, L("Optimizing toolpath")); + BOOST_LOG_TRIVIAL(debug) << "Simplify infill extrusion path of object in parallel - start"; + //BBS: infills + tbb::parallel_for( + tbb::blocked_range(0, m_layers.size()), + [this](const tbb::blocked_range& range) { + for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + m_print->throw_if_canceled(); + m_layers[layer_idx]->simplify_infill_extrusion_path(); + } + } + ); + m_print->throw_if_canceled(); + BOOST_LOG_TRIVIAL(debug) << "Simplify infill extrusion path of object in parallel - end"; + this->set_done(posSimplifyInfill); + } + if (this->set_started(posSimplifySupportPath)) { //BBS: share same progress m_print->set_status(75, L("Optimizing toolpath")); @@ -764,6 +783,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "support_angle" || opt_key == "support_on_build_plate_only" || opt_key == "support_critical_regions_only" + || opt_key == "support_remove_small_overhang" || opt_key == "enforce_support_layers" || opt_key == "support_filament" || opt_key == "support_line_width" @@ -939,15 +959,15 @@ bool PrintObject::invalidate_step(PrintObjectStep step) // propagate to dependent steps if (step == posPerimeters) { - invalidated |= this->invalidate_steps({ posPrepareInfill, posInfill, posIroning, posSimplifyPath }); + invalidated |= this->invalidate_steps({ posPrepareInfill, posInfill, posIroning, posSimplifyPath, posSimplifyInfill }); invalidated |= m_print->invalidate_steps({ psSkirtBrim }); } else if (step == posPrepareInfill) { - invalidated |= this->invalidate_steps({ posInfill, posIroning, posSimplifyPath }); + invalidated |= this->invalidate_steps({ posInfill, posIroning, posSimplifyPath, posSimplifyInfill }); } else if (step == posInfill) { - invalidated |= this->invalidate_steps({ posIroning, posSimplifyPath }); + invalidated |= this->invalidate_steps({ posIroning, posSimplifyInfill }); invalidated |= m_print->invalidate_steps({ psSkirtBrim }); } else if (step == posSlice) { - invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportMaterial, posSimplifyPath }); + invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportMaterial, posSimplifyPath, posSimplifyInfill }); invalidated |= m_print->invalidate_steps({ psSkirtBrim }); m_slicing_params.valid = false; } else if (step == posSupportMaterial) { @@ -2036,6 +2056,31 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c return updated; } +//BBS: +void PrintObject::get_certain_layers(float start, float end, std::vector &out, std::vector &boundingbox_objects) +{ + BoundingBox temp; + LayerPtrs out_temp; + for (const auto &layer : layers()) { + if (layer->print_z < start) continue; + + if (layer->print_z > end + EPSILON) break; + temp.merge(layer->loverhangs_bbox); + out_temp.emplace_back(layer); + } + boundingbox_objects.emplace_back(std::move(temp)); + out.emplace_back(std::move(out_temp)); +}; + +std::vector PrintObject::get_instances_shift_without_plate_offset() +{ + std::vector out; + out.reserve(m_instances.size()); + for (const auto& instance : m_instances) + out.push_back(instance.shift_without_plate_offset()); + + return out; +} // Only active if config->infill_only_where_needed. This step trims the sparse infill, // so it acts as an internal support. It maintains all other infill types intact. diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 540c59434a..bf5494c7a4 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2677,9 +2677,8 @@ void TabFilament::build() optgroup = page->new_optgroup(L("Print temperature"), L"param_temperature"); optgroup->split_multi_line = true; optgroup->option_label_at_right = true; - line = { L("Chamber temperature"), L("Chamber temperature") }; - line.append_option(optgroup->get_option("chamber_temperature")); - optgroup->append_line(line); + optgroup->append_single_option_line("chamber_temperatures"); + line = { L("Nozzle"), L("Nozzle temperature when printing") }; line.append_option(optgroup->get_option("nozzle_temperature_initial_layer")); @@ -2897,7 +2896,7 @@ void TabFilament::toggle_options() toggle_line("cool_plate_temp_initial_layer", is_BBL_printer); toggle_line("eng_plate_temp_initial_layer", is_BBL_printer); toggle_line("textured_plate_temp_initial_layer", is_BBL_printer); - toggle_option("chamber_temperature", !is_BBL_printer); + toggle_option("chamber_temperatures", !is_BBL_printer); } if (m_active_page->title() == "Setting Overrides") update_filament_overrides_page(); @@ -3690,7 +3689,7 @@ void TabPrinter::toggle_options() // SoftFever: hide BBL specific settings for (auto el : - {"scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time", "nozzle_type", "bbl_calib_mark_logo"}) + {"scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time", "bbl_calib_mark_logo"}) toggle_line(el, is_BBL_printer); // SoftFever: hide non-BBL settings