Added C++ command line processing, thanks @alexrj and @loh

This commit is contained in:
bubnikv 2018-09-20 16:48:13 +02:00
parent 6ca5a18d05
commit add45a8f6e
11 changed files with 467 additions and 105 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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)
{

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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";
}

View file

@ -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);

View file

@ -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) {