mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-25 15:47:25 +08:00
Merge branch 'tm_arrange_bugfixes'
This commit is contained in:
commit
b0e5dda489
@ -167,6 +167,8 @@ struct NfpPConfig {
|
|||||||
const ItemGroup& // remaining items
|
const ItemGroup& // remaining items
|
||||||
)> before_packing;
|
)> before_packing;
|
||||||
|
|
||||||
|
std::function<void(const ItemGroup &, NfpPConfig &config)> on_preload;
|
||||||
|
|
||||||
NfpPConfig(): rotations({0.0, Pi/2.0, Pi, 3*Pi/2}),
|
NfpPConfig(): rotations({0.0, Pi/2.0, Pi, 3*Pi/2}),
|
||||||
alignment(Alignment::CENTER), starting_point(Alignment::CENTER) {}
|
alignment(Alignment::CENTER), starting_point(Alignment::CENTER) {}
|
||||||
};
|
};
|
||||||
@ -577,6 +579,12 @@ public:
|
|||||||
Base::clearItems();
|
Base::clearItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void preload(const ItemGroup& packeditems) {
|
||||||
|
Base::preload(packeditems);
|
||||||
|
if (config_.on_preload)
|
||||||
|
config_.on_preload(packeditems, config_);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
using Shapes = TMultiShape<RawShape>;
|
using Shapes = TMultiShape<RawShape>;
|
||||||
|
@ -109,6 +109,7 @@ void fill_config(PConf& pcfg, const ArrangeParams ¶ms) {
|
|||||||
|
|
||||||
// Apply penalty to object function result. This is used only when alignment
|
// Apply penalty to object function result. This is used only when alignment
|
||||||
// after arrange is explicitly disabled (PConfig::Alignment::DONT_ALIGN)
|
// after arrange is explicitly disabled (PConfig::Alignment::DONT_ALIGN)
|
||||||
|
// Also, this will only work well for Box shaped beds.
|
||||||
static double fixed_overfit(const std::tuple<double, Box>& result, const Box &binbb)
|
static double fixed_overfit(const std::tuple<double, Box>& result, const Box &binbb)
|
||||||
{
|
{
|
||||||
double score = std::get<0>(result);
|
double score = std::get<0>(result);
|
||||||
@ -348,6 +349,17 @@ public:
|
|||||||
|
|
||||||
m_pconf.object_function = get_objfn();
|
m_pconf.object_function = get_objfn();
|
||||||
|
|
||||||
|
m_pconf.on_preload = [this](const ItemGroup &items, PConfig &cfg) {
|
||||||
|
if (items.empty()) return;
|
||||||
|
|
||||||
|
cfg.alignment = PConfig::Alignment::DONT_ALIGN;
|
||||||
|
auto bb = sl::boundingBox(m_bin);
|
||||||
|
auto bbcenter = bb.center();
|
||||||
|
cfg.object_function = [this, bb, bbcenter](const Item &item) {
|
||||||
|
return fixed_overfit(objfunc(item, bbcenter), bb);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
auto on_packed = params.on_packed;
|
auto on_packed = params.on_packed;
|
||||||
|
|
||||||
if (progressind || on_packed)
|
if (progressind || on_packed)
|
||||||
@ -384,13 +396,6 @@ public:
|
|||||||
const PConfig& config() const { return m_pconf; }
|
const PConfig& config() const { return m_pconf; }
|
||||||
|
|
||||||
inline void preload(std::vector<Item>& fixeditems) {
|
inline void preload(std::vector<Item>& fixeditems) {
|
||||||
m_pconf.alignment = PConfig::Alignment::DONT_ALIGN;
|
|
||||||
auto bb = sl::boundingBox(m_bin);
|
|
||||||
auto bbcenter = bb.center();
|
|
||||||
m_pconf.object_function = [this, bb, bbcenter](const Item &item) {
|
|
||||||
return fixed_overfit(objfunc(item, bbcenter), bb);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build the rtree for queries to work
|
// Build the rtree for queries to work
|
||||||
|
|
||||||
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
||||||
@ -398,7 +403,6 @@ public:
|
|||||||
itm.markAsFixedInBin(itm.binId());
|
itm.markAsFixedInBin(itm.binId());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pck.configure(m_pconf);
|
|
||||||
m_item_count += fixeditems.size();
|
m_item_count += fixeditems.size();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -62,6 +62,15 @@ struct ArrangePolygon {
|
|||||||
|
|
||||||
/// Test if arrange() was called previously and gave a successful result.
|
/// Test if arrange() was called previously and gave a successful result.
|
||||||
bool is_arranged() const { return bed_idx != UNARRANGED; }
|
bool is_arranged() const { return bed_idx != UNARRANGED; }
|
||||||
|
|
||||||
|
inline ExPolygon transformed_poly() const
|
||||||
|
{
|
||||||
|
ExPolygon ret = poly;
|
||||||
|
ret.rotate(rotation);
|
||||||
|
ret.translate(translation.x(), translation.y());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using ArrangePolygons = std::vector<ArrangePolygon>;
|
using ArrangePolygons = std::vector<ArrangePolygon>;
|
||||||
|
@ -53,6 +53,9 @@ public:
|
|||||||
return point(0) >= this->min(0) && point(0) <= this->max(0)
|
return point(0) >= this->min(0) && point(0) <= this->max(0)
|
||||||
&& point(1) >= this->min(1) && point(1) <= this->max(1);
|
&& point(1) >= this->min(1) && point(1) <= this->max(1);
|
||||||
}
|
}
|
||||||
|
bool contains(const BoundingBoxBase<PointClass> &other) const {
|
||||||
|
return contains(other.min) && contains(other.max);
|
||||||
|
}
|
||||||
bool overlap(const BoundingBoxBase<PointClass> &other) const {
|
bool overlap(const BoundingBoxBase<PointClass> &other) const {
|
||||||
return ! (this->max(0) < other.min(0) || this->min(0) > other.max(0) ||
|
return ! (this->max(0) < other.min(0) || this->min(0) > other.max(0) ||
|
||||||
this->max(1) < other.min(1) || this->min(1) > other.max(1));
|
this->max(1) < other.min(1) || this->min(1) > other.max(1));
|
||||||
|
@ -29,7 +29,9 @@ void FillBedJob::prepare()
|
|||||||
for (ModelInstance *inst : model_object->instances)
|
for (ModelInstance *inst : model_object->instances)
|
||||||
if (inst->printable) {
|
if (inst->printable) {
|
||||||
ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater);
|
ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater);
|
||||||
++ap.priority; // need to be included in the result
|
// Existing objects need to be included in the result. Only
|
||||||
|
// the needed amount of object will be added, no more.
|
||||||
|
++ap.priority;
|
||||||
m_selected.emplace_back(ap);
|
m_selected.emplace_back(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,11 +40,18 @@ void FillBedJob::prepare()
|
|||||||
m_bedpts = get_bed_shape(*m_plater->config());
|
m_bedpts = get_bed_shape(*m_plater->config());
|
||||||
|
|
||||||
auto &objects = m_plater->model().objects;
|
auto &objects = m_plater->model().objects;
|
||||||
|
BoundingBox bedbb = get_extents(m_bedpts);
|
||||||
|
|
||||||
for (size_t idx = 0; idx < objects.size(); ++idx)
|
for (size_t idx = 0; idx < objects.size(); ++idx)
|
||||||
if (int(idx) != m_object_idx)
|
if (int(idx) != m_object_idx)
|
||||||
for (ModelInstance *mi : objects[idx]->instances) {
|
for (ModelInstance *mi : objects[idx]->instances) {
|
||||||
m_unselected.emplace_back(get_arrange_poly(PtrWrapper{mi}, m_plater));
|
ArrangePolygon ap = get_arrange_poly(PtrWrapper{mi}, m_plater);
|
||||||
m_unselected.back().bed_idx = 0;
|
auto ap_bb = ap.transformed_poly().contour.bounding_box();
|
||||||
|
|
||||||
|
if (ap.bed_idx == 0 && !bedbb.contains(ap_bb))
|
||||||
|
ap.bed_idx = arrangement::UNARRANGED;
|
||||||
|
|
||||||
|
m_unselected.emplace_back(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto wt = get_wipe_tower_arrangepoly(*m_plater))
|
if (auto wt = get_wipe_tower_arrangepoly(*m_plater))
|
||||||
@ -55,18 +64,17 @@ void FillBedJob::prepare()
|
|||||||
double unsel_area = std::accumulate(m_unselected.begin(),
|
double unsel_area = std::accumulate(m_unselected.begin(),
|
||||||
m_unselected.end(), 0.,
|
m_unselected.end(), 0.,
|
||||||
[](double s, const auto &ap) {
|
[](double s, const auto &ap) {
|
||||||
return s + ap.poly.area();
|
return s + (ap.bed_idx == 0) * ap.poly.area();
|
||||||
}) / sc;
|
}) / sc;
|
||||||
|
|
||||||
double fixed_area = unsel_area + m_selected.size() * poly_area;
|
double fixed_area = unsel_area + m_selected.size() * poly_area;
|
||||||
|
|
||||||
// This is the maximum range, the real number will always be close but less.
|
|
||||||
double bed_area = Polygon{m_bedpts}.area() / sc;
|
double bed_area = Polygon{m_bedpts}.area() / sc;
|
||||||
|
|
||||||
m_status_range = (bed_area - fixed_area) / poly_area;
|
// This is the maximum number of items, the real number will always be close but less.
|
||||||
|
int needed_items = (bed_area - fixed_area) / poly_area;
|
||||||
|
|
||||||
ModelInstance *mi = model_object->instances[0];
|
ModelInstance *mi = model_object->instances[0];
|
||||||
for (int i = 0; i < m_status_range; ++i) {
|
for (int i = 0; i < needed_items; ++i) {
|
||||||
ArrangePolygon ap;
|
ArrangePolygon ap;
|
||||||
ap.poly = m_selected.front().poly;
|
ap.poly = m_selected.front().poly;
|
||||||
ap.bed_idx = arrangement::UNARRANGED;
|
ap.bed_idx = arrangement::UNARRANGED;
|
||||||
@ -77,6 +85,14 @@ void FillBedJob::prepare()
|
|||||||
};
|
};
|
||||||
m_selected.emplace_back(ap);
|
m_selected.emplace_back(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_status_range = m_selected.size();
|
||||||
|
|
||||||
|
// The strides have to be removed from the fixed items. For the
|
||||||
|
// arrangeable (selected) items bed_idx is ignored and the
|
||||||
|
// translation is irrelevant.
|
||||||
|
double stride = bed_stride(m_plater);
|
||||||
|
for (auto &p : m_unselected) p.translation(X) -= p.bed_idx * stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillBedJob::process()
|
void FillBedJob::process()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user