mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-24 09:11:23 -06:00
Not handling logical beds in arrange()
This commit is contained in:
parent
9372f1c6ad
commit
df7bb94daf
12 changed files with 256 additions and 272 deletions
|
|
@ -341,9 +341,9 @@ public:
|
|||
m_pck.configure(m_pconf);
|
||||
}
|
||||
|
||||
template<class...Args> inline PackGroup operator()(Args&&...args) {
|
||||
template<class...Args> inline void operator()(Args&&...args) {
|
||||
m_rtree.clear();
|
||||
return m_pck.execute(std::forward<Args>(args)...);
|
||||
m_pck.execute(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline void preload(std::vector<Item>& fixeditems) {
|
||||
|
|
@ -513,7 +513,7 @@ BedShapeHint bedShape(const Polyline &bed) {
|
|||
}
|
||||
|
||||
template<class BinT> // Arrange for arbitrary bin type
|
||||
_NestResult<clppr::Polygon> _arrange(
|
||||
void _arrange(
|
||||
std::vector<Item> & shapes,
|
||||
std::vector<Item> & excludes,
|
||||
const BinT & bin,
|
||||
|
|
@ -553,40 +553,30 @@ _NestResult<clppr::Polygon> _arrange(
|
|||
for (auto &itm : shapes ) inp.emplace_back(itm);
|
||||
for (auto &itm : excludes) inp.emplace_back(itm);
|
||||
|
||||
return arranger(inp.begin(), inp.end());
|
||||
}
|
||||
|
||||
inline SLIC3R_CONSTEXPR coord_t stride_padding(coord_t w)
|
||||
{
|
||||
return w + w / 5;
|
||||
arranger(inp.begin(), inp.end());
|
||||
}
|
||||
|
||||
// The final client function for arrangement. A progress indicator and
|
||||
// a stop predicate can be also be passed to control the process.
|
||||
bool arrange(ArrangeablePtrs & arrangables,
|
||||
const ArrangeablePtrs & excludes,
|
||||
void arrange(ArrangePolygons & arrangables,
|
||||
const ArrangePolygons & excludes,
|
||||
coord_t min_obj_dist,
|
||||
const BedShapeHint & bedhint,
|
||||
std::function<void(unsigned)> progressind,
|
||||
std::function<bool()> stopcondition)
|
||||
{
|
||||
bool ret = true;
|
||||
namespace clppr = ClipperLib;
|
||||
|
||||
std::vector<Item> items, fixeditems;
|
||||
items.reserve(arrangables.size());
|
||||
coord_t binwidth = 0;
|
||||
|
||||
|
||||
// Create Item from Arrangeable
|
||||
auto process_arrangeable =
|
||||
[](const Arrangeable *arrangeable, std::vector<Item> &outp)
|
||||
[](const ArrangePolygon &arrpoly, std::vector<Item> &outp)
|
||||
{
|
||||
assert(arrangeable);
|
||||
|
||||
auto arrangeitem = arrangeable->get_arrange_polygon();
|
||||
|
||||
Polygon & p = std::get<0>(arrangeitem);
|
||||
const Vec2crd &offs = std::get<1>(arrangeitem);
|
||||
double rotation = std::get<2>(arrangeitem);
|
||||
Polygon p = arrpoly.poly.contour;
|
||||
const Vec2crd & offs = arrpoly.translation;
|
||||
double rotation = arrpoly.rotation;
|
||||
|
||||
if (p.is_counter_clockwise()) p.reverse();
|
||||
|
||||
|
|
@ -600,10 +590,10 @@ bool arrange(ArrangeablePtrs & arrangables,
|
|||
outp.back().translation({offs.x(), offs.y()});
|
||||
};
|
||||
|
||||
for (Arrangeable *arrangeable : arrangables)
|
||||
for (ArrangePolygon &arrangeable : arrangables)
|
||||
process_arrangeable(arrangeable, items);
|
||||
|
||||
for (const Arrangeable * fixed: excludes)
|
||||
for (const ArrangePolygon &fixed: excludes)
|
||||
process_arrangeable(fixed, fixeditems);
|
||||
|
||||
// Integer ceiling the min distance from the bed perimeters
|
||||
|
|
@ -619,7 +609,6 @@ bool arrange(ArrangeablePtrs & arrangables,
|
|||
BoundingBox bbb = bedhint.shape.box;
|
||||
bbb.min -= Point{md, md}, bbb.max += Point{md, md};
|
||||
Box binbb{{bbb.min(X), bbb.min(Y)}, {bbb.max(X), bbb.max(Y)}};
|
||||
binwidth = coord_t(binbb.width());
|
||||
|
||||
_arrange(items, fixeditems, binbb, min_obj_dist, pri, cfn);
|
||||
break;
|
||||
|
|
@ -627,7 +616,6 @@ bool arrange(ArrangeablePtrs & arrangables,
|
|||
case BedShapeType::CIRCLE: {
|
||||
auto c = bedhint.shape.circ;
|
||||
auto cc = to_lnCircle(c);
|
||||
binwidth = scaled(c.radius());
|
||||
|
||||
_arrange(items, fixeditems, cc, min_obj_dist, pri, cfn);
|
||||
break;
|
||||
|
|
@ -636,7 +624,6 @@ bool arrange(ArrangeablePtrs & arrangables,
|
|||
auto ctour = Slic3rMultiPoint_to_ClipperPath(bedhint.shape.polygon);
|
||||
auto irrbed = sl::create<clppr::Polygon>(std::move(ctour));
|
||||
BoundingBox polybb(bedhint.shape.polygon);
|
||||
binwidth = (polybb.max(X) - polybb.min(X));
|
||||
|
||||
_arrange(items, fixeditems, irrbed, min_obj_dist, pri, cfn);
|
||||
break;
|
||||
|
|
@ -655,19 +642,22 @@ bool arrange(ArrangeablePtrs & arrangables,
|
|||
}
|
||||
};
|
||||
|
||||
if(stopcondition && stopcondition()) return false;
|
||||
|
||||
return ret;
|
||||
for(size_t i = 0; i < items.size(); ++i) {
|
||||
clppr::IntPoint tr = items[i].translation();
|
||||
arrangables[i].translation = {coord_t(tr.X), coord_t(tr.Y)};
|
||||
arrangables[i].rotation = items[i].rotation();
|
||||
arrangables[i].bed_idx = items[i].binId();
|
||||
}
|
||||
}
|
||||
|
||||
// Arrange, without the fixed items (excludes)
|
||||
bool arrange(ArrangeablePtrs & inp,
|
||||
coord_t min_d,
|
||||
const BedShapeHint & bedhint,
|
||||
std::function<void(unsigned)> prfn,
|
||||
std::function<bool()> stopfn)
|
||||
void arrange(ArrangePolygons & inp,
|
||||
coord_t min_d,
|
||||
const BedShapeHint & bedhint,
|
||||
std::function<void(unsigned)> prfn,
|
||||
std::function<bool()> stopfn)
|
||||
{
|
||||
return arrange(inp, {}, min_d, bedhint, prfn, stopfn);
|
||||
arrange(inp, {}, min_d, bedhint, prfn, stopfn);
|
||||
}
|
||||
|
||||
} // namespace arr
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef MODELARRANGE_HPP
|
||||
#define MODELARRANGE_HPP
|
||||
|
||||
#include "Polygon.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
|
@ -37,34 +37,57 @@ enum class BedShapeType {
|
|||
/// Info about the print bed for the arrange() function.
|
||||
struct BedShapeHint {
|
||||
BedShapeType type = BedShapeType::INFINITE;
|
||||
/*union*/ struct { // I know but who cares... TODO: use variant from cpp17?
|
||||
union BedShape_u { // I know but who cares... TODO: use variant from cpp17?
|
||||
CircleBed circ;
|
||||
BoundingBox box;
|
||||
Polyline polygon;
|
||||
InfiniteBed infinite;
|
||||
InfiniteBed infinite{};
|
||||
~BedShape_u() {}
|
||||
BedShape_u() {};
|
||||
} shape;
|
||||
|
||||
BedShapeHint() {};
|
||||
|
||||
~BedShapeHint() {
|
||||
if (type == BedShapeType::IRREGULAR)
|
||||
shape.polygon.Slic3r::Polyline::~Polyline();
|
||||
};
|
||||
|
||||
BedShapeHint(const BedShapeHint &cpy) {
|
||||
*this = cpy;
|
||||
}
|
||||
|
||||
BedShapeHint& operator=(const BedShapeHint &cpy) {
|
||||
type = cpy.type;
|
||||
switch(type) {
|
||||
case BedShapeType::BOX: shape.box = cpy.shape.box; break;
|
||||
case BedShapeType::CIRCLE: shape.circ = cpy.shape.circ; break;
|
||||
case BedShapeType::IRREGULAR: shape.polygon = cpy.shape.polygon; break;
|
||||
case BedShapeType::INFINITE: shape.infinite = cpy.shape.infinite; break;
|
||||
case BedShapeType::UNKNOWN: break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// Get a bed shape hint for arrange() from a naked Polyline.
|
||||
BedShapeHint bedShape(const Polyline& bed);
|
||||
|
||||
/**
|
||||
* @brief Classes implementing the Arrangeable interface can be used as input
|
||||
* to the arrange function.
|
||||
*/
|
||||
class Arrangeable {
|
||||
public:
|
||||
static const constexpr long UNARRANGED = -1;
|
||||
|
||||
struct ArrangePolygon {
|
||||
const ExPolygon poly;
|
||||
Vec2crd translation{0, 0};
|
||||
double rotation{0.0};
|
||||
long bed_idx{UNARRANGED};
|
||||
|
||||
virtual ~Arrangeable() = default;
|
||||
|
||||
/// Apply the result transformation calculated by the arrangement.
|
||||
virtual void apply_arrange_result(Vec2d offset, double rotation_rads, unsigned bed_num) = 0;
|
||||
|
||||
/// Get the 2D silhouette to arrange and an initial offset and rotation
|
||||
virtual std::tuple<Polygon, Vec2crd, double> get_arrange_polygon() const = 0;
|
||||
ArrangePolygon(const ExPolygon &p, const Vec2crd &tr = {}, double rot = 0.0)
|
||||
: poly{p}, translation{tr}, rotation{rot}
|
||||
{}
|
||||
};
|
||||
|
||||
using ArrangeablePtrs = std::vector<Arrangeable*>;
|
||||
using ArrangePolygons = std::vector<ArrangePolygon>;
|
||||
|
||||
/**
|
||||
* \brief Arranges the model objects on the screen.
|
||||
|
|
@ -97,20 +120,20 @@ using ArrangeablePtrs = std::vector<Arrangeable*>;
|
|||
*
|
||||
* \param stopcondition A predicate returning true if abort is needed.
|
||||
*/
|
||||
bool arrange(ArrangeablePtrs &items,
|
||||
coord_t min_obj_distance,
|
||||
const BedShapeHint& bedhint,
|
||||
std::function<void(unsigned)> progressind = nullptr,
|
||||
std::function<bool(void)> stopcondition = nullptr);
|
||||
void arrange(ArrangePolygons & items,
|
||||
coord_t min_obj_distance,
|
||||
const BedShapeHint & bedhint,
|
||||
std::function<void(unsigned)> progressind = nullptr,
|
||||
std::function<bool(void)> stopcondition = nullptr);
|
||||
|
||||
/// Same as the previous, only that it takes unmovable items as an
|
||||
/// additional argument.
|
||||
bool arrange(ArrangeablePtrs &items,
|
||||
const ArrangeablePtrs &excludes,
|
||||
coord_t min_obj_distance,
|
||||
const BedShapeHint& bedhint,
|
||||
std::function<void(unsigned)> progressind = nullptr,
|
||||
std::function<bool(void)> stopcondition = nullptr);
|
||||
void arrange(ArrangePolygons & items,
|
||||
const ArrangePolygons & excludes,
|
||||
coord_t min_obj_distance,
|
||||
const BedShapeHint & bedhint,
|
||||
std::function<void(unsigned)> progressind = nullptr,
|
||||
std::function<bool(void)> stopcondition = nullptr);
|
||||
|
||||
} // arr
|
||||
} // Slic3r
|
||||
|
|
|
|||
|
|
@ -404,11 +404,16 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
|||
size_t count = 0;
|
||||
for (auto obj : objects) count += obj->instances.size();
|
||||
|
||||
arrangement::ArrangeablePtrs input;
|
||||
arrangement::ArrangePolygons input;
|
||||
ModelInstancePtrs instances;
|
||||
input.reserve(count);
|
||||
instances.reserve(count);
|
||||
for (ModelObject *mo : objects)
|
||||
for (ModelInstance *minst : mo->instances)
|
||||
input.emplace_back(minst);
|
||||
for (ModelInstance *minst : mo->instances) {
|
||||
input.emplace_back(minst->get_arrange_polygon());
|
||||
instances.emplace_back(minst);
|
||||
}
|
||||
|
||||
|
||||
arrangement::BedShapeHint bedhint;
|
||||
|
||||
|
|
@ -417,7 +422,22 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
|||
bedhint.shape.box = BoundingBox(scaled(bb->min), scaled(bb->max));
|
||||
}
|
||||
|
||||
return arrangement::arrange(input, scaled(dist), bedhint);
|
||||
arrangement::arrange(input, scaled(dist), bedhint);
|
||||
|
||||
bool ret = true;
|
||||
|
||||
for(size_t i = 0; i < input.size(); ++i) {
|
||||
auto inst = instances[i];
|
||||
inst->set_rotation(Z, input[i].rotation);
|
||||
auto tr = unscaled<double>(input[i].translation);
|
||||
inst->set_offset(X, tr.x());
|
||||
inst->set_offset(Y, tr.y());
|
||||
|
||||
if (input[i].bed_idx != 0) ret = false; // no logical beds are allowed
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Duplicate the entire model preserving instance relative positions.
|
||||
|
|
@ -1819,7 +1839,7 @@ void ModelInstance::transform_polygon(Polygon* polygon) const
|
|||
polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin
|
||||
}
|
||||
|
||||
std::tuple<Polygon, Vec2crd, double> ModelInstance::get_arrange_polygon() const
|
||||
arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
||||
{
|
||||
static const double SIMPLIFY_TOLERANCE_MM = 0.1;
|
||||
|
||||
|
|
@ -1835,15 +1855,15 @@ std::tuple<Polygon, Vec2crd, double> ModelInstance::get_arrange_polygon() const
|
|||
|
||||
// this may happen for malformed models, see:
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/2209
|
||||
if (p.points.empty()) return {};
|
||||
if (p.points.empty()) return {{}};
|
||||
|
||||
Polygons pp{p};
|
||||
pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
|
||||
if (!pp.empty()) p = pp.front();
|
||||
|
||||
return std::make_tuple(p,
|
||||
Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))},
|
||||
get_rotation(Z));
|
||||
|
||||
ExPolygon ep; ep.contour = std::move(p);
|
||||
|
||||
return {ep, Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))}, get_rotation(Z)};
|
||||
}
|
||||
|
||||
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||
|
|
|
|||
|
|
@ -491,7 +491,7 @@ private:
|
|||
|
||||
// A single instance of a ModelObject.
|
||||
// Knows the affine transformation of an object.
|
||||
class ModelInstance : public ModelBase, public arrangement::Arrangeable
|
||||
class ModelInstance : public ModelBase
|
||||
{
|
||||
public:
|
||||
enum EPrintVolumeState : unsigned char
|
||||
|
|
@ -555,19 +555,19 @@ public:
|
|||
bool is_printable() const { return print_volume_state == PVS_Inside; }
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////
|
||||
// Implement arr::Arrangeable interface
|
||||
// Implement arrangement::Arrangeable interface
|
||||
// /////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Getting the input polygon for arrange
|
||||
virtual std::tuple<Polygon, Vec2crd, double> get_arrange_polygon() const override;
|
||||
arrangement::ArrangePolygon get_arrange_polygon() const;
|
||||
|
||||
// Apply the arrange result on the ModelInstance
|
||||
virtual void apply_arrange_result(Vec2d offs, double rot_rads, unsigned /*bed_num*/) override
|
||||
void apply_arrange_result(Vec2crd offs, double rot_rads)
|
||||
{
|
||||
// write the transformation data into the model instance
|
||||
set_rotation(Z, rot_rads);
|
||||
set_offset(X, offs(X));
|
||||
set_offset(Y, offs(Y));
|
||||
set_offset(X, unscale<double>(offs(X)));
|
||||
set_offset(Y, unscale<double>(offs(Y)));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue