diff --git a/resources/data/printer_gantries/geometries.txt b/resources/data/printer_gantries/geometries.txt new file mode 100644 index 0000000000..5362014d63 --- /dev/null +++ b/resources/data/printer_gantries/geometries.txt @@ -0,0 +1,99 @@ +{ + "printers": [ + { + "printer_notes_regex": ".*PRINTER_MODEL_MK4.*", + "gantry_model_filename": "prusa3d_mk4_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-5,-5;5,-5;5,5;-5,5" + ] + }, + { + "height": "3", + "type": "convex", + "polygons": [ + "-10,-21;37,-21;37,44;-10,44", + "-40,-45;38,-45;38,20;-40,20" + ] + }, + { + "height": "11", + "type": "box", + "polygons": [ + "-350,-23;350,-23;350,-35;-350,-35" + ] + }, + { + "height": "13", + "type": "box", + "polygons": [ + "-13,-84;11,-84;11,-38;-13,-38", + "11,-300;300,-300;300,-84;11,-84" + ] + } + ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_MK3.*", + "gantry_model_filename": "prusa3d_mk3_gantry.stl", + "slices": [ + { + "height": "0", + "type": "convex", + "polygons": [ + "-5,-5;5,-5;5,5;-5,5", + "-30,-12;-14,-12;-14,2;-30,2" + ] + }, + { + "height": "2", + "type": "convex", + "polygons": [ + "-20,-38;44,-38;44,18;-20,18" + ] + }, + { + "height": "6", + "type": "convex", + "polygons": [ + "-34,-43;37,-43;37,16;-34,16", + "-45,9;37,9;37,69;-45,69" + ] + }, + { + "height": "11", + "type": "box", + "polygons": [ + "-8,-82;8,-82;8,-36;-8,-36", + "-8,-82;250,-82;250,-300;-8,-300" + ] + }, + { + "height": "17", + "type": "box", + "polygons": [ + "-300,-35;300,-35;300,-21;-300,-21" + ] + } + ] + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_MINI.*", + "gantry_model_filename": "prusa3d_mini_gantry.stl", + "slices": "" + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_XL.*", + "gantry_model_filename": "prusa3d_xl_gantry.stl", + "slices": "" + }, + { + "printer_notes_regex": ".*PRINTER_MODEL_CORE.*", + "gantry_model_filename": "prusa3d_coreone_gantry.stl", + "slices": "" + } + ] +} diff --git a/src/slic3r/GUI/ArrangeHelper.cpp b/src/slic3r/GUI/ArrangeHelper.cpp index 530a0d0d25..b5f5699376 100644 --- a/src/slic3r/GUI/ArrangeHelper.cpp +++ b/src/slic3r/GUI/ArrangeHelper.cpp @@ -3,15 +3,19 @@ #include "libslic3r/Model.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/MultipleBeds.hpp" +#include "libslic3r/PresetBundle.hpp" #include +#include "boost/regex.hpp" + namespace Slic3r { -static Sequential::PrinterGeometry get_printer_geometry() { +static Sequential::PrinterGeometry get_printer_geometry(const DynamicPrintConfig& config) +{ enum ShapeType { BOX, CONVEX @@ -23,31 +27,35 @@ static Sequential::PrinterGeometry get_printer_geometry() { }; - // Just hardcode geometry (simplified head model) for the Original Prusa MK4. + std::vector> printers_geometries; + std::vector> printers_regexps; std::vector slices; + + // Just hardcode geometry (simplified head model) for the Original Prusa MK4. slices.push_back(ExtruderSlice{ 0, CONVEX, { { { -5000000, -5000000 }, { 5000000, -5000000 }, { 5000000, 5000000 }, { -5000000, 5000000 } } } }); slices.push_back(ExtruderSlice{ 3000000, CONVEX, { { { -10000000, -21000000 }, { 37000000, -21000000 }, { 37000000, 44000000 }, { -10000000, 44000000 } }, { { -40000000, -45000000 }, { 38000000, -45000000 }, { 38000000, 20000000 }, { -40000000, 20000000 } } } }); slices.push_back(ExtruderSlice{ 11000000, BOX, { { {-350000000, -23000000 }, { 350000000, -23000000 }, { 350000000, -35000000 }, {-350000000, -35000000 } } } }); slices.push_back(ExtruderSlice{ 13000000, BOX, { { { -13000000, -84000000 }, { 11000000, -84000000 }, { 11000000, -38000000 }, { -13000000, -38000000 } }, { { 11000000, -300000000 }, { 300000000, -300000000 }, { 300000000, -84000000 }, { 11000000, -84000000 } } } }); - + printers_geometries.emplace_back(slices); + printers_regexps.push_back({ ".*PRINTER_MODEL_MK4.*", "prusa3d_mk4_gantry.stl" }); + slices = {}; + // Geometry (simplified head model) for the Original Prusa MK3S+ printer - /* - std::vector slices; - slices.push_back(ExtruderSlice{ 0, CONVEX, { { { -5000000, -5000000 }, { 5000000, -5000000 }, { 5000000, 5000000 }, { -5000000, 5000000 } } , - { { -30000000, -12000000 }, { -14000000, -12000000 }, { -14000000, 2000000 }, { -30000000, 2000000 } } } }); - slices.push_back(ExtruderSlice{ 2000000, CONVEX, { { { -20000000, -38000000 }, { 44000000, -38000000 }, { 44000000, 18000000 }, { -20000000, 18000000 } } } }); - slices.push_back(ExtruderSlice{ 6000000, CONVEX, { { { -34000000, -43000000 }, { 37000000, -43000000 }, { 37000000, 16000000 }, { -34000000, 16000000 } }, + slices.push_back(ExtruderSlice{ 0, CONVEX, { { { -5000000, -5000000 }, { 5000000, -5000000 }, { 5000000, 5000000 }, { -5000000, 5000000 } } , + { { -30000000, -12000000 }, { -14000000, -12000000 }, { -14000000, 2000000 }, { -30000000, 2000000 } } } }); + slices.push_back(ExtruderSlice{ 2000000, CONVEX, { { { -20000000, -38000000 }, { 44000000, -38000000 }, { 44000000, 18000000 }, { -20000000, 18000000 } } } }); + slices.push_back(ExtruderSlice{ 6000000, CONVEX, { { { -34000000, -43000000 }, { 37000000, -43000000 }, { 37000000, 16000000 }, { -34000000, 16000000 } }, { { -45000000, 9000000 }, { 37000000, 9000000 }, { 37000000, 69000000 }, { -45000000, 69000000 } } } }); slices.push_back(ExtruderSlice{11000000, BOX, { { { -8000000, -82000000 }, { 8000000, -82000000 }, { 8000000, -36000000 }, { -8000000, -36000000 } }, { { -8000000, -82000000 }, { 250000000, -82000000 }, { 250000000, -300000000 }, { -8000000, -300000000 } } } }); slices.push_back(ExtruderSlice{17000000, BOX, { { { -300000000, -35000000 }, { 300000000, -35000000 }, { 300000000, -21000000 }, { -300000000, -21000000 } } } }); - */ + printers_geometries.emplace_back(slices); + printers_regexps.push_back({ ".*PRINTER_MODEL_MK3.*", "prusa3d_mk3s_gantry.stl" }); + slices = {}; // Geometry (simplified head model) for the Original Prusa Mini+ printer - /* - std::vector slices; slices.push_back(ExtruderSlice{ 0, CONVEX, { { { -5000000, -5000000 }, { 5000000, -5000000 }, { 5000000, 5000000 }, { -5000000, 5000000 } }, { { 24000000, -3000000 }, { 35000000, -3000000 }, { 35000000, 10000000 }, { 24000000, 10000000 } }, { { -5000000, 4000000 }, { 5000000, 4000000 }, { 5000000, 18000000 }, { -5000000, 18000000 } } } }); @@ -56,32 +64,127 @@ static Sequential::PrinterGeometry get_printer_geometry() { { { -17000000, -44000000 }, { 43000000, -44000000 }, { 43000000, 33000000 }, { -17000000, 33000000 } } } }); slices.push_back(ExtruderSlice{ 22000000, BOX, { { {-200000000, -28000000 }, { 200000000, -28000000 }, { 200000000, -14000000 }, { -200000000, -14000000 } } } }); slices.push_back(ExtruderSlice{100000000, BOX, { { {-200000000, -200000000 }, { 10000000, -200000000 }, { 10000000, 10000000 }, { -200000000, 10000000 } } } }); - */ + printers_geometries.emplace_back(slices); + printers_regexps.push_back({ ".*PRINTER_MODEL_MINI.*", "prusa3d_mini_gantry.stl" }); + slices = {}; + // Geometry (simplified head model) for the Original Prusa XL printer - /* - std::vector slices; slices.push_back(ExtruderSlice{0, CONVEX, { { { -5000000, -5000000 }, { 5000000, -5000000 }, { 5000000, 5000000 }, { -5000000, 5000000 } } } }); slices.push_back(ExtruderSlice{2000000, CONVEX, { { { -10000000, -47000000 }, { 34000000, -47000000 }, { 34000000, 16000000 }, { -10000000, 16000000 } }, { { -34000000, 13000000 }, { 32000000, 13000000 }, { 32000000, 67000000 }, { -34000000, 67000000 } } } }); slices.push_back(ExtruderSlice{23000000, CONVEX, { { { -42000000, 11000000 }, { 32000000, 11000000 }, { 32000000, 66000000 }, { -42000000, 66000000 } }, { { -33000000, -37000000 }, { 43000000, -37000000 }, { 43000000, 18000000 }, { -33000000, 18000000 } }, { { -13000000, -68000000 }, { 47000000, -68000000 }, { 47000000, -30000000 }, { -13000000, -30000000 } } } }); - slices.push_back(ExtruderSlice{19000000, BOX, { { { -400000000, 24000000 }, { 400000000, 24000000 }, { 400000000, 50000000 }, { -400000000, 50000000 } } } }); - slices.push_back(ExtruderSlice{180000000, BOX, { { { -400000000, -400000000 }, { 400000000, -400000000 }, { 400000000, 10000000 }, { -400000000, 10000000 } } } }); - slices.push_back(ExtruderSlice{220000000, BOX, { { { -400000000, -400000000 }, { 400000000, -400000000 }, { 400000000, 400000000 }, { -400000000, 400000000 } } } }); - */ + slices.push_back(ExtruderSlice{19000000, BOX, { { { -400000000, 24000000 }, { 400000000, 24000000 }, { 400000000, 50000000 }, { -400000000, 50000000 } } } }); + slices.push_back(ExtruderSlice{180000000, BOX, { { { -400000000, -400000000 }, { 400000000, -400000000 }, { 400000000, 10000000 }, { -400000000, 10000000 } } } }); + slices.push_back(ExtruderSlice{220000000, BOX, { { { -400000000, -400000000 }, { 400000000, -400000000 }, { 400000000, 400000000 }, { -400000000, 400000000 } } } }); + printers_geometries.emplace_back(slices); + printers_regexps.push_back({ ".*PRINTER_MODEL_XL.*", "prusa3d_xl_gantry.stl" }); + slices = {}; - Sequential::PrinterGeometry out; - /* - out.x_size = scaled(s_multiple_beds.get_bed_size().x()); - out.y_size = scaled(s_multiple_beds.get_bed_size().y()); - */ - coord_t plate_x_size = scaled(s_multiple_beds.get_bed_size().x()); - coord_t plate_y_size = scaled(s_multiple_beds.get_bed_size().y()); - out.plate = { { 0, 0 }, { plate_x_size, 0}, { plate_x_size, plate_y_size }, { 0, plate_y_size } }; - + double bed_x = s_multiple_beds.get_bed_size().x(); + double bed_y = s_multiple_beds.get_bed_size().y(); + + + { + // JUST FOR DEBUGGING: Dump slices into JSON. + int printer_id = 0; + boost::property_tree::ptree pt; + boost::property_tree::ptree printers_array; + for (const auto& printer : printers_geometries) { + boost::property_tree::ptree printer_node; + printer_node.put("printer_notes_regex", printers_regexps[printer_id][0]); + printer_node.put("gantry_model_filename", printers_regexps[printer_id++][1]); + boost::property_tree::ptree slices_array; + for (const auto& slice : printer) { + boost::property_tree::ptree slice_node; + slice_node.put("height", unscaled(slice.height)); + slice_node.put("type", slice.shape_type == BOX ? "box" : "convex"); + + boost::property_tree::ptree polygons_array; + for (const auto& polygon : slice.polygons) { + boost::property_tree::ptree polygon_node; + std::string s; + for (auto& pt : polygon.points) + s += std::to_string(int(unscaled(pt.x()))) + "," + std::to_string(int(unscaled(pt.y()))) + ";"; + s.pop_back(); + polygon_node.put("", s); // "" for array elements + polygons_array.push_back(std::make_pair("", polygon_node)); + } + slice_node.add_child("polygons", polygons_array); + slices_array.push_back(std::make_pair("", slice_node)); + } + printer_node.add_child("slices", slices_array); + printers_array.push_back(std::make_pair("", printer_node)); + } + pt.add_child("printers", printers_array); + boost::property_tree::write_json("out.txt", pt); + } + + + + + slices = {}; + const std::string printer_notes = config.opt_string("printer_notes"); + { + if (! printer_notes.empty()) { + try { + std::ifstream in(resources_dir() + "/data/printer_gantries/geometries.txt"); + boost::property_tree::ptree pt; + boost::property_tree::read_json(in, pt); + for (const auto& printer : pt.get_child("printers")) { + slices = {}; + std::string printer_notes_match = printer.second.get("printer_notes_regex"); + boost::regex rgx(printer_notes_match); + if (! boost::regex_match(printer_notes, rgx)) + continue; + + for (const auto& obj : printer.second.get_child("slices")) { + ExtruderSlice slice; + slice.height = scaled(obj.second.get("height")); + std::string type_str = obj.second.get("type"); + slice.shape_type = type_str == "box" ? BOX : CONVEX; + for (const auto& polygon : obj.second.get_child("polygons")) { + Polygon pgn; + std::string pgn_str = polygon.second.data(); + boost::replace_all(pgn_str, ";", " "); + boost::replace_all(pgn_str, ",", " "); + std::stringstream ss(pgn_str); + while (ss) { + double x = 0.; + double y = 0.; + ss >> x >> y; + if (ss) + pgn.points.emplace_back(Point::new_scale(x, y)); + } + if (! pgn.points.empty()) + slice.polygons.emplace_back(std::move(pgn)); + } + slices.emplace_back(std::move(slice)); + } + break; + } + } + catch (const boost::property_tree::json_parser_error&) { + // Failed to parse JSON. slices are empty, fallback will be used. + } + } + if (slices.empty()) { + // Fallback to primitive model using radius and height. + coord_t r = scaled(std::max(0.1, config.opt_float("extruder_clearance_radius"))); + coord_t h = scaled(std::max(0.1, config.opt_float("extruder_clearance_height"))); + slices.push_back(ExtruderSlice{ 0, CONVEX, { { { -5000000, -5000000 }, { 5000000, -5000000 }, { 5000000, 5000000 }, { -5000000, 5000000 } } } }); + slices.push_back(ExtruderSlice{ 1000000, BOX, { { { -r, -r }, { r, -r }, { r, r }, { -r, r } } } }); + slices.push_back(ExtruderSlice{ h, BOX, { { { -scaled(bed_x), -r }, { scaled(bed_x), -r }, { scaled(bed_x), r }, { -scaled(bed_x), r}}}}); + } + } + + + // Convert the read data so libseqarrange understands them. + Sequential::PrinterGeometry out; + out.plate = { { 0, 0 }, { scaled(bed_x), 0}, {scaled(bed_x), scaled(bed_y)}, {0, scaled(bed_y)}}; 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)); @@ -125,18 +228,18 @@ static std::vector get_objects_to_print(const Model& -void arrange_model_sequential(Model& model) +void arrange_model_sequential(Model& model, const DynamicPrintConfig& config) { - SeqArrange seq_arrange(model); + SeqArrange seq_arrange(model, config); seq_arrange.process_seq_arrange([](int) {}); seq_arrange.apply_seq_arrange(model); } -SeqArrange::SeqArrange(const Model& model) +SeqArrange::SeqArrange(const Model& model, const DynamicPrintConfig& config) { - m_printer_geometry = get_printer_geometry(); + m_printer_geometry = get_printer_geometry(config); m_solver_configuration = get_solver_config(m_printer_geometry); m_objects = get_objects_to_print(model, m_printer_geometry); @@ -201,9 +304,9 @@ void SeqArrange::apply_seq_arrange(Model& model) const -bool check_seq_printability(const Model& model) +bool check_seq_printability(const Model& model, const DynamicPrintConfig& config) { - Sequential::PrinterGeometry printer_geometry = get_printer_geometry(); + Sequential::PrinterGeometry printer_geometry = get_printer_geometry(config); Sequential::SolverConfiguration solver_config = get_solver_config(printer_geometry); std::vector objects = get_objects_to_print(model, printer_geometry); diff --git a/src/slic3r/GUI/ArrangeHelper.hpp b/src/slic3r/GUI/ArrangeHelper.hpp index f602cefddb..c9b1983df6 100644 --- a/src/slic3r/GUI/ArrangeHelper.hpp +++ b/src/slic3r/GUI/ArrangeHelper.hpp @@ -8,9 +8,10 @@ namespace Slic3r { class Model; + class DynamicPrintConfig; - void arrange_model_sequential(Model& model); - bool check_seq_printability(const Model& model); + void arrange_model_sequential(Model& model, const DynamicPrintConfig& config); + bool check_seq_printability(const Model& model, const DynamicPrintConfig& config); // This is just a helper class to collect data for seq. arrangement, running the arrangement @@ -18,7 +19,7 @@ namespace Slic3r { // into a separate thread without copying the Model or sharing it with UI thread. class SeqArrange { public: - explicit SeqArrange(const Model& model); + explicit SeqArrange(const Model& model, const DynamicPrintConfig& config); void process_seq_arrange(std::function progress_fn); void apply_seq_arrange(Model& model) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1b07ecb7e8..a81687918a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2231,7 +2231,7 @@ void GLCanvas3D::render() ImGui::Begin("TESTING ONLY (arrange)"); if (ImGui::Button("Test seq printability:")) { - last_res = check_seq_printability(wxGetApp().plater()->model()); + last_res = check_seq_printability(wxGetApp().plater()->model(), *m_config); time_start = std::chrono::high_resolution_clock::now(); } ImGui::SameLine(); diff --git a/src/slic3r/GUI/Jobs/SeqArrangeJob.cpp b/src/slic3r/GUI/Jobs/SeqArrangeJob.cpp index 663096712f..5cd54a9403 100644 --- a/src/slic3r/GUI/Jobs/SeqArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/SeqArrangeJob.cpp @@ -13,9 +13,9 @@ namespace Slic3r { namespace GUI { -SeqArrangeJob::SeqArrangeJob(const Model& model) +SeqArrangeJob::SeqArrangeJob(const Model& model, const DynamicPrintConfig& config) { - m_seq_arrange.reset(new SeqArrange(model)); + m_seq_arrange.reset(new SeqArrange(model, config)); } diff --git a/src/slic3r/GUI/Jobs/SeqArrangeJob.hpp b/src/slic3r/GUI/Jobs/SeqArrangeJob.hpp index 8ae2a284e2..9a1ae5f5a6 100644 --- a/src/slic3r/GUI/Jobs/SeqArrangeJob.hpp +++ b/src/slic3r/GUI/Jobs/SeqArrangeJob.hpp @@ -16,7 +16,7 @@ namespace GUI { class SeqArrangeJob : public Job { public: - explicit SeqArrangeJob(const Model& model); + explicit SeqArrangeJob(const Model& model, const DynamicPrintConfig& config); virtual void process(Ctl &ctl) override; virtual void finalize(bool /*canceled*/, std::exception_ptr&) override; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 91010be3f7..2b06c03944 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -625,7 +625,7 @@ Plater::priv::priv(Plater* q, MainFrame* main_frame) : q(q) , main_frame(main_frame) , config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({ - "bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", + "bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "extruder_clearance_height", "skirts", "skirt_distance", "brim_width", "brim_separation", "brim_type", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material", "wipe_tower", "wipe_tower_width", "wipe_tower_brim_width", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_extruder", "extruder_colour", "filament_colour", "material_colour", "max_print_height", "printer_model", "printer_notes", "printer_technology", @@ -7158,7 +7158,7 @@ void Plater::arrange() if (p->can_arrange()) { if (sequential) - replace_job(this->get_ui_job_worker(), std::make_unique(this->model())); + replace_job(this->get_ui_job_worker(), std::make_unique(this->model(), *p->config)); else { auto& w = get_ui_job_worker(); arrange(w, mode);