AppController integration
This commit is contained in:
parent
5446b9f1e5
commit
ad4d95f60c
17 changed files with 1435 additions and 12 deletions
|
@ -19,6 +19,7 @@ use Wx::Locale gettext => 'L';
|
|||
our $qs_last_input_file;
|
||||
our $qs_last_output_file;
|
||||
our $last_config;
|
||||
our $appController;
|
||||
|
||||
# Events to be sent from a C++ Tab implementation:
|
||||
# 1) To inform about a change of a configuration value.
|
||||
|
@ -31,6 +32,9 @@ sub new {
|
|||
|
||||
my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE);
|
||||
Slic3r::GUI::set_main_frame($self);
|
||||
|
||||
$appController = Slic3r::AppController->new();
|
||||
|
||||
if ($^O eq 'MSWin32') {
|
||||
# Load the icon either from the exe, or from the ico file.
|
||||
my $iconfile = Slic3r::decode_path($FindBin::Bin) . '\slic3r.exe';
|
||||
|
@ -62,6 +66,15 @@ sub new {
|
|||
$self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases"));
|
||||
$self->SetStatusBar($self->{statusbar});
|
||||
|
||||
# Make the global status bar and its progress indicator available in C++
|
||||
$appController->set_global_progress_indicator(
|
||||
$self->{statusbar}->{prog}->GetId(),
|
||||
$self->{statusbar}->GetId(),
|
||||
);
|
||||
|
||||
$appController->set_model($self->{plater}->{model});
|
||||
$appController->set_print($self->{plater}->{print});
|
||||
|
||||
$self->{loaded} = 1;
|
||||
|
||||
# initialize layout
|
||||
|
|
|
@ -240,6 +240,10 @@ add_library(libslic3r_gui STATIC
|
|||
${LIBDIR}/slic3r/Utils/PresetUpdater.hpp
|
||||
${LIBDIR}/slic3r/Utils/Time.cpp
|
||||
${LIBDIR}/slic3r/Utils/Time.hpp
|
||||
${LIBDIR}/slic3r/IProgressIndicator.hpp
|
||||
${LIBDIR}/slic3r/AppController.hpp
|
||||
${LIBDIR}/slic3r/AppController.cpp
|
||||
${LIBDIR}/slic3r/AppControllerWx.cpp
|
||||
)
|
||||
|
||||
add_library(admesh STATIC
|
||||
|
|
|
@ -142,6 +142,9 @@ inline void ShapeLike::offset(PolygonImpl& sh, TCoord<PointImpl> distance) {
|
|||
using ClipperLib::etClosedPolygon;
|
||||
using ClipperLib::Paths;
|
||||
|
||||
// If the input is not at least a triangle, we can not do this algorithm
|
||||
if(sh.Contour.size() <= 3) throw GeometryException(GeoErr::OFFSET);
|
||||
|
||||
ClipperOffset offs;
|
||||
Paths result;
|
||||
offs.AddPath(sh.Contour, jtMiter, etClosedPolygon);
|
||||
|
@ -151,7 +154,8 @@ inline void ShapeLike::offset(PolygonImpl& sh, TCoord<PointImpl> distance) {
|
|||
// it removes the last vertex as well so boost will not have a closed
|
||||
// polygon
|
||||
|
||||
assert(result.size() == 1);
|
||||
if(result.size() != 1) throw GeometryException(GeoErr::OFFSET);
|
||||
|
||||
sh.Contour = result.front();
|
||||
|
||||
// recreate closed polygon
|
||||
|
|
|
@ -205,5 +205,36 @@ inline Radians::Radians(const Degrees °s): Double( degs * Pi/180) {}
|
|||
|
||||
inline double Radians::toDegrees() { return operator Degrees(); }
|
||||
|
||||
enum class GeoErr : std::size_t {
|
||||
OFFSET,
|
||||
MERGE,
|
||||
NFP
|
||||
};
|
||||
|
||||
static const std::string ERROR_STR[] = {
|
||||
"Offsetting could not be done! An invalid geometry may have been added."
|
||||
"Error while merging geometries!"
|
||||
"No fit polygon cannaot be calculated."
|
||||
};
|
||||
|
||||
class GeometryException: public std::exception {
|
||||
|
||||
virtual const char * errorstr(GeoErr errcode) const {
|
||||
return ERROR_STR[static_cast<std::size_t>(errcode)].c_str();
|
||||
}
|
||||
|
||||
GeoErr errcode_;
|
||||
public:
|
||||
|
||||
GeometryException(GeoErr code): errcode_(code) {}
|
||||
|
||||
GeoErr errcode() const { return errcode_; }
|
||||
|
||||
virtual const char * what() const override {
|
||||
return errorstr(errcode_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif // LIBNEST2D_CONFIG_HPP
|
||||
|
|
|
@ -648,6 +648,8 @@ public:
|
|||
|
||||
using IndexedPackGroup = _IndexedPackGroup<typename Item::ShapeType>;
|
||||
using PackGroup = _PackGroup<typename Item::ShapeType>;
|
||||
using ResultType = PackGroup;
|
||||
using ResultTypeIndexed = IndexedPackGroup;
|
||||
|
||||
private:
|
||||
BinType bin_;
|
||||
|
|
|
@ -74,10 +74,370 @@ void arrangeRectangles() {
|
|||
// {{0, 0}, {0, 20*SCALE}, {10*SCALE, 0}, {0, 0}}
|
||||
// };
|
||||
|
||||
std::vector<Item> crasher = {
|
||||
{
|
||||
{-10836093, -2542602},
|
||||
{-10834392, -1849197},
|
||||
{-10826793, 1172203},
|
||||
{-10824993, 1884506},
|
||||
{-10823291, 2547500},
|
||||
{-10822994, 2642700},
|
||||
{-10807392, 2768295},
|
||||
{-10414295, 3030403},
|
||||
{-9677799, 3516204},
|
||||
{-9555896, 3531204},
|
||||
{-9445194, 3534698},
|
||||
{9353008, 3487297},
|
||||
{9463504, 3486999},
|
||||
{9574008, 3482902},
|
||||
{9695903, 3467399},
|
||||
{10684803, 2805702},
|
||||
{10814098, 2717803},
|
||||
{10832805, 2599502},
|
||||
{10836200, 2416801},
|
||||
{10819705, -2650299},
|
||||
{10800403, -2772300},
|
||||
{10670505, -2859596},
|
||||
{9800403, -3436599},
|
||||
{9678203, -3516197},
|
||||
{9556308, -3531196},
|
||||
{9445903, -3534698},
|
||||
{9084011, -3533798},
|
||||
{-9234294, -3487701},
|
||||
{-9462894, -3486999},
|
||||
{-9573497, -3483001},
|
||||
{-9695392, -3467300},
|
||||
{-9816898, -3387199},
|
||||
{-10429492, -2977798},
|
||||
{-10821193, -2714096},
|
||||
{-10836200, -2588195},
|
||||
{-10836093, -2542602},
|
||||
},
|
||||
{
|
||||
{-3533699, -9084051},
|
||||
{-3487197, 9352449},
|
||||
{-3486797, 9462949},
|
||||
{-3482795, 9573547},
|
||||
{-3467201, 9695350},
|
||||
{-3386997, 9816949},
|
||||
{-2977699, 10429548},
|
||||
{-2713897, 10821249},
|
||||
{-2587997, 10836149},
|
||||
{-2542396, 10836149},
|
||||
{-2054698, 10834949},
|
||||
{2223503, 10824150},
|
||||
{2459800, 10823547},
|
||||
{2555002, 10823247},
|
||||
{2642601, 10822948},
|
||||
{2768301, 10807350},
|
||||
{3030302, 10414247},
|
||||
{3516099, 9677850},
|
||||
{3531002, 9555850},
|
||||
{3534502, 9445247},
|
||||
{3534301, 9334949},
|
||||
{3487300, -9353052},
|
||||
{3486904, -9463548},
|
||||
{3482801, -9574148},
|
||||
{3467302, -9695848},
|
||||
{2805601, -10684751},
|
||||
{2717802, -10814149},
|
||||
{2599403, -10832952},
|
||||
{2416801, -10836149},
|
||||
{-2650199, -10819749},
|
||||
{-2772197, -10800451},
|
||||
{-2859397, -10670450},
|
||||
{-3436401, -9800451},
|
||||
{-3515998, -9678350},
|
||||
{-3530998, -9556451},
|
||||
{-3534500, -9445848},
|
||||
{-3533699, -9084051},
|
||||
},
|
||||
{
|
||||
{-3533798, -9084051},
|
||||
{-3487697, 9234249},
|
||||
{-3486999, 9462949},
|
||||
{-3482997, 9573547},
|
||||
{-3467296, 9695350},
|
||||
{-3387199, 9816949},
|
||||
{-2977798, 10429548},
|
||||
{-2714096, 10821249},
|
||||
{-2588199, 10836149},
|
||||
{-2542594, 10836149},
|
||||
{-2054798, 10834949},
|
||||
{2223701, 10824150},
|
||||
{2459903, 10823547},
|
||||
{2555202, 10823247},
|
||||
{2642704, 10822948},
|
||||
{2768302, 10807350},
|
||||
{3030403, 10414247},
|
||||
{3516204, 9677850},
|
||||
{3531204, 9555850},
|
||||
{3534702, 9445247},
|
||||
{3487300, -9353052},
|
||||
{3486999, -9463548},
|
||||
{3482902, -9574148},
|
||||
{3467403, -9695848},
|
||||
{2805702, -10684751},
|
||||
{2717803, -10814149},
|
||||
{2599502, -10832952},
|
||||
{2416801, -10836149},
|
||||
{-2650299, -10819749},
|
||||
{-2772296, -10800451},
|
||||
{-2859596, -10670450},
|
||||
{-3436595, -9800451},
|
||||
{-3516197, -9678350},
|
||||
{-3531196, -9556451},
|
||||
{-3534698, -9445848},
|
||||
{-3533798, -9084051},
|
||||
},
|
||||
{
|
||||
{-49433151, 4289947},
|
||||
{-49407352, 4421947},
|
||||
{-49355751, 4534446},
|
||||
{-29789449, 36223850},
|
||||
{-29737350, 36307445},
|
||||
{-29512149, 36401447},
|
||||
{-29089149, 36511646},
|
||||
{-28894351, 36550342},
|
||||
{-18984951, 37803447},
|
||||
{-18857151, 37815151},
|
||||
{-18271148, 37768947},
|
||||
{-18146148, 37755146},
|
||||
{-17365447, 37643947},
|
||||
{-17116649, 37601146},
|
||||
{11243545, 29732448},
|
||||
{29276451, 24568149},
|
||||
{29497543, 24486148},
|
||||
{29654548, 24410953},
|
||||
{31574546, 23132640},
|
||||
{33732849, 21695148},
|
||||
{33881950, 21584445},
|
||||
{34019454, 21471950},
|
||||
{34623153, 20939151},
|
||||
{34751945, 20816951},
|
||||
{35249244, 20314647},
|
||||
{36681549, 18775447},
|
||||
{36766548, 18680446},
|
||||
{36794250, 18647144},
|
||||
{36893951, 18521953},
|
||||
{37365951, 17881946},
|
||||
{37440948, 17779247},
|
||||
{37529243, 17642444},
|
||||
{42233245, 10012245},
|
||||
{42307250, 9884048},
|
||||
{42452949, 9626548},
|
||||
{44258949, 4766647},
|
||||
{48122245, -5990951},
|
||||
{48160751, -6117950},
|
||||
{49381546, -17083953},
|
||||
{49412246, -17420953},
|
||||
{49429450, -18011253},
|
||||
{49436141, -18702651},
|
||||
{49438949, -20087953},
|
||||
{49262947, -24000852},
|
||||
{49172546, -24522455},
|
||||
{48847549, -25859151},
|
||||
{48623847, -26705650},
|
||||
{48120246, -28514953},
|
||||
{48067146, -28699455},
|
||||
{48017845, -28862453},
|
||||
{47941543, -29096954},
|
||||
{47892547, -29246852},
|
||||
{47813545, -29466651},
|
||||
{47758453, -29612955},
|
||||
{47307548, -30803253},
|
||||
{46926544, -31807151},
|
||||
{46891448, -31899551},
|
||||
{46672546, -32475852},
|
||||
{46502449, -32914852},
|
||||
{46414451, -33140853},
|
||||
{46294250, -33447650},
|
||||
{46080146, -33980255},
|
||||
{46039245, -34071853},
|
||||
{45970542, -34186653},
|
||||
{45904243, -34295955},
|
||||
{45786247, -34475650},
|
||||
{43063247, -37740955},
|
||||
{42989547, -37815151},
|
||||
{12128349, -36354953},
|
||||
{12101844, -36343955},
|
||||
{11806152, -36217453},
|
||||
{7052848, -34171649},
|
||||
{-3234352, -29743150},
|
||||
{-15684650, -24381851},
|
||||
{-16573852, -23998851},
|
||||
{-20328948, -22381254},
|
||||
{-20383052, -22357254},
|
||||
{-20511447, -22280651},
|
||||
{-42221252, -8719951},
|
||||
{-42317150, -8653255},
|
||||
{-42457851, -8528949},
|
||||
{-42600151, -8399852},
|
||||
{-47935852, -2722949},
|
||||
{-48230651, -2316852},
|
||||
{-48500850, -1713150},
|
||||
{-48516853, -1676551},
|
||||
{-48974651, -519649},
|
||||
{-49003852, -412551},
|
||||
{-49077850, -129650},
|
||||
{-49239753, 735946},
|
||||
{-49312652, 1188549},
|
||||
{-49349349, 1467647},
|
||||
{-49351650, 1513347},
|
||||
{-49438949, 4165744},
|
||||
{-49433151, 4289947},
|
||||
},
|
||||
// {
|
||||
// {6000, 5851},
|
||||
// {-6000, -5851},
|
||||
// {6000, 5851},
|
||||
// },
|
||||
{
|
||||
{-10836097, -2542396},
|
||||
{-10834396, -1848999},
|
||||
{-10826797, 1172000},
|
||||
{-10825000, 1884403},
|
||||
{-10823299, 2547401},
|
||||
{-10822998, 2642604},
|
||||
{-10807395, 2768299},
|
||||
{-10414299, 3030300},
|
||||
{-9677799, 3516101},
|
||||
{-9555896, 3531002},
|
||||
{-9445198, 3534500},
|
||||
{-9334899, 3534297},
|
||||
{9353000, 3487300},
|
||||
{9463499, 3486904},
|
||||
{9573999, 3482799},
|
||||
{9695901, 3467300},
|
||||
{10684803, 2805603},
|
||||
{10814102, 2717800},
|
||||
{10832803, 2599399},
|
||||
{10836200, 2416797},
|
||||
{10819700, -2650199},
|
||||
{10800401, -2772201},
|
||||
{10670499, -2859397},
|
||||
{9800401, -3436397},
|
||||
{9678201, -3515998},
|
||||
{9556303, -3530998},
|
||||
{9445901, -3534500},
|
||||
{9083999, -3533699},
|
||||
{-9352500, -3487201},
|
||||
{-9462898, -3486797},
|
||||
{-9573501, -3482799},
|
||||
{-9695396, -3467201},
|
||||
{-9816898, -3386997},
|
||||
{-10429500, -2977699},
|
||||
{-10821197, -2713897},
|
||||
{-10836196, -2588001},
|
||||
{-10836097, -2542396},
|
||||
},
|
||||
{
|
||||
{-47073699, 26300853},
|
||||
{-47009803, 27392650},
|
||||
{-46855804, 28327953},
|
||||
{-46829402, 28427051},
|
||||
{-46764102, 28657550},
|
||||
{-46200401, 30466648},
|
||||
{-46066703, 30832347},
|
||||
{-45887104, 31247554},
|
||||
{-45663700, 31670848},
|
||||
{-45414802, 32080554},
|
||||
{-45273700, 32308956},
|
||||
{-45179702, 32431850},
|
||||
{-45057804, 32549350},
|
||||
{-34670803, 40990154},
|
||||
{-34539802, 41094348},
|
||||
{-34393600, 41184452},
|
||||
{-34284805, 41229953},
|
||||
{-34080402, 41267154},
|
||||
{17335296, 48077648},
|
||||
{18460296, 48153553},
|
||||
{18976600, 48182147},
|
||||
{20403999, 48148555},
|
||||
{20562301, 48131153},
|
||||
{20706001, 48102855},
|
||||
{20938796, 48053150},
|
||||
{21134101, 48010051},
|
||||
{21483192, 47920154},
|
||||
{21904701, 47806346},
|
||||
{22180099, 47670154},
|
||||
{22357795, 47581645},
|
||||
{22615295, 47423046},
|
||||
{22782295, 47294651},
|
||||
{24281791, 45908344},
|
||||
{24405296, 45784854},
|
||||
{41569297, 21952449},
|
||||
{41784301, 21638050},
|
||||
{41938491, 21393650},
|
||||
{42030899, 21245052},
|
||||
{42172996, 21015850},
|
||||
{42415298, 20607151},
|
||||
{42468299, 20504650},
|
||||
{42553100, 20320850},
|
||||
{42584594, 20250644},
|
||||
{42684997, 20004344},
|
||||
{42807098, 19672351},
|
||||
{42939002, 19255153},
|
||||
{43052299, 18693950},
|
||||
{45094100, 7846851},
|
||||
{45118400, 7684154},
|
||||
{47079101, -16562252},
|
||||
{47082000, -16705646},
|
||||
{46916297, -22172447},
|
||||
{46911598, -22294349},
|
||||
{46874893, -22358146},
|
||||
{44866996, -25470146},
|
||||
{30996795, -46852050},
|
||||
{30904998, -46933750},
|
||||
{30864791, -46945850},
|
||||
{9315696, -48169147},
|
||||
{9086494, -48182147},
|
||||
{8895500, -48160049},
|
||||
{8513496, -48099548},
|
||||
{8273696, -48057350},
|
||||
{8180198, -48039051},
|
||||
{7319801, -47854949},
|
||||
{6288299, -47569950},
|
||||
{6238498, -47554248},
|
||||
{5936199, -47453250},
|
||||
{-11930000, -41351551},
|
||||
{-28986402, -33654148},
|
||||
{-29111103, -33597148},
|
||||
{-29201803, -33544147},
|
||||
{-29324401, -33467845},
|
||||
{-29467000, -33352848},
|
||||
{-29606603, -33229351},
|
||||
{-31140401, -31849147},
|
||||
{-31264303, -31736450},
|
||||
{-31385803, -31625452},
|
||||
{-31829103, -31216148},
|
||||
{-32127403, -30935951},
|
||||
{-32253803, -30809648},
|
||||
{-32364803, -30672147},
|
||||
{-34225402, -28078847},
|
||||
{-35819404, -25762451},
|
||||
{-36304801, -25035346},
|
||||
{-36506103, -24696445},
|
||||
{-36574104, -24560146},
|
||||
{-36926700, -23768646},
|
||||
{-39767402, -17341148},
|
||||
{-39904102, -16960147},
|
||||
{-41008602, -11799850},
|
||||
{-43227401, -704147},
|
||||
{-43247303, -577148},
|
||||
{-47057403, 24847454},
|
||||
{-47077602, 25021648},
|
||||
{-47080101, 25128650},
|
||||
{-47082000, 25562953},
|
||||
{-47073699, 26300853},
|
||||
},
|
||||
};
|
||||
|
||||
std::vector<Item> input;
|
||||
input.insert(input.end(), prusaParts().begin(), prusaParts().end());
|
||||
// input.insert(input.end(), prusaParts().begin(), prusaParts().end());
|
||||
// input.insert(input.end(), stegoParts().begin(), stegoParts().end());
|
||||
// input.insert(input.end(), rects.begin(), rects.end());
|
||||
input.insert(input.end(), crasher.begin(), crasher.end());
|
||||
|
||||
Box bin(250*SCALE, 210*SCALE);
|
||||
|
||||
|
@ -90,7 +450,7 @@ void arrangeRectangles() {
|
|||
// pconf.rotations = {0.0, Pi/2.0, Pi, 3*Pi/2};
|
||||
Packer::SelectionConfig sconf;
|
||||
sconf.allow_parallel = true;
|
||||
sconf.force_parallel = false;
|
||||
sconf.force_parallel = true;
|
||||
sconf.try_reverse_order = false;
|
||||
Packer arrange(bin, min_obj_distance, pconf, sconf);
|
||||
|
||||
|
@ -107,8 +467,17 @@ void arrangeRectangles() {
|
|||
Benchmark bench;
|
||||
|
||||
bench.start();
|
||||
auto result = arrange.arrange(input.begin(),
|
||||
input.end());
|
||||
Packer::ResultType result;
|
||||
|
||||
try {
|
||||
result = arrange.arrange(input.begin(), input.end());
|
||||
} catch(GeometryException& ge) {
|
||||
std::cerr << "Geometry error: " << ge.what() << std::endl;
|
||||
return ;
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
bench.stop();
|
||||
|
||||
|
|
|
@ -377,7 +377,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
|||
* them).
|
||||
*/
|
||||
bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
bool first_bin_only)
|
||||
bool first_bin_only,
|
||||
std::function<void(unsigned)> progressind)
|
||||
{
|
||||
using ArrangeResult = _IndexedPackGroup<PolygonImpl>;
|
||||
|
||||
|
@ -435,7 +436,7 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
|||
biggest = &item;
|
||||
}
|
||||
}
|
||||
shapes.push_back(std::ref(it.second));
|
||||
if(it.second.vertexCount() > 3) shapes.push_back(std::ref(it.second));
|
||||
});
|
||||
|
||||
Box bin;
|
||||
|
@ -471,12 +472,19 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
|||
Arranger arranger(bin, min_obj_distance, pcfg, scfg);
|
||||
arranger.useMinimumBoundigBoxRotation();
|
||||
|
||||
arranger.progressIndicator(progressind);
|
||||
|
||||
std::cout << "Arranging model..." << std::endl;
|
||||
bench.start();
|
||||
// Arrange and return the items with their respective indices within the
|
||||
// input sequence.
|
||||
ArrangeResult result =
|
||||
arranger.arrangeIndexed(shapes.begin(), shapes.end());
|
||||
|
||||
ArrangeResult result;
|
||||
try {
|
||||
result = arranger.arrangeIndexed(shapes.begin(), shapes.end());
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "An exception occured: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
bench.stop();
|
||||
std::cout << "Model arranged in " << bench.getElapsedSec()
|
||||
|
@ -543,12 +551,13 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
|||
|
||||
/* arrange objects preserving their instance count
|
||||
but altering their instance positions */
|
||||
bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
||||
bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb,
|
||||
std::function<void(unsigned)> progressind)
|
||||
{
|
||||
bool ret = false;
|
||||
if(bb != nullptr && bb->defined) {
|
||||
const bool FIRST_BIN_ONLY = false;
|
||||
ret = arr::arrange(*this, dist, bb, FIRST_BIN_ONLY);
|
||||
ret = arr::arrange(*this, dist, bb, FIRST_BIN_ONLY, progressind);
|
||||
} else {
|
||||
// get the (transformed) size of each instance so that we take
|
||||
// into account their different transformations when packing
|
||||
|
|
|
@ -274,7 +274,8 @@ public:
|
|||
void center_instances_around_point(const Pointf &point);
|
||||
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
||||
TriangleMesh mesh() const;
|
||||
bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL);
|
||||
bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL,
|
||||
std::function<void(unsigned)> progressind = [](unsigned){});
|
||||
// Croaks if the duplicated objects do not fit the print bed.
|
||||
void duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL);
|
||||
void duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL);
|
||||
|
|
|
@ -65,6 +65,8 @@ REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
|
|||
REGISTER_CLASS(TabIface, "GUI::Tab");
|
||||
REGISTER_CLASS(PresetUpdater, "PresetUpdater");
|
||||
REGISTER_CLASS(OctoPrint, "OctoPrint");
|
||||
REGISTER_CLASS(AppController, "AppController");
|
||||
REGISTER_CLASS(PrintController, "PrintController");
|
||||
|
||||
SV* ConfigBase__as_hash(ConfigBase* THIS)
|
||||
{
|
||||
|
|
310
xs/src/slic3r/AppController.cpp
Normal file
310
xs/src/slic3r/AppController.cpp
Normal file
|
@ -0,0 +1,310 @@
|
|||
#include "AppController.hpp"
|
||||
|
||||
#include <future>
|
||||
#include <sstream>
|
||||
#include <cstdarg>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <slic3r/GUI/GUI.hpp>
|
||||
#include <slic3r/GUI/PresetBundle.hpp>
|
||||
|
||||
#include <PrintConfig.hpp>
|
||||
#include <Print.hpp>
|
||||
#include <Model.hpp>
|
||||
#include <Utils.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class AppControllerBoilerplate::PriMap {
|
||||
public:
|
||||
using M = std::unordered_map<std::thread::id, ProgresIndicatorPtr>;
|
||||
std::mutex m;
|
||||
M store;
|
||||
std::thread::id ui_thread;
|
||||
|
||||
inline explicit PriMap(std::thread::id uit): ui_thread(uit) {}
|
||||
};
|
||||
|
||||
AppControllerBoilerplate::AppControllerBoilerplate()
|
||||
:progressind_(new PriMap(std::this_thread::get_id())) {}
|
||||
|
||||
AppControllerBoilerplate::~AppControllerBoilerplate() {
|
||||
progressind_.reset();
|
||||
}
|
||||
|
||||
bool AppControllerBoilerplate::is_main_thread() const
|
||||
{
|
||||
return progressind_->ui_thread == std::this_thread::get_id();
|
||||
}
|
||||
|
||||
namespace GUI {
|
||||
PresetBundle* get_preset_bundle();
|
||||
}
|
||||
|
||||
static const PrintObjectStep STEP_SLICE = posSlice;
|
||||
static const PrintObjectStep STEP_PERIMETERS = posPerimeters;
|
||||
static const PrintObjectStep STEP_PREPARE_INFILL = posPrepareInfill;
|
||||
static const PrintObjectStep STEP_INFILL = posInfill;
|
||||
static const PrintObjectStep STEP_SUPPORTMATERIAL = posSupportMaterial;
|
||||
static const PrintStep STEP_SKIRT = psSkirt;
|
||||
static const PrintStep STEP_BRIM = psBrim;
|
||||
static const PrintStep STEP_WIPE_TOWER = psWipeTower;
|
||||
|
||||
void AppControllerBoilerplate::progress_indicator(
|
||||
AppControllerBoilerplate::ProgresIndicatorPtr progrind) {
|
||||
progressind_->m.lock();
|
||||
progressind_->store[std::this_thread::get_id()] = progrind;
|
||||
progressind_->m.unlock();
|
||||
}
|
||||
|
||||
void AppControllerBoilerplate::progress_indicator(unsigned statenum,
|
||||
const std::string &title,
|
||||
const std::string &firstmsg)
|
||||
{
|
||||
progressind_->m.lock();
|
||||
progressind_->store[std::this_thread::get_id()] =
|
||||
create_progress_indicator(statenum, title, firstmsg);;
|
||||
progressind_->m.unlock();
|
||||
}
|
||||
|
||||
AppControllerBoilerplate::ProgresIndicatorPtr
|
||||
AppControllerBoilerplate::progress_indicator() {
|
||||
|
||||
PriMap::M::iterator pret;
|
||||
ProgresIndicatorPtr ret;
|
||||
|
||||
progressind_->m.lock();
|
||||
if( (pret = progressind_->store.find(std::this_thread::get_id()))
|
||||
== progressind_->store.end())
|
||||
{
|
||||
progressind_->store[std::this_thread::get_id()] = ret =
|
||||
global_progressind_;
|
||||
} else ret = pret->second;
|
||||
progressind_->m.unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PrintController::make_skirt()
|
||||
{
|
||||
assert(print_ != nullptr);
|
||||
|
||||
// prerequisites
|
||||
for(auto obj : print_->objects) make_perimeters(obj);
|
||||
for(auto obj : print_->objects) infill(obj);
|
||||
for(auto obj : print_->objects) gen_support_material(obj);
|
||||
|
||||
if(!print_->state.is_done(STEP_SKIRT)) {
|
||||
print_->state.set_started(STEP_SKIRT);
|
||||
print_->skirt.clear();
|
||||
if(print_->has_skirt()) print_->_make_skirt();
|
||||
|
||||
print_->state.set_done(STEP_SKIRT);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintController::make_brim()
|
||||
{
|
||||
assert(print_ != nullptr);
|
||||
|
||||
// prerequisites
|
||||
for(auto obj : print_->objects) make_perimeters(obj);
|
||||
for(auto obj : print_->objects) infill(obj);
|
||||
for(auto obj : print_->objects) gen_support_material(obj);
|
||||
make_skirt();
|
||||
|
||||
if(!print_->state.is_done(STEP_BRIM)) {
|
||||
print_->state.set_started(STEP_BRIM);
|
||||
|
||||
// since this method must be idempotent, we clear brim paths *before*
|
||||
// checking whether we need to generate them
|
||||
print_->brim.clear();
|
||||
|
||||
if(print_->config.brim_width > 0) print_->_make_brim();
|
||||
|
||||
print_->state.set_done(STEP_BRIM);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintController::make_wipe_tower()
|
||||
{
|
||||
assert(print_ != nullptr);
|
||||
|
||||
// prerequisites
|
||||
for(auto obj : print_->objects) make_perimeters(obj);
|
||||
for(auto obj : print_->objects) infill(obj);
|
||||
for(auto obj : print_->objects) gen_support_material(obj);
|
||||
make_skirt();
|
||||
make_brim();
|
||||
|
||||
if(!print_->state.is_done(STEP_WIPE_TOWER)) {
|
||||
print_->state.set_started(STEP_WIPE_TOWER);
|
||||
|
||||
// since this method must be idempotent, we clear brim paths *before*
|
||||
// checking whether we need to generate them
|
||||
print_->brim.clear();
|
||||
|
||||
if(print_->has_wipe_tower()) print_->_make_wipe_tower();
|
||||
|
||||
print_->state.set_done(STEP_WIPE_TOWER);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintController::slice(PrintObject *pobj)
|
||||
{
|
||||
assert(pobj != nullptr && print_ != nullptr);
|
||||
|
||||
if(pobj->state.is_done(STEP_SLICE)) return;
|
||||
|
||||
pobj->state.set_started(STEP_SLICE);
|
||||
|
||||
pobj->_slice();
|
||||
|
||||
auto msg = pobj->_fix_slicing_errors();
|
||||
if(!msg.empty()) report_issue(IssueType::WARN, msg);
|
||||
|
||||
// simplify slices if required
|
||||
if (print_->config.resolution)
|
||||
pobj->_simplify_slices(scale_(print_->config.resolution));
|
||||
|
||||
|
||||
if(pobj->layers.empty())
|
||||
report_issue(IssueType::ERR,
|
||||
"No layers were detected. You might want to repair your "
|
||||
"STL file(s) or check their size or thickness and retry"
|
||||
);
|
||||
|
||||
pobj->state.set_done(STEP_SLICE);
|
||||
}
|
||||
|
||||
void PrintController::make_perimeters(PrintObject *pobj)
|
||||
{
|
||||
assert(pobj != nullptr);
|
||||
|
||||
slice(pobj);
|
||||
|
||||
auto&& prgind = progress_indicator();
|
||||
|
||||
if (!pobj->state.is_done(STEP_PERIMETERS)) {
|
||||
pobj->_make_perimeters();
|
||||
}
|
||||
}
|
||||
|
||||
void PrintController::infill(PrintObject *pobj)
|
||||
{
|
||||
assert(pobj != nullptr);
|
||||
|
||||
make_perimeters(pobj);
|
||||
|
||||
if (!pobj->state.is_done(STEP_PREPARE_INFILL)) {
|
||||
pobj->state.set_started(STEP_PREPARE_INFILL);
|
||||
|
||||
pobj->_prepare_infill();
|
||||
|
||||
pobj->state.set_done(STEP_PREPARE_INFILL);
|
||||
}
|
||||
|
||||
pobj->_infill();
|
||||
}
|
||||
|
||||
void PrintController::gen_support_material(PrintObject *pobj)
|
||||
{
|
||||
assert(pobj != nullptr);
|
||||
|
||||
// prerequisites
|
||||
slice(pobj);
|
||||
|
||||
if(!pobj->state.is_done(STEP_SUPPORTMATERIAL)) {
|
||||
pobj->state.set_started(STEP_SUPPORTMATERIAL);
|
||||
|
||||
pobj->clear_support_layers();
|
||||
|
||||
if((pobj->config.support_material || pobj->config.raft_layers > 0)
|
||||
&& pobj->layers.size() > 1) {
|
||||
pobj->_generate_support_material();
|
||||
}
|
||||
|
||||
pobj->state.set_done(STEP_SUPPORTMATERIAL);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintController::slice()
|
||||
{
|
||||
Slic3r::trace(3, "Starting the slicing process.");
|
||||
|
||||
progress_indicator()->update(20u, "Generating perimeters");
|
||||
for(auto obj : print_->objects) make_perimeters(obj);
|
||||
|
||||
progress_indicator()->update(60u, "Infilling layers");
|
||||
for(auto obj : print_->objects) infill(obj);
|
||||
|
||||
progress_indicator()->update(70u, "Generating support material");
|
||||
for(auto obj : print_->objects) gen_support_material(obj);
|
||||
|
||||
progress_indicator()->message_fmt("Weight: %.1fg, Cost: %.1f",
|
||||
print_->total_weight,
|
||||
print_->total_cost);
|
||||
|
||||
progress_indicator()->state(85u);
|
||||
|
||||
|
||||
progress_indicator()->update(88u, "Generating skirt");
|
||||
make_skirt();
|
||||
|
||||
|
||||
progress_indicator()->update(90u, "Generating brim");
|
||||
make_brim();
|
||||
|
||||
progress_indicator()->update(95u, "Generating wipe tower");
|
||||
make_wipe_tower();
|
||||
|
||||
progress_indicator()->update(100u, "Done");
|
||||
|
||||
// time to make some statistics..
|
||||
|
||||
Slic3r::trace(3, "Slicing process finished.");
|
||||
}
|
||||
|
||||
void IProgressIndicator::message_fmt(
|
||||
const std::string &fmtstr, ...) {
|
||||
std::stringstream ss;
|
||||
va_list args;
|
||||
va_start(args, fmtstr);
|
||||
|
||||
auto fmt = fmtstr.begin();
|
||||
|
||||
while (*fmt != '\0') {
|
||||
if (*fmt == 'd') {
|
||||
int i = va_arg(args, int);
|
||||
ss << i << '\n';
|
||||
} else if (*fmt == 'c') {
|
||||
// note automatic conversion to integral type
|
||||
int c = va_arg(args, int);
|
||||
ss << static_cast<char>(c) << '\n';
|
||||
} else if (*fmt == 'f') {
|
||||
double d = va_arg(args, double);
|
||||
ss << d << '\n';
|
||||
}
|
||||
++fmt;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
message(ss.str());
|
||||
}
|
||||
|
||||
void AppController::arrange_model()
|
||||
{
|
||||
std::async(supports_asynch()? std::launch::async : std::launch::deferred,
|
||||
[this](){
|
||||
auto pind = progress_indicator();
|
||||
|
||||
// my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape);
|
||||
// my $success = $self->{model}->arrange_objects(wxTheApp->{preset_bundle}->full_config->min_object_distance, $bb);
|
||||
double dist = GUI::get_preset_bundle()->full_config().option("min_object_distance")->getFloat();
|
||||
|
||||
std::cout << dist << std::endl;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
267
xs/src/slic3r/AppController.hpp
Normal file
267
xs/src/slic3r/AppController.hpp
Normal file
|
@ -0,0 +1,267 @@
|
|||
#ifndef APPCONTROLLER_HPP
|
||||
#define APPCONTROLLER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
|
||||
#include "IProgressIndicator.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class Print;
|
||||
class PrintObject;
|
||||
|
||||
/**
|
||||
* @brief A boilerplate class for creating application logic. It should provide
|
||||
* features as issue reporting and progress indication, etc...
|
||||
*
|
||||
* The lower lever UI independent classes can be manipulated with a subclass
|
||||
* of this controller class. We can also catch any exceptions that lower level
|
||||
* methods could throw and display appropriate errors and warnings.
|
||||
*
|
||||
* Note that the outer and the inner interface of this class is free from any
|
||||
* UI toolkit dependencies. We can implement it with any UI framework or make it
|
||||
* a cli client.
|
||||
*/
|
||||
class AppControllerBoilerplate {
|
||||
class PriMap; // Some structure to store progress indication data
|
||||
public:
|
||||
|
||||
/// A Progress indicator object smart pointer
|
||||
using ProgresIndicatorPtr = std::shared_ptr<IProgressIndicator>;
|
||||
|
||||
private:
|
||||
|
||||
// Pimpl data for thread safe progress indication features
|
||||
std::unique_ptr<PriMap> progressind_;
|
||||
|
||||
public:
|
||||
|
||||
AppControllerBoilerplate();
|
||||
~AppControllerBoilerplate();
|
||||
|
||||
using Path = std::string;
|
||||
using PathList = std::vector<Path>;
|
||||
|
||||
/// Common runtime issue types
|
||||
enum class IssueType {
|
||||
INFO,
|
||||
WARN,
|
||||
WARN_Q, // Warning with a question to continue
|
||||
ERR,
|
||||
FATAL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Query some paths from the user.
|
||||
*
|
||||
* It should display a file chooser dialog in case of a UI application.
|
||||
* @param title Title of a possible query dialog.
|
||||
* @param extensions Recognized file extensions.
|
||||
* @return Returns a list of paths choosed by the user.
|
||||
*/
|
||||
PathList query_destination_paths(
|
||||
const std::string& title,
|
||||
const std::string& extensions) const;
|
||||
|
||||
/**
|
||||
* @brief Same as query_destination_paths but works for directories only.
|
||||
*/
|
||||
PathList query_destination_dirs(
|
||||
const std::string& title) const;
|
||||
|
||||
/**
|
||||
* @brief Same as query_destination_paths but returns only one path.
|
||||
*/
|
||||
Path query_destination_path(
|
||||
const std::string& title,
|
||||
const std::string& extensions,
|
||||
const std::string& hint = "") const;
|
||||
|
||||
/**
|
||||
* @brief Report an issue to the user be it fatal or recoverable.
|
||||
*
|
||||
* In a UI app this should display some message dialog.
|
||||
*
|
||||
* @param issuetype The type of the runtime issue.
|
||||
* @param description A somewhat longer description of the issue.
|
||||
* @param brief A very brief description. Can be used for message dialog
|
||||
* title.
|
||||
*/
|
||||
bool report_issue(IssueType issuetype,
|
||||
const std::string& description,
|
||||
const std::string& brief = "");
|
||||
|
||||
/**
|
||||
* @brief Set up a progress indicator for the current thread.
|
||||
* @param progrind An already created progress indicator object.
|
||||
*/
|
||||
void progress_indicator(ProgresIndicatorPtr progrind);
|
||||
|
||||
/**
|
||||
* @brief Create and set up a new progress indicator for the current thread.
|
||||
* @param statenum The number of states for the given procedure.
|
||||
* @param title The title of the procedure.
|
||||
* @param firstmsg The message for the first subtask to be displayed.
|
||||
*/
|
||||
void progress_indicator(unsigned statenum,
|
||||
const std::string& title,
|
||||
const std::string& firstmsg = "");
|
||||
|
||||
/**
|
||||
* @brief Return the progress indicator set up for the current thread. This
|
||||
* can be empty as well.
|
||||
* @return A progress indicator object implementing IProgressIndicator. If
|
||||
* a global progress indicator is available for the current implementation
|
||||
* than this will be set up for the current thread and returned.
|
||||
*/
|
||||
ProgresIndicatorPtr progress_indicator();
|
||||
|
||||
/**
|
||||
* @brief A predicate telling the caller whether it is the thread that
|
||||
* created the AppConroller object itself. This probably means that the
|
||||
* execution is in the UI thread. Otherwise it returns false meaning that
|
||||
* some worker thread called this function.
|
||||
* @return Return true for the same caller thread that created this
|
||||
* object and false for every other.
|
||||
*/
|
||||
bool is_main_thread() const;
|
||||
|
||||
/**
|
||||
* @brief The frontend supports asynch execution.
|
||||
*
|
||||
* A Graphic UI will support this, a CLI may not. This can be used in
|
||||
* subclass methods to decide whether to start threads for block free UI.
|
||||
*
|
||||
* Note that even a progress indicator's update called regularly can solve
|
||||
* the blocking UI problem in some cases even when an event loop is present.
|
||||
* This is how wxWidgets gauge work but creating a separate thread will make
|
||||
* the UI even more fluent.
|
||||
*
|
||||
* @return true if a job or method can be executed asynchronously, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool supports_asynch() const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief Create a new progress indicator and return a smart pointer to it.
|
||||
* @param statenum The number of states for the given procedure.
|
||||
* @param title The title of the procedure.
|
||||
* @param firstmsg The message for the first subtask to be displayed.
|
||||
* @return Smart pointer to the created object.
|
||||
*/
|
||||
ProgresIndicatorPtr create_progress_indicator(
|
||||
unsigned statenum,
|
||||
const std::string& title,
|
||||
const std::string& firstmsg = "") const;
|
||||
|
||||
// This is a global progress indicator placeholder. In the Slic3r UI it can
|
||||
// contain the progress indicator on the statusbar.
|
||||
ProgresIndicatorPtr global_progressind_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implementation of the printing logic.
|
||||
*/
|
||||
class PrintController: public AppControllerBoilerplate {
|
||||
Print *print_ = nullptr;
|
||||
protected:
|
||||
|
||||
void make_skirt();
|
||||
void make_brim();
|
||||
void make_wipe_tower();
|
||||
|
||||
void make_perimeters(PrintObject *pobj);
|
||||
void infill(PrintObject *pobj);
|
||||
void gen_support_material(PrintObject *pobj);
|
||||
|
||||
public:
|
||||
|
||||
// Must be public for perl to use it
|
||||
explicit inline PrintController(Print *print): print_(print) {}
|
||||
|
||||
PrintController(const PrintController&) = delete;
|
||||
PrintController(PrintController&&) = delete;
|
||||
|
||||
using Ptr = std::unique_ptr<PrintController>;
|
||||
|
||||
inline static Ptr create(Print *print) {
|
||||
return PrintController::Ptr( new PrintController(print) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Slice one pront object.
|
||||
* @param pobj The print object.
|
||||
*/
|
||||
void slice(PrintObject *pobj);
|
||||
|
||||
/**
|
||||
* @brief Slice the loaded print scene.
|
||||
*/
|
||||
void slice();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Top level controller.
|
||||
*/
|
||||
class AppController: public AppControllerBoilerplate {
|
||||
Model *model_ = nullptr;
|
||||
PrintController::Ptr printctl;
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Get the print controller object.
|
||||
*
|
||||
* @return Return a raw pointer instead of a smart one for perl to be able
|
||||
* to use this function and access the print controller.
|
||||
*/
|
||||
PrintController * print_ctl() { return printctl.get(); }
|
||||
|
||||
/**
|
||||
* @brief Set a model object.
|
||||
*
|
||||
* @param model A raw pointer to the model object. This can be used from
|
||||
* perl.
|
||||
*/
|
||||
void set_model(Model *model) { model_ = model; }
|
||||
|
||||
/**
|
||||
* @brief Set the print object from perl.
|
||||
*
|
||||
* This will create a print controller that will then be accessible from
|
||||
* perl.
|
||||
* @param print A print object which can be a perl-ish extension as well.
|
||||
*/
|
||||
void set_print(Print *print) {
|
||||
printctl = PrintController::create(print);
|
||||
printctl->progress_indicator(progress_indicator());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set up a global progress indicator.
|
||||
*
|
||||
* In perl we have a progress indicating status bar on the bottom of the
|
||||
* window which is defined and created in perl. We can pass the ID-s of the
|
||||
* gauge and the statusbar id and make a wrapper implementation of the
|
||||
* IProgressIndicator interface so we can use this GUI widget from C++.
|
||||
*
|
||||
* This function should be called from perl.
|
||||
*
|
||||
* @param gauge_id The ID of the gague widget of the status bar.
|
||||
* @param statusbar_id The ID of the status bar.
|
||||
*/
|
||||
void set_global_progress_indicator(unsigned gauge_id,
|
||||
unsigned statusbar_id);
|
||||
|
||||
void arrange_model();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // APPCONTROLLER_HPP
|
295
xs/src/slic3r/AppControllerWx.cpp
Normal file
295
xs/src/slic3r/AppControllerWx.cpp
Normal file
|
@ -0,0 +1,295 @@
|
|||
#include "AppController.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <future>
|
||||
|
||||
#include <slic3r/GUI/GUI.hpp>
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/gauge.h>
|
||||
#include <wx/statusbr.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
// This source file implements the UI dependent methods of the AppControllers.
|
||||
// It will be clear what is needed to be reimplemented in case of a UI framework
|
||||
// change or a CLI client creation. In this particular case we use wxWidgets to
|
||||
// implement everything.
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
bool AppControllerBoilerplate::supports_asynch() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AppControllerBoilerplate::PathList
|
||||
AppControllerBoilerplate::query_destination_paths(
|
||||
const std::string &title,
|
||||
const std::string &extensions) const
|
||||
{
|
||||
|
||||
wxFileDialog dlg(wxTheApp->GetTopWindow(), wxString(title) );
|
||||
dlg.SetWildcard(extensions);
|
||||
|
||||
dlg.ShowModal();
|
||||
|
||||
wxArrayString paths;
|
||||
dlg.GetPaths(paths);
|
||||
|
||||
PathList ret(paths.size(), "");
|
||||
for(auto& p : paths) ret.push_back(p.ToStdString());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
AppControllerBoilerplate::Path
|
||||
AppControllerBoilerplate::query_destination_path(
|
||||
const std::string &title,
|
||||
const std::string &extensions,
|
||||
const std::string& hint) const
|
||||
{
|
||||
wxFileDialog dlg(wxTheApp->GetTopWindow(), title );
|
||||
dlg.SetWildcard(extensions);
|
||||
|
||||
dlg.SetFilename(hint);
|
||||
|
||||
Path ret;
|
||||
|
||||
if(dlg.ShowModal() == wxID_OK) {
|
||||
ret = Path(dlg.GetPath());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AppControllerBoilerplate::report_issue(IssueType issuetype,
|
||||
const std::string &description,
|
||||
const std::string &brief)
|
||||
{
|
||||
auto icon = wxICON_INFORMATION;
|
||||
auto style = wxOK|wxCENTRE;
|
||||
switch(issuetype) {
|
||||
case IssueType::INFO: break;
|
||||
case IssueType::WARN: icon = wxICON_WARNING; break;
|
||||
case IssueType::WARN_Q: icon = wxICON_WARNING; style |= wxCANCEL; break;
|
||||
case IssueType::ERR:
|
||||
case IssueType::FATAL: icon = wxICON_ERROR;
|
||||
}
|
||||
|
||||
auto ret = wxMessageBox(description, brief, icon | style);
|
||||
return ret != wxCANCEL;
|
||||
}
|
||||
|
||||
wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent);
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
* A simple thread safe progress dialog implementation that can be used from
|
||||
* the main thread as well.
|
||||
*/
|
||||
class GuiProgressIndicator:
|
||||
public IProgressIndicator, public wxEvtHandler {
|
||||
|
||||
std::shared_ptr<wxProgressDialog> gauge_;
|
||||
using Base = IProgressIndicator;
|
||||
wxString message_;
|
||||
int range_; wxString title_;
|
||||
unsigned prc_ = 0;
|
||||
bool is_asynch_ = false;
|
||||
|
||||
const int id_ = wxWindow::NewControlId();
|
||||
|
||||
// status update handler
|
||||
void _state( wxCommandEvent& evt) {
|
||||
unsigned st = evt.GetInt();
|
||||
_state(st);
|
||||
}
|
||||
|
||||
// Status update implementation
|
||||
void _state( unsigned st) {
|
||||
if(st < max()) {
|
||||
if(!gauge_) gauge_ = std::make_shared<wxProgressDialog>(
|
||||
title_, message_, range_, wxTheApp->GetTopWindow(),
|
||||
wxPD_APP_MODAL | wxPD_AUTO_HIDE
|
||||
);
|
||||
|
||||
if(!gauge_->IsShown()) gauge_->ShowModal();
|
||||
Base::state(st);
|
||||
gauge_->Update(static_cast<int>(st), message_);
|
||||
}
|
||||
|
||||
if(st == max()) {
|
||||
prc_++;
|
||||
if(prc_ == Base::procedure_count()) {
|
||||
gauge_.reset();
|
||||
prc_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Setting whether it will be used from the UI thread or some worker thread
|
||||
inline void asynch(bool is) { is_asynch_ = is; }
|
||||
|
||||
/// Get the mode of parallel operation.
|
||||
inline bool asynch() const { return is_asynch_; }
|
||||
|
||||
inline GuiProgressIndicator(int range, const std::string& title,
|
||||
const std::string& firstmsg) :
|
||||
range_(range), message_(_(firstmsg)), title_(_(title))
|
||||
{
|
||||
Base::max(static_cast<float>(range));
|
||||
Base::states(static_cast<unsigned>(range));
|
||||
|
||||
Bind(PROGRESS_STATUS_UPDATE_EVENT,
|
||||
&GuiProgressIndicator::_state,
|
||||
this, id_);
|
||||
}
|
||||
|
||||
virtual void cancel() override {
|
||||
update(max(), "Abort");
|
||||
IProgressIndicator::cancel();
|
||||
}
|
||||
|
||||
virtual void state(float val) override {
|
||||
if( val >= 1.0) state(static_cast<unsigned>(val));
|
||||
}
|
||||
|
||||
void state(unsigned st) {
|
||||
// send status update event
|
||||
if(is_asynch_) {
|
||||
auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_);
|
||||
evt->SetInt(st);
|
||||
wxQueueEvent(this, evt);
|
||||
} else _state(st);
|
||||
}
|
||||
|
||||
virtual void message(const std::string & msg) override {
|
||||
message_ = _(msg);
|
||||
}
|
||||
|
||||
virtual void messageFmt(const std::string& fmt, ...) {
|
||||
va_list arglist;
|
||||
va_start(arglist, fmt);
|
||||
message_ = wxString::Format(_(fmt), arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
|
||||
virtual void title(const std::string & title) override {
|
||||
title_ = _(title);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
AppControllerBoilerplate::ProgresIndicatorPtr
|
||||
AppControllerBoilerplate::create_progress_indicator(
|
||||
unsigned statenum, const std::string& title,
|
||||
const std::string& firstmsg) const
|
||||
{
|
||||
auto pri =
|
||||
std::make_shared<GuiProgressIndicator>(statenum, title, firstmsg);
|
||||
|
||||
// We set up the mode of operation depending of the creator thread's
|
||||
// identity
|
||||
pri->asynch(!is_main_thread());
|
||||
|
||||
return pri;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// A wrapper progress indicator class around the statusbar created in perl.
|
||||
class Wrapper: public IProgressIndicator, public wxEvtHandler {
|
||||
wxGauge *gauge_;
|
||||
wxStatusBar *stbar_;
|
||||
using Base = IProgressIndicator;
|
||||
std::string message_;
|
||||
AppControllerBoilerplate& ctl_;
|
||||
|
||||
void showProgress(bool show = true) {
|
||||
gauge_->Show(show);
|
||||
}
|
||||
|
||||
void _state(unsigned st) {
|
||||
if( st <= max() ) {
|
||||
Base::state(st);
|
||||
|
||||
if(!gauge_->IsShown()) showProgress(true);
|
||||
|
||||
stbar_->SetStatusText(message_);
|
||||
if(st == gauge_->GetRange()) {
|
||||
gauge_->SetValue(0);
|
||||
showProgress(false);
|
||||
} else {
|
||||
gauge_->SetValue(static_cast<int>(st));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// status update handler
|
||||
void _state( wxCommandEvent& evt) {
|
||||
unsigned st = evt.GetInt(); _state(st);
|
||||
}
|
||||
|
||||
const int id_ = wxWindow::NewControlId();
|
||||
|
||||
public:
|
||||
|
||||
inline Wrapper(wxGauge *gauge, wxStatusBar *stbar,
|
||||
AppControllerBoilerplate& ctl):
|
||||
gauge_(gauge), stbar_(stbar), ctl_(ctl)
|
||||
{
|
||||
Base::max(static_cast<float>(gauge->GetRange()));
|
||||
Base::states(static_cast<unsigned>(gauge->GetRange()));
|
||||
|
||||
Bind(PROGRESS_STATUS_UPDATE_EVENT,
|
||||
&Wrapper::_state,
|
||||
this, id_);
|
||||
}
|
||||
|
||||
virtual void state(float val) override {
|
||||
if(val >= 1.0) state(unsigned(val));
|
||||
}
|
||||
|
||||
void state(unsigned st) {
|
||||
if(!ctl_.is_main_thread()) {
|
||||
auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_);
|
||||
evt->SetInt(st);
|
||||
wxQueueEvent(this, evt);
|
||||
} else _state(st);
|
||||
}
|
||||
|
||||
virtual void message(const std::string & msg) override {
|
||||
message_ = msg;
|
||||
}
|
||||
|
||||
virtual void message_fmt(const std::string& fmt, ...) override {
|
||||
va_list arglist;
|
||||
va_start(arglist, fmt);
|
||||
message_ = wxString::Format(_(fmt), arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
|
||||
virtual void title(const std::string & /*title*/) override {}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
void AppController::set_global_progress_indicator(
|
||||
unsigned gid,
|
||||
unsigned sid)
|
||||
{
|
||||
wxGauge* gauge = dynamic_cast<wxGauge*>(wxWindow::FindWindowById(gid));
|
||||
wxStatusBar* sb = dynamic_cast<wxStatusBar*>(wxWindow::FindWindowById(sid));
|
||||
|
||||
if(gauge && sb) {
|
||||
global_progressind_ = std::make_shared<Wrapper>(gauge, sb, *this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
84
xs/src/slic3r/IProgressIndicator.hpp
Normal file
84
xs/src/slic3r/IProgressIndicator.hpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#ifndef IPROGRESSINDICATOR_HPP
|
||||
#define IPROGRESSINDICATOR_HPP
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
/**
|
||||
* @brief Generic progress indication interface.
|
||||
*/
|
||||
class IProgressIndicator {
|
||||
public:
|
||||
using CancelFn = std::function<void(void)>; // Cancel functio signature.
|
||||
|
||||
private:
|
||||
float state_ = .0f, max_ = 1.f, step_;
|
||||
CancelFn cancelfunc_ = [](){};
|
||||
unsigned proc_count_ = 1;
|
||||
|
||||
public:
|
||||
|
||||
inline virtual ~IProgressIndicator() {}
|
||||
|
||||
/// Get the maximum of the progress range.
|
||||
float max() const { return max_; }
|
||||
|
||||
/// Get the current progress state
|
||||
float state() const { return state_; }
|
||||
|
||||
/// Set the maximum of hte progress range
|
||||
virtual void max(float maxval) { max_ = maxval; }
|
||||
|
||||
/// Set the current state of the progress.
|
||||
virtual void state(float val) { state_ = val; }
|
||||
|
||||
/**
|
||||
* @brief Number of states int the progress. Can be used insted of giving a
|
||||
* maximum value.
|
||||
*/
|
||||
virtual void states(unsigned statenum) {
|
||||
step_ = max_ / statenum;
|
||||
}
|
||||
|
||||
/// Message shown on the next status update.
|
||||
virtual void message(const std::string&) = 0;
|
||||
|
||||
/// Title of the operaton.
|
||||
virtual void title(const std::string&) = 0;
|
||||
|
||||
/// Formatted message for the next status update. Works just like sprinf.
|
||||
virtual void message_fmt(const std::string& fmt, ...);
|
||||
|
||||
/// Set up a cancel callback for the operation if feasible.
|
||||
inline void on_cancel(CancelFn func) { cancelfunc_ = func; }
|
||||
|
||||
/**
|
||||
* Explicitly shut down the progress indicator and call the associated
|
||||
* callback.
|
||||
*/
|
||||
virtual void cancel() { cancelfunc_(); }
|
||||
|
||||
/**
|
||||
* \brief Set up how many subprocedures does the whole operation contain.
|
||||
*
|
||||
* This was neccesary from practical reasons. If the progress indicator is
|
||||
* a dialog and we want to show the progress of a few sub operations than
|
||||
* the dialog wont be closed and reopened each time a new sub operation is
|
||||
* started. This is not a mandatory feature and can be ignored completely.
|
||||
*/
|
||||
inline void procedure_count(unsigned pc) { proc_count_ = pc; }
|
||||
|
||||
/// Get the current procedure count
|
||||
inline unsigned procedure_count() const { return proc_count_; }
|
||||
|
||||
/// Convinience function to call message and status update in one function.
|
||||
void update(float st, const std::string& msg) {
|
||||
message(msg); state(st);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // IPROGRESSINDICATOR_HPP
|
|
@ -80,6 +80,7 @@ extern "C" {
|
|||
#include <Polygon.hpp>
|
||||
#include <Polyline.hpp>
|
||||
#include <TriangleMesh.hpp>
|
||||
#include <slic3r/AppController.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
27
xs/xsp/AppController.xsp
Normal file
27
xs/xsp/AppController.xsp
Normal file
|
@ -0,0 +1,27 @@
|
|||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "slic3r/AppController.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::PrintController} class PrintController {
|
||||
|
||||
PrintController(Print *print);
|
||||
|
||||
void slice();
|
||||
};
|
||||
|
||||
%name{Slic3r::AppController} class AppController {
|
||||
|
||||
AppController();
|
||||
|
||||
PrintController *print_ctl();
|
||||
void set_model(Model *model);
|
||||
void set_print(Print *print);
|
||||
void set_global_progress_indicator(unsigned gauge_id, unsigned statusbar_id);
|
||||
|
||||
void arrange_model();
|
||||
};
|
|
@ -216,6 +216,8 @@ Ref<PrintObjectSupportMaterial> O_OBJECT_SLIC3R_T
|
|||
Clone<PrintObjectSupportMaterial> O_OBJECT_SLIC3R_T
|
||||
|
||||
AppConfig* O_OBJECT_SLIC3R
|
||||
AppController* O_OBJECT_SLIC3R
|
||||
PrintController* O_OBJECT_SLIC3R
|
||||
Ref<AppConfig> O_OBJECT_SLIC3R_T
|
||||
|
||||
GLShader* O_OBJECT_SLIC3R
|
||||
|
|
|
@ -268,3 +268,5 @@
|
|||
$CVar = (PrintObjectStep)SvUV($PerlVar);
|
||||
%};
|
||||
};
|
||||
%typemap{AppController*};
|
||||
%typemap{PrintController*};
|
||||
|
|
Loading…
Reference in a new issue