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