mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 06:15:57 +08:00
add sorting for complete_objects
fix (hopefully) a problem with sequential_print_horizontal_clearance_valid
This commit is contained in:
parent
90b129e585
commit
3bb0b228bc
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user