Solved issue with virtual bed management.

libnest2d: Fix for unclosed polygons after merge.
This commit is contained in:
tamasmeszaros 2019-07-17 13:32:31 +02:00
parent 44801f4429
commit 2728f41123
5 changed files with 64 additions and 67 deletions

View File

@ -260,9 +260,11 @@ inline TMultiShape<PolygonImpl> clipper_execute(
assert(!pptr->IsHole()); assert(!pptr->IsHole());
if(pptr->IsOpen()) { if(!poly.Contour.empty() ) {
auto front_p = poly.Contour.front(); auto front_p = poly.Contour.front();
poly.Contour.emplace_back(front_p); auto &back_p = poly.Contour.back();
if(front_p.X != back_p.X || front_p.Y != back_p.X)
poly.Contour.emplace_back(front_p);
} }
for(auto h : pptr->Childs) { processHole(h, poly); } for(auto h : pptr->Childs) { processHole(h, poly); }
@ -275,9 +277,11 @@ inline TMultiShape<PolygonImpl> clipper_execute(
assert(pptr->IsHole()); assert(pptr->IsHole());
if(pptr->IsOpen()) { if(!poly.Contour.empty() ) {
auto front_p = poly.Holes.back().front(); auto front_p = poly.Contour.front();
poly.Holes.back().emplace_back(front_p); auto &back_p = poly.Contour.back();
if(front_p.X != back_p.X || front_p.Y != back_p.X)
poly.Contour.emplace_back(front_p);
} }
for(auto c : pptr->Childs) processPoly(c); for(auto c : pptr->Childs) processPoly(c);

View File

@ -402,9 +402,11 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
for(size_t i = 0; i < input.size(); ++i) { for(size_t i = 0; i < input.size(); ++i) {
if (input[i].bed_idx != 0) ret = false; if (input[i].bed_idx != 0) ret = false;
if (input[i].bed_idx >= 0) if (input[i].bed_idx >= 0) {
instances[i]->apply_arrange_result(input[i], input[i].translation += Vec2crd{input[i].bed_idx * stride, 0};
{input[i].bed_idx * stride, 0}); instances[i]->apply_arrange_result(input[i].translation,
input[i].rotation);
}
} }
return ret; return ret;
@ -1826,23 +1828,20 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
// this may happen for malformed models, see: // this may happen for malformed models, see:
// https://github.com/prusa3d/PrusaSlicer/issues/2209 // https://github.com/prusa3d/PrusaSlicer/issues/2209
if (p.points.empty()) return {}; if (!p.points.empty()) {
Polygons pp{p};
pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
if (!pp.empty()) p = pp.front();
}
Polygons pp{p};
pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
if (!pp.empty()) p = pp.front();
m_arrange_cache.poly.contour = std::move(p); m_arrange_cache.poly.contour = std::move(p);
m_arrange_cache.bed_origin = {0, 0};
m_arrange_cache.bed_idx = arrangement::UNARRANGED;
m_arrange_cache.valid = true; m_arrange_cache.valid = true;
} }
arrangement::ArrangePolygon ret; arrangement::ArrangePolygon ret;
ret.poly = m_arrange_cache.poly; ret.poly = m_arrange_cache.poly;
ret.translation = Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))} - ret.translation = Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))};
m_arrange_cache.bed_origin;
ret.rotation = get_rotation(Z); ret.rotation = get_rotation(Z);
ret.bed_idx = m_arrange_cache.bed_idx;
return ret; return ret;
} }

View File

@ -558,15 +558,12 @@ public:
arrangement::ArrangePolygon get_arrange_polygon() 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 arrangement::ArrangePolygon& ap, void apply_arrange_result(const Vec2crd& offs, double rotation)
const Vec2crd& bed_origin = {0, 0})
{ {
// write the transformation data into the model instance // write the transformation data into the model instance
set_rotation(Z, ap.rotation); set_rotation(Z, rotation);
set_offset(X, unscale<double>(ap.translation(X) + bed_origin.x())); set_offset(X, unscale<double>(offs(X)));
set_offset(Y, unscale<double>(ap.translation(Y) + bed_origin.y())); set_offset(Y, unscale<double>(offs(Y)));
m_arrange_cache.bed_origin = bed_origin;
m_arrange_cache.bed_idx = ap.bed_idx;
} }
protected: protected:
@ -601,9 +598,7 @@ private:
// Warning! This object is not guarded against concurrency. // Warning! This object is not guarded against concurrency.
mutable struct ArrangeCache { mutable struct ArrangeCache {
bool valid = false; bool valid = false;
Vec2crd bed_origin {0, 0};
ExPolygon poly; ExPolygon poly;
int bed_idx = arrangement::UNARRANGED;
} m_arrange_cache; } m_arrange_cache;
}; };

View File

@ -4,7 +4,6 @@
#include <stddef.h> #include <stddef.h>
#include <memory> #include <memory>
#include "libslic3r/Arrange.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#include "GLToolbar.hpp" #include "GLToolbar.hpp"
#include "Event.hpp" #include "Event.hpp"

View File

@ -1264,21 +1264,18 @@ struct Plater::priv
// Cache the wti info // Cache the wti info
class WipeTower: public GLCanvas3D::WipeTowerInfo { class WipeTower: public GLCanvas3D::WipeTowerInfo {
Vec2d m_bed_origin = {0., 0.}; using ArrangePolygon = arrangement::ArrangePolygon;
int m_bed_idx = arrangement::UNARRANGED; static const constexpr auto UNARRANGED = arrangement::UNARRANGED;
friend priv; friend priv;
public: public:
void apply_arrange_result(const arrangement::ArrangePolygon& ap, void apply_arrange_result(const Vec2crd& tr, double rotation)
const Vec2crd& bedc) { {
m_bed_origin = unscaled(bedc); m_pos = unscaled(tr); m_rotation = rotation;
m_pos = unscaled(ap.translation) + m_bed_origin;
m_rotation = ap.rotation;
m_bed_idx = ap.bed_idx;
apply_wipe_tower(); apply_wipe_tower();
} }
arrangement::ArrangePolygon get_arrange_polygon() const ArrangePolygon get_arrange_polygon() const
{ {
Polygon p({ Polygon p({
{coord_t(0), coord_t(0)}, {coord_t(0), coord_t(0)},
@ -1288,28 +1285,20 @@ struct Plater::priv
{coord_t(0), coord_t(0)}, {coord_t(0), coord_t(0)},
}); });
arrangement::ArrangePolygon ret; ArrangePolygon ret;
ret.poly.contour = std::move(p); ret.poly.contour = std::move(p);
ret.translation = scaled(m_pos) - scaled(m_bed_origin); ret.translation = scaled(m_pos);
ret.rotation = m_rotation; ret.rotation = m_rotation;
ret.bed_idx = m_bed_idx;
return ret; return ret;
} }
} wipetower;
// For future use WipeTower& updated_wipe_tower() {
int bed_index() const { return m_bed_idx; }
};
private:
WipeTower m_wipetower;
public:
WipeTower& wipe_tower() {
auto wti = view3D->get_canvas3d()->get_wipe_tower_info(); auto wti = view3D->get_canvas3d()->get_wipe_tower_info();
m_wipetower.m_pos = wti.pos(); wipetower.m_pos = wti.pos();
m_wipetower.m_rotation = wti.rotation(); wipetower.m_rotation = wti.rotation();
m_wipetower.m_bb_size = wti.bb_size(); wipetower.m_bb_size = wti.bb_size();
return m_wipetower; return wipetower;
} }
// A class to handle UI jobs like arranging and optimizing rotation. // A class to handle UI jobs like arranging and optimizing rotation.
@ -1506,9 +1495,13 @@ public:
ModelInstance *mi = mo->instances[i]; ModelInstance *mi = mo->instances[i];
ArrangePolygon ap = mi->get_arrange_polygon(); ArrangePolygon ap = mi->get_arrange_polygon();
ap.priority = 0; ap.priority = 0;
ap.bed_idx = ap.translation.x() / stride;
ap.setter = [mi, stride](const ArrangePolygon &p) { ap.setter = [mi, stride](const ArrangePolygon &p) {
if (p.bed_idx != UNARRANGED) if (p.bed_idx != UNARRANGED) {
mi->apply_arrange_result(p, {p.bed_idx * stride, 0}); auto t = p.translation; t.x() += p.bed_idx * stride;
mi->apply_arrange_result(t, p.rotation);
}
}; };
inst_sel[i] ? inst_sel[i] ?
@ -1517,15 +1510,16 @@ public:
} }
} }
auto& wti = plater().wipe_tower(); auto& wti = plater().updated_wipe_tower();
if (wti) { if (wti) {
ArrangePolygon ap = wti.get_arrange_polygon(); ArrangePolygon ap = wti.get_arrange_polygon();
ap.bed_idx = ap.translation.x() / stride;
ap.priority = 1; // Wipe tower should be on physical bed
ap.setter = [&wti, stride](const ArrangePolygon &p) { ap.setter = [&wti, stride](const ArrangePolygon &p) {
if (p.bed_idx != UNARRANGED) auto t = p.translation; t.x() += p.bed_idx * stride;
wti.apply_arrange_result(p, {p.bed_idx * stride, 0}); wti.apply_arrange_result(t, p.rotation);
}; };
ap.priority = 1;
sel.is_wipe_tower() ? sel.is_wipe_tower() ?
m_selected.emplace_back(std::move(ap)) : m_selected.emplace_back(std::move(ap)) :
m_unselected.emplace_back(std::move(ap)); m_unselected.emplace_back(std::move(ap));
@ -1533,6 +1527,11 @@ public:
// If the selection was empty arrange everything // If the selection was empty arrange everything
if (m_selected.empty()) m_selected.swap(m_unselected); if (m_selected.empty()) m_selected.swap(m_unselected);
// The strides have to be removed from the fixed items. For the
// arrangeable (selected) items it bed_idx is ignored and the
// translation is irrelevant.
for (auto &p : m_unselected) p.translation(X) -= p.bed_idx * stride;
} }
public: public:
@ -2553,14 +2552,15 @@ void Plater::priv::find_new_position(const ModelInstancePtrs &instances,
movable.emplace_back(std::move(arrpoly)); movable.emplace_back(std::move(arrpoly));
} }
if (wipe_tower()) if (updated_wipe_tower())
fixed.emplace_back(m_wipetower.get_arrange_polygon()); fixed.emplace_back(wipetower.get_arrange_polygon());
arrangement::arrange(movable, fixed, min_d, get_bed_shape_hint()); arrangement::arrange(movable, fixed, min_d, get_bed_shape_hint());
for (size_t i = 0; i < instances.size(); ++i) for (size_t i = 0; i < instances.size(); ++i)
if (movable[i].bed_idx == 0) if (movable[i].bed_idx == 0)
instances[i]->apply_arrange_result(movable[i]); instances[i]->apply_arrange_result(movable[i].translation,
movable[i].rotation);
} }
void Plater::priv::ArrangeJob::process() { void Plater::priv::ArrangeJob::process() {