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.
bool user_center_specified = false;
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;
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);
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) {
try {
// 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) {
boost::nowide::cerr << "error: " << ex.what() << std::endl;
return 1;
@ -481,9 +479,9 @@ int CLI::run(int argc, char **argv)
}
if (user_center_specified) {
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
arrange_objects(print, model, bed, arrange_cfg);
arrange_objects(model, bed, arrange_cfg);
}
if (printer_technology == ptFFF) {
for (auto* mo : model.objects)

View File

@ -1855,15 +1855,16 @@ 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 PrintBase *print_base) const
arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
{
static const double SIMPLIFY_TOLERANCE_MM = 0.1;
Vec3d rotation = get_rotation();
rotation.z() = 0.;
rotation.z() = 0.;
Transform3d trafo_instance =
Geometry::assemble_transform(Vec3d::Zero(), rotation,
get_scaling_factor(), get_mirror());
get_scaling_factor(), get_mirror());
Polygon p = get_object()->convex_hull_2d(trafo_instance);
@ -1872,59 +1873,19 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon(const PrintBase *
// this may happen for malformed models, see:
// https://github.com/prusa3d/PrusaSlicer/issues/2209
if (!p.points.empty()) {
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));
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);
ret.translation = Vec2crd{ scaled(get_offset(X)), scaled(get_offset(Y)) };
ret.rotation = get_rotation(Z);
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
{
TriangleSelector selector(mv.mesh());

View File

@ -874,7 +874,7 @@ public:
bool is_printable() const { return object->printable && printable && (print_volume_state == ModelInstancePVS_Inside); }
// 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
void apply_arrange_result(const Vec2d& offs, double rotation)

View File

@ -5,7 +5,7 @@
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;
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);
for (ModelObject *mo : model.objects)
for (ModelInstance *minst : mo->instances) {
input.emplace_back(minst->get_arrange_polygon(print));
input.emplace_back(minst->get_arrange_polygon());
instances.emplace_back(minst);
}
@ -36,13 +36,13 @@ bool apply_arrange_polys(ArrangePolygons &input, ModelInstancePtrs &instances, V
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;
Points &apts = ap.poly.contour.points;
for (const ModelObject *mo : model.objects)
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.translate(obj_ap.translation.x(), obj_ap.translation.y());
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");
}
ArrangePolygons get_arrange_polys(const PrintBase* print, const Model &model, ModelInstancePtrs &instances);
ArrangePolygon get_arrange_poly(const PrintBase* print, const Model &model);
ArrangePolygons get_arrange_polys(const Model &model, ModelInstancePtrs &instances);
ArrangePolygon get_arrange_poly(const Model &model);
bool apply_arrange_polys(ArrangePolygons &polys, ModelInstancePtrs &instances, VirtualBedFn);
void duplicate(Model &model, ArrangePolygons &copies, VirtualBedFn);
void duplicate_objects(Model &model, size_t copies_num);
template<class TBed>
bool arrange_objects(PrintBase* print,
Model & model,
bool arrange_objects(Model & model,
const TBed & bed,
const ArrangeParams &params,
VirtualBedFn vfn = throw_if_out_of_bed)
{
ModelInstancePtrs instances;
ArrangePolygons input = get_arrange_polys(print, model, instances);
ArrangePolygons input = get_arrange_polys(model, instances);
arrangement::arrange(input, bed, params);
return apply_arrange_polys(input, instances, vfn);
}
template<class TBed>
void duplicate(PrintBase* print,
Model & model,
void duplicate(Model & model,
size_t copies_num,
const TBed & bed,
const ArrangeParams &params,
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);
duplicate(model, copies, vfn);
}
template<class TBed>
void duplicate_objects(PrintBase* print,
Model & model,
void duplicate_objects(Model & model,
size_t copies_num,
const TBed & bed,
const ArrangeParams &params,
VirtualBedFn vfn = throw_if_out_of_bed)
{
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)
{
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()) {
double dist_grow = PrintConfig::min_object_distance(&print_object->config());
assert(! print_object->model_object()->instances.empty());
assert(! print_object->instances().empty());
//ObjectID model_object_id = print_object->model_object()->id();
//auto it_convex_hull = map_model_object_to_convex_hull.find(model_object_id);
ObjectID model_object_id = print_object->model_object()->id();
auto it_convex_hull = map_model_object_to_convex_hull.find(model_object_id);
// Get convex hull of all printable volumes assigned to this print object.
// ModelInstance *model_instance0 = print_object->model_object()->instances.front();
// if (it_convex_hull == map_model_object_to_convex_hull.end()) {
// // Calculate the convex hull of a printable object.
// // Grow convex hull with the clearance margin.
// // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
// // which causes that the warning will be showed after arrangement with the
// // appropriate object distance. Even if I set this to jtMiter the warning still shows up.
// it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
// offset(print_object->model_object()->convex_hull_2d(
// Geometry::assemble_transform(Vec3d::Zero(), model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
// // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
// // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
// float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)),
// jtRound, float(scale_(0.1))).front());
// }
// // Make a copy, so it may be rotated for instances.
// //FIXME seems like the rotation isn't taken into account
// Polygon convex_hull0 = it_convex_hull->second;
// //this can create bugs in macos, for reasons.
//double z_diff = Geometry::rotation_diff_z(model_instance0->get_rotation(), print_object->instances().front().model_instance->get_rotation());
//if (std::abs(z_diff) > EPSILON)
// convex_hull0.rotate(z_diff);
ModelInstance *model_instance0 = print_object->model_object()->instances.front();
if (it_convex_hull == map_model_object_to_convex_hull.end()) {
// Calculate the convex hull of a printable object.
// Grow convex hull with the clearance margin.
// FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
// which causes that the warning will be showed after arrangement with the
// appropriate object distance. Even if I set this to jtMiter the warning still shows up.
it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
offset(print_object->model_object()->convex_hull_2d(
Geometry::assemble_transform(Vec3d::Zero(), model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
float(scale_(0.5 * dist_grow - EPSILON)),
jtRound, float(scale_(0.1))).front());
}
// Make a copy, so it may be rotated for instances.
//FIXME seems like the rotation isn't taken into account
Polygon convex_hull0 = it_convex_hull->second;
//this can create bugs in macos, for reasons.
double z_diff = Geometry::rotation_diff_z(model_instance0->get_rotation(), print_object->instances().front().model_instance->get_rotation());
if (std::abs(z_diff) > EPSILON)
convex_hull0.rotate(z_diff);
// Now we check that no instance of convex_hull intersects any of the previously checked object instances.
for (const PrintInstance& instance : print_object->instances()) {
Polygon convex_hull = convex_hull0;
// 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.
for (const PrintInstance &instance : print_object->instances()) {
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()));
// 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.
@ -1305,13 +1319,14 @@ static inline bool sequential_print_horizontal_clearance_valid(const Print &prin
poly.translate(instance.shift - print_object->center_offset());
if (! intersection(
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;
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)
convex_hull = offset(convex_hull, scale_(extra_grow));
polygons_append(convex_hulls_other, convex_hull);
}
*/
}
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...
if (dd_opt == nullptr) return 0;
double duplicate_distance = dd_opt->value;
double base_dist = duplicate_distance / 2;
// /2 becasue we only count the grawing for the current object
const double duplicate_distance = dd_opt->value / 2;
double base_dist = duplicate_distance;
//std::cout << "START min_object_distance =>" << base_dist << "\n";
const ConfigOptionBool* co_opt = config->option<ConfigOptionBool>("complete_objects");
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);
// 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.
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) {
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";
//FIXME: now brim can be per-object, so you ahve to get a different min_object_distance per object
//add brim width
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
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";
}
} else if (config->option("brim_width")->getFloat() + 1 > base_dist) {
base_dist = config->option("brim_width")->getFloat();
}
//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;
if (ref_height <= skirt_height) {
skirt_dist = config->option("skirt_distance")->getFloat();

View File

@ -5,6 +5,7 @@
#include <map>
#include <vector>
#include "Jobs/ProgressIndicator.hpp"
#include "GUI_App.hpp"
#include "GUI_Utils.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 Slic3r

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "Plater.hpp"
@ -98,6 +99,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
}
/// --- translate ---;
bool has_to_arrange = false;
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 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++) {
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 ---
@ -141,6 +145,17 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
ObjectList* obj = this->gui_app->obj_list();
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->select_view_3D("Preview");

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "Plater.hpp"
@ -101,6 +102,7 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
}
/// --- translate ---;
bool has_to_arrange = false;
const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius");
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
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[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 });
//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 ---
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();
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->select_view_3D("Preview");

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "Plater.hpp"
@ -85,6 +86,7 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) {
}
/// --- translate ---;
bool has_to_arrange = false;
const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius");
const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape");
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[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 });
//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 ---
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();
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->select_view_3D("Preview");

View File

@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#include "Jobs/ArrangeJob.hpp"
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "Plater.hpp"
@ -190,22 +191,20 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
}
/// --- translate ---;
bool has_to_arrange = false;
const ConfigOptionFloat* extruder_clearance_radius = print_config->option<ConfigOptionFloat>("extruder_clearance_radius");
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.);
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
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) {
model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 });
} else {
for (size_t i = 0; i < nb_items; i++) {
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 });
}
has_to_arrange = true;
}
/// --- custom config ---
for (size_t i = 0; i < nb_items; i++) {
//speed
@ -252,16 +251,29 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
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);
plat->on_config_change(new_print_config);
this->gui_app->get_tab(Preset::TYPE_PRINT)->update_dirty();
plat->on_config_change(new_print_config);
}
//update plater
plat->changed_objects(objs_idx);
//if (plat->printer_technology() == ptFFF)
//plat->fff_print().full_print_config().apply(plat->config());
//update everything, easier to code.
ObjectList* obj = this->gui_app->obj_list();
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->select_view_3D("Preview");

View File

@ -28,7 +28,7 @@ public:
apply_wipe_tower();
}
ArrangePolygon get_arrange_polygon(const PrintBase* print_base) const
ArrangePolygon get_arrange_polygon() const
{
Polygon ap({
{coord_t(0), coord_t(0)},
@ -80,11 +80,11 @@ void ArrangeJob::prepare_all() {
for (ModelObject *obj: m_plater->model().objects)
for (ModelInstance *mi : obj->instances) {
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))
m_selected.emplace_back(wti.get_arrange_polygon(m_plater->current_print()));
m_selected.emplace_back(wti.get_arrange_polygon());
}
void ArrangeJob::prepare_selected() {
@ -112,7 +112,7 @@ void ArrangeJob::prepare_selected() {
inst_sel[size_t(inst_id)] = true;
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 ?
(inst_sel[i] ? m_selected :
@ -124,7 +124,7 @@ void ArrangeJob::prepare_selected() {
}
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_selected.emplace_back(std::move(ap)) :
@ -149,10 +149,10 @@ void ArrangeJob::process()
{
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;
params.min_obj_distance = scaled(dist);
params.min_obj_distance = scaled(dist) * 2;
auto count = unsigned(m_selected.size() + m_unprintable.size());
Points bedpts = get_bed_shape(*m_plater->config());
@ -214,7 +214,7 @@ void ArrangeJob::finalize() {
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)

View File

@ -29,9 +29,9 @@ class ArrangeJob : public Job
double bed_stride() const;
// 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.bed_idx = ap.translation.x() / bed_stride();
ap.setter = [obj, this](const ArrangePolygon &p) {
@ -44,8 +44,6 @@ class ArrangeJob : public Job
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
// selected, behaves as if everything would be selected.
@ -56,6 +54,11 @@ protected:
void prepare() override;
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)
: 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 ModelInstance *inst : mo->instances) {
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())
fixed.emplace_back(std::move(arrpoly));