diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 650e6ad02..6cea47e75 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -119,6 +119,19 @@ int CLI::run(int argc, char **argv) { Model m; for (auto &model : this->models) m.merge(model); + + // Rearrange instances unless --dont-arrange is supplied + if (!this->config.getBool("dont_arrange")) { + m.add_default_instances(); + const BoundingBoxf bb{ this->full_print_config.bed_shape.values }; + m.arrange_objects( + this->full_print_config.min_object_distance(), + // if we are going to use the merged model for printing, honor + // the configured print bed for arranging, otherwise do it freely + this->has_print_action() ? &bb : nullptr + ); + } + this->models = {m}; } else if (opt_key == "duplicate") { const BoundingBoxf bb{ this->full_print_config.bed_shape.values }; @@ -144,30 +157,38 @@ int CLI::run(int argc, char **argv) { model.duplicate_objects_grid(x, y, (distance > 0) ? distance : 6); // TODO: this is not the right place for setting a default } else if (opt_key == "center") { for (auto &model : this->models) { + model.add_default_instances(); + // this affects instances: model.center_instances_around_point(config.opt("center")->value); + // this affects volumes: model.align_to_ground(); } } else if (opt_key == "align_xy") { const Pointf p{ this->config.opt("align_xy")->value }; for (auto &model : this->models) { BoundingBoxf3 bb{ model.bounding_box() }; + // this affects volumes: model.translate(-(bb.min.x - p.x), -(bb.min.y - p.y), -bb.min.z); } } else if (opt_key == "rotate") { for (auto &model : this->models) for (auto &o : model.objects) + // this affects volumes: o->rotate(Geometry::deg2rad(config.getFloat(opt_key)), Z); } else if (opt_key == "rotate_x") { for (auto &model : this->models) for (auto &o : model.objects) + // this affects volumes: o->rotate(Geometry::deg2rad(config.getFloat(opt_key)), X); } else if (opt_key == "rotate_y") { for (auto &model : this->models) for (auto &o : model.objects) + // this affects volumes: o->rotate(Geometry::deg2rad(config.getFloat(opt_key)), Y); } else if (opt_key == "scale") { for (auto &model : this->models) for (auto &o : model.objects) + // this affects volumes: o->scale(config.get_abs_value(opt_key, 1)); } else if (opt_key == "scale_to_fit") { const auto opt = config.opt(opt_key); @@ -177,6 +198,7 @@ int CLI::run(int argc, char **argv) { } for (auto &model : this->models) for (auto &o : model.objects) + // this affects volumes: o->scale_to_fit(opt->value); } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") { std::vector new_models; @@ -253,13 +275,21 @@ int CLI::run(int argc, char **argv) { this->print_config.save(config.getString("save")); } else if (opt_key == "info") { // --info works on unrepaired model - for (const Model &model : this->models) + for (Model &model : this->models) { + model.add_default_instances(); model.print_info(); + } } else if (opt_key == "export_stl") { + for (auto &model : this->models) + model.add_default_instances(); this->export_models(IO::STL); } else if (opt_key == "export_obj") { + for (auto &model : this->models) + model.add_default_instances(); this->export_models(IO::OBJ); } else if (opt_key == "export_pov") { + for (auto &model : this->models) + model.add_default_instances(); this->export_models(IO::POV); } else if (opt_key == "export_amf") { this->export_models(IO::AMF); @@ -278,11 +308,16 @@ int CLI::run(int argc, char **argv) { } } else if (opt_key == "export_gcode") { for (const Model &model : this->models) { + // If all objects have defined instances, their relative positions will be + // honored when printing (they will be only centered, unless --dont-arrange + // is supplied); if any object has no instances, it will get a default one + // and all instances will be rearranged (unless --dont-arrange is supplied). SimplePrint print; print.status_cb = [](int ln, const std::string& msg) { boost::nowide::cout << msg << std::endl; }; print.apply_config(this->print_config); + print.arrange = !this->config.getBool("dont_arrange"); print.center = !this->config.has("center") && !this->config.has("align_xy") && !this->config.getBool("dont_arrange"); @@ -365,8 +400,7 @@ CLI::print_help(bool include_print_options) const { void CLI::export_models(IO::ExportFormat format) { - for (size_t i = 0; i < this->models.size(); ++i) { - Model &model = this->models[i]; + for (const Model& model : this->models) { const std::string outfile = this->output_filepath(model, format); IO::write_model.at(format)(model, outfile); diff --git a/src/slic3r.hpp b/src/slic3r.hpp index 8e8e099d8..e4ba4a498 100644 --- a/src/slic3r.hpp +++ b/src/slic3r.hpp @@ -27,6 +27,10 @@ class CLI { /// Exports loaded models to a file of the specified format, according to the options affecting output filename. void export_models(IO::ExportFormat format); + bool has_print_action() const { + return this->config.has("export_gcode") || this->config.has("export_sla_svg"); + }; + std::string output_filepath(const Model &model, IO::ExportFormat format) const; }; diff --git a/xs/src/libslic3r/IO.cpp b/xs/src/libslic3r/IO.cpp index 68b977ee2..7433d5465 100644 --- a/xs/src/libslic3r/IO.cpp +++ b/xs/src/libslic3r/IO.cpp @@ -170,20 +170,17 @@ bool POV::write(const Model &model, std::string output_file) { TriangleMesh mesh{ model.mesh() }; - return STL::write(mesh, output_file); + return POV::write(mesh, output_file); } bool POV::write(const TriangleMesh& mesh, std::string output_file) { - TriangleMesh mesh2 = mesh; - mesh2.center_around_origin(); - using namespace std; boost::nowide::ofstream pov; pov.open(output_file.c_str(), ios::out | ios::trunc); - for (int i = 0; i < mesh2.stl.stats.number_of_facets; ++i) { - const stl_facet &f = mesh2.stl.facet_start[i]; + for (int i = 0; i < mesh.stl.stats.number_of_facets; ++i) { + const stl_facet &f = mesh.stl.facet_start[i]; pov << "triangle { "; pov << "<" << f.vertex[0].x << "," << f.vertex[0].y << "," << f.vertex[0].z << ">,"; pov << "<" << f.vertex[1].x << "," << f.vertex[1].y << "," << f.vertex[1].z << ">,"; diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index a867a663f..973472a7e 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -933,7 +933,7 @@ ModelObject::print_info() const cout << fixed; cout << "[" << boost::filesystem::path(this->input_file).filename().string() << "]" << endl; - TriangleMesh mesh = this->raw_mesh(); + TriangleMesh mesh = this->mesh(); mesh.check_topology(); BoundingBoxf3 bb = mesh.bounding_box(); Sizef3 size = bb.size(); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 27b695cbb..d0113b502 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -2092,7 +2092,7 @@ CLIMiscConfigDef::CLIMiscConfigDef() def = this->add("output", coString); def->label = __TRANS("Output File"); def->tooltip = __TRANS("The file where the output will be written (if not specified, it will be based on the input file)."); - def->cli = "output"; + def->cli = "output|o"; #ifdef USE_WX def = this->add("autosave", coString); diff --git a/xs/src/libslic3r/SimplePrint.cpp b/xs/src/libslic3r/SimplePrint.cpp index d305ff523..8fcd58ec7 100644 --- a/xs/src/libslic3r/SimplePrint.cpp +++ b/xs/src/libslic3r/SimplePrint.cpp @@ -11,15 +11,19 @@ SimplePrint::set_model(const Model &model) { // make method idempotent so that the object is reusable this->_print.clear_objects(); - // make sure all objects have at least one defined instance - this->_model.add_default_instances(); - // align to z = 0 for (ModelObject* o : this->_model.objects) o->translate(0, 0, -o->bounding_box().min.z); + // make sure all objects have at least one defined instance + if (this->_model.add_default_instances() && this->arrange) { + // if we added at least one default instance, we need to rearrange + const BoundingBoxf bb{ this->_print.config.bed_shape.values }; + this->_model.arrange_objects(this->_print.config.min_object_distance(), &bb); + } + if (this->center) { - Polygon bed_polygon{ scale(this->_print.config.bed_shape.values) }; + const Polygon bed_polygon{ scale(this->_print.config.bed_shape.values) }; this->_model.center_instances_around_point(Slic3r::Pointf::new_unscale(bed_polygon.centroid())); } diff --git a/xs/src/libslic3r/SimplePrint.hpp b/xs/src/libslic3r/SimplePrint.hpp index b6e9ad2f6..fec816426 100644 --- a/xs/src/libslic3r/SimplePrint.hpp +++ b/xs/src/libslic3r/SimplePrint.hpp @@ -9,6 +9,7 @@ namespace Slic3r { class SimplePrint { public: + bool arrange{true}; bool center{true}; std::function status_cb {nullptr};