Merge prusa 2.6.1

This commit is contained in:
QIDI TECH
2023-09-16 16:26:29 +08:00
parent 1338e60f8b
commit 963e22db99
203 changed files with 25254 additions and 6453 deletions

View File

@@ -0,0 +1,92 @@
#ifndef ARBITRARYDATASTORE_HPP
#define ARBITRARYDATASTORE_HPP
#include <string>
#include <map>
#include <any>
#include "libslic3r/Arrange/Core/DataStoreTraits.hpp"
namespace Slic3r { namespace arr2 {
// An associative container able to store and retrieve any data type.
// Based on std::any
class ArbitraryDataStore {
std::map<std::string, std::any> m_data;
public:
template<class T> void add(const std::string &key, T &&data)
{
m_data[key] = std::any{std::forward<T>(data)};
}
void add(const std::string &key, std::any &&data)
{
m_data[key] = std::move(data);
}
// Return nullptr if the key does not exist or the stored data has a
// type other then T. Otherwise returns a pointer to the stored data.
template<class T> const T *get(const std::string &key) const
{
auto it = m_data.find(key);
return it != m_data.end() ? std::any_cast<T>(&(it->second)) :
nullptr;
}
// Same as above just not const.
template<class T> T *get(const std::string &key)
{
auto it = m_data.find(key);
return it != m_data.end() ? std::any_cast<T>(&(it->second)) : nullptr;
}
bool has_key(const std::string &key) const
{
auto it = m_data.find(key);
return it != m_data.end();
}
};
// Some items can be containers of arbitrary data stored under string keys.
template<> struct DataStoreTraits_<ArbitraryDataStore>
{
static constexpr bool Implemented = true;
template<class T>
static const T *get(const ArbitraryDataStore &s, const std::string &key)
{
return s.get<T>(key);
}
// Same as above just not const.
template<class T>
static T *get(ArbitraryDataStore &s, const std::string &key)
{
return s.get<T>(key);
}
template<class T>
static bool has_key(ArbitraryDataStore &s, const std::string &key)
{
return s.has_key(key);
}
};
template<> struct WritableDataStoreTraits_<ArbitraryDataStore>
{
static constexpr bool Implemented = true;
template<class T>
static void set(ArbitraryDataStore &store,
const std::string &key,
T &&data)
{
store.add(key, std::forward<T>(data));
}
};
}} // namespace Slic3r::arr2
#endif // ARBITRARYDATASTORE_HPP

View File

@@ -0,0 +1,206 @@
#include "ArrangeItem.hpp"
#include "libslic3r/Arrange/Core/NFP/NFPConcave_Tesselate.hpp"
#include "libslic3r/Arrange/ArrangeImpl.hpp"
#include "libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp"
#include "libslic3r/Arrange/Tasks/FillBedTaskImpl.hpp"
#include "libslic3r/Arrange/Tasks/MultiplySelectionTaskImpl.hpp"
#include "libslic3r/Geometry/ConvexHull.hpp"
namespace Slic3r { namespace arr2 {
const Polygons &DecomposedShape::transformed_outline() const
{
constexpr auto sc = scaled<double>(1.) * scaled<double>(1.);
if (!m_transformed_outline_valid) {
m_transformed_outline = contours();
for (Polygon &poly : m_transformed_outline) {
poly.rotate(rotation());
poly.translate(translation());
}
m_area = std::accumulate(m_transformed_outline.begin(),
m_transformed_outline.end(), 0.,
[sc](double s, const auto &p) {
return s + p.area() / sc;
});
m_convex_hull = Geometry::convex_hull(m_transformed_outline);
m_bounding_box = get_extents(m_convex_hull);
m_transformed_outline_valid = true;
}
return m_transformed_outline;
}
const Polygon &DecomposedShape::convex_hull() const
{
if (!m_transformed_outline_valid)
transformed_outline();
return m_convex_hull;
}
const BoundingBox &DecomposedShape::bounding_box() const
{
if (!m_transformed_outline_valid)
transformed_outline();
return m_bounding_box;
}
const Vec2crd &DecomposedShape::reference_vertex() const
{
if (!m_reference_vertex_valid) {
m_reference_vertex = Slic3r::reference_vertex(transformed_outline());
m_refs.clear();
m_mins.clear();
m_refs.reserve(m_transformed_outline.size());
m_mins.reserve(m_transformed_outline.size());
for (auto &poly : m_transformed_outline) {
m_refs.emplace_back(Slic3r::reference_vertex(poly));
m_mins.emplace_back(Slic3r::min_vertex(poly));
}
m_reference_vertex_valid = true;
}
return m_reference_vertex;
}
const Vec2crd &DecomposedShape::reference_vertex(size_t i) const
{
if (!m_reference_vertex_valid) {
reference_vertex();
}
return m_refs[i];
}
const Vec2crd &DecomposedShape::min_vertex(size_t idx) const
{
if (!m_reference_vertex_valid) {
reference_vertex();
}
return m_mins[idx];
}
Vec2crd DecomposedShape::centroid() const
{
constexpr double area_sc = scaled<double>(1.) * scaled(1.);
if (!m_centroid_valid) {
double total_area = 0.0;
Vec2d cntr = Vec2d::Zero();
for (const Polygon& poly : transformed_outline()) {
double parea = poly.area() / area_sc;
Vec2d pcntr = unscaled(poly.centroid());
total_area += parea;
cntr += pcntr * parea;
}
cntr /= total_area;
m_centroid = scaled(cntr);
m_centroid_valid = true;
}
return m_centroid;
}
DecomposedShape decompose(const ExPolygons &shape)
{
return DecomposedShape{convex_decomposition_tess(shape)};
}
DecomposedShape decompose(const Polygon &shape)
{
Polygons convex_shapes;
bool is_convex = polygon_is_convex(shape);
if (is_convex) {
convex_shapes.emplace_back(shape);
} else {
convex_shapes = convex_decomposition_tess(shape);
}
return DecomposedShape{std::move(convex_shapes)};
}
ArrangeItem::ArrangeItem(const ExPolygons &shape)
: m_shape{decompose(shape)}, m_envelope{&m_shape}
{}
ArrangeItem::ArrangeItem(Polygon shape)
: m_shape{decompose(shape)}, m_envelope{&m_shape}
{}
ArrangeItem::ArrangeItem(const ArrangeItem &other)
{
this->operator= (other);
}
ArrangeItem::ArrangeItem(ArrangeItem &&other) noexcept
{
this->operator=(std::move(other));
}
ArrangeItem &ArrangeItem::operator=(const ArrangeItem &other)
{
m_shape = other.m_shape;
m_datastore = other.m_datastore;
m_bed_idx = other.m_bed_idx;
m_priority = other.m_priority;
if (other.m_envelope.get() == &other.m_shape)
m_envelope = &m_shape;
else
m_envelope = std::make_unique<DecomposedShape>(other.envelope());
return *this;
}
void ArrangeItem::set_shape(DecomposedShape shape)
{
m_shape = std::move(shape);
m_envelope = &m_shape;
}
void ArrangeItem::set_envelope(DecomposedShape envelope)
{
m_envelope = std::make_unique<DecomposedShape>(std::move(envelope));
// Initial synch of transformations of envelope and shape.
// They need to be in synch all the time
m_envelope->translation(m_shape.translation());
m_envelope->rotation(m_shape.rotation());
}
ArrangeItem &ArrangeItem::operator=(ArrangeItem &&other) noexcept
{
m_shape = std::move(other.m_shape);
m_datastore = std::move(other.m_datastore);
m_bed_idx = other.m_bed_idx;
m_priority = other.m_priority;
if (other.m_envelope.get() == &other.m_shape)
m_envelope = &m_shape;
else
m_envelope = std::move(other.m_envelope);
return *this;
}
template struct ImbueableItemTraits_<ArrangeItem>;
template class ArrangeableToItemConverter<ArrangeItem>;
template struct ArrangeTask<ArrangeItem>;
template struct FillBedTask<ArrangeItem>;
template struct MultiplySelectionTask<ArrangeItem>;
template class Arranger<ArrangeItem>;
}} // namespace Slic3r::arr2

View File

@@ -0,0 +1,481 @@
#ifndef ARRANGEITEM_HPP
#define ARRANGEITEM_HPP
#include <optional>
#include <boost/variant.hpp>
#include "libslic3r/ExPolygon.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/AnyPtr.hpp"
#include "libslic3r/Arrange/Core/PackingContext.hpp"
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
#include "libslic3r/Arrange/Core/NFP/NFP.hpp"
#include "libslic3r/Arrange/Items/MutableItemTraits.hpp"
#include "libslic3r/Arrange/Arrange.hpp"
#include "libslic3r/Arrange/Tasks/ArrangeTask.hpp"
#include "libslic3r/Arrange/Tasks/FillBedTask.hpp"
#include "libslic3r/Arrange/Tasks/MultiplySelectionTask.hpp"
#include "libslic3r/Arrange/Items/ArbitraryDataStore.hpp"
#include <libslic3r/ClipperUtils.hpp>
namespace Slic3r { namespace arr2 {
inline bool check_polygons_are_convex(const Polygons &pp) {
return std::all_of(pp.begin(), pp.end(), [](const Polygon &p) {
return polygon_is_convex(p);
});
}
// A class that stores a set of polygons that are garanteed to be all convex.
// They collectively represent a decomposition of a more complex shape into
// its convex part. Note that this class only stores the result of the decomp,
// does not do the job itself. In debug mode, an explicit check is done for
// each component to be convex.
//
// Additionally class stores a translation vector and a rotation angle for the
// stored polygon, plus additional privitives that are all cached cached after
// appying a the transformations. The caching is not thread safe!
class DecomposedShape
{
Polygons m_shape;
Vec2crd m_translation{0, 0}; // The translation of the poly
double m_rotation{0.0}; // The rotation of the poly in radians
mutable Polygons m_transformed_outline;
mutable bool m_transformed_outline_valid = false;
mutable Point m_reference_vertex;
mutable std::vector<Point> m_refs;
mutable std::vector<Point> m_mins;
mutable bool m_reference_vertex_valid = false;
mutable Point m_centroid;
mutable bool m_centroid_valid = false;
mutable Polygon m_convex_hull;
mutable BoundingBox m_bounding_box;
mutable double m_area = 0;
public:
DecomposedShape() = default;
explicit DecomposedShape(Polygon sh)
{
m_shape.emplace_back(std::move(sh));
assert(check_polygons_are_convex(m_shape));
}
explicit DecomposedShape(std::initializer_list<Point> pts)
: DecomposedShape(Polygon{pts})
{}
explicit DecomposedShape(Polygons sh) : m_shape{std::move(sh)}
{
assert(check_polygons_are_convex(m_shape));
}
const Polygons &contours() const { return m_shape; }
const Vec2crd &translation() const { return m_translation; }
double rotation() const { return m_rotation; }
void translation(const Vec2crd &v)
{
m_translation = v;
m_transformed_outline_valid = false;
m_reference_vertex_valid = false;
m_centroid_valid = false;
}
void rotation(double v)
{
m_rotation = v;
m_transformed_outline_valid = false;
m_reference_vertex_valid = false;
m_centroid_valid = false;
}
const Polygons &transformed_outline() const;
const Polygon &convex_hull() const;
const BoundingBox &bounding_box() const;
// The cached reference vertex in the context of NFP creation. Always
// refers to the leftmost upper vertex.
const Vec2crd &reference_vertex() const;
const Vec2crd &reference_vertex(size_t idx) const;
// Also for NFP calculations, the rightmost lowest vertex of the shape.
const Vec2crd &min_vertex(size_t idx) const;
double area_unscaled() const
{
// update cache
transformed_outline();
return m_area;
}
Vec2crd centroid() const;
};
DecomposedShape decompose(const ExPolygons &polys);
DecomposedShape decompose(const Polygon &p);
class ArrangeItem
{
private:
DecomposedShape m_shape; // Shape of item when it's not moving
AnyPtr<DecomposedShape> m_envelope; // Possibly different shape when packed
ArbitraryDataStore m_datastore;
int m_bed_idx{Unarranged}; // To which logical bed does this item belong
int m_priority{0}; // For sorting
public:
ArrangeItem() = default;
explicit ArrangeItem(DecomposedShape shape)
: m_shape(std::move(shape)), m_envelope{&m_shape}
{}
explicit ArrangeItem(DecomposedShape shape, DecomposedShape envelope)
: m_shape(std::move(shape))
, m_envelope{std::make_unique<DecomposedShape>(std::move(envelope))}
{}
explicit ArrangeItem(const ExPolygons &shape);
explicit ArrangeItem(Polygon shape);
explicit ArrangeItem(std::initializer_list<Point> pts)
: ArrangeItem(Polygon{pts})
{}
ArrangeItem(const ArrangeItem &);
ArrangeItem(ArrangeItem &&) noexcept;
ArrangeItem & operator=(const ArrangeItem &);
ArrangeItem & operator=(ArrangeItem &&) noexcept;
int bed_idx() const { return m_bed_idx; }
int priority() const { return m_priority; }
void bed_idx(int v) { m_bed_idx = v; }
void priority(int v) { m_priority = v; }
const ArbitraryDataStore &datastore() const { return m_datastore; }
ArbitraryDataStore &datastore() { return m_datastore; }
const DecomposedShape & shape() const { return m_shape; }
void set_shape(DecomposedShape shape);
const DecomposedShape & envelope() const { return *m_envelope; }
void set_envelope(DecomposedShape envelope);
const Vec2crd &translation() const { return m_shape.translation(); }
double rotation() const { return m_shape.rotation(); }
void translation(const Vec2crd &v)
{
m_shape.translation(v);
m_envelope->translation(v);
}
void rotation(double v)
{
m_shape.rotation(v);
m_envelope->rotation(v);
}
void update_caches() const
{
m_shape.reference_vertex();
m_envelope->reference_vertex();
m_shape.centroid();
m_envelope->centroid();
}
};
template<> struct ArrangeItemTraits_<ArrangeItem>
{
static const Vec2crd &get_translation(const ArrangeItem &itm)
{
return itm.translation();
}
static double get_rotation(const ArrangeItem &itm)
{
return itm.rotation();
}
static int get_bed_index(const ArrangeItem &itm)
{
return itm.bed_idx();
}
static int get_priority(const ArrangeItem &itm)
{
return itm.priority();
}
// Setters:
static void set_translation(ArrangeItem &itm, const Vec2crd &v)
{
itm.translation(v);
}
static void set_rotation(ArrangeItem &itm, double v)
{
itm.rotation(v);
}
static void set_bed_index(ArrangeItem &itm, int v)
{
itm.bed_idx(v);
}
};
// Some items can be containers of arbitrary data stored under string keys.
template<> struct DataStoreTraits_<ArrangeItem>
{
static constexpr bool Implemented = true;
template<class T>
static const T *get(const ArrangeItem &itm, const std::string &key)
{
return itm.datastore().get<T>(key);
}
// Same as above just not const.
template<class T>
static T *get(ArrangeItem &itm, const std::string &key)
{
return itm.datastore().get<T>(key);
}
static bool has_key(const ArrangeItem &itm, const std::string &key)
{
return itm.datastore().has_key(key);
}
};
template<> struct WritableDataStoreTraits_<ArrangeItem>
{
static constexpr bool Implemented = true;
template<class T>
static void set(ArrangeItem &itm,
const std::string &key,
T &&data)
{
itm.datastore().add(key, std::forward<T>(data));
}
};
template<class FixedIt, class StopCond = DefaultStopCondition>
static Polygons calculate_nfp_unnormalized(const ArrangeItem &item,
const Range<FixedIt> &fixed_items,
StopCond &&stop_cond = {})
{
size_t cap = 0;
for (const ArrangeItem &fixitem : fixed_items) {
const Polygons &outlines = fixitem.shape().transformed_outline();
cap += outlines.size();
}
const Polygons &item_outlines = item.envelope().transformed_outline();
auto nfps = reserve_polygons(cap * item_outlines.size());
Vec2crd ref_whole = item.envelope().reference_vertex();
Polygon subnfp;
for (const ArrangeItem &fixed : fixed_items) {
// fixed_polys should already be a set of strictly convex polygons,
// as ArrangeItem stores convex-decomposed polygons
const Polygons & fixed_polys = fixed.shape().transformed_outline();
for (const Polygon &fixed_poly : fixed_polys) {
Point max_fixed = Slic3r::reference_vertex(fixed_poly);
for (size_t mi = 0; mi < item_outlines.size(); ++mi) {
const Polygon &movable = item_outlines[mi];
const Vec2crd &mref = item.envelope().reference_vertex(mi);
subnfp = nfp_convex_convex_legacy(fixed_poly, movable);
Vec2crd min_movable = item.envelope().min_vertex(mi);
Vec2crd dtouch = max_fixed - min_movable;
Vec2crd top_other = mref + dtouch;
Vec2crd max_nfp = Slic3r::reference_vertex(subnfp);
auto dnfp = top_other - max_nfp;
auto d = ref_whole - mref + dnfp;
subnfp.translate(d);
nfps.emplace_back(subnfp);
}
if (stop_cond())
break;
nfps = union_(nfps);
}
if (stop_cond()) {
nfps.clear();
break;
}
}
return nfps;
}
template<> struct NFPArrangeItemTraits_<ArrangeItem> {
template<class Context, class Bed, class StopCond>
static ExPolygons calculate_nfp(const ArrangeItem &item,
const Context &packing_context,
const Bed &bed,
StopCond &&stopcond)
{
auto static_items = all_items_range(packing_context);
Polygons nfps = arr2::calculate_nfp_unnormalized(item, static_items, stopcond);
ExPolygons nfp_ex;
if (!stopcond()) {
if constexpr (!std::is_convertible_v<Bed, InfiniteBed>) {
ExPolygons ifpbed = ifp_convex(bed, item.envelope().convex_hull());
nfp_ex = diff_ex(ifpbed, nfps);
} else {
nfp_ex = union_ex(nfps);
}
}
item.update_caches();
return nfp_ex;
}
static const Vec2crd& reference_vertex(const ArrangeItem &item)
{
return item.envelope().reference_vertex();
}
static BoundingBox envelope_bounding_box(const ArrangeItem &itm)
{
return itm.envelope().bounding_box();
}
static BoundingBox fixed_bounding_box(const ArrangeItem &itm)
{
return itm.shape().bounding_box();
}
static double envelope_area(const ArrangeItem &itm)
{
return itm.envelope().area_unscaled() * scaled<double>(1.) *
scaled<double>(1.);
}
static double fixed_area(const ArrangeItem &itm)
{
return itm.shape().area_unscaled() * scaled<double>(1.) *
scaled<double>(1.);
}
static const Polygons & envelope_outline(const ArrangeItem &itm)
{
return itm.envelope().transformed_outline();
}
static const Polygons & fixed_outline(const ArrangeItem &itm)
{
return itm.shape().transformed_outline();
}
static const Polygon & envelope_convex_hull(const ArrangeItem &itm)
{
return itm.envelope().convex_hull();
}
static const Polygon & fixed_convex_hull(const ArrangeItem &itm)
{
return itm.shape().convex_hull();
}
static const std::vector<double>& allowed_rotations(const ArrangeItem &itm)
{
static const std::vector<double> ret_zero = {0.};
const std::vector<double> * ret_ptr = &ret_zero;
auto rots = get_data<std::vector<double>>(itm, "rotations");
if (rots) {
ret_ptr = rots;
}
return *ret_ptr;
}
static Vec2crd fixed_centroid(const ArrangeItem &itm)
{
return itm.shape().centroid();
}
static Vec2crd envelope_centroid(const ArrangeItem &itm)
{
return itm.envelope().centroid();
}
};
template<> struct IsMutableItem_<ArrangeItem>: public std::true_type {};
template<>
struct MutableItemTraits_<ArrangeItem> {
static void set_priority(ArrangeItem &itm, int p) { itm.priority(p); }
static void set_convex_shape(ArrangeItem &itm, const Polygon &shape)
{
itm.set_shape(DecomposedShape{shape});
}
static void set_shape(ArrangeItem &itm, const ExPolygons &shape)
{
itm.set_shape(decompose(shape));
}
static void set_convex_envelope(ArrangeItem &itm, const Polygon &envelope)
{
itm.set_envelope(DecomposedShape{envelope});
}
static void set_envelope(ArrangeItem &itm, const ExPolygons &envelope)
{
itm.set_envelope(decompose(envelope));
}
template<class T>
static void set_arbitrary_data(ArrangeItem &itm, const std::string &key, T &&data)
{
set_data(itm, key, std::forward<T>(data));
}
static void set_allowed_rotations(ArrangeItem &itm, const std::vector<double> &rotations)
{
set_data(itm, "rotations", rotations);
}
};
extern template struct ImbueableItemTraits_<ArrangeItem>;
extern template class ArrangeableToItemConverter<ArrangeItem>;
extern template struct ArrangeTask<ArrangeItem>;
extern template struct FillBedTask<ArrangeItem>;
extern template struct MultiplySelectionTask<ArrangeItem>;
extern template class Arranger<ArrangeItem>;
}} // namespace Slic3r::arr2
#endif // ARRANGEITEM_HPP

View File

@@ -0,0 +1,137 @@
#ifndef MutableItemTraits_HPP
#define MutableItemTraits_HPP
#include "libslic3r/Arrange/Core/ArrangeItemTraits.hpp"
#include "libslic3r/Arrange/Core/DataStoreTraits.hpp"
#include "libslic3r/ExPolygon.hpp"
namespace Slic3r { namespace arr2 {
template<class Itm> struct IsMutableItem_ : public std::false_type
{};
// Using this interface to set up any arrange item. Provides default
// implementation but it needs to be explicitly switched on with
// IsMutableItem_ or completely reimplement a specialization.
template<class Itm, class En = void> struct MutableItemTraits_
{
static_assert(IsMutableItem_<Itm>::value, "Not a Writable item type!");
static void set_priority(Itm &itm, int p) { itm.set_priority(p); }
static void set_convex_shape(Itm &itm, const Polygon &shape)
{
itm.set_convex_shape(shape);
}
static void set_shape(Itm &itm, const ExPolygons &shape)
{
itm.set_shape(shape);
}
static void set_convex_envelope(Itm &itm, const Polygon &envelope)
{
itm.set_convex_envelope(envelope);
}
static void set_envelope(Itm &itm, const ExPolygons &envelope)
{
itm.set_envelope(envelope);
}
template<class T>
static void set_arbitrary_data(Itm &itm, const std::string &key, T &&data)
{
if constexpr (IsWritableDataStore<Itm>)
set_data(itm, key, std::forward<T>(data));
}
static void set_allowed_rotations(Itm &itm,
const std::vector<double> &rotations)
{
itm.set_allowed_rotations(rotations);
}
};
template<class T>
using MutableItemTraits = MutableItemTraits_<StripCVRef<T>>;
template<class T> constexpr bool IsMutableItem = IsMutableItem_<T>::value;
template<class T, class TT = T>
using MutableItemOnly = std::enable_if_t<IsMutableItem<T>, TT>;
template<class Itm> void set_priority(Itm &itm, int p)
{
MutableItemTraits<Itm>::set_priority(itm, p);
}
template<class Itm> void set_convex_shape(Itm &itm, const Polygon &shape)
{
MutableItemTraits<Itm>::set_convex_shape(itm, shape);
}
template<class Itm> void set_shape(Itm &itm, const ExPolygons &shape)
{
MutableItemTraits<Itm>::set_shape(itm, shape);
}
template<class Itm>
void set_convex_envelope(Itm &itm, const Polygon &envelope)
{
MutableItemTraits<Itm>::set_convex_envelope(itm, envelope);
}
template<class Itm> void set_envelope(Itm &itm, const ExPolygons &envelope)
{
MutableItemTraits<Itm>::set_envelope(itm, envelope);
}
template<class T, class Itm>
void set_arbitrary_data(Itm &itm, const std::string &key, T &&data)
{
MutableItemTraits<Itm>::set_arbitrary_data(itm, key, std::forward<T>(data));
}
template<class Itm>
void set_allowed_rotations(Itm &itm, const std::vector<double> &rotations)
{
MutableItemTraits<Itm>::set_allowed_rotations(itm, rotations);
}
template<class ArrItem> int raise_priority(ArrItem &itm)
{
int ret = get_priority(itm) + 1;
set_priority(itm, ret);
return ret;
}
template<class ArrItem> int reduce_priority(ArrItem &itm)
{
int ret = get_priority(itm) - 1;
set_priority(itm, ret);
return ret;
}
template<class It> int lowest_priority(const Range<It> &item_range)
{
auto minp_it = std::min_element(item_range.begin(),
item_range.end(),
[](auto &itm1, auto &itm2) {
return get_priority(itm1) <
get_priority(itm2);
});
int min_priority = 0;
if (minp_it != item_range.end())
min_priority = get_priority(*minp_it);
return min_priority;
}
}} // namespace Slic3r::arr2
#endif // MutableItemTraits_HPP

View File

@@ -0,0 +1,25 @@
#include "SimpleArrangeItem.hpp"
#include "libslic3r/Arrange/ArrangeImpl.hpp"
#include "libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp"
#include "libslic3r/Arrange/Tasks/FillBedTaskImpl.hpp"
#include "libslic3r/Arrange/Tasks/MultiplySelectionTaskImpl.hpp"
namespace Slic3r { namespace arr2 {
Polygon SimpleArrangeItem::outline() const
{
Polygon ret = shape();
ret.rotate(m_rotation);
ret.translate(m_translation);
return ret;
}
template class ArrangeableToItemConverter<SimpleArrangeItem>;
template struct ArrangeTask<SimpleArrangeItem>;
template struct FillBedTask<SimpleArrangeItem>;
template struct MultiplySelectionTask<SimpleArrangeItem>;
template class Arranger<SimpleArrangeItem>;
}} // namespace Slic3r::arr2

View File

@@ -0,0 +1,219 @@
#ifndef SIMPLEARRANGEITEM_HPP
#define SIMPLEARRANGEITEM_HPP
#include "libslic3r/Arrange/Core/PackingContext.hpp"
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
#include "libslic3r/Arrange/Core/NFP/NFP.hpp"
#include "libslic3r/Arrange/Arrange.hpp"
#include "libslic3r/Arrange/Tasks/ArrangeTask.hpp"
#include "libslic3r/Arrange/Tasks/FillBedTask.hpp"
#include "libslic3r/Arrange/Tasks/MultiplySelectionTask.hpp"
#include "libslic3r/Polygon.hpp"
#include "libslic3r/Geometry/ConvexHull.hpp"
#include "MutableItemTraits.hpp"
namespace Slic3r { namespace arr2 {
class SimpleArrangeItem {
Polygon m_shape;
Vec2crd m_translation = Vec2crd::Zero();
double m_rotation = 0.;
int m_priority = 0;
int m_bed_idx = Unarranged;
std::vector<double> m_allowed_rotations = {0.};
ObjectID m_obj_id;
public:
explicit SimpleArrangeItem(Polygon chull = {}): m_shape{std::move(chull)} {}
void set_shape(Polygon chull) { m_shape = std::move(chull); }
const Vec2crd& get_translation() const noexcept { return m_translation; }
double get_rotation() const noexcept { return m_rotation; }
int get_priority() const noexcept { return m_priority; }
int get_bed_index() const noexcept { return m_bed_idx; }
void set_translation(const Vec2crd &v) { m_translation = v; }
void set_rotation(double v) noexcept { m_rotation = v; }
void set_priority(int v) noexcept { m_priority = v; }
void set_bed_index(int v) noexcept { m_bed_idx = v; }
const Polygon &shape() const { return m_shape; }
Polygon outline() const;
const auto &allowed_rotations() const noexcept
{
return m_allowed_rotations;
}
void set_allowed_rotations(std::vector<double> rots)
{
m_allowed_rotations = std::move(rots);
}
void set_object_id(const ObjectID &id) noexcept { m_obj_id = id; }
const ObjectID & get_object_id() const noexcept { return m_obj_id; }
};
template<> struct NFPArrangeItemTraits_<SimpleArrangeItem>
{
template<class Context, class Bed, class StopCond>
static ExPolygons calculate_nfp(const SimpleArrangeItem &item,
const Context &packing_context,
const Bed &bed,
StopCond &&stop_cond)
{
auto fixed_items = all_items_range(packing_context);
auto nfps = reserve_polygons(fixed_items.size());
for (const SimpleArrangeItem &fixed_part : fixed_items) {
Polygon subnfp = nfp_convex_convex_legacy(fixed_part.outline(),
item.outline());
nfps.emplace_back(subnfp);
if (stop_cond()) {
nfps.clear();
break;
}
}
ExPolygons nfp_ex;
if (!stop_cond()) {
if constexpr (!std::is_convertible_v<Bed, InfiniteBed>) {
ExPolygons ifpbed = ifp_convex(bed, item.outline());
nfp_ex = diff_ex(ifpbed, nfps);
} else {
nfp_ex = union_ex(nfps);
}
}
return nfp_ex;
}
static Vec2crd reference_vertex(const SimpleArrangeItem &item)
{
return Slic3r::reference_vertex(item.outline());
}
static BoundingBox envelope_bounding_box(const SimpleArrangeItem &itm)
{
return get_extents(itm.outline());
}
static BoundingBox fixed_bounding_box(const SimpleArrangeItem &itm)
{
return get_extents(itm.outline());
}
static Polygons envelope_outline(const SimpleArrangeItem &itm)
{
return {itm.outline()};
}
static Polygons fixed_outline(const SimpleArrangeItem &itm)
{
return {itm.outline()};
}
static Polygon envelope_convex_hull(const SimpleArrangeItem &itm)
{
return Geometry::convex_hull(itm.outline());
}
static Polygon fixed_convex_hull(const SimpleArrangeItem &itm)
{
return Geometry::convex_hull(itm.outline());
}
static double envelope_area(const SimpleArrangeItem &itm)
{
return itm.shape().area();
}
static double fixed_area(const SimpleArrangeItem &itm)
{
return itm.shape().area();
}
static const auto& allowed_rotations(const SimpleArrangeItem &itm) noexcept
{
return itm.allowed_rotations();
}
static Vec2crd fixed_centroid(const SimpleArrangeItem &itm) noexcept
{
return itm.outline().centroid();
}
static Vec2crd envelope_centroid(const SimpleArrangeItem &itm) noexcept
{
return itm.outline().centroid();
}
};
template<> struct IsMutableItem_<SimpleArrangeItem>: public std::true_type {};
template<>
struct MutableItemTraits_<SimpleArrangeItem> {
static void set_priority(SimpleArrangeItem &itm, int p) { itm.set_priority(p); }
static void set_convex_shape(SimpleArrangeItem &itm, const Polygon &shape)
{
itm.set_shape(shape);
}
static void set_shape(SimpleArrangeItem &itm, const ExPolygons &shape)
{
itm.set_shape(Geometry::convex_hull(shape));
}
static void set_convex_envelope(SimpleArrangeItem &itm, const Polygon &envelope)
{
itm.set_shape(envelope);
}
static void set_envelope(SimpleArrangeItem &itm, const ExPolygons &envelope)
{
itm.set_shape(Geometry::convex_hull(envelope));
}
template<class T>
static void set_data(SimpleArrangeItem &itm, const std::string &key, T &&data)
{}
static void set_allowed_rotations(SimpleArrangeItem &itm, const std::vector<double> &rotations)
{
itm.set_allowed_rotations(rotations);
}
};
template<> struct ImbueableItemTraits_<SimpleArrangeItem>
{
static void imbue_id(SimpleArrangeItem &itm, const ObjectID &id)
{
itm.set_object_id(id);
}
static std::optional<ObjectID> retrieve_id(const SimpleArrangeItem &itm)
{
std::optional<ObjectID> ret;
if (itm.get_object_id().valid())
ret = itm.get_object_id();
return ret;
}
};
extern template class ArrangeableToItemConverter<SimpleArrangeItem>;
extern template struct ArrangeTask<SimpleArrangeItem>;
extern template struct FillBedTask<SimpleArrangeItem>;
extern template struct MultiplySelectionTask<SimpleArrangeItem>;
extern template class Arranger<SimpleArrangeItem>;
}} // namespace Slic3r::arr2
#endif // SIMPLEARRANGEITEM_HPP

View File

@@ -0,0 +1,80 @@
#ifndef TRAFOONLYARRANGEITEM_HPP
#define TRAFOONLYARRANGEITEM_HPP
#include "libslic3r/Arrange/Core/ArrangeItemTraits.hpp"
#include "libslic3r/Arrange/Items/ArbitraryDataStore.hpp"
#include "libslic3r/Arrange/Items/MutableItemTraits.hpp"
namespace Slic3r { namespace arr2 {
class TrafoOnlyArrangeItem {
int m_bed_idx = Unarranged;
int m_priority = 0;
Vec2crd m_translation = Vec2crd::Zero();
double m_rotation = 0.;
ArbitraryDataStore m_datastore;
public:
TrafoOnlyArrangeItem() = default;
template<class ArrItm>
explicit TrafoOnlyArrangeItem(const ArrItm &other)
: m_bed_idx{arr2::get_bed_index(other)},
m_priority{arr2::get_priority(other)},
m_translation(arr2::get_translation(other)),
m_rotation{arr2::get_rotation(other)}
{}
const Vec2crd& get_translation() const noexcept { return m_translation; }
double get_rotation() const noexcept { return m_rotation; }
int get_bed_index() const noexcept { return m_bed_idx; }
int get_priority() const noexcept { return m_priority; }
const ArbitraryDataStore &datastore() const noexcept { return m_datastore; }
ArbitraryDataStore &datastore() { return m_datastore; }
};
template<> struct DataStoreTraits_<TrafoOnlyArrangeItem>
{
static constexpr bool Implemented = true;
template<class T>
static const T *get(const TrafoOnlyArrangeItem &itm, const std::string &key)
{
return itm.datastore().get<T>(key);
}
template<class T>
static T *get(TrafoOnlyArrangeItem &itm, const std::string &key)
{
return itm.datastore().get<T>(key);
}
static bool has_key(const TrafoOnlyArrangeItem &itm, const std::string &key)
{
return itm.datastore().has_key(key);
}
};
template<> struct IsMutableItem_<TrafoOnlyArrangeItem>: public std::true_type {};
template<> struct WritableDataStoreTraits_<TrafoOnlyArrangeItem>
{
static constexpr bool Implemented = true;
template<class T>
static void set(TrafoOnlyArrangeItem &itm,
const std::string &key,
T &&data)
{
set_data(itm.datastore(), key, std::forward<T>(data));
}
};
} // namespace arr2
} // namespace Slic3r
#endif // TRAFOONLYARRANGEITEM_HPP