diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index aeaf17ad1..0beb2df68 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -186,16 +186,18 @@ int CLI::run(int argc, char **argv) for (ModelObject *o : model.objects) m.add_object(*o); // Rearrange instances unless --dont-arrange is supplied - if (! m_config.opt_bool("dont_arrange")) { - m.add_default_instances(); - const BoundingBoxf &bb = fff_print_config.bed_shape.values; - m.arrange_objects( - fff_print_config.min_object_distance(), - // If we are going to use the merged model for printing, honor - // the configured print bed for arranging, otherwise do it freely. - this->has_print_action() ? &bb : nullptr - ); - } + //shoudl be done later + //TODO: test it! + //if (! m_config.opt_bool("dont_arrange")) { + // m.add_default_instances(); + // const BoundingBoxf &bb = fff_print_config.bed_shape.values; + // m.arrange_objects( + // fff_print_config, + // // If we are going to use the merged model for printing, honor + // // the configured print bed for arranging, otherwise do it freely. + // this->has_print_action() ? &bb : nullptr + // ); + //} m_models.clear(); m_models.emplace_back(std::move(m)); } else if (opt_key == "duplicate") { @@ -415,7 +417,7 @@ int CLI::run(int argc, char **argv) PrintBase *print = (printer_technology == ptFFF) ? static_cast(&fff_print) : static_cast(&sla_print); if (! m_config.opt_bool("dont_arrange")) { //FIXME make the min_object_distance configurable. - model.arrange_objects(fff_print.config().min_object_distance()); + model.arrange_objects(fff_print); model.center_instances_around_point((! user_center_specified && m_print_config.has("bed_shape")) ? BoundingBoxf(m_print_config.opt("bed_shape")->values).center() : m_config.option("center")->value); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 56dc2abc0..7c4327d93 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1,5 +1,6 @@ #include "Model.hpp" #include "Geometry.hpp" +#include "Print.hpp" #include "MTUtils.hpp" #include "Format/AMF.hpp" @@ -386,7 +387,7 @@ static bool _arrange(const Pointfs &sizes, coordf_t dist, const BoundingBoxf* bb /* arrange objects preserving their instance count but altering their instance positions */ -bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) +bool Model::arrange_objects(const Print &print, const BoundingBoxf* bb) { size_t count = 0; for (auto obj : objects) count += obj->instances.size(); @@ -397,7 +398,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) instances.reserve(count); for (ModelObject *mo : objects) for (ModelInstance *minst : mo->instances) { - input.emplace_back(minst->get_arrange_polygon()); + input.emplace_back(minst->get_arrange_polygon(print)); instances.emplace_back(minst); } @@ -410,7 +411,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) BoundingBox(scaled(bb->min), scaled(bb->max))); } - arrangement::arrange(input, scaled(dist), bedhint); + arrangement::arrange(input, scale_(1), bedhint); bool ret = true; coord_t stride = bedwidth + bedwidth / 5; @@ -450,8 +451,7 @@ void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) } } -/* this will append more instances to each object - and then automatically rearrange everything */ +/* this will append more instances to each object */ void Model::duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) { for (ModelObject *o : this->objects) { @@ -461,8 +461,6 @@ void Model::duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBo for (size_t k = 2; k <= copies_num; ++ k) o->add_instance(*i); } - - this->arrange_objects(dist, bb); } void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist) @@ -1820,7 +1818,7 @@ void ModelInstance::transform_polygon(Polygon* polygon) const polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin } -arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const +arrangement::ArrangePolygon ModelInstance::get_arrange_polygon(const Print& print) const { static const double SIMPLIFY_TOLERANCE_MM = 0.1; @@ -1838,7 +1836,13 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const // https://github.com/prusa3d/PrusaSlicer/issues/2209 if (!p.points.empty()) { Polygons pp{p}; - pp = p.simplify(scaled(SIMPLIFY_TOLERANCE_MM)); + //grow + double dist = print.config().min_object_distance(&print.full_print_config()); + std::cout << "min_object_distance = " << dist << "\n"; + pp = offset(pp, scale_(dist)); + //simplify + if (!pp.empty()) + pp = pp.front().simplify(scaled(SIMPLIFY_TOLERANCE_MM)); if (!pp.empty()) p = pp.front(); } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 96e9ef64e..9e59be454 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -665,7 +665,7 @@ public: bool is_printable() const { return object->printable && printable && (print_volume_state == PVS_Inside); } // Getting the input polygon for arrange - arrangement::ArrangePolygon get_arrange_polygon() const; + arrangement::ArrangePolygon get_arrange_polygon(const Print& print) const; // Apply the arrange result on the ModelInstance void apply_arrange_result(const Vec2crd& offs, double rotation) @@ -802,7 +802,7 @@ public: bool center_instances_around_point(const Vec2d &point); void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); } TriangleMesh mesh() const; - bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL); + bool arrange_objects(const Print& print, const BoundingBoxf* bb = NULL); // Croaks if the duplicated objects do not fit the print bed. void duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); void duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3e31d60e4..6b3e66735 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1240,20 +1240,24 @@ static inline bool sequential_print_horizontal_clearance_valid(const Print &prin // 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()) { - Polygons convex_hull = offset(print_object->model_object()->convex_hull_2d( + Polygons convex_hull = 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())), + 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))); + /*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[0].translate(instance.shift - print_object->center_offset()); - if (! intersection(convex_hulls_other, convex_hull[0]).empty()) + for(Polygon &poly : convex_hull) + poly.translate(instance.shift - print_object->center_offset()); + if (! intersection(convex_hulls_other, offset(convex_hull[0], scale_(print.config().min_object_distance(&instance.print_object->config(),0.)) - SCALED_EPSILON, jtRound, float(scale_(0.1)))).empty()) return false; + double extra_grow = print.config().min_object_distance(&instance.print_object->config(), 1.); + if (extra_grow > 0) + convex_hull = offset(convex_hull, scale_(extra_grow)); polygons_append(convex_hulls_other, convex_hull); } } @@ -1276,16 +1280,16 @@ static inline bool sequential_print_vertical_clearance_valid(const Print &print) std::pair Print::validate() const { if (m_objects.empty()) - return { PrintValidationError::WrongPosition, L("All objects are outside of the print volume.") }; + return { PrintBase::PrintValidationError::WrongPosition, L("All objects are outside of the print volume.") }; if (extruders().empty()) - return { PrintValidationError::NoPrint, L("The supplied settings will cause an empty print.") }; + return { PrintBase::PrintValidationError::NoPrint, L("The supplied settings will cause an empty print.") }; if (m_config.complete_objects) { if (! sequential_print_horizontal_clearance_valid(*this)) - return { PrintValidationError::WrongPosition, L("Some objects are too close; your extruder will collide with them.") }; + return { PrintBase::PrintValidationError::WrongPosition, L("Some objects are too close; your extruder will collide with them.") }; if (! sequential_print_vertical_clearance_valid(*this)) - return { PrintValidationError::WrongPosition,L("Some objects are too tall and cannot be printed without extruder collisions.") }; + return { PrintBase::PrintValidationError::WrongPosition,L("Some objects are too tall and cannot be printed without extruder collisions.") }; } if (m_config.spiral_vase) { @@ -1294,14 +1298,14 @@ std::pair Print::validate() const total_copies_count += object->instances().size(); // #4043 if (total_copies_count > 1 && ! m_config.complete_objects.value) - return { PrintValidationError::WrongSettings,L("The Spiral Vase option can only be used when printing a single object.") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Spiral Vase option can only be used when printing a single object.") }; assert(m_objects.size() == 1 || config().complete_objects.value); size_t num_regions = 0; for (const std::vector> &volumes_per_region : m_objects.front()->region_volumes) if (! volumes_per_region.empty()) ++ num_regions; if (num_regions > 1) - return { PrintValidationError::WrongSettings,L("The Spiral Vase option can only be used when printing single material objects.") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Spiral Vase option can only be used when printing single material objects.") }; } if (this->has_wipe_tower() && ! m_objects.empty()) { @@ -1314,21 +1318,21 @@ std::pair Print::validate() const double filament_diam = m_config.filament_diameter.get_at(extruder_idx); if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam || std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1) - return { PrintValidationError::WrongSettings,L("The wipe tower is only supported if all extruders have the same nozzle diameter " + return { PrintBase::PrintValidationError::WrongSettings,L("The wipe tower is only supported if all extruders have the same nozzle diameter " "and use filaments of the same diameter.") }; } if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlin && m_config.gcode_flavor != gcfKlipper) - return { PrintValidationError::WrongSettings,L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.") }; if (! m_config.use_relative_e_distances) - return { PrintValidationError::WrongSettings,L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") }; if (m_config.ooze_prevention) - return { PrintValidationError::WrongSettings,L("Ooze prevention is currently not supported with the wipe tower enabled.") }; + return { PrintBase::PrintValidationError::WrongSettings,L("Ooze prevention is currently not supported with the wipe tower enabled.") }; if (m_config.use_volumetric_e) - return { PrintValidationError::WrongSettings,L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0).") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0).") }; if (m_config.complete_objects && extruders().size() > 1) - return { PrintValidationError::WrongSettings,L("The Wipe Tower is currently not supported for multimaterial sequential prints.") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower is currently not supported for multimaterial sequential prints.") }; if (m_objects.size() > 1) { bool has_custom_layering = false; @@ -1349,15 +1353,15 @@ std::pair Print::validate() const const SlicingParameters &slicing_params = object->slicing_parameters(); if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON || std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON) - return { PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they have equal layer heights") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they have equal layer heights") }; if (slicing_params.raft_layers() != slicing_params0.raft_layers()) - return { PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers") }; if (object->config().support_material_contact_distance_type != m_objects.front()->config().support_material_contact_distance_type || object->config().support_material_contact_distance_top != m_objects.front()->config().support_material_contact_distance_top || object->config().support_material_contact_distance_bottom != m_objects.front()->config().support_material_contact_distance_bottom) - return { PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance") }; if (! equal_layering(slicing_params, slicing_params0)) - return { PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are sliced equally.") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower is only supported for multiple objects if they are sliced equally.") }; if (has_custom_layering) { PrintObject::update_layer_height_profile(*object->model_object(), slicing_params, layer_height_profiles[i]); if (*(layer_height_profiles[i].end()-2) > *(layer_height_profiles[tallest_object_idx].end()-2)) @@ -1399,7 +1403,7 @@ std::pair Print::validate() const } while (ref_z == next_ref_z); } if (std::abs(this_height - ref_height) > EPSILON) - return { PrintValidationError::WrongSettings,L("The Wipe tower is only supported if all objects have the same variable layer height") }; + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe tower is only supported if all objects have the same variable layer height") }; i += 2; } } @@ -1448,7 +1452,7 @@ std::pair Print::validate() const // The object has some form of support and either support_material_extruder or support_material_interface_extruder // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles // are of the same diameter. - return { PrintValidationError::WrongSettings,L("Printing with multiple extruders of differing nozzle diameters. " + return { PrintBase::PrintValidationError::WrongSettings,L("Printing with multiple extruders of differing nozzle diameters. " "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), " "all nozzles have to be of the same diameter.") }; } @@ -1456,11 +1460,11 @@ std::pair Print::validate() const if (object->config().support_material_contact_distance_type == zdNone) { // Soluble interface if (! object->config().support_material_synchronize_layers) - return { PrintValidationError::WrongSettings,L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.") }; + return { PrintBase::PrintValidationError::WrongSettings,L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.") }; } else { // Non-soluble interface if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0) - return { PrintValidationError::WrongSettings,L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " + return { PrintBase::PrintValidationError::WrongSettings,L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " "(both support_material_extruder and support_material_interface_extruder need to be set to 0).") }; } } @@ -1482,23 +1486,23 @@ std::pair Print::validate() const first_layer_min_nozzle_diameter = min_nozzle_diameter; } if (first_layer_height > first_layer_min_nozzle_diameter) - return { PrintValidationError::WrongSettings,L("First layer height can't be greater than nozzle diameter") }; + return { PrintBase::PrintValidationError::WrongSettings,L("First layer height can't be greater than nozzle diameter") }; // validate layer_height double layer_height = object->config().layer_height.value; if (layer_height > min_nozzle_diameter) - return { PrintValidationError::WrongSettings,L("Layer height can't be greater than nozzle diameter") }; + return { PrintBase::PrintValidationError::WrongSettings,L("Layer height can't be greater than nozzle diameter") }; // Validate extrusion widths. std::string err_msg; if (! validate_extrusion_width(object->config(), "extrusion_width", layer_height, err_msg)) - return { PrintValidationError::WrongSettings,err_msg }; + return { PrintBase::PrintValidationError::WrongSettings,err_msg }; if ((object->config().support_material || object->config().raft_layers > 0) && ! validate_extrusion_width(object->config(), "support_material_extrusion_width", layer_height, err_msg)) - return { PrintValidationError::WrongSettings,err_msg }; + return { PrintBase::PrintValidationError::WrongSettings,err_msg }; for (const char *opt_key : { "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width" }) - for (size_t i = 0; i < object->region_volumes.size(); ++ i) - if (! object->region_volumes[i].empty() && ! validate_extrusion_width(this->get_region(i)->config(), opt_key, layer_height, err_msg)) - return { PrintValidationError::WrongSettings, err_msg }; + for (size_t i = 0; i < object->region_volumes.size(); ++ i) + if (! object->region_volumes[i].empty() && ! validate_extrusion_width(this->get_region(i)->config(), opt_key, layer_height, err_msg)) + return { PrintBase::PrintValidationError::WrongSettings, err_msg }; } } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d346dff02..5bfafe870 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1,4 +1,5 @@ #include "PrintConfig.hpp" +#include "Flow.hpp" #include "I18N.hpp" #include @@ -4427,43 +4428,53 @@ double PrintConfig::min_object_distance() const return PrintConfig::min_object_distance(static_cast(this)); } -double PrintConfig::min_object_distance(const ConfigBase *config) +double PrintConfig::min_object_distance(const ConfigBase *config, double ref_height) { double duplicate_distance = config->option("duplicate_distance")->getFloat(); - double base_dist = duplicate_distance; + double base_dist = duplicate_distance / 2; + //std::cout << "START min_object_distance =>" << base_dist << "\n"; if (config->option("complete_objects")->getBool()) { - std::vector vals = dynamic_cast(config->option("nozzle_diameter"))->values; - double max_nozzle_diam = 0; - for (double val : vals) max_nozzle_diam = std::fmax(max_nozzle_diam, val); + double brim_dist = 0; + double skirt_dist = 0; + try { + std::vector vals = dynamic_cast(config->option("nozzle_diameter"))->values; + double max_nozzle_diam = 0; + for (double val : vals) max_nozzle_diam = std::fmax(max_nozzle_diam, val); - // min object distance is max(duplicate_distance, clearance_radius) - //add 1 as safety offset. - double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat() + 1; - if (extruder_clearance_radius > base_dist) { - base_dist = extruder_clearance_radius; + // min object distance is max(duplicate_distance, clearance_radius) + //add 1 as safety offset. + double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat(); + if (extruder_clearance_radius > base_dist) { + base_dist = extruder_clearance_radius / 2; + } + + //std::cout << " min_object_distance add extruder_clearance_radius ("<< extruder_clearance_radius <<") =>" << base_dist << "\n"; + //add brim width + const double first_layer_height = config->get_abs_value("first_layer_height"); + if (ref_height <= first_layer_height) { + //FIXME: does not take into account object-defined brim !!! you can crash yoursefl with it + if (config->option("brim_width")->getFloat() > 0) { + brim_dist += config->option("brim_width")->getFloat(); + //std::cout << " Set brim=" << config->option("brim_width")->getFloat() << " => " << brim_dist << "\n"; + } + } + //add the skirt + if (config->option("skirts")->getInt() > 0 && config->option("skirt_height")->getInt() > 0 && !config->option("complete_objects_one_skirt")->getBool()) { + double skirt_height = ((double)config->option("skirt_height")->getInt() - 1) * config->get_abs_value("layer_height") + first_layer_height; + if (ref_height <= skirt_height) { + skirt_dist = config->option("skirt_distance")->getFloat(); + const double first_layer_width = config->get_abs_value("first_layer_extrusion_width"); + Flow flow(first_layer_width, first_layer_height, max_nozzle_diam); + skirt_dist += first_layer_width + (flow.spacing() * ((double)config->option("skirts")->getInt() - 1)); + //std::cout << " Set skirt_dist=" << config->option("skirt_distance")->getFloat() << " => " << skirt_dist << "\n"; + } + } } - //std::cout << "min_object_distance! extruder_clearance_radius=" << extruder_clearance_radius << "\n"; - //add brim width - //FIXME: does not take into account object-defined brim !!! you can crash yoursefl with it - if (config->option("brim_width")->getFloat() > 0) { - base_dist += config->option("brim_width")->getFloat(); + catch (const std::exception & ex) { + boost::nowide::cerr << ex.what() << std::endl; } - //std::cout << "min_object_distance! adding brim=" << config->option("brim_width")->getFloat()<< " => "<< base_dist << "\n"; - //add the skirt - if (config->option("skirts")->getInt() > 0 && !config->option("complete_objects_one_skirt")->getBool()) { - //add skirt dist - double dist_skirt = config->option("skirt_distance")->getFloat(); - dist_skirt += max_nozzle_diam * config->option("skirts")->getInt() * 1.5; - //std::cout << "min_object_distance! adding dist_skirt=" << dist_skirt << " ? " << (dist_skirt > config->option("brim_width")->getFloat()) - // << " ?x2 " << (dist_skirt * 2 > config->option("brim_width")->getFloat() && config->option("skirt_height")->getInt() > 3); - //add skirt width if needed - if (dist_skirt > config->option("brim_width")->getFloat()) - base_dist += (dist_skirt - config->option("brim_width")->getFloat()); - //consider skrit as part of the object if it's tall enough to be considered as a ooze shield. - else if (dist_skirt * 2 > config->option("brim_width")->getFloat() && config->option("skirt_height")->getInt() > 3) - base_dist += (dist_skirt * 2 - config->option("brim_width")->getFloat()); - } - //std::cout << " => " << base_dist << "\n"; + //std::cout << "END min_object_distance =>" << (base_dist + std::max(skirt_dist, brim_dist)) << "\n"; + return base_dist + std::max(skirt_dist, brim_dist); } return base_dist; } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 25ef4c60f..d660de996 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1016,7 +1016,7 @@ class PrintConfig : public MachineEnvelopeConfig, public GCodeConfig PrintConfig() : MachineEnvelopeConfig(0), GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); } public: double min_object_distance() const; - static double min_object_distance(const ConfigBase *config); + static double min_object_distance(const ConfigBase *config, double height = 0); ConfigOptionBool allow_empty_layers; ConfigOptionBool avoid_crossing_perimeters; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8b0dcb700..e2cfb0191 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1522,7 +1522,7 @@ struct Plater::priv apply_wipe_tower(); } - ArrangePolygon get_arrange_polygon() const + ArrangePolygon get_arrange_polygon(const Print &print) const { Polygon p({ {coord_t(0), coord_t(0)}, @@ -1627,7 +1627,7 @@ struct Plater::priv // Set up arrange polygon for a ModelInstance and Wipe tower template ArrangePolygon get_arrange_poly(T *obj) const { - ArrangePolygon ap = obj->get_arrange_polygon(); + ArrangePolygon ap = obj->get_arrange_polygon(this->plater().fff_print); ap.priority = 0; ap.bed_idx = ap.translation.x() / bed_stride(); ap.setter = [obj, this](const ArrangePolygon &p) { @@ -2885,7 +2885,7 @@ void Plater::priv::find_new_position(const ModelInstancePtrs &instances, for (const ModelObject *mo : model.objects) for (const ModelInstance *inst : mo->instances) { auto it = std::find(instances.begin(), instances.end(), inst); - auto arrpoly = inst->get_arrange_polygon(); + auto arrpoly = inst->get_arrange_polygon(this->fff_print); if (it == instances.end()) fixed.emplace_back(std::move(arrpoly)); @@ -2894,7 +2894,7 @@ void Plater::priv::find_new_position(const ModelInstancePtrs &instances, } if (updated_wipe_tower()) - fixed.emplace_back(wipetower.get_arrange_polygon()); + fixed.emplace_back(wipetower.get_arrange_polygon(this->fff_print)); arrangement::arrange(movable, fixed, min_d, get_bed_shape_hint()); diff --git a/tests/superslicerlibslic3r/CMakeLists.txt b/tests/superslicerlibslic3r/CMakeLists.txt index 39e26228b..e21252161 100644 --- a/tests/superslicerlibslic3r/CMakeLists.txt +++ b/tests/superslicerlibslic3r/CMakeLists.txt @@ -2,7 +2,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp - # test_complete_objects.cpp + test_complete_objects.cpp # test_fill.cpp # test_flow.cpp # test_gcodewriter.cpp diff --git a/tests/superslicerlibslic3r/test_complete_objects.cpp b/tests/superslicerlibslic3r/test_complete_objects.cpp index 6f83c2d95..3d9419975 100644 --- a/tests/superslicerlibslic3r/test_complete_objects.cpp +++ b/tests/superslicerlibslic3r/test_complete_objects.cpp @@ -1,6 +1,7 @@ //#define CATCH_CONFIG_DISABLE -#include +//#include +#include #include #include "test_data.hpp" @@ -11,5 +12,153 @@ using namespace Slic3r::Test; using namespace Slic3r; using namespace std::literals; -SCENARIO("Complete objects separatly") { + +std::unique_ptr init_print_with_dist(DynamicPrintConfig &config, float distance) { + TestMesh m = TestMesh::cube_20x20x20; + Model model{}; + + std::unique_ptr print(new Print{}); + ModelObject* object{ model.add_object() }; + object->name += std::string(mesh_names.at(m)) + ".stl"s; + object->add_volume(mesh(m)); + + ModelInstance* inst1{ object->add_instance() }; + inst1->set_offset(Vec3d(-distance/2, 0, 0)); + inst1->set_rotation(Vec3d(0, 0, 0)); + inst1->set_scaling_factor(Vec3d(1, 1, 1)); + + ModelInstance* inst2{ object->add_instance() }; + inst2->set_offset(Vec3d(distance/2, 0, 0)); + inst2->set_rotation(Vec3d(0, 0, 0)); + inst2->set_scaling_factor(Vec3d(1, 1, 1)); + for (auto* mo : model.objects) { + print->auto_assign_extruders(mo); + } + + if (distance <= 0) { + print->apply(model, config); + model.arrange_objects(*print);// print->config().min_object_distance(&print->config(), 999999)); + model.center_instances_around_point(Slic3r::Vec2d(100, 100)); + } + + std::cout << "inst1 pos = " << inst1->get_offset().x() << ":" << inst1->get_offset().y() << "\n"; + std::cout << "inst2 pos = " << inst2->get_offset().x() << ":" << inst2->get_offset().y() << "\n"; + + print->apply(model, config); + return print; +} + +SCENARIO("Complete objects separatly") { + GIVEN("20mm cubes and extruder_clearance_radius to 10") { + DynamicPrintConfig& config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_key_value("fill_density", new ConfigOptionPercent(0)); + config.set_deserialize("nozzle_diameter", "0.4"); + config.set_deserialize("layer_height", "0.3"); + config.set_deserialize("extruder_clearance_height", "50"); + config.set_deserialize("extruder_clearance_radius", "10"); + config.set_deserialize("skirts", "0"); + config.set_deserialize("skirt_height", "0"); + config.set_deserialize("brim_width", "0"); + + std::pair result; + + WHEN("2 mm appart") { + + //model.arrange_objects(print.config().min_object_distance()); + //model.center_instances_around_point(Slic3r::Vec2d(100, 100)); + THEN("no complete objects") { + result = init_print_with_dist(config, 22)->validate(); + REQUIRE(result.second == ""); + } + + //now with complete_objects + THEN("complete objects") { + config.set_key_value("complete_objects", new ConfigOptionBool(true)); + result = init_print_with_dist(config, 22)->validate(); + REQUIRE(result.first == PrintBase::PrintValidationError::WrongPosition); + } + } + WHEN("at the limit (~30 mm)") { + config.set_key_value("complete_objects", new ConfigOptionBool(true)); + THEN("(too near)") { + result = init_print_with_dist(config, 29.9)->validate(); + REQUIRE(result.first == PrintBase::PrintValidationError::WrongPosition); + } + THEN("(ok far)") { + result = init_print_with_dist(config, 30.1)->validate(); + REQUIRE(result.second == ""); + REQUIRE(result.first == PrintBase::PrintValidationError::None); + } + } + WHEN("with a 10 mm brim, so the dist should be 40mm ") { + config.set_key_value("complete_objects", new ConfigOptionBool(true)); + config.set_deserialize("brim_width", "10"); + THEN("(too near)") { + result = init_print_with_dist(config, 39.9)->validate(); + REQUIRE(result.first == PrintBase::PrintValidationError::WrongPosition); + } + THEN("(ok far)") { + result = init_print_with_dist(config, 40.1)->validate(); + REQUIRE(result.second == ""); + REQUIRE(result.first == PrintBase::PrintValidationError::None); + } + } + WHEN("with a 10 mm dist short skirt, so the dist should be 40mm +extrusionwidth") { + config.set_key_value("complete_objects", new ConfigOptionBool(true)); + config.set_deserialize("skirts", "1"); + config.set_deserialize("skirt_height", "1"); + config.set_deserialize("skirt_distance", "10"); + config.set_deserialize("complete_objects_one_skirt", "0"); + + THEN("(too near)") { + result = init_print_with_dist(config, 40)->validate(); + REQUIRE(result.first == PrintBase::PrintValidationError::WrongPosition); + } + THEN("(ok far)") { + result = init_print_with_dist(config, 40.8)->validate(); + REQUIRE(result.second == ""); + REQUIRE(result.first == PrintBase::PrintValidationError::None); + } + } + } +} +SCENARIO("Arrange is good enough") { + GIVEN("20mm cubes and extruder_clearance_radius to 10") { + DynamicPrintConfig& config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_key_value("fill_density", new ConfigOptionPercent(0)); + config.set_deserialize("nozzle_diameter", "0.4"); + config.set_deserialize("layer_height", "0.3"); + config.set_deserialize("extruder_clearance_height", "50"); + config.set_deserialize("extruder_clearance_radius", "10"); + config.set_deserialize("skirts", "0"); + config.set_deserialize("skirt_height", "0"); + config.set_deserialize("brim_width", "0"); + + std::pair result; + + WHEN("no complete objects") { + result = init_print_with_dist(config,-1)->validate(); + REQUIRE(result.second == ""); + } + WHEN("complete objects") { + config.set_key_value("complete_objects", new ConfigOptionBool(true)); + result = init_print_with_dist(config, -1)->validate(); + REQUIRE(result.second == ""); + } + WHEN("complete objects whith brim") { + config.set_key_value("complete_objects", new ConfigOptionBool(true)); + config.set_deserialize("brim_width", "10"); + result = init_print_with_dist(config, -1)->validate(); + REQUIRE(result.second == ""); + } + WHEN("complete objects whith skirt") { + config.set_key_value("complete_objects", new ConfigOptionBool(true)); + config.set_deserialize("skirts", "1"); + config.set_deserialize("skirt_height", "1"); + config.set_deserialize("skirt_distance", "10"); + config.set_deserialize("complete_objects_one_skirt", "0"); + result = init_print_with_dist(config, -1)->validate(); + REQUIRE(result.second == ""); + } + } } diff --git a/tests/superslicerlibslic3r/test_data.cpp b/tests/superslicerlibslic3r/test_data.cpp index ede8195c2..ac908c322 100644 --- a/tests/superslicerlibslic3r/test_data.cpp +++ b/tests/superslicerlibslic3r/test_data.cpp @@ -286,7 +286,7 @@ void init_print(Print& print, std::initializer_list meshes, Slic3r::Mo inst->set_scaling_factor(Vec3d(1, 1, 1)); } - model.arrange_objects(print.config().min_object_distance()); + model.arrange_objects(print); model.center_instances_around_point(Slic3r::Vec2d(100,100)); for (auto* mo : model.objects) { print.auto_assign_extruders(mo); @@ -318,7 +318,7 @@ void init_print(Print& print, std::initializer_list meshes, Slic3r inst->set_scaling_factor(Vec3d(1, 1, 1)); } - model.arrange_objects(print.config().min_object_distance()); + model.arrange_objects(print); model.center_instances_around_point(Slic3r::Vec2d(100,100)); print.apply(model, config); for (ModelObject* mo : model.objects) { diff --git a/tests/superslicerlibslic3r/test_print.cpp b/tests/superslicerlibslic3r/test_print.cpp index 268b3c7d1..6a9d85b33 100644 --- a/tests/superslicerlibslic3r/test_print.cpp +++ b/tests/superslicerlibslic3r/test_print.cpp @@ -1,7 +1,9 @@ -//#define CATCH_CONFIG_DISABLE +#define CATCH_CONFIG_DISABLE + +//#include +#include -#include #include "test_data.hpp" #include #include