add sorting for complete_objects

fix (hopefully) a problem with sequential_print_horizontal_clearance_valid
This commit is contained in:
supermerill 2020-05-23 01:28:04 +02:00
parent 90b129e585
commit 3bb0b228bc
12 changed files with 138 additions and 45 deletions

View File

@ -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

View File

@ -9,6 +9,7 @@
#include "ShortestPath.hpp"
#include "Utils.hpp"
#include "libslic3r.h"
#include "PrintConfig.hpp"
#include <algorithm>
#include <cstdlib>
@ -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<const PrintInstance*> sort_object_instances_by_max_z(const Print &print)
static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(const Print& print)
{
std::vector<const PrintObject*> 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<const PrintInstance*> 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<const PrintInstance*> 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<const PrintInstance*> sort_object_instances_by_max_y(const Print& print)
{
std::vector<const PrintObject*> 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<const PrintInstance*> instances;
instances.reserve(objects.size());
std::map<const PrintInstance*, coord_t> 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 PrintInstance*>::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) {

View File

@ -69,7 +69,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
// or they are only notes not influencing the generated G-code.
static std::unordered_set<std::string> 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<t_config_option
"bridge_fan_speed",
"colorprint_heights",
"top_fan_speed",
"complete_objects_sort",
"cooling",
"default_acceleration",
"deretract_speed",
@ -95,7 +96,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"extrusion_multiplier",
"fan_always_on",
"fan_below_layer_time",
"fan_speedup_time",
"fan_speedup_time",
"filament_colour",
"filament_diameter",
"filament_density",
@ -1203,40 +1204,50 @@ bool Print::has_skirt() const
static inline bool sequential_print_horizontal_clearance_valid(const Print &print)
{
Polygons convex_hulls_other;
std::map<ObjectID, Polygon> map_model_object_to_convex_hull;
//std::map<ObjectID, Polygon> 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);
}

View File

@ -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<CompleteObjectSort>::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<CompleteObjectSort>(cosObject));
def = this->add("cooling", coBools);
def->label = L("Enable auto cooling");
def->category = OptionCategory::cooling;

View File

@ -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<CompleteObjectSort>::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<PrinterTechnology>::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<CompleteObjectSort> 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);

View File

@ -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");

View File

@ -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<SeamPosition>(val);
}
else if (m_opt_id.compare("complete_objects_sort") == 0)
val = idx_from_enum_value<CompleteObjectSort>(val);
else if (m_opt_id.compare("gcode_flavor") == 0)
val = idx_from_enum_value<GCodeFlavor>(val);
else if (m_opt_id.compare("support_material_pattern") == 0)
@ -1063,6 +1065,8 @@ boost::any& Choice::get_value()
convert_to_enum_value<InfillPattern>(ret_enum);
else if (m_opt_id.compare("gcode_flavor") == 0)
convert_to_enum_value<GCodeFlavor>(ret_enum);
else if (m_opt_id.compare("complete_objects_sort") == 0)
convert_to_enum_value<CompleteObjectSort>(ret_enum);
else if (m_opt_id.compare("support_material_pattern") == 0)
convert_to_enum_value<SupportMaterialPattern>(ret_enum);
else if (m_opt_id.compare("seam_position") == 0)

View File

@ -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<InfillPattern>(boost::any_cast<InfillPattern>(value)));
config.set_key_value(opt_key, new ConfigOptionEnum<InfillPattern>(boost::any_cast<InfillPattern>(value)));
else if (opt_key.compare("complete_objects_sort") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<CompleteObjectSort>(boost::any_cast<CompleteObjectSort>(value)));
else if (opt_key.compare("gcode_flavor") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<GCodeFlavor>(boost::any_cast<GCodeFlavor>(value)));
else if (opt_key.compare("support_material_interface_pattern") == 0)

View File

@ -746,6 +746,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
opt_key == "fill_pattern" ) {
ret = static_cast<int>(config.option<ConfigOptionEnum<InfillPattern>>(opt_key)->value);
}
else if (opt_key.compare("complete_objects_sort") == 0 ) {
ret = static_cast<int>(config.option<ConfigOptionEnum<CompleteObjectSort>>(opt_key)->value);
}
else if (opt_key.compare("gcode_flavor") == 0 ) {
ret = static_cast<int>(config.option<ConfigOptionEnum<GCodeFlavor>>(opt_key)->value);
}

View File

@ -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",

View File

@ -484,6 +484,7 @@ const std::vector<std::string>& 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",

View File

@ -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;
}