#include "AppController.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Slic3r { class AppControllerBoilerplate::PriData { public: std::mutex m; std::thread::id ui_thread; inline explicit PriData(std::thread::id uit): ui_thread(uit) {} }; AppControllerBoilerplate::AppControllerBoilerplate() :pri_data_(new PriData(std::this_thread::get_id())) {} AppControllerBoilerplate::~AppControllerBoilerplate() { pri_data_.reset(); } bool AppControllerBoilerplate::is_main_thread() const { return pri_data_->ui_thread == std::this_thread::get_id(); } namespace GUI { PresetBundle* get_preset_bundle(); } AppControllerBoilerplate::ProgresIndicatorPtr AppControllerBoilerplate::global_progress_indicator() { ProgresIndicatorPtr ret; pri_data_->m.lock(); ret = global_progressind_; pri_data_->m.unlock(); return ret; } void AppControllerBoilerplate::global_progress_indicator( AppControllerBoilerplate::ProgresIndicatorPtr gpri) { pri_data_->m.lock(); global_progressind_ = gpri; pri_data_->m.unlock(); } void ProgressIndicator::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(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() { using Coord = libnest2d::TCoord; if(arranging_.load()) return; // to prevent UI reentrancies arranging_.store(true); unsigned count = 0; for(auto obj : model_->objects) count += obj->instances.size(); auto pind = global_progress_indicator(); float pmax = 1.0; if(pind) { pmax = pind->max(); // Set the range of the progress to the object count pind->max(count); pind->on_cancel([this](){ arranging_.store(false); }); } auto dist = print_ctl()->config().min_object_distance(); // Create the arranger config auto min_obj_distance = static_cast(dist/SCALING_FACTOR); auto& bedpoints = print_ctl()->config().bed_shape.values; Polyline bed; bed.points.reserve(bedpoints.size()); for(auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1))); if(pind) pind->update(0, L("Arranging objects...")); try { arr::BedShapeHint hint; // TODO: from Sasha from GUI hint.type = arr::BedShapeType::WHO_KNOWS; arr::arrange(*model_, min_obj_distance, bed, hint, false, // create many piles not just one pile [this, pind, count](unsigned rem) { if(pind) 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, L("Could not arrange model objects! " "Some geometries may be invalid."), L("Exception occurred")); } // Restore previous max value if(pind) { pind->max(pmax); pind->update(0, arranging_.load() ? L("Arranging done.") : L("Arranging canceled.")); pind->on_cancel(/*remove cancel function*/); } arranging_.store(false); } }