Added C++ command line processing, thanks @alexrj and @loh
This commit is contained in:
parent
6ca5a18d05
commit
add45a8f6e
11 changed files with 467 additions and 105 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
186
src/slic3r.cpp
186
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";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue