From 3bb0b228bc03467179f1b2214a60195cb3fecfa4 Mon Sep 17 00:00:00 2001 From: supermerill Date: Sat, 23 May 2020 01:28:04 +0200 Subject: [PATCH] add sorting for complete_objects fix (hopefully) a problem with sequential_print_horizontal_clearance_valid --- resources/ui_layout/print.ui | 1 + src/libslic3r/GCode.cpp | 54 +++++++++++++++++---- src/libslic3r/Print.cpp | 67 ++++++++++++++++----------- src/libslic3r/PrintConfig.cpp | 17 +++++++ src/libslic3r/PrintConfig.hpp | 26 +++++++++-- src/slic3r/GUI/ConfigManipulation.cpp | 3 +- src/slic3r/GUI/Field.cpp | 4 ++ src/slic3r/GUI/GUI.cpp | 4 +- src/slic3r/GUI/OptionsGroup.cpp | 3 ++ src/slic3r/GUI/Plater.cpp | 1 + src/slic3r/GUI/Preset.cpp | 1 + src/slic3r/GUI/Tab.cpp | 2 +- 12 files changed, 138 insertions(+), 45 deletions(-) diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index 7a96e15e5..d2767c952 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -268,6 +268,7 @@ group:Plater group:Sequential printing setting:complete_objects setting:complete_objects_one_skirt + setting:complete_objects_sort line:Extruder clearance (mm) setting:width$6:extruder_clearance_radius setting:width$6:extruder_clearance_height diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 567b77210..c93303257 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -9,6 +9,7 @@ #include "ShortestPath.hpp" #include "Utils.hpp" #include "libslic3r.h" +#include "PrintConfig.hpp" #include #include @@ -1113,16 +1114,45 @@ namespace DoExport { } // Sort the PrintObjects by their increasing Z, likely useful for avoiding colisions on Deltas during sequential prints. -static inline std::vector sort_object_instances_by_max_z(const Print &print) +static inline std::vector sort_object_instances_by_max_z(const Print& print) { std::vector objects(print.objects().begin(), print.objects().end()); - std::sort(objects.begin(), objects.end(), [](const PrintObject *po1, const PrintObject *po2) { return po1->height() < po2->height(); }); - std::vector instances; - instances.reserve(objects.size()); - for (const PrintObject *object : objects) - for (size_t i = 0; i < object->instances().size(); ++ i) - instances.emplace_back(&object->instances()[i]); - return instances; + std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->height() < po2->height(); }); + std::vector instances; + instances.reserve(objects.size()); + for (const PrintObject* object : objects) + for (size_t i = 0; i < object->instances().size(); ++i) + instances.emplace_back(&object->instances()[i]); + return instances; +} + +// Sort the PrintObjects by their increasing Y, likely useful for avoiding colisions on printer with a x-bar during sequential prints. +static inline std::vector sort_object_instances_by_max_y(const Print& print) +{ + std::vector objects(print.objects().begin(), print.objects().end()); + std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->height() < po2->height(); }); + std::vector instances; + instances.reserve(objects.size()); + std::map map_min_y; + for (const PrintObject* object : objects) { + for (size_t i = 0; i < object->instances().size(); ++i) { + instances.emplace_back(&object->instances()[i]); + // Calculate the convex hull of a printable object. + Polygon poly = object->model_object()->convex_hull_2d( + Geometry::assemble_transform(Vec3d::Zero(), + object->instances()[i].model_instance->get_rotation(), + object->instances()[i].model_instance->get_scaling_factor(), + object->instances()[i].model_instance->get_mirror())); + poly.translate(object->instances()[i].shift - object->center_offset()); + coord_t min_y = poly.first_point().y(); + for (const Point& point : poly.points) + if (point.y() < min_y) + min_y = point.y(); + map_min_y[instances.back()] = min_y; + } + } + std::sort(instances.begin(), instances.end(), [&map_min_y](const PrintInstance* po1, const PrintInstance* po2) { return map_min_y[po1] < map_min_y[po2]; }); + return instances; } // Produce a vector of PrintObjects in the order of their respective ModelObjects in print.model(). @@ -1302,8 +1332,12 @@ void GCode::_do_export(Print &print, FILE *file) std::vector::const_iterator print_object_instance_sequential_active; if (print.config().complete_objects.value) { // Order object instances for sequential print. - print_object_instances_ordering = sort_object_instances_by_model_order(print); -// print_object_instances_ordering = sort_object_instances_by_max_z(print); + if(print.config().complete_objects_sort.value == cosObject) + print_object_instances_ordering = sort_object_instances_by_model_order(print); + else if (print.config().complete_objects_sort.value == cosZ) + print_object_instances_ordering = sort_object_instances_by_max_z(print); + else if (print.config().complete_objects_sort.value == cosY) + print_object_instances_ordering = sort_object_instances_by_max_y(print); // Find the 1st printing object, find its tool ordering and the initial extruder ID. print_object_instance_sequential_active = print_object_instances_ordering.begin(); for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++ print_object_instance_sequential_active) { diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 8e827fa57..0da8e6fdb 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -69,7 +69,7 @@ bool Print::invalidate_state_by_config_options(const std::vector steps_gcode = { "avoid_crossing_perimeters", - "avoid_crossing_not_first_layer", + "avoid_crossing_not_first_layer", "bed_shape", "bed_temperature", "chamber_temperature", @@ -79,6 +79,7 @@ bool Print::invalidate_state_by_config_options(const std::vector map_model_object_to_convex_hull; + //std::map map_model_object_to_convex_hull; for (const PrintObject *print_object : print.objects()) { assert(! print_object->model_object()->instances.empty()); assert(! print_object->instances().empty()); - ObjectID model_object_id = print_object->model_object()->id(); - auto it_convex_hull = map_model_object_to_convex_hull.find(model_object_id); + //ObjectID model_object_id = print_object->model_object()->id(); + //auto it_convex_hull = map_model_object_to_convex_hull.find(model_object_id); // Get convex hull of all printable volumes assigned to this print object. - ModelInstance *model_instance0 = print_object->model_object()->instances.front(); - if (it_convex_hull == map_model_object_to_convex_hull.end()) { - // Calculate the convex hull of a printable object. - // Grow convex hull with the clearance margin. - // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2) - // which causes that the warning will be showed after arrangement with the - // appropriate object distance. Even if I set this to jtMiter the warning still shows up. - it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id, - offset(print_object->model_object()->convex_hull_2d( - Geometry::assemble_transform(Vec3d::Zero(), model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())), - // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects - // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. - float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), - jtRound, float(scale_(0.1))).front()); - } - // Make a copy, so it may be rotated for instances. - Polygon convex_hull0 = it_convex_hull->second; - double z_diff = Geometry::rotation_diff_z(model_instance0->get_rotation(), print_object->instances().front().model_instance->get_rotation()); - if (std::abs(z_diff) > EPSILON) - convex_hull0.rotate(z_diff); + // ModelInstance *model_instance0 = print_object->model_object()->instances.front(); + // if (it_convex_hull == map_model_object_to_convex_hull.end()) { + // // Calculate the convex hull of a printable object. + // // Grow convex hull with the clearance margin. + // // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2) + // // which causes that the warning will be showed after arrangement with the + // // appropriate object distance. Even if I set this to jtMiter the warning still shows up. + // it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id, + // offset(print_object->model_object()->convex_hull_2d( + // Geometry::assemble_transform(Vec3d::Zero(), model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())), + // // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects + // // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. + // float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), + // jtRound, float(scale_(0.1))).front()); + // } + // // Make a copy, so it may be rotated for instances. + // //FIXME seems like the rotation isn't taken into account + // Polygon convex_hull0 = it_convex_hull->second; + // //this can create bugs in macos, for reasons. + //double z_diff = Geometry::rotation_diff_z(model_instance0->get_rotation(), print_object->instances().front().model_instance->get_rotation()); + //if (std::abs(z_diff) > EPSILON) + // convex_hull0.rotate(z_diff); // Now we check that no instance of convex_hull intersects any of the previously checked object instances. for (const PrintInstance &instance : print_object->instances()) { - Polygon convex_hull = convex_hull0; + Polygons convex_hull = offset(print_object->model_object()->convex_hull_2d( + Geometry::assemble_transform(Vec3d::Zero(), + instance.model_instance->get_rotation(), instance.model_instance->get_scaling_factor(), instance.model_instance->get_mirror())), + // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects + // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. + float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), + jtRound, float(scale_(0.1))); + if (convex_hull.empty()) + continue; // instance.shift is a position of a centered object, while model object may not be centered. // Conver the shift from the PrintObject's coordinates into ModelObject's coordinates by removing the centering offset. - convex_hull.translate(instance.shift - print_object->center_offset()); - if (! intersection(convex_hulls_other, convex_hull).empty()) + convex_hull[0].translate(instance.shift - print_object->center_offset()); + if (! intersection(convex_hulls_other, convex_hull[0]).empty()) return false; polygons_append(convex_hulls_other, convex_hull); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index b44f3b2f6..9b1371acd 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -448,6 +448,23 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("complete_objects_sort", coEnum); + def->label = L("Object sort"); + def->category = OptionCategory::output; + def->tooltip = L("When printing multiple objects or copies on after another, this will help you to choose how it's ordered." + "\nObject will sort them by the order of the right panel." + "\nLowest Y will sort them by their lowest Y point. Useful for printers with a X-bar." + "\nLowest Z will sort them by their height, useful for delta printers."); + def->mode = comAdvanced; + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("object"); + def->enum_values.push_back("lowy"); + def->enum_values.push_back("lowz"); + def->enum_labels.push_back(L("Right panel")); + def->enum_labels.push_back(L("lowest Y")); + def->enum_labels.push_back(L("lowest Z")); + def->set_default_value(new ConfigOptionEnum(cosObject)); + def = this->add("cooling", coBools); def->label = L("Enable auto cooling"); def->category = OptionCategory::cooling; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6c33fa8f9..bede9e72c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -35,6 +35,12 @@ namespace Slic3r { +enum CompleteObjectSort { + cosObject, + cosZ, + cosY, +}; + enum WipeAlgo { waLinear, waQuadra, @@ -92,14 +98,24 @@ enum SLAPillarConnectionMode { slapcmZigZag, slapcmCross, slapcmDynamic -}; +}; + +template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { + static t_config_enum_values keys_map; + if (keys_map.empty()) { + keys_map["object"] = cosObject; + keys_map["lowy"] = cosY; + keys_map["lowz"] = cosY; + } + return keys_map; +} template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { - keys_map["FFF"] = ptFFF; - keys_map["SLA"] = ptSLA; - keys_map["SLS"] = ptSLS; + keys_map["FFF"] = ptFFF; + keys_map["SLA"] = ptSLA; + keys_map["SLS"] = ptSLS; } return keys_map; } @@ -989,6 +1005,7 @@ public: ConfigOptionInts chamber_temperature; ConfigOptionBool complete_objects; ConfigOptionBool complete_objects_one_skirt; + ConfigOptionEnum complete_objects_sort; ConfigOptionFloats colorprint_heights; ConfigOptionBools cooling; ConfigOptionFloat default_acceleration; @@ -1069,6 +1086,7 @@ protected: OPT_PTR(chamber_temperature); OPT_PTR(complete_objects); OPT_PTR(complete_objects_one_skirt); + OPT_PTR(complete_objects_sort); OPT_PTR(colorprint_heights); OPT_PTR(cooling); OPT_PTR(default_acceleration); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 88791c90e..99ca09c02 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -401,7 +401,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("support_material_speed", have_support_material || have_brim || have_skirt); bool have_sequential_printing = config->opt_bool("complete_objects"); - for (auto el : { /*"extruder_clearance_radius", "extruder_clearance_height",*/ "complete_objects_one_skirt" }) + for (auto el : { /*"extruder_clearance_radius", "extruder_clearance_height",*/ "complete_objects_one_skirt", + "complete_objects_sort"}) toggle_field(el, have_sequential_printing); bool have_ooze_prevention = config->opt_bool("ooze_prevention"); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 910016f68..ef04482d9 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -980,6 +980,8 @@ void Choice::set_value(const boost::any& value, bool change_event) } else if (m_opt_id.compare("perimeter_loop_seam") == 0) { val = idx_from_enum_value(val); } + else if (m_opt_id.compare("complete_objects_sort") == 0) + val = idx_from_enum_value(val); else if (m_opt_id.compare("gcode_flavor") == 0) val = idx_from_enum_value(val); else if (m_opt_id.compare("support_material_pattern") == 0) @@ -1063,6 +1065,8 @@ boost::any& Choice::get_value() convert_to_enum_value(ret_enum); else if (m_opt_id.compare("gcode_flavor") == 0) convert_to_enum_value(ret_enum); + else if (m_opt_id.compare("complete_objects_sort") == 0) + convert_to_enum_value(ret_enum); else if (m_opt_id.compare("support_material_pattern") == 0) convert_to_enum_value(ret_enum); else if (m_opt_id.compare("seam_position") == 0) diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 60aa476fa..8d634d0f6 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -188,7 +188,9 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt opt_key == "bottom_fill_pattern" || opt_key == "solid_fill_pattern" || opt_key == "fill_pattern") - config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + else if (opt_key.compare("complete_objects_sort") == 0) + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("gcode_flavor") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("support_material_interface_pattern") == 0) diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index d47639fb6..f09c79733 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -746,6 +746,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config opt_key == "fill_pattern" ) { ret = static_cast(config.option>(opt_key)->value); } + else if (opt_key.compare("complete_objects_sort") == 0 ) { + ret = static_cast(config.option>(opt_key)->value); + } else if (opt_key.compare("gcode_flavor") == 0 ) { ret = static_cast(config.option>(opt_key)->value); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a76ae3c2b..e00911046 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2062,6 +2062,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) , config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({ "bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", + "complete_objects_sort", "complete_objects_one_skirt", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", "brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host", diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 8b173ea0c..1afbc47e5 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -484,6 +484,7 @@ const std::vector& Preset::print_options() , "support_material_buildplate_only", "dont_support_bridges", "notes", "complete_objects", "complete_objects_one_skirt", + "complete_objects_sort", "extruder_clearance_radius", "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder", "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 9cc4aa095..93315c403 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1346,7 +1346,7 @@ bool Tab::create_pages(std::string setting_type_name) if (params.size() > 1) setting_id = params.back(); if (setting_id.size() < 2) continue; if (!m_config->has(setting_id)) { - std::cerr << "No " << setting_id << " in tab ConfigOptionsGroup config.\n"; + std::cerr << "No " << setting_id << " in ConfigOptionsGroup config, tab "<< setting_type_name <<".\n"; continue; }