Abort semantics added.
Signed-off-by: tamasmeszaros <meszaros.q@gmail.com>
This commit is contained in:
parent
6e2ed48e5a
commit
6106ce9ff0
@ -640,6 +640,7 @@ public:
|
||||
|
||||
// The progress function will be called with the number of placed items
|
||||
using ProgressFunction = std::function<void(unsigned)>;
|
||||
using StopCondition = std::function<bool(void)>;
|
||||
|
||||
/**
|
||||
* A wrapper interface (trait) class for any selections strategy provider.
|
||||
@ -674,6 +675,8 @@ public:
|
||||
*/
|
||||
void progressIndicator(ProgressFunction fn) { impl_.progressIndicator(fn); }
|
||||
|
||||
void stopCondition(StopCondition cond) { impl_.stopCondition(cond); }
|
||||
|
||||
/**
|
||||
* \brief A method to start the calculation on the input sequence.
|
||||
*
|
||||
@ -864,6 +867,11 @@ public:
|
||||
selector_.progressIndicator(func); return *this;
|
||||
}
|
||||
|
||||
/// Set a predicate to tell when to abort nesting.
|
||||
inline Nester& stopCondition(StopCondition fn) {
|
||||
selector_.stopCondition(fn); return *this;
|
||||
}
|
||||
|
||||
inline PackGroup lastResult() {
|
||||
PackGroup ret;
|
||||
for(size_t i = 0; i < selector_.binCount(); i++) {
|
||||
|
@ -551,7 +551,7 @@ public:
|
||||
// Safety test: try to pack each item into an empty bin. If it fails
|
||||
// then it should be removed from the not_packed list
|
||||
{ auto it = store_.begin();
|
||||
while (it != store_.end()) {
|
||||
while (it != store_.end() && !this->stopcond_()) {
|
||||
Placer p(bin); p.configure(pconfig);
|
||||
if(!p.pack(*it, rem(it, store_))) {
|
||||
it = store_.erase(it);
|
||||
@ -592,9 +592,11 @@ public:
|
||||
|
||||
bool do_pairs = config_.try_pairs;
|
||||
bool do_triplets = config_.try_triplets;
|
||||
StopCondition stopcond = this->stopcond_;
|
||||
|
||||
// The DJD heuristic algorithm itself:
|
||||
auto packjob = [INITIAL_FILL_AREA, bin_area, w, do_triplets, do_pairs,
|
||||
stopcond,
|
||||
&tryOneByOne,
|
||||
&tryGroupsOfTwo,
|
||||
&tryGroupsOfThree,
|
||||
@ -606,12 +608,12 @@ public:
|
||||
double waste = .0;
|
||||
bool lasttry = false;
|
||||
|
||||
while(!not_packed.empty()) {
|
||||
while(!not_packed.empty() && !stopcond()) {
|
||||
|
||||
{// Fill the bin up to INITIAL_FILL_PROPORTION of its capacity
|
||||
auto it = not_packed.begin();
|
||||
|
||||
while(it != not_packed.end() &&
|
||||
while(it != not_packed.end() && !stopcond() &&
|
||||
filled_area < INITIAL_FILL_AREA)
|
||||
{
|
||||
if(placer.pack(*it, rem(it, not_packed))) {
|
||||
@ -623,14 +625,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// try pieses one by one
|
||||
// try pieces one by one
|
||||
while(tryOneByOne(placer, not_packed, waste, free_area,
|
||||
filled_area)) {
|
||||
waste = 0; lasttry = false;
|
||||
makeProgress(placer, idx, 1);
|
||||
}
|
||||
|
||||
// try groups of 2 pieses
|
||||
// try groups of 2 pieces
|
||||
while(do_pairs &&
|
||||
tryGroupsOfTwo(placer, not_packed, waste, free_area,
|
||||
filled_area)) {
|
||||
@ -638,7 +640,7 @@ public:
|
||||
makeProgress(placer, idx, 2);
|
||||
}
|
||||
|
||||
// try groups of 3 pieses
|
||||
// try groups of 3 pieces
|
||||
while(do_triplets &&
|
||||
tryGroupsOfThree(placer, not_packed, waste, free_area,
|
||||
filled_area)) {
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
placer.configure(pconfig);
|
||||
|
||||
auto it = store_.begin();
|
||||
while(it != store_.end()) {
|
||||
while(it != store_.end() && !this->stopcond_()) {
|
||||
if(!placer.pack(*it, {std::next(it), store_.end()})) {
|
||||
if(packed_bins_.back().empty()) ++it;
|
||||
placer.clearItems();
|
||||
|
@ -56,10 +56,12 @@ public:
|
||||
this->progress_(static_cast<unsigned>(--total));
|
||||
};
|
||||
|
||||
auto& cancelled = this->stopcond_;
|
||||
|
||||
// Safety test: try to pack each item into an empty bin. If it fails
|
||||
// then it should be removed from the list
|
||||
{ auto it = store_.begin();
|
||||
while (it != store_.end()) {
|
||||
while (it != store_.end() && !cancelled()) {
|
||||
Placer p(bin); p.configure(pconfig);
|
||||
if(!p.pack(*it)) {
|
||||
it = store_.erase(it);
|
||||
@ -67,13 +69,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto it = store_.begin();
|
||||
|
||||
while(it != store_.end()) {
|
||||
while(it != store_.end() && !cancelled()) {
|
||||
bool was_packed = false;
|
||||
size_t j = 0;
|
||||
while(!was_packed) {
|
||||
for(; j < placers.size() && !was_packed; j++) {
|
||||
while(!was_packed && !cancelled()) {
|
||||
for(; j < placers.size() && !was_packed && !cancelled(); j++) {
|
||||
if((was_packed = placers[j].pack(*it, rem(it, store_) )))
|
||||
makeProgress(placers[j], j);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define SELECTION_BOILERPLATE_HPP
|
||||
|
||||
#include "../libnest2d.hpp"
|
||||
#include <atomic>
|
||||
|
||||
namespace libnest2d { namespace selections {
|
||||
|
||||
@ -25,14 +26,15 @@ public:
|
||||
return packed_bins_[binIndex];
|
||||
}
|
||||
|
||||
inline void progressIndicator(ProgressFunction fn) {
|
||||
progress_ = fn;
|
||||
}
|
||||
inline void progressIndicator(ProgressFunction fn) { progress_ = fn; }
|
||||
|
||||
inline void stopCondition(StopCondition cond) { stopcond_ = cond; }
|
||||
|
||||
protected:
|
||||
|
||||
PackGroup packed_bins_;
|
||||
ProgressFunction progress_ = [](unsigned){};
|
||||
StopCondition stopcond_ = [](){ return false; };
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -299,7 +299,8 @@ protected:
|
||||
public:
|
||||
|
||||
_ArrBase(const TBin& bin, Distance dist,
|
||||
std::function<void(unsigned)> progressind):
|
||||
std::function<void(unsigned)> progressind,
|
||||
std::function<bool(void)> stopcond):
|
||||
pck_(bin, dist), bin_area_(sl::area(bin)),
|
||||
norm_(std::sqrt(sl::area(bin)))
|
||||
{
|
||||
@ -330,6 +331,7 @@ public:
|
||||
};
|
||||
|
||||
pck_.progressIndicator(progressind);
|
||||
pck_.stopCondition(stopcond);
|
||||
}
|
||||
|
||||
template<class...Args> inline IndexedPackGroup operator()(Args&&...args) {
|
||||
@ -343,8 +345,9 @@ class AutoArranger<Box>: public _ArrBase<Box> {
|
||||
public:
|
||||
|
||||
AutoArranger(const Box& bin, Distance dist,
|
||||
std::function<void(unsigned)> progressind):
|
||||
_ArrBase<Box>(bin, dist, progressind)
|
||||
std::function<void(unsigned)> progressind,
|
||||
std::function<bool(void)> stopcond):
|
||||
_ArrBase<Box>(bin, dist, progressind, stopcond)
|
||||
{
|
||||
|
||||
pconf_.object_function = [this, bin] (const Item &item) {
|
||||
@ -380,8 +383,9 @@ class AutoArranger<lnCircle>: public _ArrBase<lnCircle> {
|
||||
public:
|
||||
|
||||
AutoArranger(const lnCircle& bin, Distance dist,
|
||||
std::function<void(unsigned)> progressind):
|
||||
_ArrBase<lnCircle>(bin, dist, progressind) {
|
||||
std::function<void(unsigned)> progressind,
|
||||
std::function<bool(void)> stopcond):
|
||||
_ArrBase<lnCircle>(bin, dist, progressind, stopcond) {
|
||||
|
||||
pconf_.object_function = [this, &bin] (const Item &item) {
|
||||
|
||||
@ -421,8 +425,9 @@ template<>
|
||||
class AutoArranger<PolygonImpl>: public _ArrBase<PolygonImpl> {
|
||||
public:
|
||||
AutoArranger(const PolygonImpl& bin, Distance dist,
|
||||
std::function<void(unsigned)> progressind):
|
||||
_ArrBase<PolygonImpl>(bin, dist, progressind)
|
||||
std::function<void(unsigned)> progressind,
|
||||
std::function<bool(void)> stopcond):
|
||||
_ArrBase<PolygonImpl>(bin, dist, progressind, stopcond)
|
||||
{
|
||||
pconf_.object_function = [this, &bin] (const Item &item) {
|
||||
|
||||
@ -449,8 +454,9 @@ template<> // Specialization with no bin
|
||||
class AutoArranger<bool>: public _ArrBase<Box> {
|
||||
public:
|
||||
|
||||
AutoArranger(Distance dist, std::function<void(unsigned)> progressind):
|
||||
_ArrBase<Box>(Box(0, 0), dist, progressind)
|
||||
AutoArranger(Distance dist, std::function<void(unsigned)> progressind,
|
||||
std::function<bool(void)> stopcond):
|
||||
_ArrBase<Box>(Box(0, 0), dist, progressind, stopcond)
|
||||
{
|
||||
this->pconf_.object_function = [this] (const Item &item) {
|
||||
|
||||
@ -680,12 +686,16 @@ void applyResult(
|
||||
* remaining items which do not fit onto the print area next to the print
|
||||
* bed or leave them untouched (let the user arrange them by hand or remove
|
||||
* them).
|
||||
* \param progressind Progress indicator callback called when an object gets
|
||||
* packed. The unsigned argument is the number of items remaining to pack.
|
||||
* \param stopcondition A predicate returning true if abort is needed.
|
||||
*/
|
||||
bool arrange(Model &model, coordf_t min_obj_distance,
|
||||
const Slic3r::Polyline& bed,
|
||||
BedShapeHint bedhint,
|
||||
bool first_bin_only,
|
||||
std::function<void(unsigned)> progressind)
|
||||
std::function<void(unsigned)> progressind,
|
||||
std::function<bool(void)> stopcondition)
|
||||
{
|
||||
using ArrangeResult = _IndexedPackGroup<PolygonImpl>;
|
||||
|
||||
@ -710,6 +720,8 @@ bool arrange(Model &model, coordf_t min_obj_distance,
|
||||
|
||||
BoundingBox bbb(bed);
|
||||
|
||||
auto& cfn = stopcondition;
|
||||
|
||||
auto binbb = Box({
|
||||
static_cast<libnest2d::Coord>(bbb.min(0)),
|
||||
static_cast<libnest2d::Coord>(bbb.min(1))
|
||||
@ -723,7 +735,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
|
||||
case BedShapeType::BOX: {
|
||||
|
||||
// Create the arranger for the box shaped bed
|
||||
AutoArranger<Box> arrange(binbb, min_obj_distance, progressind);
|
||||
AutoArranger<Box> arrange(binbb, min_obj_distance, progressind, cfn);
|
||||
|
||||
// Arrange and return the items with their respective indices within the
|
||||
// input sequence.
|
||||
@ -735,7 +747,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
|
||||
auto c = bedhint.shape.circ;
|
||||
auto cc = lnCircle(c);
|
||||
|
||||
AutoArranger<lnCircle> arrange(cc, min_obj_distance, progressind);
|
||||
AutoArranger<lnCircle> arrange(cc, min_obj_distance, progressind, cfn);
|
||||
result = arrange(shapes.begin(), shapes.end());
|
||||
break;
|
||||
}
|
||||
@ -747,7 +759,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
|
||||
auto ctour = Slic3rMultiPoint_to_ClipperPath(bed);
|
||||
P irrbed = sl::create<PolygonImpl>(std::move(ctour));
|
||||
|
||||
AutoArranger<P> arrange(irrbed, min_obj_distance, progressind);
|
||||
AutoArranger<P> arrange(irrbed, min_obj_distance, progressind, cfn);
|
||||
|
||||
// Arrange and return the items with their respective indices within the
|
||||
// input sequence.
|
||||
@ -756,7 +768,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
|
||||
}
|
||||
};
|
||||
|
||||
if(result.empty()) return false;
|
||||
if(result.empty() || stopcondition()) return false;
|
||||
|
||||
if(first_bin_only) {
|
||||
applyResult(result.front(), 0, shapemap);
|
||||
|
@ -438,6 +438,11 @@ void AppController::arrange_model()
|
||||
{
|
||||
using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
|
||||
|
||||
if(arranging_.load()) return;
|
||||
|
||||
// to prevent UI reentrancies
|
||||
arranging_.store(true);
|
||||
|
||||
unsigned count = 0;
|
||||
for(auto obj : model_->objects) count += obj->instances.size();
|
||||
|
||||
@ -451,8 +456,8 @@ void AppController::arrange_model()
|
||||
// Set the range of the progress to the object count
|
||||
pind->max(count);
|
||||
|
||||
pind->on_cancel([](){
|
||||
std::cout << "Cannot be cancelled!" << std::endl;
|
||||
pind->on_cancel([this](){
|
||||
arranging_.store(false);
|
||||
});
|
||||
}
|
||||
|
||||
@ -478,10 +483,12 @@ void AppController::arrange_model()
|
||||
bed,
|
||||
hint,
|
||||
false, // create many piles not just one pile
|
||||
[pind, count](unsigned rem) {
|
||||
[this, pind, count](unsigned rem) {
|
||||
if(pind)
|
||||
pind->update(count - rem, _(L("Arranging objects...")));
|
||||
});
|
||||
pind->update(count - rem, L("Arranging objects..."));
|
||||
|
||||
process_events();
|
||||
}, [this] () { return !arranging_.load(); });
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
report_issue(IssueType::ERR,
|
||||
@ -493,9 +500,13 @@ void AppController::arrange_model()
|
||||
// Restore previous max value
|
||||
if(pind) {
|
||||
pind->max(pmax);
|
||||
pind->update(0, _(L("Arranging done.")));
|
||||
pind->update(0, arranging_.load() ? L("Arranging done.") :
|
||||
L("Arranging canceled."));
|
||||
|
||||
pind->on_cancel(/*remove cancel function*/);
|
||||
}
|
||||
|
||||
arranging_.store(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -237,6 +237,7 @@ public:
|
||||
class AppController: public AppControllerBoilerplate {
|
||||
Model *model_ = nullptr;
|
||||
PrintController::Ptr printctl;
|
||||
std::atomic<bool> arranging_;
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -28,7 +28,7 @@ bool AppControllerBoilerplate::supports_asynch() const
|
||||
|
||||
void AppControllerBoilerplate::process_events()
|
||||
{
|
||||
wxSafeYield();
|
||||
wxYieldIfNeeded();
|
||||
}
|
||||
|
||||
AppControllerBoilerplate::PathList
|
||||
|
Loading…
Reference in New Issue
Block a user