Merge remote-tracking branch 'origin/dev' into new_main_page_ui

This commit is contained in:
YuSanka 2018-09-13 16:12:07 +02:00
commit a31ac857ef
16 changed files with 102 additions and 37 deletions

View File

@ -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++) {

View File

@ -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)) {

View File

@ -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();

View File

@ -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);
} }

View File

@ -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; };
}; };
} }

View File

@ -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);

View File

@ -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);
} }
} }

View File

@ -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:
/** /**

View File

@ -28,7 +28,7 @@ bool AppControllerBoilerplate::supports_asynch() const
void AppControllerBoilerplate::process_events() void AppControllerBoilerplate::process_events()
{ {
wxSafeYield(); wxYieldIfNeeded();
} }
AppControllerBoilerplate::PathList AppControllerBoilerplate::PathList

View File

@ -2164,6 +2164,11 @@ int _3DScene::get_first_volume_id(wxGLCanvas* canvas, int obj_idx)
return s_canvas_mgr.get_first_volume_id(canvas, obj_idx); return s_canvas_mgr.get_first_volume_id(canvas, obj_idx);
} }
int _3DScene::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx)
{
return s_canvas_mgr.get_in_object_volume_id(canvas, scene_vol_idx);
}
void _3DScene::reload_scene(wxGLCanvas* canvas, bool force) void _3DScene::reload_scene(wxGLCanvas* canvas, bool force)
{ {
s_canvas_mgr.reload_scene(canvas, force); s_canvas_mgr.reload_scene(canvas, force);

View File

@ -577,6 +577,7 @@ public:
static std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx); static std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx);
static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx); static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx);
static int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx);
static void reload_scene(wxGLCanvas* canvas, bool force); static void reload_scene(wxGLCanvas* canvas, bool force);

View File

@ -2493,6 +2493,11 @@ int GLCanvas3D::get_first_volume_id(int obj_idx) const
return -1; return -1;
} }
int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const
{
return ((0 <= scene_vol_idx) && (scene_vol_idx < (int)m_volumes.volumes.size())) ? m_volumes.volumes[scene_vol_idx]->volume_idx() : -1;
}
void GLCanvas3D::reload_scene(bool force) void GLCanvas3D::reload_scene(bool force)
{ {
if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr))

View File

@ -105,7 +105,6 @@ class GLCanvas3D
void reset() { first_volumes.clear(); } void reset() { first_volumes.clear(); }
}; };
public:
struct Camera struct Camera
{ {
enum EType : unsigned char enum EType : unsigned char
@ -441,7 +440,6 @@ public:
void render(const GLCanvas3D& canvas) const; void render(const GLCanvas3D& canvas) const;
}; };
private:
wxGLCanvas* m_canvas; wxGLCanvas* m_canvas;
wxGLContext* m_context; wxGLContext* m_context;
LegendTexture m_legend_texture; LegendTexture m_legend_texture;
@ -605,6 +603,7 @@ public:
std::vector<int> load_object(const Model& model, int obj_idx); std::vector<int> load_object(const Model& model, int obj_idx);
int get_first_volume_id(int obj_idx) const; int get_first_volume_id(int obj_idx) const;
int get_in_object_volume_id(int scene_vol_idx) const;
void reload_scene(bool force); void reload_scene(bool force);

View File

@ -548,6 +548,12 @@ int GLCanvas3DManager::get_first_volume_id(wxGLCanvas* canvas, int obj_idx) cons
return (it != m_canvases.end()) ? it->second->get_first_volume_id(obj_idx) : -1; return (it != m_canvases.end()) ? it->second->get_first_volume_id(obj_idx) : -1;
} }
int GLCanvas3DManager::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const
{
CanvasesMap::const_iterator it = _get_canvas(canvas);
return (it != m_canvases.end()) ? it->second->get_in_object_volume_id(scene_vol_idx) : -1;
}
void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force) void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force)
{ {
CanvasesMap::iterator it = _get_canvas(canvas); CanvasesMap::iterator it = _get_canvas(canvas);

View File

@ -138,6 +138,7 @@ public:
std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx); std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx);
int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const; int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const;
int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const;
void reload_scene(wxGLCanvas* canvas, bool force); void reload_scene(wxGLCanvas* canvas, bool force);

View File

@ -767,6 +767,15 @@ get_first_volume_id(canvas, obj_idx)
OUTPUT: OUTPUT:
RETVAL RETVAL
int
get_in_object_volume_id(canvas, scene_vol_idx)
SV *canvas;
int scene_vol_idx;
CODE:
RETVAL = _3DScene::get_in_object_volume_id((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), scene_vol_idx);
OUTPUT:
RETVAL
std::vector<int> std::vector<int>
load_model(canvas, model, obj_idx) load_model(canvas, model, obj_idx)
SV *canvas; SV *canvas;