diff --git a/CMakeLists.txt b/CMakeLists.txt index 65a124055..24fae45c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,6 +241,7 @@ add_subdirectory(resources/localization) # libslic3r, Slic3r GUI and the slic3r executable. add_subdirectory(src) +set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT slic3r) # Perl bindings, currently only used for the unit / integration tests of libslic3r. # Also runs the unit / integration tests. diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index e7442d773..bf8be7feb 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -566,6 +566,103 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre return opt; } +void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra) +{ + std::vector<char*> args; + // push a bogus executable name (argv[0]) + args.emplace_back(const_cast<char*>("")); + for (size_t i = 0; i < tokens.size(); ++ i) + args.emplace_back(const_cast<char *>(tokens[i].c_str())); + this->read_cli(args.size(), &args[0], extra); +} + +bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra) +{ + // cache the CLI option => opt_key mapping + std::map<std::string,std::string> opts; + for (const auto &oit : this->def()->options) { + std::string cli = oit.second.cli; + cli = cli.substr(0, cli.find("=")); + boost::trim_right_if(cli, boost::is_any_of("!")); + std::vector<std::string> tokens; + boost::split(tokens, cli, boost::is_any_of("|")); + for (const std::string &t : tokens) + opts[t] = oit.first; + } + + bool parse_options = true; + for (int i = 1; i < argc; ++ i) { + std::string token = argv[i]; + // Store non-option arguments in the provided vector. + if (! parse_options || ! boost::starts_with(token, "-")) { + extra->push_back(token); + continue; + } + // Stop parsing tokens as options when -- is supplied. + if (token == "--") { + parse_options = false; + continue; + } + // Remove leading dashes + boost::trim_left_if(token, boost::is_any_of("-")); + // Remove the "no-" prefix used to negate boolean options. + bool no = false; + if (boost::starts_with(token, "no-")) { + no = true; + boost::replace_first(token, "no-", ""); + } + // Read value when supplied in the --key=value form. + std::string value; + { + size_t equals_pos = token.find("="); + if (equals_pos != std::string::npos) { + value = token.substr(equals_pos+1); + token.erase(equals_pos); + } + } + // Look for the cli -> option mapping. + const auto it = opts.find(token); + if (it == opts.end()) { + printf("Warning: unknown option --%s\n", token.c_str()); + // instead of continuing, return false to caller + // to stop execution and print usage + return false; + //continue; + } + const t_config_option_key opt_key = it->second; + const ConfigOptionDef &optdef = this->def()->options.at(opt_key); + // If the option type expects a value and it was not already provided, + // look for it in the next token. + if (optdef.type != coBool && optdef.type != coBools && value.empty()) { + if (i == (argc-1)) { + printf("No value supplied for --%s\n", token.c_str()); + continue; + } + value = argv[++ i]; + } + // Store the option value. + const bool existing = this->has(opt_key); + if (ConfigOptionBool* opt = this->opt<ConfigOptionBool>(opt_key, true)) { + opt->value = !no; + } else if (ConfigOptionBools* opt = this->opt<ConfigOptionBools>(opt_key, true)) { + if (!existing) opt->values.clear(); // remove the default values + opt->values.push_back(!no); + } else if (ConfigOptionStrings* opt = this->opt<ConfigOptionStrings>(opt_key, true)) { + if (!existing) opt->values.clear(); // remove the default values + opt->deserialize(value, true); + } else if (ConfigOptionFloats* opt = this->opt<ConfigOptionFloats>(opt_key, true)) { + if (!existing) opt->values.clear(); // remove the default values + opt->deserialize(value, true); + } else if (ConfigOptionPoints* opt = this->opt<ConfigOptionPoints>(opt_key, true)) { + if (!existing) opt->values.clear(); // remove the default values + opt->deserialize(value, true); + } else { + this->set_deserialize(opt_key, value, true); + } + } + return true; +} + t_config_option_keys DynamicConfig::keys() const { t_config_option_keys keys; diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index e3cd14335..2704bbcf3 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -976,7 +976,7 @@ public: // Map from a config option name to its definition. // The definition does not carry an actual value of the config option, only its constant default value. // t_config_option_key is std::string -typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map; +typedef std::map<t_config_option_key, ConfigOptionDef> t_optiondef_map; // Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling. // The configuration definition is static: It does not carry the actual configuration values, @@ -984,18 +984,27 @@ typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map; class ConfigDef { public: - t_optiondef_map options; - ~ConfigDef() { for (auto &opt : this->options) delete opt.second.default_value; } - ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type) { - ConfigOptionDef* opt = &this->options[opt_key]; - opt->type = type; - return opt; - } + t_optiondef_map options; + bool has(const t_config_option_key &opt_key) const { return this->options.count(opt_key) > 0; } const ConfigOptionDef* get(const t_config_option_key &opt_key) const { t_optiondef_map::iterator it = const_cast<ConfigDef*>(this)->options.find(opt_key); return (it == this->options.end()) ? nullptr : &it->second; } + std::vector<std::string> keys() const { + std::vector<std::string> out; + out.reserve(options.size()); + for(auto const& kvp : options) + out.push_back(kvp.first); + return out; + } + +protected: + ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type) { + ConfigOptionDef* opt = &this->options[opt_key]; + opt->type = type; + return opt; + } }; // An abstract configuration store. @@ -1219,6 +1228,10 @@ public: bool opt_bool(const t_config_option_key &opt_key) const { return this->option<ConfigOptionBool>(opt_key)->value != 0; } bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; } + // Command line processing + void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra); + bool read_cli(int argc, char** argv, t_config_option_keys* extra); + private: typedef std::map<t_config_option_key,ConfigOption*> t_options_map; t_options_map options; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ec7447352..ed705e007 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -113,6 +113,12 @@ Model Model::read_from_archive(const std::string &input_file, PresetBundle* bund return model; } +void Model::repair() +{ + for (ModelObject *o : this->objects) + o->repair(); +} + ModelObject* Model::add_object() { this->objects.emplace_back(new ModelObject(this)); @@ -886,6 +892,12 @@ void ModelObject::split(ModelObjectPtrs* new_objects) return; } +void ModelObject::repair() +{ + for (ModelVolume *v : this->volumes) + v->mesh.repair(); +} + // Called by Print::validate() from the UI thread. void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 4c2356429..3acf9b8d2 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -120,6 +120,7 @@ public: void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); } void translate(coordf_t x, coordf_t y, coordf_t z); void scale(const Vec3d &versor); + void scale(const double s) { this->scale(Vec3d(s, s, s)); } void rotate(float angle, const Axis &axis); void rotate(float angle, const Vec3d& axis); void mirror(const Axis &axis); @@ -128,6 +129,7 @@ public: bool needed_repair() const; void cut(coordf_t z, Model* model) const; void split(ModelObjectPtrs* new_objects); + void repair(); // Called by Print::validate() from the UI thread. void check_instances_print_volume_state(const BoundingBoxf3& print_volume); @@ -190,11 +192,11 @@ public: // Split this volume, append the result to the object owning this volume. // Return the number of volumes created from this one. // This is useful to assign different materials to different volumes of an object. - size_t split(unsigned int max_extruders); + size_t split(unsigned int max_extruders); - ModelMaterial* assign_unique_material(); + ModelMaterial* assign_unique_material(); - void calculate_convex_hull(); + void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; // Helpers for loading / storing into AMF / 3MF files. @@ -325,6 +327,10 @@ public: static Model read_from_file(const std::string &input_file, bool add_default_instances = true); static Model read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances = true); + /// Repair the ModelObjects of the current Model. + /// This function calls repair function on each TriangleMesh of each model object volume + void repair(); + ModelObject* add_object(); ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ed02f6d43..061233069 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2345,7 +2345,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } } -PrintConfigDef print_config_def; +const PrintConfigDef print_config_def; DynamicPrintConfig* DynamicPrintConfig::new_from_defaults() { @@ -2601,4 +2601,135 @@ StaticPrintConfig::StaticCache<class Slic3r::SLAMaterialConfig> SLAMaterialConf StaticPrintConfig::StaticCache<class Slic3r::SLAPrinterConfig> SLAPrinterConfig::s_cache_SLAPrinterConfig; StaticPrintConfig::StaticCache<class Slic3r::SLAFullPrintConfig> SLAFullPrintConfig::s_cache_SLAFullPrintConfig; + +CLIConfigDef::CLIConfigDef() +{ + ConfigOptionDef *def; + + def = this->add("cut", coFloat); + def->label = L("Cut"); + def->tooltip = L("Cut model at the given Z."); + def->cli = "cut"; + def->default_value = new ConfigOptionFloat(0); + + def = this->add("export_3mf", coBool); + def->label = L("Export 3MF"); + def->tooltip = L("Slice the model and export slices as 3MF."); + def->cli = "export-3mf"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("slice", coBool); + def->label = L("Slice"); + def->tooltip = L("Slice the model and export gcode."); + def->cli = "slice"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("help", coBool); + def->label = L("Help"); + def->tooltip = L("Show this help."); + def->cli = "help"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("gui", coBool); + def->label = L("Use GUI"); + def->tooltip = L("Start the Slic3r GUI."); + def->cli = "gui"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("info", coBool); + def->label = L("Output Model Info"); + def->tooltip = L("Write information about the model to the console."); + def->cli = "info"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("load", coStrings); + def->label = L("Load config file"); + def->tooltip = L("Load configuration from the specified file. It can be used more than once to load options from multiple files."); + def->cli = "load"; + def->default_value = new ConfigOptionStrings(); + + def = this->add("output", coString); + def->label = L("Output File"); + def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file)."); + def->cli = "output"; + def->default_value = new ConfigOptionString(""); + + def = this->add("rotate", coFloat); + def->label = L("Rotate"); + def->tooltip = L("Rotation angle around the Z axis in degrees (0-360, default: 0)."); + def->cli = "rotate"; + def->default_value = new ConfigOptionFloat(0); + + def = this->add("rotate_x", coFloat); + def->label = L("Rotate around X"); + def->tooltip = L("Rotation angle around the X axis in degrees (0-360, default: 0)."); + def->cli = "rotate-x"; + def->default_value = new ConfigOptionFloat(0); + + def = this->add("rotate_y", coFloat); + def->label = L("Rotate around Y"); + def->tooltip = L("Rotation angle around the Y axis in degrees (0-360, default: 0)."); + def->cli = "rotate-y"; + def->default_value = new ConfigOptionFloat(0); + + def = this->add("save", coString); + def->label = L("Save config file"); + def->tooltip = L("Save configuration to the specified file."); + def->cli = "save"; + def->default_value = new ConfigOptionString(); + + def = this->add("scale", coFloat); + def->label = L("Scale"); + def->tooltip = L("Scaling factor (default: 1)."); + def->cli = "scale"; + def->default_value = new ConfigOptionFloat(1); + +/* + def = this->add("scale_to_fit", coPoint3); + def->label = L("Scale to Fit"); + def->tooltip = L("Scale to fit the given volume."); + def->cli = "scale-to-fit"; + def->default_value = new ConfigOptionPoint3(Pointf3(0,0,0)); +*/ + + def = this->add("center", coPoint); + def->label = L("Center"); + def->tooltip = L("Center the print around the given center (default: 100, 100)."); + def->cli = "center"; + def->default_value = new ConfigOptionPoint(Vec2d(100,100)); +} + +const CLIConfigDef cli_config_def; +DynamicPrintAndCLIConfig::PrintAndCLIConfigDef DynamicPrintAndCLIConfig::s_def; + +std::ostream& print_cli_options(std::ostream& out) +{ + for (const auto& opt : cli_config_def.options) { + if (opt.second.cli.size() != 0) { + out << "\t" << std::left << std::setw(40) << std::string("--") + opt.second.cli; + out << "\t" << opt.second.tooltip << "\n"; + if (opt.second.default_value != nullptr) + out << "\t" << std::setw(40) << " " << "\t" << " (default: " << opt.second.default_value->serialize() << ")"; + out << "\n"; + } + } + std::cerr << std::endl; + return out; +} + +std::ostream& print_print_options(std::ostream& out) +{ + for (const auto& opt : print_config_def.options) { + if (opt.second.cli.size() != 0) { + out << "\t" << std::left << std::setw(40) << std::string("--") + opt.second.cli; + out << "\t" << opt.second.tooltip << "\n"; + if (opt.second.default_value != nullptr) + out << "\t" << std::setw(40) << " " << "\t" << " (default: " << opt.second.default_value->serialize() << ")"; + out << "\n"; + } + } + std::cerr << std::endl; + return out; +} + } diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index bc3b0ef49..0475f4ecb 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -165,7 +165,7 @@ private: // The one and only global definition of SLic3r configuration options. // This definition is constant. -extern PrintConfigDef print_config_def; +extern const PrintConfigDef print_config_def; // Slic3r dynamic configuration, used to override the configuration // per object, per modification volume or per printing material. @@ -968,6 +968,88 @@ protected: #undef STATIC_PRINT_CONFIG_CACHE_DERIVED #undef OPT_PTR -} +class CLIConfigDef : public ConfigDef +{ +public: + CLIConfigDef(); +}; + +extern const CLIConfigDef cli_config_def; + +#define OPT_PTR(KEY) if (opt_key == #KEY) return &this->KEY + +class CLIConfig : public virtual ConfigBase, public StaticConfig +{ +public: + ConfigOptionFloat cut; + ConfigOptionBool export_3mf; + ConfigOptionBool gui; + ConfigOptionBool info; + ConfigOptionBool help; + ConfigOptionStrings load; + ConfigOptionString output; + ConfigOptionFloat rotate; + ConfigOptionFloat rotate_x; + ConfigOptionFloat rotate_y; + ConfigOptionString save; + ConfigOptionFloat scale; +// ConfigOptionPoint3 scale_to_fit; + ConfigOptionPoint center; + ConfigOptionBool slice; + + CLIConfig() : ConfigBase(), StaticConfig() + { + this->set_defaults(); + }; + + // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here. + const ConfigDef* def() const override { return &cli_config_def; } + + ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override + { + OPT_PTR(cut); + OPT_PTR(export_3mf); + OPT_PTR(gui); + OPT_PTR(help); + OPT_PTR(info); + OPT_PTR(load); + OPT_PTR(output); + OPT_PTR(rotate); + OPT_PTR(rotate_x); + OPT_PTR(rotate_y); + OPT_PTR(save); + OPT_PTR(scale); +// OPT_PTR(scale_to_fit); + OPT_PTR(slice); + return NULL; + } +}; + +#undef OPT_PTR + +class DynamicPrintAndCLIConfig : public DynamicPrintConfig +{ +public: + DynamicPrintAndCLIConfig() { this->apply(FullPrintConfig::defaults()); this->apply(CLIConfig()); } + DynamicPrintAndCLIConfig(const DynamicPrintAndCLIConfig &other) : DynamicPrintConfig(other) {} + + // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here. + const ConfigDef* def() const override { return &s_def; } + +private: + class PrintAndCLIConfigDef : public PrintConfigDef + { + public: + PrintAndCLIConfigDef() { this->options.insert(cli_config_def.options.begin(), cli_config_def.options.end()); } + }; + static PrintAndCLIConfigDef s_def; +}; + +/// Iterate through all of the print options and write them to a stream. +std::ostream& print_print_options(std::ostream& out); +/// Iterate through all of the CLI options and write them to a stream. +std::ostream& print_cli_options(std::ostream& out); + +} // namespace Slic3r #endif diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index ef2364dc4..280b30e53 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1591,7 +1591,7 @@ std::vector<ExPolygons> PrintObject::slice_support_enforcers() const std::vector<float> zs; zs.reserve(this->layers().size()); for (const Layer *l : this->layers()) - zs.emplace_back(l->slice_z); + zs.emplace_back((float)l->slice_z); return this->_slice_volumes(zs, volumes); } @@ -1604,7 +1604,7 @@ std::vector<ExPolygons> PrintObject::slice_support_blockers() const std::vector<float> zs; zs.reserve(this->layers().size()); for (const Layer *l : this->layers()) - zs.emplace_back(l->slice_z); + zs.emplace_back((float)l->slice_z); return this->_slice_volumes(zs, volumes); } diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 8174ba0a2..5840ac0c1 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -1,7 +1,12 @@ +//#include "ConfigBase.hpp" #include "Config.hpp" #include "Geometry.hpp" +//#include "IO.hpp" #include "Model.hpp" +//#include "SLAPrint.hpp" +#include "Print.hpp" #include "TriangleMesh.hpp" +#include "Format/3mf.hpp" #include "libslic3r.h" #include <cstdio> #include <string> @@ -12,6 +17,9 @@ #include <boost/nowide/args.hpp> #include <boost/nowide/iostream.hpp> +#ifdef USE_WX +// #include "GUI/GUI.hpp" +#endif #include "slic3r/GUI/GUI.hpp" using namespace Slic3r; @@ -87,37 +95,55 @@ void MyFrame::OnHello(wxCommandEvent& event) wxLogMessage("Hello world from wxWidgets!"); } +/// utility function for displaying CLI usage +void printUsage(); -#if 1 -int -main(int argc, char **argv) +using namespace Slic3r; + +int main(int argc, char **argv) { - // Convert arguments to UTF-8 (needed on Windows). - // argv then points to memory owned by a. + // Convert arguments to UTF-8 (needed on Windows). argv then points to memory owned by a. boost::nowide::args a(argc, argv); - -#if 0 + // parse all command line options into a DynamicConfig - ConfigDef config_def; - config_def.merge(cli_config_def); - config_def.merge(print_config_def); - DynamicConfig config(&config_def); + DynamicPrintAndCLIConfig config; t_config_option_keys input_files; - config.read_cli(argc, argv, &input_files); - + // if any option is unsupported, print usage and abort immediately + if (! config.read_cli(argc, argv, &input_files)) { + printUsage(); + return 0; + } + // apply command line options to a more handy CLIConfig CLIConfig cli_config; cli_config.apply(config, true); DynamicPrintConfig print_config; - + +#if 1 + MyApp *gui = new MyApp(); + + MyApp::SetInstance(gui); + wxEntry(argc, argv); +#endif + +#ifdef USE_WX + if (cli_config.gui) { + GUI::App *gui = new GUI::App(); + GUI::App::SetInstance(gui); + wxEntry(argc, argv); + } +#else + if (cli_config.gui) { + std::cout << "GUI support has not been built." << "\n"; + } +#endif // load config files supplied via --load for (const std::string &file : cli_config.load.values) { if (!boost::filesystem::exists(file)) { boost::nowide::cout << "No such file: " << file << std::endl; exit(1); } - DynamicPrintConfig c; try { c.load(file); @@ -135,12 +161,13 @@ main(int argc, char **argv) print_config.normalize(); // write config if requested - if (!cli_config.save.value.empty()) print_config.save(cli_config.save.value); - + if (! cli_config.save.value.empty()) + print_config.save(cli_config.save.value); + // read input file(s) if any std::vector<Model> models; for (const t_config_option_key &file : input_files) { - if (!boost::filesystem::exists(file)) { + if (! boost::filesystem::exists(file)) { boost::nowide::cerr << "No such file: " << file << std::endl; exit(1); } @@ -162,9 +189,10 @@ main(int argc, char **argv) // apply command line transform options for (ModelObject* o : model.objects) { +/* if (cli_config.scale_to_fit.is_positive_volume()) o->scale_to_fit(cli_config.scale_to_fit.value); - +*/ // TODO: honor option order? o->scale(cli_config.scale.value); o->rotate(Geometry::deg2rad(cli_config.rotate_x.value), X); @@ -175,87 +203,79 @@ main(int argc, char **argv) // TODO: handle --merge models.push_back(model); } + if (cli_config.help) { + printUsage(); + return 0; + } for (Model &model : models) { if (cli_config.info) { // --info works on unrepaired model model.print_info(); - } else if (cli_config.export_obj) { + } else if (cli_config.export_3mf) { std::string outfile = cli_config.output.value; - if (outfile.empty()) outfile = model.objects.front()->input_file + ".obj"; - - TriangleMesh mesh = model.mesh(); - mesh.repair(); - IO::OBJ::write(mesh, outfile); - boost::nowide::cout << "File exported to " << outfile << std::endl; - } else if (cli_config.export_pov) { - std::string outfile = cli_config.output.value; - if (outfile.empty()) outfile = model.objects.front()->input_file + ".pov"; - - TriangleMesh mesh = model.mesh(); - mesh.repair(); - IO::POV::write(mesh, outfile); - boost::nowide::cout << "File exported to " << outfile << std::endl; - } else if (cli_config.export_svg) { - std::string outfile = cli_config.output.value; - if (outfile.empty()) outfile = model.objects.front()->input_file + ".svg"; - - SLAPrint print(&model); - print.config.apply(print_config, true); - print.slice(); - print.write_svg(outfile); - boost::nowide::cout << "SVG file exported to " << outfile << std::endl; - } else if (cli_config.cut_x > 0 || cli_config.cut_y > 0 || cli_config.cut > 0) { + if (outfile.empty()) outfile = model.objects.front()->input_file; + // Check if the file is already a 3mf. + if(outfile.substr(outfile.find_last_of('.'), outfile.length()) == ".3mf") + outfile = outfile.substr(0, outfile.find_last_of('.')) + "_2" + ".3mf"; + else + // Remove the previous extension and add .3mf extention. + outfile = outfile.substr(0, outfile.find_last_of('.')) + ".3mf"; + store_3mf(outfile.c_str(), &model, nullptr, false); + boost::nowide::cout << "File file exported to " << outfile << std::endl; + } else if (cli_config.cut > 0) { model.repair(); - model.translate(0, 0, -model.bounding_box().min.z); - - if (!model.objects.empty()) { - // FIXME: cut all objects + model.translate(0, 0, - model.bounding_box().min(2)); + if (! model.objects.empty()) { Model out; - if (cli_config.cut_x > 0) { - model.objects.front()->cut(X, cli_config.cut_x, &out); - } else if (cli_config.cut_y > 0) { - model.objects.front()->cut(Y, cli_config.cut_y, &out); - } else { - model.objects.front()->cut(Z, cli_config.cut, &out); - } - + model.objects.front()->cut(cli_config.cut, &out); ModelObject &upper = *out.objects[0]; ModelObject &lower = *out.objects[1]; - - if (upper.facets_count() > 0) { - TriangleMesh m = upper.mesh(); - IO::STL::write(m, upper.input_file + "_upper.stl"); - } - if (lower.facets_count() > 0) { - TriangleMesh m = lower.mesh(); - IO::STL::write(m, lower.input_file + "_lower.stl"); - } + // Use the input name and trim off the extension. + std::string outfile = cli_config.output.value; + if (outfile.empty()) + outfile = model.objects.front()->input_file; + outfile = outfile.substr(0, outfile.find_last_of('.')); + std::cerr << outfile << "\n"; + if (upper.facets_count() > 0) + upper.mesh().write_binary((outfile + "_upper.stl").c_str()); + if (lower.facets_count() > 0) + lower.mesh().write_binary((outfile + "_lower.stl").c_str()); } - } else if (cli_config.cut_grid.value.x > 0 && cli_config.cut_grid.value.y > 0) { - TriangleMesh mesh = model.mesh(); - mesh.repair(); - - TriangleMeshPtrs meshes = mesh.cut_by_grid(cli_config.cut_grid.value); - size_t i = 0; - for (TriangleMesh* m : meshes) { - std::ostringstream ss; - ss << model.objects.front()->input_file << "_" << i++ << ".stl"; - IO::STL::write(*m, ss.str()); - delete m; + } else if (cli_config.slice) { + std::string outfile = cli_config.output.value; + Print print; + model.arrange_objects(print.config().min_object_distance()); + model.center_instances_around_point(cli_config.center); + if (outfile.empty()) outfile = model.objects.front()->input_file + ".gcode"; + print.apply_config(print_config); + for (auto* mo : model.objects) { + print.auto_assign_extruders(mo); + print.add_model_object(mo); } + print.validate(); + print.export_gcode(outfile, nullptr); } else { boost::nowide::cerr << "error: command not supported" << std::endl; return 1; } } -#endif - - MyApp *gui = new MyApp(); - - MyApp::SetInstance(gui); - wxEntry(argc, argv); return 0; } -#endif + +void printUsage() +{ + std::cout << "Slic3r " << SLIC3R_VERSION << " is a STL-to-GCODE translator for RepRap 3D printers" << "\n" + << "written by Alessandro Ranellucci <aar@cpan.org> - http://slic3r.org/ - https://github.com/slic3r/Slic3r" << "\n" +// << "Git Version " << BUILD_COMMIT << "\n\n" + << "Usage: ./slic3r [ OPTIONS ] [ file.stl ] [ file2.stl ] ..." << "\n"; + // CLI Options + std::cout << "** CLI OPTIONS **\n"; + print_cli_options(boost::nowide::cout); + std::cout << "****\n"; + // Print options + std::cout << "** PRINT OPTIONS **\n"; + print_print_options(boost::nowide::cout); + std::cout << "****\n"; +} diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index e784d8525..e7b1868d0 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -380,7 +380,7 @@ void PageVendors::on_variant_checked() PageFirmware::PageFirmware(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))), - gcode_opt(print_config_def.options["gcode_flavor"]), + gcode_opt(*print_config_def.get("gcode_flavor")), gcode_picker(nullptr) { append_text(_(L("Choose the type of firmware used by your printer."))); @@ -440,13 +440,13 @@ PageDiameters::PageDiameters(ConfigWizard *parent) : { spin_nozzle->SetDigits(2); spin_nozzle->SetIncrement(0.1); - const auto &def_nozzle = print_config_def.options["nozzle_diameter"]; + const auto &def_nozzle = *print_config_def.get("nozzle_diameter"); auto *default_nozzle = dynamic_cast<const ConfigOptionFloats*>(def_nozzle.default_value); spin_nozzle->SetValue(default_nozzle != nullptr && default_nozzle->size() > 0 ? default_nozzle->get_at(0) : 0.5); spin_filam->SetDigits(2); spin_filam->SetIncrement(0.25); - const auto &def_filam = print_config_def.options["filament_diameter"]; + const auto &def_filam = *print_config_def.get("filament_diameter"); auto *default_filam = dynamic_cast<const ConfigOptionFloats*>(def_filam.default_value); spin_filam->SetValue(default_filam != nullptr && default_filam->size() > 0 ? default_filam->get_at(0) : 3.0); @@ -490,13 +490,13 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent) : spin_bed(new wxSpinCtrlDouble(this, wxID_ANY)) { spin_extr->SetIncrement(5.0); - const auto &def_extr = print_config_def.options["temperature"]; + const auto &def_extr = *print_config_def.get("temperature"); spin_extr->SetRange(def_extr.min, def_extr.max); auto *default_extr = dynamic_cast<const ConfigOptionInts*>(def_extr.default_value); spin_extr->SetValue(default_extr != nullptr && default_extr->size() > 0 ? default_extr->get_at(0) : 200); spin_bed->SetIncrement(5.0); - const auto &def_bed = print_config_def.options["bed_temperature"]; + const auto &def_bed = *print_config_def.get("bed_temperature"); spin_bed->SetRange(def_bed.min, def_bed.max); auto *default_bed = dynamic_cast<const ConfigOptionInts*>(def_bed.default_value); spin_bed->SetValue(default_bed != nullptr && default_bed->size() > 0 ? default_bed->get_at(0) : 0); diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp index b8ad84ba4..d5d295839 100644 --- a/xs/xsp/Config.xsp +++ b/xs/xsp/Config.xsp @@ -137,7 +137,7 @@ PROTOTYPES: DISABLE SV* print_config_def() CODE: - t_optiondef_map &def = Slic3r::print_config_def.options; + t_optiondef_map &def = *const_cast<t_optiondef_map*>(&Slic3r::print_config_def.options); HV* options_hv = newHV(); for (t_optiondef_map::iterator oit = def.begin(); oit != def.end(); ++oit) {