mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-04 09:55:11 +08:00
Solved issue with virtual bed management.
libnest2d: Fix for unclosed polygons after merge.
This commit is contained in:
parent
44801f4429
commit
2728f41123
@ -259,10 +259,12 @@ inline TMultiShape<PolygonImpl> clipper_execute(
|
|||||||
poly.Contour.swap(pptr->Contour);
|
poly.Contour.swap(pptr->Contour);
|
||||||
|
|
||||||
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); }
|
||||||
@ -274,10 +276,12 @@ inline TMultiShape<PolygonImpl> clipper_execute(
|
|||||||
poly.Holes.emplace_back(std::move(pptr->Contour));
|
poly.Holes.emplace_back(std::move(pptr->Contour));
|
||||||
|
|
||||||
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);
|
||||||
|
@ -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};
|
||||||
Polygons pp{p};
|
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();
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -516,7 +516,7 @@ public:
|
|||||||
|
|
||||||
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
||||||
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
||||||
|
|
||||||
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
|
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
|
||||||
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
|
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
|
||||||
|
|
||||||
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
|
||||||
int bed_index() const { return m_bed_idx; }
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
WipeTower& updated_wipe_tower() {
|
||||||
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,26 +1495,31 @@ 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.setter = [mi, stride](const ArrangePolygon &p) {
|
ap.bed_idx = ap.translation.x() / stride;
|
||||||
if (p.bed_idx != UNARRANGED)
|
|
||||||
mi->apply_arrange_result(p, {p.bed_idx * stride, 0});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
ap.setter = [mi, stride](const ArrangePolygon &p) {
|
||||||
|
if (p.bed_idx != UNARRANGED) {
|
||||||
|
auto t = p.translation; t.x() += p.bed_idx * stride;
|
||||||
|
mi->apply_arrange_result(t, p.rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
inst_sel[i] ?
|
inst_sel[i] ?
|
||||||
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user