From a52a4bcbb215f8157de55d8cdb1f2c497147bf4a Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Sun, 29 Sep 2024 13:18:13 +0200 Subject: [PATCH] Start using the new interface --- src/slic3r/GUI/ArrangeHelper.cpp | 222 +++++++++++-------------------- src/slic3r/GUI/ArrangeHelper.hpp | 5 +- src/slic3r/GUI/GLCanvas3D.cpp | 50 +++---- 3 files changed, 97 insertions(+), 180 deletions(-) diff --git a/src/slic3r/GUI/ArrangeHelper.cpp b/src/slic3r/GUI/ArrangeHelper.cpp index 5b39409eab..f90ae679cd 100644 --- a/src/slic3r/GUI/ArrangeHelper.cpp +++ b/src/slic3r/GUI/ArrangeHelper.cpp @@ -3,180 +3,122 @@ #include "libslic3r/Model.hpp" #include "libslic3r/TriangleMesh.hpp" -#include "boost/algorithm/string/split.hpp" -#include "boost/filesystem/path.hpp" - #include +#include "libseqarrange/include/seq_interface.hpp" +#include "libseqarrange/include/seq_sequential.hpp" + namespace Slic3r { +static Sequential::PrinterGeometry get_printer_geometry() { + enum ShapeType { + BOX, + CONVEX + }; + struct ExtruderSlice { + coord_t height; + ShapeType shape_type; + std::vector polygons; -static bool find_and_remove(std::string& src, const std::string& key) -{ - size_t pos = src.find(key); - if (pos != std::string::npos) { - src.erase(pos, key.length()); - return true; + }; + + // Just hardcode MK4 geometry for now. + std::vector slices; + slices.push_back(ExtruderSlice{ 0, CONVEX, { { { -500000, -500000 }, { 500000, -500000 }, { 500000, 500000 }, { -500000, 500000 } } } }); + slices.push_back(ExtruderSlice{ 3000000, CONVEX, { { { -1000000, -21000000 }, { 37000000, -21000000 }, { 37000000, 44000000 }, { -1000000, 44000000 } }, + { { -40000000, -45000000 }, { 38000000, -45000000 }, { 38000000, 20000000 }, { -40000000, 20000000 } } } }); + slices.push_back(ExtruderSlice{ 11000000, BOX, { { {-350000000, -4000000 }, {350000000, -4000000 }, {350000000, -14000000 }, {-350000000, -14000000 } } } }); + slices.push_back(ExtruderSlice{ 13000000, BOX, { { { -12000000, -350000000 }, { 9000000, -350000000 }, { 9000000, -39000000 }, { -12000000, -39000000 } }, + { { -12000000, -350000000 }, {250000000, -350000000 }, {250000000, -82000000 }, { -12000000, -82000000} } } }); + + Sequential::PrinterGeometry out; + out.x_size = 250000000; + out.y_size = 210000000; + for (const ExtruderSlice& slice : slices) { + (slice.shape_type == CONVEX ? out.convex_heights : out.box_heights).emplace(slice.height); + out.extruder_slices.insert(std::make_pair(slice.height, slice.polygons)); } - return false; + return out; } -struct ObjectToPrint { - int id = 0; - coord_t total_height = 0; - std::vector> pgns_at_height; -}; - -std::vector load_exported_data(const std::string& filename) +static Sequential::SolverConfiguration get_solver_config(const Sequential::PrinterGeometry& printer_geometry) { - std::vector objects_to_print; - - std::ifstream in(filename); - if (! in) - throw std::runtime_error("NO EXPORTED FILE WAS FOUND"); - std::string line; - - while (in) { - std::getline(in, line); - if (find_and_remove(line, "OBJECT_ID")) { - objects_to_print.push_back(ObjectToPrint()); - objects_to_print.back().id = std::stoi(line); - } - if (find_and_remove(line, "TOTAL_HEIGHT")) - objects_to_print.back().total_height = std::stoi(line); - if (find_and_remove(line, "POLYGON_AT_HEIGHT")) - objects_to_print.back().pgns_at_height.emplace_back(std::make_pair(std::stoi(line), Polygon())); - if (find_and_remove(line, "POINT")) { - std::stringstream ss(line); - std::string val; - ss >> val; - Point pt(std::stoi(val), 0); - ss >> val; - pt.y() = std::stoi(val); - objects_to_print.back().pgns_at_height.back().second.append(pt); - } - } - return objects_to_print; + return Sequential::SolverConfiguration(printer_geometry); } -std::vector read_required_heights() +static std::vector get_objects_to_print(const Model& model, const Sequential::PrinterGeometry& printer_geometry) { + // First extract the heights of interest. std::vector heights; - std::ifstream out("printer_geometry.mk4.txt"); - std::string line; - std::array keys = {"CONVEX_HEIGHT", "BOX_HEIGHT"}; - while (out) { - std::getline(out, line); - for (const std::string& key : keys) { - if (size_t pos = line.find(key); pos != std::string::npos) { - line = line.substr(pos + key.size()); - heights.push_back(double(std::stoi(line)) * SCALING_FACTOR); - break; - } - } - } - return heights; -} + for (const auto& [height, pgns] : printer_geometry.extruder_slices) + heights.push_back(unscaled(height)); + Slic3r::sort_remove_duplicates(heights); - - -void export_arrange_data(const Model& model, const std::vector& heights) -{ - std::ofstream out("arrange_data_export.txt"); + // Now collect all objects and projections of convex hull above respective heights. + std::vector objects; for (const ModelObject* mo : model.objects) { - // Calculate polygon describing convex hull of everything above given heights. const ModelInstance* mi = mo->instances.front(); - out << "OBJECT_ID" << mo->id().id << std::endl; - out << "TOTAL_HEIGHT" << scaled(mo->instance_bounding_box(0).size().z()) << std::endl;; + objects.emplace_back(Sequential::ObjectToPrint{int(mo->id().id), scaled(mo->instance_bounding_box(0).size().z()), {}}); for (double height : heights) { auto tr = Transform3d::Identity(); Vec3d offset = mi->get_offset(); tr.translate(Vec3d(-offset.x(), -offset.y(), 0.)); Polygon pgn = its_convex_hull_2d_above(mo->mesh().its, tr.cast(), height); - out << "POLYGON_AT_HEIGHT" << scaled(height) << std::endl; - for (const Point& pt : pgn) - out << "POINT" << pt.x() << " " << pt.y() << std::endl; + objects.back().pgns_at_height.emplace_back(std::make_pair(scaled(height), pgn)); } } + return objects; } -void import_arrange_data(Model& model, bool delete_files) +void arrange_model_sequential(Model& model) { - // First go through all files in the current directory - // and remember all which match the pattern. - namespace fs = boost::filesystem; - fs::path p("."); - fs::directory_iterator end_itr; - std::vector filenames; - for (fs::directory_iterator itr(p); itr != end_itr; ++itr) - { - if (fs::is_regular_file(itr->path())) { - std::string name = itr->path().filename().string(); - if (boost::starts_with(name, "arrange_data_import") && boost::ends_with(name, ".txt")) - filenames.emplace_back(name); - } - } - // Sort the files alphabetically. - std::sort(filenames.begin(), filenames.end()); - + Sequential::PrinterGeometry printer_geometry = get_printer_geometry(); + Sequential::SolverConfiguration solver_config = get_solver_config(printer_geometry); + std::vector objects = get_objects_to_print(model, printer_geometry); + + // Everything ready - let libseqarrange do the actual arrangement. + std::vector plates = + Sequential::schedule_ObjectsForSequentialPrint( + solver_config, + printer_geometry, + objects); + // Extract the result and move the objects in Model accordingly. struct MoveData { - size_t id; - coord_t x; - coord_t y; + Sequential::ScheduledObject scheduled_object; size_t bed_idx; }; - // A vector to collect move data for all the files. + // A vector to collect move data for all the objects. std::vector move_data_all; - // Now iterate through all the files, read the data and move the objects accordingly. // Save the move data from this file to move_data_all. size_t bed_idx = 0; - for (const std::string& name : filenames) { - std::cout << " - loading file " << name << "..." << std::endl; - std::ifstream in(name); - - std::string line; - std::vector move_data; - while (in) { - std::getline(in, line); - std::vector values; - boost::split(values, line, boost::is_any_of(" ")); - if (values.size() > 2) - move_data.emplace_back(MoveData{size_t(std::stoi(values[0])), std::stoi(values[1]), std::stoi(values[2]), bed_idx}); - } - + for (const Sequential::ScheduledPlate& plate : plates) { // Iterate the same way as when exporting. for (ModelObject* mo : model.objects) { ModelInstance* mi = mo->instances.front(); const ObjectID& oid = mo->id(); - auto it = std::find_if(move_data.begin(), move_data.end(), [&oid](const auto& md) { return md.id == oid.id; }); - if (it != move_data.end()) { + auto it = std::find_if(plate.scheduled_objects.begin(), plate.scheduled_objects.end(), [&oid](const auto& md) { return md.id == oid.id; }); + if (it != plate.scheduled_objects.end()) { mi->set_offset(Vec3d(unscaled(it->x) + bed_idx * 300, unscaled(it->y), mi->get_offset().z())); } } - move_data_all.insert(move_data_all.end(), move_data.begin(), move_data.end()); + for (const Sequential::ScheduledObject& object : plate.scheduled_objects) + move_data_all.push_back({ object, bed_idx }); ++bed_idx; } - if (delete_files) { - std::cout << " - removing all the files..."; - for (const std::string& name : filenames) - fs::remove(fs::path(name)); - std::cout << "done" << std::endl; - } - // Now reorder the objects in the model so they are in the same order as requested. auto comp = [&move_data_all](ModelObject* mo1, ModelObject* mo2) { - auto it1 = std::find_if(move_data_all.begin(), move_data_all.end(), [&mo1](const auto& md) { return md.id == mo1->id().id; }); - auto it2 = std::find_if(move_data_all.begin(), move_data_all.end(), [&mo2](const auto& md) { return md.id == mo2->id().id; }); + auto it1 = std::find_if(move_data_all.begin(), move_data_all.end(), [&mo1](const auto& md) { return md.scheduled_object.id == mo1->id().id; }); + auto it2 = std::find_if(move_data_all.begin(), move_data_all.end(), [&mo2](const auto& md) { return md.scheduled_object.id == mo2->id().id; }); return it1->bed_idx == it2->bed_idx ? it1 < it2 : it1->bed_idx < it2->bed_idx; }; std::sort(model.objects.begin(), model.objects.end(), comp); @@ -184,35 +126,21 @@ void import_arrange_data(Model& model, bool delete_files) -void export_run_and_import_arrange_data(Model& model, const std::string& cmd, bool delete_files) +bool check_seq_printability(const Model& model) { - std::cout << "Reading height from printer_geometry.mk4.txt" << std::endl; - std::vector heights = read_required_heights(); - if (heights.empty()) { - std::cout << "unable" << std::endl; - return; + Sequential::PrinterGeometry printer_geometry = get_printer_geometry(); + Sequential::SolverConfiguration solver_config = get_solver_config(printer_geometry); + std::vector objects = get_objects_to_print(model, printer_geometry); + + // FIXME: This does not consider plates, non-printable objects and instances. + Sequential::ScheduledPlate plate; + for (ModelObject* mo : model.objects) { + ModelInstance* mi = mo->instances.front(); + plate.scheduled_objects.emplace_back(mo->id().id, scaled(mi->get_offset().x()), scaled(mi->get_offset().y())); } - std::cout << "Exporting the arrange data..."; - export_arrange_data(model, heights); - std::cout << "done" << std::endl; - - std::cout << "Running " << cmd << std::endl; - int out = wxExecute(wxString::FromUTF8(cmd), wxEXEC_SYNC); - if (out == -1) { - std::cout << "unable" << std::endl; - return; - } - std::cout << "sequential_prusa returned " << out << (out == 0 ? ": ok" : ": appears to be an error") << std::endl; - - if (out ==0 ) { - std::cout << "Importing the arrange data..." << std::endl; - import_arrange_data(model, delete_files); - std::cout << "Import done" << std::endl; - } + return Sequential::check_ScheduledObjectsForSequentialPrintability(solver_config, printer_geometry, objects, std::vector(1, plate)); } - - -} +} // namespace Slic3r diff --git a/src/slic3r/GUI/ArrangeHelper.hpp b/src/slic3r/GUI/ArrangeHelper.hpp index 63cc351e56..953babe43e 100644 --- a/src/slic3r/GUI/ArrangeHelper.hpp +++ b/src/slic3r/GUI/ArrangeHelper.hpp @@ -4,9 +4,8 @@ class Model; namespace Slic3r { - void export_run_and_import_arrange_data(Model&, const std::string&, bool); - void export_arrange_data(const Model& model, const std::vector& heights); - void import_arrange_data(Model& model, bool delete_files); + void arrange_model_sequential(Model& model); + bool check_seq_printability(const Model& model); } #endif // slic3r_Arrange_Helper_hpp \ No newline at end of file diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4eda5dca27..4848105926 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2224,39 +2224,29 @@ void GLCanvas3D::render() // This is just temporary pipe to export data to the separate arrange algorithm // and importing the result back. TESTING ONLY !!! ImGui::Begin("TESTING ONLY (arrange)"); - static bool decimation = true; - static bool precision_high = false; - static bool assumptions = false; - static int object_group_size = 4; - static bool delete_files = true; - static std::string printer_file = "printer_geometry.mk4.txt"; - ImGui::Checkbox("Decimation", &decimation); - ImGui::Checkbox("Precision", &precision_high); - ImGui::Checkbox("Assumptions", &assumptions); - ImGui::InputInt("Group size", &object_group_size); - wxGetApp().imgui()->disabled_begin(true); - ImGui::InputText("Printer file", printer_file.data(), printer_file.size()); - wxGetApp().imgui()->disabled_end(); - ImGui::Separator(); - ImGui::Checkbox("Delete files after use", &delete_files); - - std::stringstream ss; - ss << "./sequential_prusa" - << " --decimation=" << (decimation ? "yes" : "no") - << " --precision=" << (precision_high ? "high" : "low") - << " --assumptions=" << (assumptions ? "yes" : "no") - << " --object-group-size=" << object_group_size - << " --printer-file=" << printer_file - << " --interactive=no"; - ImGui::Text((std::string("Command: '") + ss.str() + "'").c_str()); - - - if (ImGui::Button("Do external arrange")) { - export_run_and_import_arrange_data(wxGetApp().plater()->model(), ss.str(), delete_files); + if (ImGui::Button("Do sequential arrange")) { + arrange_model_sequential(wxGetApp().plater()->model()); reload_scene(true, true); wxGetApp().obj_list()->update_after_undo_redo(); } - ImGui::End(); + + static auto time_start = std::chrono::high_resolution_clock::now(); + auto time_now = std::chrono::high_resolution_clock::now(); + int time_limit_s = 1; + static bool last_res = 0; + bool valid = std::chrono::duration_cast(time_now - time_start).count() < time_limit_s; + + ImGui::Text(""); + ImGui::Separator(); + ImGui::Text(""); + if (ImGui::Button("Test:")) { + last_res = check_seq_printability(wxGetApp().plater()->model()); + time_start = std::chrono::high_resolution_clock::now(); + } + ImGui::SameLine(); + ImGui::TextColored((valid && last_res ? ImVec4(0.,1.,0.,1.) : (valid ? ImVec4(1.,0.,0.,1.) : ImVec4(0.5,.5,0.5,1.))) , "\u25a0"); + ImGui::Text("(So far, multiple beds are not accounted for.)"); + ImGui::End(); }