update to arrange, add some arrange tests. Not better than before, but it's moving in the right direction, i guess?

This commit is contained in:
supermerill 2020-06-01 00:41:40 +02:00
parent 3e517ac50b
commit 43f9d15a55
11 changed files with 270 additions and 98 deletions

View File

@ -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<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&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<ConfigOptionPoints>("bed_shape")->values).center() :
m_config.option<ConfigOptionPoint>("center")->value);

View File

@ -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<double>(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<double>(SIMPLIFY_TOLERANCE_MM));
if (!pp.empty()) p = pp.front();
}

View File

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

View File

@ -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<PrintBase::PrintValidationError, std::string> 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<PrintBase::PrintValidationError, std::string> 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<std::pair<t_layer_height_range, int>> &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<PrintBase::PrintValidationError, std::string> 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<PrintBase::PrintValidationError, std::string> 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<PrintBase::PrintValidationError, std::string> 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<PrintBase::PrintValidationError, std::string> 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<PrintBase::PrintValidationError, std::string> 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<PrintBase::PrintValidationError, std::string> 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 };
}
}

View File

@ -1,4 +1,5 @@
#include "PrintConfig.hpp"
#include "Flow.hpp"
#include "I18N.hpp"
#include <set>
@ -4427,43 +4428,53 @@ double PrintConfig::min_object_distance() const
return PrintConfig::min_object_distance(static_cast<const ConfigBase*>(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<double> vals = dynamic_cast<const ConfigOptionFloats*>(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<double> vals = dynamic_cast<const ConfigOptionFloats*>(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;
}

View File

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

View File

@ -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<class T> 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());

View File

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

View File

@ -1,6 +1,7 @@
//#define CATCH_CONFIG_DISABLE
#include <catch2/catch.hpp>
//#include <catch2/catch.hpp>
#include <catch_main.hpp>
#include <string>
#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<Print> init_print_with_dist(DynamicPrintConfig &config, float distance) {
TestMesh m = TestMesh::cube_20x20x20;
Model model{};
std::unique_ptr<Print> 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<PrintBase::PrintValidationError, std::string> 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<PrintBase::PrintValidationError, std::string> 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 == "");
}
}
}

View File

@ -286,7 +286,7 @@ void init_print(Print& print, std::initializer_list<TestMesh> 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<TriangleMesh> 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) {

View File

@ -1,7 +1,9 @@
//#define CATCH_CONFIG_DISABLE
#define CATCH_CONFIG_DISABLE
//#include <catch_main.hpp>
#include <catch2/catch.hpp>
#include <catch_main.hpp>
#include "test_data.hpp"
#include <libslic3r/libslic3r.h>
#include <libslic3r/SVG.hpp>