update to arrange: a little bit more sane (but need more work)

also calibration can now use arrange if needed
This commit is contained in:
supermerill 2020-11-22 01:56:52 +01:00
parent 0b94eee824
commit 29d393ec9c
15 changed files with 185 additions and 129 deletions

View File

@ -232,8 +232,6 @@ int CLI::run(int argc, char **argv)
// Loop through transform options. // Loop through transform options.
bool user_center_specified = false; bool user_center_specified = false;
Points bed = get_bed_shape(m_print_config); Points bed = get_bed_shape(m_print_config);
ArrangeParams arrange_cfg;
arrange_cfg.min_obj_distance = scaled(PrintConfig::min_object_distance(&m_print_config));
int dups = 1; int dups = 1;
for (auto const &opt_key : m_transforms) { for (auto const &opt_key : m_transforms) {
@ -467,13 +465,13 @@ int CLI::run(int argc, char **argv)
PrintBase *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print); PrintBase *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print);
if (! m_config.opt_bool("dont_arrange")) { if (! m_config.opt_bool("dont_arrange")) {
print->apply(model, m_print_config); // arrange_objects needs that the print has the config ArrangeParams arrange_cfg;
arrange_cfg.min_obj_distance = scaled(PrintConfig::min_object_distance(&m_print_config)) * 2;
if (dups > 1) { if (dups > 1) {
try { try {
// if all input objects have defined position(s) apply duplication to the whole model // if all input objects have defined position(s) apply duplication to the whole model
duplicate(print, model, size_t(dups), bed, arrange_cfg); duplicate(model, size_t(dups), bed, arrange_cfg);
} catch (std::exception & ex) { } catch (std::exception & ex) {
boost::nowide::cerr << "error: " << ex.what() << std::endl; boost::nowide::cerr << "error: " << ex.what() << std::endl;
return 1; return 1;
@ -481,9 +479,9 @@ int CLI::run(int argc, char **argv)
} }
if (user_center_specified) { if (user_center_specified) {
Vec2d c = m_config.option<ConfigOptionPoint>("center")->value; Vec2d c = m_config.option<ConfigOptionPoint>("center")->value;
arrange_objects(print, model, InfiniteBed{scaled(c)}, arrange_cfg); arrange_objects(model, InfiniteBed{scaled(c)}, arrange_cfg);
} else } else
arrange_objects(print, model, bed, arrange_cfg); arrange_objects(model, bed, arrange_cfg);
} }
if (printer_technology == ptFFF) { if (printer_technology == ptFFF) {
for (auto* mo : model.objects) for (auto* mo : model.objects)

View File

@ -1855,7 +1855,8 @@ void ModelInstance::transform_polygon(Polygon* polygon) const
polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin
} }
arrangement::ArrangePolygon ModelInstance::get_arrange_polygon(const PrintBase *print_base) const
arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
{ {
static const double SIMPLIFY_TOLERANCE_MM = 0.1; static const double SIMPLIFY_TOLERANCE_MM = 0.1;
@ -1873,15 +1874,6 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon(const PrintBase *
// https://github.com/prusa3d/PrusaSlicer/issues/2209 // https://github.com/prusa3d/PrusaSlicer/issues/2209
if (!p.points.empty()) { if (!p.points.empty()) {
Polygons pp{ p }; Polygons pp{ p };
if (const Print* print = dynamic_cast<const Print*>(print_base))
{
//grow
double dist = print->config().min_object_distance(&print->full_print_config());
pp = offset(pp, scale_(dist));
//simplify
if (!pp.empty())
pp = pp.front().simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
}else
pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM)); pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
if (!pp.empty()) p = pp.front(); if (!pp.empty()) p = pp.front();
} }
@ -1894,37 +1886,6 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon(const PrintBase *
return ret; return ret;
} }
//
//arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
//{
// static const double SIMPLIFY_TOLERANCE_MM = 0.1;
//
// Vec3d rotation = get_rotation();
// rotation.z() = 0.;
// Transform3d trafo_instance =
// Geometry::assemble_transform(Vec3d::Zero(), rotation,
// get_scaling_factor(), get_mirror());
//
// Polygon p = get_object()->convex_hull_2d(trafo_instance);
//
// assert(!p.points.empty());
//
// // this may happen for malformed models, see:
// // https://github.com/prusa3d/PrusaSlicer/issues/2209
// if (!p.points.empty()) {
// Polygons pp{ p };
// pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
// if (!pp.empty()) p = pp.front();
// }
//
// arrangement::ArrangePolygon ret;
// ret.poly.contour = std::move(p);
// ret.translation = Vec2crd{ scaled(get_offset(X)), scaled(get_offset(Y)) };
// ret.rotation = get_rotation(Z);
//
// return ret;
//}
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const
{ {
TriangleSelector selector(mv.mesh()); TriangleSelector selector(mv.mesh());

View File

@ -874,7 +874,7 @@ public:
bool is_printable() const { return object->printable && printable && (print_volume_state == ModelInstancePVS_Inside); } bool is_printable() const { return object->printable && printable && (print_volume_state == ModelInstancePVS_Inside); }
// Getting the input polygon for arrange // Getting the input polygon for arrange
arrangement::ArrangePolygon get_arrange_polygon(const PrintBase* print) const; arrangement::ArrangePolygon get_arrange_polygon() const;
// Apply the arrange result on the ModelInstance // Apply the arrange result on the ModelInstance
void apply_arrange_result(const Vec2d& offs, double rotation) void apply_arrange_result(const Vec2d& offs, double rotation)

View File

@ -5,7 +5,7 @@
namespace Slic3r { namespace Slic3r {
arrangement::ArrangePolygons get_arrange_polys(const PrintBase* print, const Model &model, ModelInstancePtrs &instances) arrangement::ArrangePolygons get_arrange_polys(const Model &model, ModelInstancePtrs &instances)
{ {
size_t count = 0; size_t count = 0;
for (auto obj : model.objects) count += obj->instances.size(); for (auto obj : model.objects) count += obj->instances.size();
@ -15,7 +15,7 @@ arrangement::ArrangePolygons get_arrange_polys(const PrintBase* print, const Mod
instances.clear(); instances.reserve(count); instances.clear(); instances.reserve(count);
for (ModelObject *mo : model.objects) for (ModelObject *mo : model.objects)
for (ModelInstance *minst : mo->instances) { for (ModelInstance *minst : mo->instances) {
input.emplace_back(minst->get_arrange_polygon(print)); input.emplace_back(minst->get_arrange_polygon());
instances.emplace_back(minst); instances.emplace_back(minst);
} }
@ -36,13 +36,13 @@ bool apply_arrange_polys(ArrangePolygons &input, ModelInstancePtrs &instances, V
return ret; return ret;
} }
Slic3r::arrangement::ArrangePolygon get_arrange_poly(const PrintBase* print, const Model &model) Slic3r::arrangement::ArrangePolygon get_arrange_poly(const Model &model)
{ {
ArrangePolygon ap; ArrangePolygon ap;
Points &apts = ap.poly.contour.points; Points &apts = ap.poly.contour.points;
for (const ModelObject *mo : model.objects) for (const ModelObject *mo : model.objects)
for (const ModelInstance *minst : mo->instances) { for (const ModelInstance *minst : mo->instances) {
ArrangePolygon obj_ap = minst->get_arrange_polygon(print); ArrangePolygon obj_ap = minst->get_arrange_polygon();
ap.poly.contour.rotate(obj_ap.rotation); ap.poly.contour.rotate(obj_ap.rotation);
ap.poly.contour.translate(obj_ap.translation.x(), obj_ap.translation.y()); ap.poly.contour.translate(obj_ap.translation.x(), obj_ap.translation.y());
const Points &pts = obj_ap.poly.contour.points; const Points &pts = obj_ap.poly.contour.points;

View File

@ -24,50 +24,47 @@ using VirtualBedFn = std::function<void(arrangement::ArrangePolygon&)>;
throw Slic3r::RuntimeError("Objects could not fit on the bed"); throw Slic3r::RuntimeError("Objects could not fit on the bed");
} }
ArrangePolygons get_arrange_polys(const PrintBase* print, const Model &model, ModelInstancePtrs &instances); ArrangePolygons get_arrange_polys(const Model &model, ModelInstancePtrs &instances);
ArrangePolygon get_arrange_poly(const PrintBase* print, const Model &model); ArrangePolygon get_arrange_poly(const Model &model);
bool apply_arrange_polys(ArrangePolygons &polys, ModelInstancePtrs &instances, VirtualBedFn); bool apply_arrange_polys(ArrangePolygons &polys, ModelInstancePtrs &instances, VirtualBedFn);
void duplicate(Model &model, ArrangePolygons &copies, VirtualBedFn); void duplicate(Model &model, ArrangePolygons &copies, VirtualBedFn);
void duplicate_objects(Model &model, size_t copies_num); void duplicate_objects(Model &model, size_t copies_num);
template<class TBed> template<class TBed>
bool arrange_objects(PrintBase* print, bool arrange_objects(Model & model,
Model & model,
const TBed & bed, const TBed & bed,
const ArrangeParams &params, const ArrangeParams &params,
VirtualBedFn vfn = throw_if_out_of_bed) VirtualBedFn vfn = throw_if_out_of_bed)
{ {
ModelInstancePtrs instances; ModelInstancePtrs instances;
ArrangePolygons input = get_arrange_polys(print, model, instances); ArrangePolygons input = get_arrange_polys(model, instances);
arrangement::arrange(input, bed, params); arrangement::arrange(input, bed, params);
return apply_arrange_polys(input, instances, vfn); return apply_arrange_polys(input, instances, vfn);
} }
template<class TBed> template<class TBed>
void duplicate(PrintBase* print, void duplicate(Model & model,
Model & model,
size_t copies_num, size_t copies_num,
const TBed & bed, const TBed & bed,
const ArrangeParams &params, const ArrangeParams &params,
VirtualBedFn vfn = throw_if_out_of_bed) VirtualBedFn vfn = throw_if_out_of_bed)
{ {
ArrangePolygons copies(copies_num, get_arrange_poly(print, model)); ArrangePolygons copies(copies_num, get_arrange_poly(model));
arrangement::arrange(copies, bed, params); arrangement::arrange(copies, bed, params);
duplicate(model, copies, vfn); duplicate(model, copies, vfn);
} }
template<class TBed> template<class TBed>
void duplicate_objects(PrintBase* print, void duplicate_objects(Model & model,
Model & model,
size_t copies_num, size_t copies_num,
const TBed & bed, const TBed & bed,
const ArrangeParams &params, const ArrangeParams &params,
VirtualBedFn vfn = throw_if_out_of_bed) VirtualBedFn vfn = throw_if_out_of_bed)
{ {
duplicate_objects(model, copies_num); duplicate_objects(model, copies_num);
arrange_objects(print, model, bed, params, vfn); arrange_objects(model, bed, params, vfn);
} }
} }

View File

@ -1259,35 +1259,49 @@ bool Print::has_skirt() const
static inline bool sequential_print_horizontal_clearance_valid(const Print &print) static inline bool sequential_print_horizontal_clearance_valid(const Print &print)
{ {
Polygons convex_hulls_other; 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()) { for (const PrintObject *print_object : print.objects()) {
double dist_grow = PrintConfig::min_object_distance(&print_object->config());
assert(! print_object->model_object()->instances.empty()); assert(! print_object->model_object()->instances.empty());
assert(! print_object->instances().empty()); assert(! print_object->instances().empty());
//ObjectID model_object_id = print_object->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); 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. // Get convex hull of all printable volumes assigned to this print object.
// ModelInstance *model_instance0 = print_object->model_object()->instances.front(); ModelInstance *model_instance0 = print_object->model_object()->instances.front();
// if (it_convex_hull == map_model_object_to_convex_hull.end()) { if (it_convex_hull == map_model_object_to_convex_hull.end()) {
// // Calculate the convex hull of a printable object. // Calculate the convex hull of a printable object.
// // Grow convex hull with the clearance margin. // Grow convex hull with the clearance margin.
// // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2) // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
// // which causes that the warning will be showed after arrangement with the // 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. // 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, 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( 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())), 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 // 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. // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
// float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), float(scale_(0.5 * dist_grow - EPSILON)),
// jtRound, float(scale_(0.1))).front()); jtRound, float(scale_(0.1))).front());
// } }
// // Make a copy, so it may be rotated for instances. // Make a copy, so it may be rotated for instances.
// //FIXME seems like the rotation isn't taken into account //FIXME seems like the rotation isn't taken into account
// Polygon convex_hull0 = it_convex_hull->second; Polygon convex_hull0 = it_convex_hull->second;
// //this can create bugs in macos, for reasons. //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()); 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) if (std::abs(z_diff) > EPSILON)
// convex_hull0.rotate(z_diff); 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;
// 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())
return false;
polygons_append(convex_hulls_other, convex_hull);
}
/*
'old' superslicer sequential_print_horizontal_clearance_valid, that is better at skirts, but need some works, as the arrange has changed.
// Now we check that no instance of convex_hull intersects any of the previously checked object instances. // Now we check that no instance of convex_hull intersects any of the previously checked object instances.
for (const PrintInstance &instance : print_object->instances()) { for (const PrintInstance &instance : print_object->instances()) {
Polygons convex_hull = print_object->model_object()->convex_hull_2d( Polygons convex_hull = print_object->model_object()->convex_hull_2d(
@ -1295,8 +1309,8 @@ static inline bool sequential_print_horizontal_clearance_valid(const Print &prin
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 // 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. // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
/*float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), //float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)),
jtRound, float(scale_(0.1)));*/ //jtRound, float(scale_(0.1)));
if (convex_hull.empty()) if (convex_hull.empty())
continue; continue;
// instance.shift is a position of a centered object, while model object may not be centered. // instance.shift is a position of a centered object, while model object may not be centered.
@ -1305,13 +1319,14 @@ static inline bool sequential_print_horizontal_clearance_valid(const Print &prin
poly.translate(instance.shift - print_object->center_offset()); poly.translate(instance.shift - print_object->center_offset());
if (! intersection( if (! intersection(
convex_hulls_other, convex_hulls_other,
offset(convex_hull[0], double(scale_(print.config().min_object_distance(&instance.print_object->config(),0.)) - SCALED_EPSILON), jtRound, scale_(0.1))).empty()) offset(convex_hull[0], double(scale_(PrintConfig::min_object_distance(&instance.print_object->config(),0.)) - SCALED_EPSILON), jtRound, scale_(0.1))).empty())
return false; return false;
double extra_grow = print.config().min_object_distance(&instance.print_object->config(), 1.); double extra_grow = PrintConfig::min_object_distance(&instance.print_object->config(), 1.);
if (extra_grow > 0) if (extra_grow > 0)
convex_hull = offset(convex_hull, scale_(extra_grow)); convex_hull = offset(convex_hull, scale_(extra_grow));
polygons_append(convex_hulls_other, convex_hull); polygons_append(convex_hulls_other, convex_hull);
} }
*/
} }
return true; return true;
} }

View File

@ -5205,8 +5205,9 @@ double PrintConfig::min_object_distance(const ConfigBase *config, double ref_hei
//test if called from usaslicer::l240 where it's called on an empty config... //test if called from usaslicer::l240 where it's called on an empty config...
if (dd_opt == nullptr) return 0; if (dd_opt == nullptr) return 0;
double duplicate_distance = dd_opt->value; // /2 becasue we only count the grawing for the current object
double base_dist = duplicate_distance / 2; const double duplicate_distance = dd_opt->value / 2;
double base_dist = duplicate_distance;
//std::cout << "START min_object_distance =>" << base_dist << "\n"; //std::cout << "START min_object_distance =>" << base_dist << "\n";
const ConfigOptionBool* co_opt = config->option<ConfigOptionBool>("complete_objects"); const ConfigOptionBool* co_opt = config->option<ConfigOptionBool>("complete_objects");
if (co_opt && co_opt->value) { if (co_opt && co_opt->value) {
@ -5218,24 +5219,35 @@ double PrintConfig::min_object_distance(const ConfigBase *config, double ref_hei
for (double val : vals) max_nozzle_diam = std::fmax(max_nozzle_diam, val); for (double val : vals) max_nozzle_diam = std::fmax(max_nozzle_diam, val);
// min object distance is max(duplicate_distance, clearance_radius) // min object distance is max(duplicate_distance, clearance_radius)
// /2 becasue we only count the grawing for the current object
//add 1 as safety offset. //add 1 as safety offset.
double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat(); double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat() / 2 + 1;
if (extruder_clearance_radius > base_dist) { if (extruder_clearance_radius > base_dist) {
base_dist = extruder_clearance_radius / 2; base_dist = extruder_clearance_radius;
} }
//std::cout << " min_object_distance add extruder_clearance_radius ("<< extruder_clearance_radius <<") =>" << base_dist << "\n"; //std::cout << " min_object_distance add extruder_clearance_radius ("<< extruder_clearance_radius <<") =>" << base_dist << "\n";
//FIXME: now brim can be per-object, so you ahve to get a different min_object_distance per object
//add brim width //add brim width
const double first_layer_height = config->get_abs_value("first_layer_height"); const double first_layer_height = config->get_abs_value("first_layer_height");
if (ref_height <= first_layer_height) { if (ref_height <= first_layer_height && ref_height != 0) {
//FIXME: does not take into account object-defined brim !!! you can crash yoursefl with it //FIXME: does not take into account object-defined brim !!! you can crash yoursefl with it
if (config->option("brim_width")->getFloat() > 0) { if (config->option("brim_width")->getFloat() > 0) {
brim_dist += config->option("brim_width")->getFloat(); brim_dist += config->option("brim_width")->getFloat();
//std::cout << " Set brim=" << config->option("brim_width")->getFloat() << " => " << brim_dist << "\n"; //std::cout << " Set brim=" << config->option("brim_width")->getFloat() << " => " << brim_dist << "\n";
} }
} else if (config->option("brim_width")->getFloat() + 1 > base_dist) {
base_dist = config->option("brim_width")->getFloat();
} }
//add the skirt //add the skirt
if (config->option("skirts")->getInt() > 0 && config->option("skirt_height")->getInt() > 0 && !config->option("complete_objects_one_skirt")->getBool()) { if (config->option("skirts")->getInt() > 0 && config->option("skirt_height")->getInt() == 1 && ref_height == 0) {
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));
base_dist = std::max(base_dist, skirt_dist + 1);
skirt_dist = 0;
}else 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; double skirt_height = ((double)config->option("skirt_height")->getInt() - 1) * config->get_abs_value("layer_height") + first_layer_height;
if (ref_height <= skirt_height) { if (ref_height <= skirt_height) {
skirt_dist = config->option("skirt_distance")->getFloat(); skirt_dist = config->option("skirt_distance")->getFloat();

View File

@ -5,6 +5,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "Jobs/ProgressIndicator.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "MainFrame.hpp" #include "MainFrame.hpp"
@ -48,6 +49,18 @@ protected:
}; };
class ProgressIndicatorStub : ProgressIndicator {
public:
virtual ~ProgressIndicatorStub() override = default;
virtual void set_range(int range) override {}
virtual void set_cancel_callback(CancelFn = CancelFn()) override {}
virtual void set_progress(int pr) override {}
virtual void set_status_text(const char*) override {}
virtual int get_range() const override { return 0; }
};
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp" #include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "Plater.hpp" #include "Plater.hpp"
@ -98,6 +99,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
} }
/// --- translate ---; /// --- translate ---;
bool has_to_arrange = false;
const float brim_width = std::max(print_config->option<ConfigOptionFloat>("brim_width")->value, nozzle_diameter * 5.); const float brim_width = std::max(print_config->option<ConfigOptionFloat>("brim_width")->value, nozzle_diameter * 5.);
const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius"); const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius");
const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape"); const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape");
@ -108,7 +110,9 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
for (int i = 1; i < nb_items; i++) { for (int i = 1; i < nb_items; i++) {
model.objects[objs_idx[i]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2 + (i % 2 == 0 ? -1 : 1) * offsety * ((i + 1) / 2), 0 }); model.objects[objs_idx[i]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2 + (i % 2 == 0 ? -1 : 1) * offsety * ((i + 1) / 2), 0 });
} }
//TODO: if not enough space, forget about complete_objects // if not enough space, forget about complete_objects
if (bed_size.y() < offsety * (nb_items + 1))
has_to_arrange = true;
/// --- main config, please modify object config when possible --- /// --- main config, please modify object config when possible ---
@ -141,6 +145,17 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
ObjectList* obj = this->gui_app->obj_list(); ObjectList* obj = this->gui_app->obj_list();
obj->update_after_undo_redo(); obj->update_after_undo_redo();
// arrange if needed, after new settings, to take them into account
if (has_to_arrange) {
//update print config (done at reslice but we need it here)
if (plat->printer_technology() == ptFFF)
plat->fff_print().apply(plat->model(), *plat->config());
std::shared_ptr<ProgressIndicatorStub> fake_statusbar = std::make_shared<ProgressIndicatorStub>();
ArrangeJob arranger(std::dynamic_pointer_cast<ProgressIndicator>(fake_statusbar), plat);
arranger.prepare_all();
arranger.process();
arranger.finalize();
}
plat->reslice(); plat->reslice();
plat->select_view_3D("Preview"); plat->select_view_3D("Preview");

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp" #include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "Plater.hpp" #include "Plater.hpp"
@ -101,6 +102,7 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
} }
/// --- translate ---; /// --- translate ---;
bool has_to_arrange = false;
const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius"); const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius");
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape"); const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
const double brim_width = nozzle_diameter * 3.5; const double brim_width = nozzle_diameter * 3.5;
@ -113,8 +115,10 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 }); model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 });
model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 }); model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 });
model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 }); model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 });
//TODO: if not enough space, forget about complete_objects
// if not enough space, forget about complete_objects
if (bed_size.y() < offsety * 2 + 25 * xyScale + brim_width || bed_size.x() < offsetx + 25 * xyScale + brim_width)
has_to_arrange = true;
/// --- main config, please modify object config when possible --- /// --- main config, please modify object config when possible ---
DynamicPrintConfig new_print_config = *print_config; //make a copy DynamicPrintConfig new_print_config = *print_config; //make a copy
@ -157,6 +161,17 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
ObjectList* obj = this->gui_app->obj_list(); ObjectList* obj = this->gui_app->obj_list();
obj->update_after_undo_redo(); obj->update_after_undo_redo();
// arrange if needed, after new settings, to take them into account
if (has_to_arrange) {
//update print config (done at reslice but we need it here)
if (plat->printer_technology() == ptFFF)
plat->fff_print().apply(plat->model(), *plat->config());
std::shared_ptr<ProgressIndicatorStub> fake_statusbar = std::make_shared<ProgressIndicatorStub>();
ArrangeJob arranger(std::dynamic_pointer_cast<ProgressIndicator>(fake_statusbar), plat);
arranger.prepare_all();
arranger.process();
arranger.finalize();
}
plat->reslice(); plat->reslice();
plat->select_view_3D("Preview"); plat->select_view_3D("Preview");

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp" #include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "Plater.hpp" #include "Plater.hpp"
@ -85,6 +86,7 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) {
} }
/// --- translate ---; /// --- translate ---;
bool has_to_arrange = false;
const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius"); const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius");
const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape"); const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape");
const float brim_width = print_config->option<ConfigOptionFloat>("brim_width")->getFloat(); const float brim_width = print_config->option<ConfigOptionFloat>("brim_width")->getFloat();
@ -98,8 +100,10 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) {
model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 }); model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 });
model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 , 0 }); model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 , 0 });
model.objects[objs_idx[5]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 }); model.objects[objs_idx[5]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 });
//TODO: if not enough space, forget about complete_objects
// if not enough space, forget about complete_objects
if (bed_size.y() < offsety * 2 + 30 * xyz_scale + brim_width || bed_size.x() < offsetx + 35 * xyz_scale + brim_width)
has_to_arrange = true;
/// --- main config, please modify object config when possible --- /// --- main config, please modify object config when possible ---
DynamicPrintConfig new_print_config = *print_config; //make a copy DynamicPrintConfig new_print_config = *print_config; //make a copy
@ -136,6 +140,17 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) {
ObjectList* obj = this->gui_app->obj_list(); ObjectList* obj = this->gui_app->obj_list();
obj->update_after_undo_redo(); obj->update_after_undo_redo();
// arrange if needed, after new settings, to take them into account
if (has_to_arrange) {
//update print config (done at reslice but we need it here)
if (plat->printer_technology() == ptFFF)
plat->fff_print().apply(plat->model(), *plat->config());
std::shared_ptr<ProgressIndicatorStub> fake_statusbar = std::make_shared<ProgressIndicatorStub>();
ArrangeJob arranger(std::dynamic_pointer_cast<ProgressIndicator>(fake_statusbar), plat);
arranger.prepare_all();
arranger.process();
arranger.finalize();
}
plat->reslice(); plat->reslice();
plat->select_view_3D("Preview"); plat->select_view_3D("Preview");

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp" #include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "Plater.hpp" #include "Plater.hpp"
@ -190,20 +191,18 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
} }
/// --- translate ---; /// --- translate ---;
bool has_to_arrange = false;
const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius"); const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius");
const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape"); const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape");
const float brim_width = std::max(print_config->option<ConfigOptionFloat>("brim_width")->value, nozzle_diameter * 5.); const float brim_width = std::max(print_config->option<ConfigOptionFloat>("brim_width")->value, nozzle_diameter * 5.);
Vec2d bed_size = BoundingBoxf(bed_shape->values).size(); Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min; Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offset = 4 + 26 * 1 + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0); float offset = 4 + 26 * scale * 1 + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0);
if (nb_items == 1) { if (nb_items == 1) {
model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 }); model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 });
} else { } else {
for (size_t i = 0; i < nb_items; i++) { has_to_arrange = true;
model.objects[objs_idx[i]]->translate({ bed_min.x() + bed_size.x() / 2 + (i%2 ==0 ? -offset/2: offset/2), bed_min.y() + bed_size.y() / 2 + ( (i/2) % 2 == 0 ? -1 : 1) * offset * (((i / 2) + 1) / 2), 0 });
} }
}
/// --- custom config --- /// --- custom config ---
@ -252,16 +251,29 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true));
} }
this->gui_app->get_tab(Preset::TYPE_PRINT)->load_config(new_print_config); this->gui_app->get_tab(Preset::TYPE_PRINT)->load_config(new_print_config);
plat->on_config_change(new_print_config);
this->gui_app->get_tab(Preset::TYPE_PRINT)->update_dirty(); this->gui_app->get_tab(Preset::TYPE_PRINT)->update_dirty();
plat->on_config_change(new_print_config);
} }
//update plater //update plater
plat->changed_objects(objs_idx); plat->changed_objects(objs_idx);
//if (plat->printer_technology() == ptFFF)
//plat->fff_print().full_print_config().apply(plat->config());
//update everything, easier to code. //update everything, easier to code.
ObjectList* obj = this->gui_app->obj_list(); ObjectList* obj = this->gui_app->obj_list();
obj->update_after_undo_redo(); obj->update_after_undo_redo();
// arrange if needed, after new settings, to take them into account
if (has_to_arrange) {
//update print config (done at reslice but we need it here)
if (plat->printer_technology() == ptFFF)
plat->fff_print().apply(plat->model(), *plat->config());
std::shared_ptr<ProgressIndicatorStub> fake_statusbar = std::make_shared<ProgressIndicatorStub>();
ArrangeJob arranger(std::dynamic_pointer_cast<ProgressIndicator>(fake_statusbar), plat);
arranger.prepare_all();
arranger.process();
arranger.finalize();
}
plat->reslice(); plat->reslice();
plat->select_view_3D("Preview"); plat->select_view_3D("Preview");

View File

@ -28,7 +28,7 @@ public:
apply_wipe_tower(); apply_wipe_tower();
} }
ArrangePolygon get_arrange_polygon(const PrintBase* print_base) const ArrangePolygon get_arrange_polygon() const
{ {
Polygon ap({ Polygon ap({
{coord_t(0), coord_t(0)}, {coord_t(0), coord_t(0)},
@ -80,11 +80,11 @@ void ArrangeJob::prepare_all() {
for (ModelObject *obj: m_plater->model().objects) for (ModelObject *obj: m_plater->model().objects)
for (ModelInstance *mi : obj->instances) { for (ModelInstance *mi : obj->instances) {
ArrangePolygons & cont = mi->printable ? m_selected : m_unprintable; ArrangePolygons & cont = mi->printable ? m_selected : m_unprintable;
cont.emplace_back(get_arrange_poly(m_plater->current_print(), mi)); cont.emplace_back(get_arrange_poly(mi));
} }
if (auto wti = get_wipe_tower(*m_plater)) if (auto wti = get_wipe_tower(*m_plater))
m_selected.emplace_back(wti.get_arrange_polygon(m_plater->current_print())); m_selected.emplace_back(wti.get_arrange_polygon());
} }
void ArrangeJob::prepare_selected() { void ArrangeJob::prepare_selected() {
@ -112,7 +112,7 @@ void ArrangeJob::prepare_selected() {
inst_sel[size_t(inst_id)] = true; inst_sel[size_t(inst_id)] = true;
for (size_t i = 0; i < inst_sel.size(); ++i) { for (size_t i = 0; i < inst_sel.size(); ++i) {
ArrangePolygon &&ap = get_arrange_poly(m_plater->current_print(), mo->instances[i]); ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]);
ArrangePolygons &cont = mo->instances[i]->printable ? ArrangePolygons &cont = mo->instances[i]->printable ?
(inst_sel[i] ? m_selected : (inst_sel[i] ? m_selected :
@ -124,7 +124,7 @@ void ArrangeJob::prepare_selected() {
} }
if (auto wti = get_wipe_tower(*m_plater)) { if (auto wti = get_wipe_tower(*m_plater)) {
ArrangePolygon &&ap = get_arrange_poly(m_plater->current_print(), &wti); ArrangePolygon &&ap = get_arrange_poly(&wti);
m_plater->get_selection().is_wipe_tower() ? m_plater->get_selection().is_wipe_tower() ?
m_selected.emplace_back(std::move(ap)) : m_selected.emplace_back(std::move(ap)) :
@ -149,10 +149,10 @@ void ArrangeJob::process()
{ {
static const auto arrangestr = _(L("Arranging")); static const auto arrangestr = _(L("Arranging"));
double dist = PrintConfig::min_object_distance(m_plater->config()); double dist = PrintConfig::min_object_distance(&m_plater->current_print()->full_print_config());
arrangement::ArrangeParams params; arrangement::ArrangeParams params;
params.min_obj_distance = scaled(dist); params.min_obj_distance = scaled(dist) * 2;
auto count = unsigned(m_selected.size() + m_unprintable.size()); auto count = unsigned(m_selected.size() + m_unprintable.size());
Points bedpts = get_bed_shape(*m_plater->config()); Points bedpts = get_bed_shape(*m_plater->config());
@ -214,7 +214,7 @@ void ArrangeJob::finalize() {
arrangement::ArrangePolygon get_wipe_tower_arrangepoly(Plater &plater) arrangement::ArrangePolygon get_wipe_tower_arrangepoly(Plater &plater)
{ {
return WipeTower{plater.canvas3D()->get_wipe_tower_info()}.get_arrange_polygon(plater.current_print()); return WipeTower{plater.canvas3D()->get_wipe_tower_info()}.get_arrange_polygon();
} }
void apply_wipe_tower_arrangepoly(Plater &plater, const arrangement::ArrangePolygon &ap) void apply_wipe_tower_arrangepoly(Plater &plater, const arrangement::ArrangePolygon &ap)

View File

@ -29,9 +29,9 @@ class ArrangeJob : public Job
double bed_stride() const; double bed_stride() const;
// Set up arrange polygon for a ModelInstance and Wipe tower // Set up arrange polygon for a ModelInstance and Wipe tower
template<class T> ArrangePolygon get_arrange_poly(const PrintBase* print_base, T *obj) const template<class T> ArrangePolygon get_arrange_poly(T *obj) const
{ {
ArrangePolygon ap = obj->get_arrange_polygon(print_base); ArrangePolygon ap = obj->get_arrange_polygon();
ap.priority = 0; ap.priority = 0;
ap.bed_idx = ap.translation.x() / bed_stride(); ap.bed_idx = ap.translation.x() / bed_stride();
ap.setter = [obj, this](const ArrangePolygon &p) { ap.setter = [obj, this](const ArrangePolygon &p) {
@ -44,8 +44,6 @@ class ArrangeJob : public Job
return ap; return ap;
} }
// Prepare all objects on the bed regardless of the selection
void prepare_all();
// Prepare the selected and unselected items separately. If nothing is // Prepare the selected and unselected items separately. If nothing is
// selected, behaves as if everything would be selected. // selected, behaves as if everything would be selected.
@ -56,6 +54,11 @@ protected:
void prepare() override; void prepare() override;
public: public:
// Prepare all objects on the bed regardless of the selection
//put on public to be accessed by calibrations
void prepare_all();
ArrangeJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater) ArrangeJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater)
: Job{std::move(pri)}, m_plater{plater} : Job{std::move(pri)}, m_plater{plater}
{} {}

View File

@ -2775,7 +2775,7 @@ void Plater::find_new_position(const ModelInstancePtrs &instances,
for (const ModelObject *mo : p->model.objects) for (const ModelObject *mo : p->model.objects)
for (const ModelInstance *inst : mo->instances) { for (const ModelInstance *inst : mo->instances) {
auto it = std::find(instances.begin(), instances.end(), inst); auto it = std::find(instances.begin(), instances.end(), inst);
arrangement::ArrangePolygon arrpoly = inst->get_arrange_polygon(this->current_print()); arrangement::ArrangePolygon arrpoly = inst->get_arrange_polygon();
if (it == instances.end()) if (it == instances.end())
fixed.emplace_back(std::move(arrpoly)); fixed.emplace_back(std::move(arrpoly));