Allow rotation of multiple selected items. Disable auto positioning

This commit is contained in:
tamasmeszaros 2021-03-31 14:50:24 +02:00
parent 804758dfed
commit 649dfca8d6
6 changed files with 99 additions and 44 deletions

View file

@ -78,7 +78,7 @@ 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(PtrWrapper{mi}, m_plater));
cont.emplace_back(get_arrange_poly(mi, m_plater));
}
if (auto wti = get_wipe_tower_arrangepoly(*m_plater))
@ -111,7 +111,7 @@ void ArrangeJob::prepare_selected() {
for (size_t i = 0; i < inst_sel.size(); ++i) {
ArrangePolygon &&ap =
get_arrange_poly(PtrWrapper{mo->instances[i]}, m_plater);
get_arrange_poly(mo->instances[i], m_plater);
ArrangePolygons &cont = mo->instances[i]->printable ?
(inst_sel[i] ? m_selected :
@ -161,12 +161,7 @@ void ArrangeJob::process()
{
static const auto arrangestr = _(L("Arranging"));
const GLCanvas3D::ArrangeSettings &settings =
static_cast<const GLCanvas3D*>(m_plater->canvas3D())->get_arrange_settings();
arrangement::ArrangeParams params;
params.allow_rotations = settings.enable_rotation;
params.min_obj_distance = scaled(settings.distance);
arrangement::ArrangeParams params = get_arrange_params(m_plater);
auto count = unsigned(m_selected.size() + m_unprintable.size());
Points bedpts = get_bed_shape(*m_plater->config());
@ -235,4 +230,23 @@ double bed_stride(const Plater *plater) {
return scaled<double>((1. + LOGICAL_BED_GAP) * bedwidth);
}
template<>
arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst,
const Plater * plater)
{
return get_arrange_poly(PtrWrapper{inst}, plater);
}
arrangement::ArrangeParams get_arrange_params(Plater *p)
{
const GLCanvas3D::ArrangeSettings &settings =
static_cast<const GLCanvas3D*>(p->canvas3D())->get_arrange_settings();
arrangement::ArrangeParams params;
params.allow_rotations = settings.enable_rotation;
params.min_obj_distance = scaled(settings.distance);
return params;
}
}} // namespace Slic3r::GUI

View file

@ -4,7 +4,11 @@
#include "PlaterJob.hpp"
#include "libslic3r/Arrange.hpp"
namespace Slic3r { namespace GUI {
namespace Slic3r {
class ModelInstance;
namespace GUI {
class ArrangeJob : public PlaterJob
{
@ -89,6 +93,11 @@ arrangement::ArrangePolygon get_arrange_poly(T obj, const Plater *plater)
return ap;
}
template<>
arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst,
const Plater * plater);
arrangement::ArrangeParams get_arrange_params(Plater *p);
}} // namespace Slic3r::GUI

View file

@ -32,36 +32,59 @@ void RotoptimizeJob::prepare()
m_method_id = std::max(size_t(0), std::min(get_methods_count() - 1, m_method_id));
m_default_print_cfg = wxGetApp().preset_bundle->full_config();
const auto &sel = m_plater->get_selection().get_content();
m_selected_object_ids.clear();
m_selected_object_ids.reserve(sel.size());
for (auto &[obj_idx, ignore] : sel)
m_selected_object_ids.emplace_back(obj_idx);
}
void RotoptimizeJob::process()
{
int obj_idx = m_plater->get_selected_object_idx();
if (obj_idx < 0)
return;
ModelObject *o = m_plater->model().objects[size_t(obj_idx)];
if (!o) return;
int prev_status = 0;
auto params =
sla::RotOptimizeParams{}
.accuracy(m_accuracy)
.print_config(&m_default_print_cfg)
.statucb([this](int s) {
.statucb([this, &prev_status](int s)
{
if (s > 0 && s < 100)
update_status(s, _(L("Searching for optimal orientation")));
update_status(prev_status + s / m_selected_object_ids.size(),
_(L("Searching for optimal orientation")));
return !was_canceled();
});
Vec2d r = Methods[m_method_id].findfn(*o, params);
double mindist = 6.0; // FIXME
for (ObjRot &objrot : m_selected_object_ids) {
ModelObject *o = m_plater->model().objects[size_t(objrot.idx)];
if (!o) continue;
if (Methods[m_method_id].findfn)
objrot.rot = Methods[m_method_id].findfn(*o, params);
prev_status += 100 / m_selected_object_ids.size();
if (was_canceled()) break;
}
update_status(100, was_canceled() ? _(L("Orientation search canceled.")) :
_(L("Orientation found.")));
}
void RotoptimizeJob::finalize()
{
if (was_canceled()) return;
for (const ObjRot &objrot : m_selected_object_ids) {
ModelObject *o = m_plater->model().objects[size_t(objrot.idx)];
if (!o) continue;
if (!was_canceled()) {
for(ModelInstance * oi : o->instances) {
oi->set_rotation({r[X], r[Y], 0.});
if (objrot.rot)
oi->set_rotation({objrot.rot->x(), objrot.rot->y(), 0.});
auto trmatrix = oi->get_transformation().get_matrix();
Polygon trchull = o->convex_hull_2d(trmatrix);
@ -77,19 +100,13 @@ void RotoptimizeJob::process()
oi->set_rotation(rt);
}
m_plater->find_new_position(o->instances, scaled(mindist));
// Correct the z offset of the object which was corrupted be
// the rotation
o->ensure_on_bed();
// m_plater->find_new_position(o->instances);
}
update_status(100, was_canceled() ? _(L("Orientation search canceled.")) :
_(L("Orientation found.")));
}
void RotoptimizeJob::finalize()
{
if (!was_canceled())
m_plater->update();

View file

@ -19,7 +19,9 @@ class RotoptimizeJob : public PlaterJob
static inline const FindMethod Methods[] = {
{ L("Best misalignment"), sla::find_best_misalignment_rotation },
{ L("Least supports"), sla::find_least_supports_rotation }
{ L("Least supports"), sla::find_least_supports_rotation },
// Just a min area bounding box that is done for all methods anyway.
{ L("Z axis only"), nullptr }
};
size_t m_method_id = 0;
@ -27,6 +29,15 @@ class RotoptimizeJob : public PlaterJob
DynamicPrintConfig m_default_print_cfg;
struct ObjRot
{
size_t idx;
std::optional<Vec2d> rot;
ObjRot(size_t id): idx{id}, rot{} {}
};
std::vector<ObjRot> m_selected_object_ids;
protected:
void prepare() override;

View file

@ -2669,32 +2669,36 @@ void Plater::priv::mirror(Axis axis)
view3D->mirror_selection(axis);
}
void Plater::find_new_position(const ModelInstancePtrs &instances,
coord_t min_d)
void Plater::find_new_position(const ModelInstancePtrs &instances)
{
arrangement::ArrangePolygons movable, fixed;
arrangement::ArrangeParams arr_params = get_arrange_params(this);
for (const ModelObject *mo : p->model.objects)
for (const ModelInstance *inst : mo->instances) {
for (ModelInstance *inst : mo->instances) {
auto it = std::find(instances.begin(), instances.end(), inst);
auto arrpoly = inst->get_arrange_polygon();
auto arrpoly = get_arrange_poly(inst, this);
if (it == instances.end())
fixed.emplace_back(std::move(arrpoly));
else
else {
arrpoly.setter = [it](const arrangement::ArrangePolygon &p) {
if (p.is_arranged() && p.bed_idx == 0) {
Vec2d t = p.translation.cast<double>();
(*it)->apply_arrange_result(t, p.rotation);
}
};
movable.emplace_back(std::move(arrpoly));
}
}
if (auto wt = get_wipe_tower_arrangepoly(*this))
fixed.emplace_back(*wt);
arrangement::arrange(movable, fixed, get_bed_shape(*config()),
arrangement::ArrangeParams{min_d});
arrangement::arrange(movable, fixed, get_bed_shape(*config()), arr_params);
for (size_t i = 0; i < instances.size(); ++i)
if (movable[i].bed_idx == 0)
instances[i]->apply_arrange_result(movable[i].translation.cast<double>(),
movable[i].rotation);
for (auto & m : movable)
m.apply();
}
void Plater::priv::split_object()

View file

@ -258,7 +258,7 @@ public:
BoundingBoxf bed_shape_bb() const;
void arrange();
void find_new_position(const ModelInstancePtrs &instances, coord_t min_d);
void find_new_position(const ModelInstancePtrs &instances);
void set_current_canvas_as_dirty();
void unbind_canvas_event_handlers();