mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-04 20:44:00 -06:00
Reworked the command line interface based on the current state
of the upstream. Thanks @alexrj, @lordofhyphens for the original code of slic3r.cpp
This commit is contained in:
parent
75cf1cde92
commit
18025cc669
22 changed files with 1131 additions and 530 deletions
|
@ -190,6 +190,110 @@ bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &o
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> ConfigOptionDef::cli_args() const
|
||||
{
|
||||
std::string cli = this->cli.substr(0, this->cli.find("="));
|
||||
boost::trim_right_if(cli, boost::is_any_of("!"));
|
||||
std::vector<std::string> args;
|
||||
boost::split(args, cli, boost::is_any_of("|"));
|
||||
return args;
|
||||
}
|
||||
|
||||
std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults) const
|
||||
{
|
||||
// prepare a function for wrapping text
|
||||
auto wrap = [](std::string text, size_t line_length) -> std::string {
|
||||
std::istringstream words(text);
|
||||
std::ostringstream wrapped;
|
||||
std::string word;
|
||||
|
||||
if (words >> word) {
|
||||
wrapped << word;
|
||||
size_t space_left = line_length - word.length();
|
||||
while (words >> word) {
|
||||
if (space_left < word.length() + 1) {
|
||||
wrapped << '\n' << word;
|
||||
space_left = line_length - word.length();
|
||||
} else {
|
||||
wrapped << ' ' << word;
|
||||
space_left -= word.length() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wrapped.str();
|
||||
};
|
||||
|
||||
// get the unique categories
|
||||
std::set<std::string> categories;
|
||||
for (const auto& opt : this->options) {
|
||||
const ConfigOptionDef& def = opt.second;
|
||||
categories.insert(def.category);
|
||||
}
|
||||
|
||||
for (auto category : categories) {
|
||||
if (category != "") {
|
||||
out << category << ":" << std::endl;
|
||||
} else if (categories.size() > 1) {
|
||||
out << "Misc options:" << std::endl;
|
||||
}
|
||||
|
||||
for (const auto& opt : this->options) {
|
||||
const ConfigOptionDef& def = opt.second;
|
||||
if (def.category != category) continue;
|
||||
|
||||
if (!def.cli.empty()) {
|
||||
// get all possible variations: --foo, --foobar, -f...
|
||||
auto cli_args = def.cli_args();
|
||||
for (auto& arg : cli_args) {
|
||||
arg.insert(0, (arg.size() == 1) ? "-" : "--");
|
||||
if (def.type == coFloat || def.type == coInt || def.type == coFloatOrPercent
|
||||
|| def.type == coFloats || def.type == coInts) {
|
||||
arg += " N";
|
||||
} else if (def.type == coPoint) {
|
||||
arg += " X,Y";
|
||||
} else if (def.type == coPoint3) {
|
||||
arg += " X,Y,Z";
|
||||
} else if (def.type == coString || def.type == coStrings) {
|
||||
arg += " ABCD";
|
||||
}
|
||||
}
|
||||
|
||||
// left: command line options
|
||||
const std::string cli = boost::algorithm::join(cli_args, ", ");
|
||||
out << " " << std::left << std::setw(20) << cli;
|
||||
|
||||
// right: option description
|
||||
std::string descr = def.tooltip;
|
||||
if (show_defaults && def.default_value != nullptr && def.type != coBool
|
||||
&& (def.type != coString || !def.default_value->serialize().empty())) {
|
||||
descr += " (";
|
||||
if (!def.sidetext.empty()) {
|
||||
descr += def.sidetext + ", ";
|
||||
} else if (!def.enum_values.empty()) {
|
||||
descr += boost::algorithm::join(def.enum_values, ", ") + "; ";
|
||||
}
|
||||
descr += "default: " + def.default_value->serialize() + ")";
|
||||
}
|
||||
|
||||
// wrap lines of description
|
||||
descr = wrap(descr, 80);
|
||||
std::vector<std::string> lines;
|
||||
boost::split(lines, descr, boost::is_any_of("\n"));
|
||||
|
||||
// if command line options are too long, print description in new line
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
if (i == 0 && cli.size() > 19)
|
||||
out << std::endl;
|
||||
if (i > 0 || cli.size() > 19)
|
||||
out << std::string(21, ' ');
|
||||
out << lines[i] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent)
|
||||
{
|
||||
// loop through options and apply them
|
||||
|
@ -508,50 +612,53 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
|
|||
// Let the parent decide what to do if the opt_key is not defined by this->def().
|
||||
return nullptr;
|
||||
ConfigOption *opt = nullptr;
|
||||
switch (optdef->type) {
|
||||
case coFloat: opt = new ConfigOptionFloat(); break;
|
||||
case coFloats: opt = new ConfigOptionFloats(); break;
|
||||
case coInt: opt = new ConfigOptionInt(); break;
|
||||
case coInts: opt = new ConfigOptionInts(); break;
|
||||
case coString: opt = new ConfigOptionString(); break;
|
||||
case coStrings: opt = new ConfigOptionStrings(); break;
|
||||
case coPercent: opt = new ConfigOptionPercent(); break;
|
||||
case coPercents: opt = new ConfigOptionPercents(); break;
|
||||
case coFloatOrPercent: opt = new ConfigOptionFloatOrPercent(); break;
|
||||
case coPoint: opt = new ConfigOptionPoint(); break;
|
||||
case coPoints: opt = new ConfigOptionPoints(); break;
|
||||
case coBool: opt = new ConfigOptionBool(); break;
|
||||
case coBools: opt = new ConfigOptionBools(); break;
|
||||
case coEnum: opt = new ConfigOptionEnumGeneric(optdef->enum_keys_map); break;
|
||||
default: throw std::runtime_error(std::string("Unknown option type for option ") + opt_key);
|
||||
if (optdef->default_value != nullptr) {
|
||||
opt = (optdef->default_value->type() == coEnum) ?
|
||||
// Special case: For a DynamicConfig, convert a templated enum to a generic enum.
|
||||
new ConfigOptionEnumGeneric(optdef->enum_keys_map, optdef->default_value->getInt()) :
|
||||
optdef->default_value->clone();
|
||||
} else {
|
||||
switch (optdef->type) {
|
||||
case coFloat: opt = new ConfigOptionFloat(); break;
|
||||
case coFloats: opt = new ConfigOptionFloats(); break;
|
||||
case coInt: opt = new ConfigOptionInt(); break;
|
||||
case coInts: opt = new ConfigOptionInts(); break;
|
||||
case coString: opt = new ConfigOptionString(); break;
|
||||
case coStrings: opt = new ConfigOptionStrings(); break;
|
||||
case coPercent: opt = new ConfigOptionPercent(); break;
|
||||
case coPercents: opt = new ConfigOptionPercents(); break;
|
||||
case coFloatOrPercent: opt = new ConfigOptionFloatOrPercent(); break;
|
||||
case coPoint: opt = new ConfigOptionPoint(); break;
|
||||
case coPoints: opt = new ConfigOptionPoints(); break;
|
||||
case coPoint3: opt = new ConfigOptionPoint3(); break;
|
||||
// case coPoint3s: opt = new ConfigOptionPoint3s(); break;
|
||||
case coBool: opt = new ConfigOptionBool(); break;
|
||||
case coBools: opt = new ConfigOptionBools(); break;
|
||||
case coEnum: opt = new ConfigOptionEnumGeneric(optdef->enum_keys_map); break;
|
||||
default: throw std::runtime_error(std::string("Unknown option type for option ") + opt_key);
|
||||
}
|
||||
}
|
||||
this->options[opt_key] = opt;
|
||||
return opt;
|
||||
}
|
||||
|
||||
void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra)
|
||||
void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys)
|
||||
{
|
||||
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(int(args.size()), &args[0], extra);
|
||||
this->read_cli(int(args.size()), &args[0], extra, keys);
|
||||
}
|
||||
|
||||
bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra)
|
||||
bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra, t_config_option_keys* keys)
|
||||
{
|
||||
// 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)
|
||||
for (const auto &oit : this->def()->options)
|
||||
for (auto t : oit.second.cli_args())
|
||||
opts[t] = oit.first;
|
||||
}
|
||||
|
||||
bool parse_options = true;
|
||||
for (int i = 1; i < argc; ++ i) {
|
||||
|
@ -611,6 +718,10 @@ bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra)
|
|||
}
|
||||
// Store the option value.
|
||||
const bool existing = this->has(opt_key);
|
||||
if (keys != nullptr && !existing) {
|
||||
// Save the order of detected keys.
|
||||
keys->push_back(opt_key);
|
||||
}
|
||||
ConfigOption *opt_base = this->option(opt_key, true);
|
||||
ConfigOptionVectorBase *opt_vector = opt_base->is_vector() ? static_cast<ConfigOptionVectorBase*>(opt_base) : nullptr;
|
||||
if (opt_vector) {
|
||||
|
|
|
@ -27,6 +27,24 @@ extern std::string escape_strings_cstyle(const std::vector<std::string> &strs);
|
|||
extern bool unescape_string_cstyle(const std::string &str, std::string &out);
|
||||
extern bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out);
|
||||
|
||||
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
|
||||
class UnknownOptionException : public std::runtime_error {
|
||||
public:
|
||||
UnknownOptionException() :
|
||||
std::runtime_error("Unknown option exception") {}
|
||||
UnknownOptionException(const std::string &opt_key) :
|
||||
std::runtime_error(std::string("Unknown option exception: ") + opt_key) {}
|
||||
};
|
||||
|
||||
/// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
|
||||
class NoDefinitionException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
NoDefinitionException() :
|
||||
std::runtime_error("No definition exception") {}
|
||||
NoDefinitionException(const std::string &opt_key) :
|
||||
std::runtime_error(std::string("No definition exception: ") + opt_key) {}
|
||||
};
|
||||
|
||||
// Type of a configuration value.
|
||||
enum ConfigOptionType {
|
||||
|
@ -54,12 +72,14 @@ enum ConfigOptionType {
|
|||
coPoint = 6,
|
||||
// vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets.
|
||||
coPoints = coPoint + coVectorType,
|
||||
coPoint3 = 7,
|
||||
// coPoint3s = coPoint3 + coVectorType,
|
||||
// single boolean value
|
||||
coBool = 7,
|
||||
coBool = 8,
|
||||
// vector of boolean values
|
||||
coBools = coBool + coVectorType,
|
||||
// a generic enum
|
||||
coEnum = 8,
|
||||
coEnum = 9,
|
||||
};
|
||||
|
||||
enum ConfigOptionMode {
|
||||
|
@ -718,6 +738,39 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class ConfigOptionPoint3 : public ConfigOptionSingle<Vec3d>
|
||||
{
|
||||
public:
|
||||
ConfigOptionPoint3() : ConfigOptionSingle<Vec3d>(Vec3d(0,0,0)) {}
|
||||
explicit ConfigOptionPoint3(const Vec3d &value) : ConfigOptionSingle<Vec3d>(value) {}
|
||||
|
||||
static ConfigOptionType static_type() { return coPoint3; }
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
ConfigOption* clone() const override { return new ConfigOptionPoint3(*this); }
|
||||
ConfigOptionPoint3& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionPoint3 &rhs) const { return this->value == rhs.value; }
|
||||
|
||||
std::string serialize() const override
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << this->value(0);
|
||||
ss << ",";
|
||||
ss << this->value(1);
|
||||
ss << ",";
|
||||
ss << this->value(2);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool deserialize(const std::string &str, bool append = false) override
|
||||
{
|
||||
UNUSED(append);
|
||||
char dummy;
|
||||
return sscanf(str.data(), " %lf , %lf , %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 2 ||
|
||||
sscanf(str.data(), " %lf x %lf x %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 2;
|
||||
}
|
||||
};
|
||||
|
||||
class ConfigOptionBool : public ConfigOptionSingle<bool>
|
||||
{
|
||||
public:
|
||||
|
@ -893,6 +946,7 @@ class ConfigOptionEnumGeneric : public ConfigOptionInt
|
|||
{
|
||||
public:
|
||||
ConfigOptionEnumGeneric(const t_config_enum_values* keys_map = nullptr) : keys_map(keys_map) {}
|
||||
explicit ConfigOptionEnumGeneric(const t_config_enum_values* keys_map, int value) : ConfigOptionInt(value), keys_map(keys_map) {}
|
||||
|
||||
const t_config_enum_values* keys_map;
|
||||
|
||||
|
@ -1010,6 +1064,9 @@ public:
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns the alternative CLI arguments for the given option.
|
||||
std::vector<std::string> cli_args() const;
|
||||
};
|
||||
|
||||
// Map from a config option name to its definition.
|
||||
|
@ -1044,6 +1101,9 @@ public:
|
|||
return out;
|
||||
}
|
||||
|
||||
/// Iterate through all of the CLI options and write them to a stream.
|
||||
std::ostream& print_cli_help(std::ostream& out, bool show_defaults) const;
|
||||
|
||||
protected:
|
||||
ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type) {
|
||||
ConfigOptionDef* opt = &this->options[opt_key];
|
||||
|
@ -1089,12 +1149,24 @@ public:
|
|||
TYPE* option(const t_config_option_key &opt_key, bool create = false)
|
||||
{
|
||||
ConfigOption *opt = this->optptr(opt_key, create);
|
||||
// assert(opt == nullptr || opt->type() == TYPE::static_type());
|
||||
return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<TYPE*>(opt);
|
||||
}
|
||||
template<typename TYPE>
|
||||
const TYPE* option(const t_config_option_key &opt_key) const
|
||||
{ return const_cast<ConfigBase*>(this)->option<TYPE>(opt_key, false); }
|
||||
template<typename TYPE>
|
||||
TYPE* option_throw(const t_config_option_key &opt_key, bool create = false)
|
||||
{
|
||||
ConfigOption *opt = this->optptr(opt_key, create);
|
||||
if (opt == nullptr)
|
||||
throw UnknownOptionException(opt_key);
|
||||
if (opt->type() != TYPE::static_type())
|
||||
throw std::runtime_error("Conversion to a wrong type");
|
||||
return static_cast<TYPE*>(opt);
|
||||
}
|
||||
template<typename TYPE>
|
||||
const TYPE* option_throw(const t_config_option_key &opt_key) const
|
||||
{ return const_cast<ConfigBase*>(this)->option_throw<TYPE>(opt_key, false); }
|
||||
// Apply all keys of other ConfigBase defined by this->def() to this ConfigBase.
|
||||
// An UnknownOptionException is thrown in case some option keys of other are not defined by this->def(),
|
||||
// or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set.
|
||||
|
@ -1276,8 +1348,8 @@ public:
|
|||
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);
|
||||
void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
|
||||
bool read_cli(int argc, char** argv, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
|
||||
|
||||
typedef std::map<t_config_option_key,ConfigOption*> t_options_map;
|
||||
t_options_map::const_iterator cbegin() const { return options.cbegin(); }
|
||||
|
@ -1303,25 +1375,6 @@ protected:
|
|||
void set_defaults();
|
||||
};
|
||||
|
||||
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
|
||||
class UnknownOptionException : public std::runtime_error {
|
||||
public:
|
||||
UnknownOptionException() :
|
||||
std::runtime_error("Unknown option exception") {}
|
||||
UnknownOptionException(const std::string &opt_key) :
|
||||
std::runtime_error(std::string("Unknown option exception: ") + opt_key) {}
|
||||
};
|
||||
|
||||
/// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
|
||||
class NoDefinitionException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
NoDefinitionException() :
|
||||
std::runtime_error("No definition exception") {}
|
||||
NoDefinitionException(const std::string &opt_key) :
|
||||
std::runtime_error(std::string("No definition exception: ") + opt_key) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -115,4 +115,23 @@ bool load_obj(const char *path, Model *model, const char *object_name_in)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool store_obj(const char *path, TriangleMesh *mesh)
|
||||
{
|
||||
//FIXME returning false even if write failed.
|
||||
mesh->WriteOBJFile(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool store_obj(const char *path, ModelObject *model_object)
|
||||
{
|
||||
TriangleMesh mesh = model_object->mesh();
|
||||
return store_obj(path, &mesh);
|
||||
}
|
||||
|
||||
bool store_obj(const char *path, Model *model)
|
||||
{
|
||||
TriangleMesh mesh = model->mesh();
|
||||
return store_obj(path, &mesh);
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
@ -9,6 +9,10 @@ class Model;
|
|||
// Load an OBJ file into a provided model.
|
||||
extern bool load_obj(const char *path, Model *model, const char *object_name = nullptr);
|
||||
|
||||
extern bool store_obj(const char *path, TriangleMesh *mesh);
|
||||
extern bool store_obj(const char *path, ModelObject *model);
|
||||
extern bool store_obj(const char *path, Model *model);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Format_OBJ_hpp_ */
|
||||
|
|
|
@ -55,4 +55,10 @@ bool store_stl(const char *path, ModelObject *model_object, bool binary)
|
|||
return store_stl(path, &mesh, binary);
|
||||
}
|
||||
|
||||
bool store_stl(const char *path, Model *model, bool binary)
|
||||
{
|
||||
TriangleMesh mesh = model->mesh();
|
||||
return store_stl(path, &mesh, binary);
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
@ -11,6 +11,7 @@ extern bool load_stl(const char *path, Model *model, const char *object_name = n
|
|||
|
||||
extern bool store_stl(const char *path, TriangleMesh *mesh, bool binary);
|
||||
extern bool store_stl(const char *path, ModelObject *model_object, bool binary);
|
||||
extern bool store_stl(const char *path, Model *model, bool binary);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
|
|
@ -577,6 +577,11 @@ end:
|
|||
return input_file;
|
||||
}
|
||||
|
||||
std::string Model::propose_export_file_name_and_path(const std::string &new_extension) const
|
||||
{
|
||||
return boost::filesystem::path(this->propose_export_file_name_and_path()).replace_extension(new_extension).string();
|
||||
}
|
||||
|
||||
ModelObject::~ModelObject()
|
||||
{
|
||||
this->clear_volumes();
|
||||
|
@ -1568,6 +1573,22 @@ void ModelVolume::scale(const Vec3d& scaling_factors)
|
|||
set_scaling_factor(get_scaling_factor().cwiseProduct(scaling_factors));
|
||||
}
|
||||
|
||||
void ModelObject::scale_to_fit(const Vec3d &size)
|
||||
{
|
||||
/*
|
||||
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
|
||||
Vec3d orig_size = this->bounding_box().size();
|
||||
float factor = fminf(
|
||||
size.x / orig_size.x,
|
||||
fminf(
|
||||
size.y / orig_size.y,
|
||||
size.z / orig_size.z
|
||||
)
|
||||
);
|
||||
this->scale(factor);
|
||||
*/
|
||||
}
|
||||
|
||||
void ModelVolume::rotate(double angle, Axis axis)
|
||||
{
|
||||
switch (axis)
|
||||
|
|
|
@ -245,6 +245,10 @@ public:
|
|||
void scale(const Vec3d &versor);
|
||||
void scale(const double s) { this->scale(Vec3d(s, s, s)); }
|
||||
void scale(double x, double y, double z) { this->scale(Vec3d(x, y, z)); }
|
||||
/// Scale the current ModelObject to fit by altering the scaling factor of ModelInstances.
|
||||
/// It operates on the total size by duplicating the object according to all the instances.
|
||||
/// \param size Sizef3 the size vector
|
||||
void scale_to_fit(const Vec3d &size);
|
||||
void rotate(double angle, Axis axis);
|
||||
void rotate(double angle, const Vec3d& axis);
|
||||
void mirror(Axis axis);
|
||||
|
@ -619,6 +623,8 @@ public:
|
|||
|
||||
// Propose an output file name & path based on the first printable object's name and source input file's path.
|
||||
std::string propose_export_file_name_and_path() const;
|
||||
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
|
||||
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
||||
|
||||
private:
|
||||
MODELBASE_DERIVED_PRIVATE_COPY_MOVE(Model)
|
||||
|
|
|
@ -1509,7 +1509,7 @@ void Print::process()
|
|||
// The export_gcode may die for various reasons (fails to process output_filename_format,
|
||||
// write error into the G-code, cannot execute post-processing scripts).
|
||||
// It is up to the caller to show an error message.
|
||||
void Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
||||
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
||||
{
|
||||
// output everything to a G-code file
|
||||
// The following call may die if the output_filename_format template substitution fails.
|
||||
|
@ -1525,6 +1525,7 @@ void Print::export_gcode(const std::string &path_template, GCodePreviewData *pre
|
|||
// The following line may die for multiple reasons.
|
||||
GCode gcode;
|
||||
gcode.do_export(this, path.c_str(), preview_data);
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
void Print::_make_skirt()
|
||||
|
@ -1693,8 +1694,10 @@ void Print::_make_brim()
|
|||
}
|
||||
polygons_append(loops, offset(islands, -0.5f * float(flow.scaled_spacing())));
|
||||
}
|
||||
|
||||
|
||||
loops = union_pt_chained(loops, false);
|
||||
// The function above produces ordering well suited for concentric infill (from outside to inside).
|
||||
// For Brim, the ordering should be reversed (from inside to outside).
|
||||
std::reverse(loops.begin(), loops.end());
|
||||
extrusion_entities_append_loops(m_brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(this->skirt_first_layer_height()));
|
||||
}
|
||||
|
|
|
@ -297,7 +297,9 @@ public:
|
|||
bool apply_config(DynamicPrintConfig config);
|
||||
|
||||
void process() override;
|
||||
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
|
||||
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
|
||||
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||
|
||||
// methods for handling state
|
||||
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
|
||||
|
|
|
@ -2955,7 +2955,7 @@ std::string FullPrintConfig::validate()
|
|||
return "--use-firmware-retraction is only supported by Marlin, Smoothie, Repetier and Machinekit firmware";
|
||||
|
||||
if (this->use_firmware_retraction.value)
|
||||
for (bool wipe : this->wipe.values)
|
||||
for (unsigned char wipe : this->wipe.values)
|
||||
if (wipe)
|
||||
return "--use-firmware-retraction is not compatible with --wipe";
|
||||
|
||||
|
@ -2999,7 +2999,7 @@ std::string FullPrintConfig::validate()
|
|||
return "Invalid value for --extruder-clearance-height";
|
||||
|
||||
// --extrusion-multiplier
|
||||
for (float em : this->extrusion_multiplier.values)
|
||||
for (double em : this->extrusion_multiplier.values)
|
||||
if (em <= 0)
|
||||
return "Invalid value for --extrusion-multiplier";
|
||||
|
||||
|
@ -3100,55 +3100,65 @@ StaticPrintConfig::StaticCache<class Slic3r::SLAPrintObjectConfig> SLAPrintObje
|
|||
StaticPrintConfig::StaticCache<class Slic3r::SLAPrinterConfig> SLAPrinterConfig::s_cache_SLAPrinterConfig;
|
||||
StaticPrintConfig::StaticCache<class Slic3r::SLAFullPrintConfig> SLAFullPrintConfig::s_cache_SLAFullPrintConfig;
|
||||
|
||||
CLIConfigDef::CLIConfigDef()
|
||||
CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
{
|
||||
ConfigOptionDef *def;
|
||||
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("dont_arrange", coBool);
|
||||
def->label = L("Dont arrange");
|
||||
def->tooltip = L("Don't arrange the objects on the build plate. The model coordinates "
|
||||
"define the absolute positions on the build plate. "
|
||||
"The option --center will be ignored.");
|
||||
def->cli = "dont-arrange";
|
||||
// Actions:
|
||||
def = this->add("export_obj", coBool);
|
||||
def->label = L("Export SVG");
|
||||
def->tooltip = L("Export the model(s) as OBJ.");
|
||||
def->cli = "export-obj";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
/*
|
||||
def = this->add("export_svg", coBool);
|
||||
def->label = L("Export SVG");
|
||||
def->tooltip = L("Slice the model and export solid slices as SVG.");
|
||||
def->cli = "export-svg";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
*/
|
||||
|
||||
def = this->add("export_sla", coBool);
|
||||
def->label = L("Export SLA");
|
||||
def->tooltip = L("Slice the model and export SLA printing layers as PNG.");
|
||||
def->cli = "export-sla|sla";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("datadir", coString);
|
||||
def->label = L("User data directory");
|
||||
def->tooltip = L("Load and store settings at the given directory. "
|
||||
"This is useful for maintaining different profiles or including "
|
||||
"configurations from a network storage.");
|
||||
def->cli = "datadir";
|
||||
def->default_value = new ConfigOptionString();
|
||||
|
||||
def = this->add("export_3mf", coBool);
|
||||
def->label = L("Export 3MF");
|
||||
def->tooltip = L("Slice the model and export slices as 3MF.");
|
||||
def->tooltip = L("Export the model(s) 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 = this->add("export_amf", coBool);
|
||||
def->label = L("Export AMF");
|
||||
def->tooltip = L("Export the model(s) as AMF.");
|
||||
def->cli = "export-amf";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("export_stl", coBool);
|
||||
def->label = L("Export STL");
|
||||
def->tooltip = L("Export the model(s) as STL.");
|
||||
def->cli = "export-stl";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("export_gcode", coBool);
|
||||
def->label = L("Export G-code");
|
||||
def->tooltip = L("Slice the model and export toolpaths as G-code.");
|
||||
def->cli = "export-gcode|gcode|g";
|
||||
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->cli = "help|h";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("gui", coBool);
|
||||
def->label = L("Use GUI");
|
||||
def->tooltip = L("Forces the GUI launch instead of command line slicing "
|
||||
"(if you supply a model file, it will be loaded into the plater)");
|
||||
def->cli = "gui";
|
||||
def = this->add("help_options", coBool);
|
||||
def->label = L("Help (options)");
|
||||
def->tooltip = L("Show the full list of print/G-code configuration options.");
|
||||
def->cli = "help-options";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("info", coBool);
|
||||
|
@ -3157,107 +3167,169 @@ CLIConfigDef::CLIConfigDef()
|
|||
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("no_gui", coBool);
|
||||
def->label = L("Do not use GUI");
|
||||
def->tooltip = L("Forces the command line slicing instead of gui. This takes precedence over --gui if both are present.");
|
||||
def->cli = "no-gui";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
CLITransformConfigDef::CLITransformConfigDef()
|
||||
{
|
||||
ConfigOptionDef* def;
|
||||
|
||||
// Transform options:
|
||||
def = this->add("align_xy", coPoint);
|
||||
def->label = L("Align XY");
|
||||
def->tooltip = L("Align the model to the given point.");
|
||||
def->cli = "align-xy";
|
||||
def->default_value = new ConfigOptionPoint(Vec2d(100,100));
|
||||
|
||||
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("cut_grid", coFloat);
|
||||
def->label = L("Cut");
|
||||
def->tooltip = L("Cut model in the XY plane into tiles of the specified max size.");
|
||||
def->cli = "cut-grid";
|
||||
def->default_value = new ConfigOptionPoint();
|
||||
|
||||
def = this->add("cut_x", coFloat);
|
||||
def->label = L("Cut");
|
||||
def->tooltip = L("Cut model at the given X.");
|
||||
def->cli = "cut-x";
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("cut_y", coFloat);
|
||||
def->label = L("Cut");
|
||||
def->tooltip = L("Cut model at the given Y.");
|
||||
def->cli = "cut-y";
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
*/
|
||||
|
||||
def = this->add("center", coPoint);
|
||||
def->label = L("Center");
|
||||
def->tooltip = L("Center the print around the given center.");
|
||||
def->cli = "center";
|
||||
def->default_value = new ConfigOptionPoint(Vec2d(100,100));
|
||||
|
||||
def = this->add("dont_arrange", coBool);
|
||||
def->label = L("Don't arrange");
|
||||
def->tooltip = L("Do not rearrange the given models before merging and keep their original XY coordinates.");
|
||||
def->cli = "dont-arrange";
|
||||
|
||||
def = this->add("duplicate", coInt);
|
||||
def->label = L("Duplicate");
|
||||
def->tooltip =L("Multiply copies by this factor.");
|
||||
def->cli = "duplicate=i";
|
||||
def->min = 1;
|
||||
|
||||
def = this->add("duplicate_grid", coPoint);
|
||||
def->label = L("Duplicate by grid");
|
||||
def->tooltip = L("Multiply copies by creating a grid.");
|
||||
def->cli = "duplicate-grid";
|
||||
|
||||
def = this->add("merge", coBool);
|
||||
def->label = L("Merge");
|
||||
def->tooltip = L("Arrange the supplied models in a plate and merge them in a single model in order to perform actions once.");
|
||||
def->cli = "merge|m";
|
||||
|
||||
def = this->add("repair", coBool);
|
||||
def->label = L("Repair");
|
||||
def->tooltip = L("Try to repair any non-manifold meshes (this option is implicitly added whenever we need to slice the model to perform the requested action).");
|
||||
def->cli = "repair";
|
||||
|
||||
def = this->add("rotate", coFloat);
|
||||
def->label = L("Rotate");
|
||||
def->tooltip = L("Rotation angle around the Z axis in degrees.");
|
||||
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.");
|
||||
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.");
|
||||
def->cli = "rotate-y";
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("scale", coFloatOrPercent);
|
||||
def->label = L("Scale");
|
||||
def->tooltip = L("Scaling factor or percentage.");
|
||||
def->cli = "scale";
|
||||
def->default_value = new ConfigOptionFloatOrPercent(1, false);
|
||||
|
||||
def = this->add("split", coBool);
|
||||
def->label = L("Split");
|
||||
def->tooltip = L("Detect unconnected parts in the given model(s) and split them into separate objects.");
|
||||
def->cli = "split";
|
||||
|
||||
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("print_center", coPoint);
|
||||
def->label = L("Print center");
|
||||
def->tooltip = L("Center the print around the given center (default: 100, 100).");
|
||||
def->cli = "print-center";
|
||||
def->default_value = new ConfigOptionPoint(Vec2d(100,100));
|
||||
def->default_value = new ConfigOptionPoint3(Vec3d(0,0,0));
|
||||
}
|
||||
|
||||
const CLIConfigDef cli_config_def;
|
||||
CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
{
|
||||
ConfigOptionDef* def;
|
||||
|
||||
def = this->add("ignore_nonexistent_config", coBool);
|
||||
def->label = L("Ignore non-existent config files");
|
||||
def->tooltip = L("Do not fail if a file supplied to --load does not exist.");
|
||||
def->cli = "ignore-nonexistent-config";
|
||||
|
||||
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 = 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|o";
|
||||
|
||||
/*
|
||||
def = this->add("autosave", coString);
|
||||
def->label = L("Autosave");
|
||||
def->tooltip = L("Automatically export current configuration to the specified file.");
|
||||
def->cli = "autosave";
|
||||
*/
|
||||
|
||||
def = this->add("datadir", coString);
|
||||
def->label = L("Data directory");
|
||||
def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage.");
|
||||
def->cli = "datadir";
|
||||
|
||||
def = this->add("loglevel", coInt);
|
||||
def->label = L("Logging level");
|
||||
def->tooltip = L("Messages with severity lower or eqal to the loglevel will be printed out. 0:trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal");
|
||||
def->cli = "loglevel";
|
||||
def->min = 0;
|
||||
}
|
||||
|
||||
const CLIActionsConfigDef cli_actions_config_def;
|
||||
const CLITransformConfigDef cli_transform_config_def;
|
||||
const CLIMiscConfigDef cli_misc_config_def;
|
||||
|
||||
DynamicPrintAndCLIConfig::PrintAndCLIConfigDef DynamicPrintAndCLIConfig::s_def;
|
||||
|
||||
void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std::string &value) const
|
||||
{
|
||||
if (cli_config_def.options.find(opt_key) == cli_config_def.options.end()) {
|
||||
PrintConfigDef::handle_legacy(opt_key, value);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (cli_actions_config_def .options.find(opt_key) == cli_actions_config_def .options.end() &&
|
||||
cli_transform_config_def.options.find(opt_key) == cli_transform_config_def.options.end() &&
|
||||
cli_misc_config_def .options.find(opt_key) == cli_misc_config_def .options.end()) {
|
||||
PrintConfigDef::handle_legacy(opt_key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ enum PrinterTechnology
|
|||
ptFFF,
|
||||
// Stereolitography
|
||||
ptSLA,
|
||||
// Unknown, useful for command line processing
|
||||
ptUnknown,
|
||||
};
|
||||
|
||||
enum GCodeFlavor {
|
||||
|
@ -1145,72 +1147,32 @@ protected:
|
|||
#undef STATIC_PRINT_CONFIG_CACHE_DERIVED
|
||||
#undef OPT_PTR
|
||||
|
||||
class CLIConfigDef : public ConfigDef
|
||||
class CLIActionsConfigDef : public ConfigDef
|
||||
{
|
||||
public:
|
||||
CLIConfigDef();
|
||||
CLIActionsConfigDef();
|
||||
};
|
||||
|
||||
extern const CLIConfigDef cli_config_def;
|
||||
|
||||
#define OPT_PTR(KEY) if (opt_key == #KEY) return &this->KEY
|
||||
|
||||
class CLIConfig : public virtual ConfigBase, public StaticConfig
|
||||
class CLITransformConfigDef : public ConfigDef
|
||||
{
|
||||
public:
|
||||
ConfigOptionFloat cut;
|
||||
ConfigOptionString datadir;
|
||||
ConfigOptionBool dont_arrange;
|
||||
ConfigOptionBool export_3mf;
|
||||
ConfigOptionBool gui;
|
||||
ConfigOptionBool info;
|
||||
ConfigOptionBool help;
|
||||
ConfigOptionStrings load;
|
||||
ConfigOptionBool no_gui;
|
||||
ConfigOptionString output;
|
||||
ConfigOptionPoint print_center;
|
||||
ConfigOptionFloat rotate;
|
||||
ConfigOptionFloat rotate_x;
|
||||
ConfigOptionFloat rotate_y;
|
||||
ConfigOptionString save;
|
||||
ConfigOptionFloat scale;
|
||||
// ConfigOptionPoint3 scale_to_fit;
|
||||
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; }
|
||||
t_config_option_keys keys() const override { return cli_config_def.keys(); }
|
||||
|
||||
ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override
|
||||
{
|
||||
OPT_PTR(cut);
|
||||
OPT_PTR(datadir);
|
||||
OPT_PTR(dont_arrange);
|
||||
OPT_PTR(export_3mf);
|
||||
OPT_PTR(gui);
|
||||
OPT_PTR(help);
|
||||
OPT_PTR(info);
|
||||
OPT_PTR(load);
|
||||
OPT_PTR(no_gui);
|
||||
OPT_PTR(output);
|
||||
OPT_PTR(print_center);
|
||||
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;
|
||||
}
|
||||
CLITransformConfigDef();
|
||||
};
|
||||
|
||||
#undef OPT_PTR
|
||||
class CLIMiscConfigDef : public ConfigDef
|
||||
{
|
||||
public:
|
||||
CLIMiscConfigDef();
|
||||
};
|
||||
|
||||
// This class defines the command line options representing actions.
|
||||
extern const CLIActionsConfigDef cli_actions_config_def;
|
||||
|
||||
// This class defines the command line options representing transforms.
|
||||
extern const CLITransformConfigDef cli_transform_config_def;
|
||||
|
||||
// This class defines all command line options that are not actions or transforms.
|
||||
extern const CLIMiscConfigDef cli_misc_config_def;
|
||||
|
||||
class DynamicPrintAndCLIConfig : public DynamicPrintConfig
|
||||
{
|
||||
|
@ -1233,19 +1195,16 @@ private:
|
|||
public:
|
||||
PrintAndCLIConfigDef() {
|
||||
this->options.insert(print_config_def.options.begin(), print_config_def.options.end());
|
||||
this->options.insert(cli_config_def.options.begin(), cli_config_def.options.end());
|
||||
this->options.insert(cli_actions_config_def.options.begin(), cli_actions_config_def.options.end());
|
||||
this->options.insert(cli_transform_config_def.options.begin(), cli_transform_config_def.options.end());
|
||||
this->options.insert(cli_misc_config_def.options.begin(), cli_misc_config_def.options.end());
|
||||
}
|
||||
// Do not release the default values, they are handled by print_config_def & cli_config_def.
|
||||
// Do not release the default values, they are handled by print_config_def & cli_actions_config_def / cli_transform_config_def / cli_misc_config_def.
|
||||
~PrintAndCLIConfigDef() { this->options.clear(); }
|
||||
};
|
||||
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
|
||||
|
|
|
@ -300,81 +300,82 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
|||
auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
|
||||
assert(it_status != model_object_status.end());
|
||||
assert(it_status->status != ModelObjectStatus::Deleted);
|
||||
if (it_status->status == ModelObjectStatus::New)
|
||||
// PrintObject instances will be added in the next loop.
|
||||
continue;
|
||||
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
||||
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
|
||||
const ModelObject &model_object_new = *model.objects[idx_model_object];
|
||||
auto it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id()));
|
||||
if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id())
|
||||
it_print_object_status = print_object_status.end();
|
||||
// Check whether a model part volume was added or removed, their transformations or order changed.
|
||||
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
|
||||
bool sla_trafo_differs = model_object.instances.empty() != model_object_new.instances.empty() ||
|
||||
(! model_object.instances.empty() && ! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)));
|
||||
if (model_parts_differ || sla_trafo_differs) {
|
||||
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||
if (it_print_object_status != print_object_status.end()) {
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_all_steps());
|
||||
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted;
|
||||
}
|
||||
// Copy content of the ModelObject including its ID, do not change the parent.
|
||||
model_object.assign_copy(model_object_new);
|
||||
} else {
|
||||
// Synchronize Object's config.
|
||||
bool object_config_changed = model_object.config != model_object_new.config;
|
||||
if (object_config_changed)
|
||||
model_object.config = model_object_new.config;
|
||||
if (! object_diff.empty() || object_config_changed) {
|
||||
SLAPrintObjectConfig new_config = m_default_object_config;
|
||||
normalize_and_apply_config(new_config, model_object.config);
|
||||
if (it_print_object_status != print_object_status.end()) {
|
||||
t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config);
|
||||
if (! diff.empty()) {
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff));
|
||||
it_print_object_status->print_object->config_apply_only(new_config, diff, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if (model_object.sla_support_points != model_object_new.sla_support_points) {
|
||||
model_object.sla_support_points = model_object_new.sla_support_points;
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
}
|
||||
if (model_object.sla_points_status != model_object_new.sla_points_status) {
|
||||
// Change of this status should invalidate support points. The points themselves are not enough, there are none
|
||||
// in case that nothing was generated OR that points were autogenerated already and not copied to the front-end.
|
||||
// These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT
|
||||
// invalidate - that would keep stopping the background processing without a reason.
|
||||
if (model_object.sla_points_status != sla::PointsStatus::Generating)
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
model_object.sla_points_status = model_object_new.sla_points_status;
|
||||
}*/
|
||||
// PrintObject for this ModelObject, if it exists.
|
||||
auto it_print_object_status = print_object_status.end();
|
||||
if (it_status->status != ModelObjectStatus::New) {
|
||||
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
||||
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
|
||||
const ModelObject &model_object_new = *model.objects[idx_model_object];
|
||||
auto it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id()));
|
||||
if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id())
|
||||
it_print_object_status = print_object_status.end();
|
||||
// Check whether a model part volume was added or removed, their transformations or order changed.
|
||||
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
|
||||
bool sla_trafo_differs = model_object.instances.empty() != model_object_new.instances.empty() ||
|
||||
(! model_object.instances.empty() && ! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)));
|
||||
if (model_parts_differ || sla_trafo_differs) {
|
||||
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||
if (it_print_object_status != print_object_status.end()) {
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_all_steps());
|
||||
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted;
|
||||
}
|
||||
// Copy content of the ModelObject including its ID, do not change the parent.
|
||||
model_object.assign_copy(model_object_new);
|
||||
} else {
|
||||
// Synchronize Object's config.
|
||||
bool object_config_changed = model_object.config != model_object_new.config;
|
||||
if (object_config_changed)
|
||||
model_object.config = model_object_new.config;
|
||||
if (! object_diff.empty() || object_config_changed) {
|
||||
SLAPrintObjectConfig new_config = m_default_object_config;
|
||||
normalize_and_apply_config(new_config, model_object.config);
|
||||
if (it_print_object_status != print_object_status.end()) {
|
||||
t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config);
|
||||
if (! diff.empty()) {
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff));
|
||||
it_print_object_status->print_object->config_apply_only(new_config, diff, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if (model_object.sla_support_points != model_object_new.sla_support_points) {
|
||||
model_object.sla_support_points = model_object_new.sla_support_points;
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
}
|
||||
if (model_object.sla_points_status != model_object_new.sla_points_status) {
|
||||
// Change of this status should invalidate support points. The points themselves are not enough, there are none
|
||||
// in case that nothing was generated OR that points were autogenerated already and not copied to the front-end.
|
||||
// These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT
|
||||
// invalidate - that would keep stopping the background processing without a reason.
|
||||
if (model_object.sla_points_status != sla::PointsStatus::Generating)
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
model_object.sla_points_status = model_object_new.sla_points_status;
|
||||
}*/
|
||||
|
||||
bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified;
|
||||
bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified;
|
||||
if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
|
||||
(! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
|
||||
(new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) {
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified;
|
||||
bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified;
|
||||
if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
|
||||
(! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
|
||||
(new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) {
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
|
||||
model_object.sla_points_status = model_object_new.sla_points_status;
|
||||
model_object.sla_support_points = model_object_new.sla_support_points;
|
||||
}
|
||||
model_object.sla_points_status = model_object_new.sla_points_status;
|
||||
model_object.sla_support_points = model_object_new.sla_support_points;
|
||||
}
|
||||
|
||||
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
|
||||
model_object.name = model_object_new.name;
|
||||
model_object.input_file = model_object_new.input_file;
|
||||
model_object.clear_instances();
|
||||
model_object.instances.reserve(model_object_new.instances.size());
|
||||
for (const ModelInstance *model_instance : model_object_new.instances) {
|
||||
model_object.instances.emplace_back(new ModelInstance(*model_instance));
|
||||
model_object.instances.back()->set_model_object(&model_object);
|
||||
}
|
||||
}
|
||||
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
|
||||
model_object.name = model_object_new.name;
|
||||
model_object.input_file = model_object_new.input_file;
|
||||
model_object.clear_instances();
|
||||
model_object.instances.reserve(model_object_new.instances.size());
|
||||
for (const ModelInstance *model_instance : model_object_new.instances) {
|
||||
model_object.instances.emplace_back(new ModelInstance(*model_instance));
|
||||
model_object.instances.back()->set_model_object(&model_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SLAPrintObject::Instance> new_instances = sla_instances(model_object);
|
||||
if (it_print_object_status != print_object_status.end() && it_print_object_status->status != PrintObjectStatus::Deleted) {
|
||||
|
|
|
@ -247,7 +247,7 @@ bool TriangleMesh::needed_repair() const
|
|||
|| this->stl.stats.backwards_edges > 0;
|
||||
}
|
||||
|
||||
void TriangleMesh::WriteOBJFile(char* output_file)
|
||||
void TriangleMesh::WriteOBJFile(const char* output_file)
|
||||
{
|
||||
stl_generate_shared_vertices(&stl);
|
||||
stl_write_obj(&stl, output_file);
|
||||
|
@ -1499,9 +1499,16 @@ void TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygo
|
|||
// Try to close gaps.
|
||||
// Do it in two rounds, first try to connect in the same direction only,
|
||||
// then try to connect the open polylines in reversed order as well.
|
||||
#if 0
|
||||
for (double max_gap : { EPSILON, 0.001, 0.1, 1., 2. }) {
|
||||
chain_open_polylines_close_gaps(open_polylines, *loops, max_gap, false);
|
||||
chain_open_polylines_close_gaps(open_polylines, *loops, max_gap, true);
|
||||
}
|
||||
#else
|
||||
const double max_gap = 2.; //mm
|
||||
chain_open_polylines_close_gaps(open_polylines, *loops, max_gap, false);
|
||||
chain_open_polylines_close_gaps(open_polylines, *loops, max_gap, true);
|
||||
#endif
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
{
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
float volume();
|
||||
void check_topology();
|
||||
bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == (int)this->stl.stats.number_of_facets; }
|
||||
void WriteOBJFile(char* output_file);
|
||||
void WriteOBJFile(const char* output_file);
|
||||
void scale(float factor);
|
||||
void scale(const Vec3d &versor);
|
||||
void translate(float x, float y, float z);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue