mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-31 17:52:00 +08:00
Validate CLI config options against min/max
This commit is contained in:
parent
bb29661a90
commit
a1464a737e
@ -718,12 +718,12 @@ void Plater::remove(int obj_idx, bool dont_push) {
|
|||||||
Slic3r::Log::info(LogChannel, "Assigned obj_ref");
|
Slic3r::Log::info(LogChannel, "Assigned obj_ref");
|
||||||
try {
|
try {
|
||||||
this->model->delete_object(obj_ref->identifier);
|
this->model->delete_object(obj_ref->identifier);
|
||||||
} catch (InvalidObjectException& ex) {
|
} catch (out_of_range &ex) {
|
||||||
Slic3r::Log::error(LogChannel, LOG_WSTRING("Failed to delete object " << obj_ref->identifier << " from Model."));
|
Slic3r::Log::error(LogChannel, LOG_WSTRING("Failed to delete object " << obj_ref->identifier << " from Model."));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this->print->delete_object(obj_ref->identifier);
|
this->print->delete_object(obj_ref->identifier);
|
||||||
} catch (InvalidObjectException& ex) {
|
} catch (out_of_range &ex) {
|
||||||
Slic3r::Log::error(LogChannel, LOG_WSTRING("Failed to delete object " << obj_ref->identifier << " from Print."));
|
Slic3r::Log::error(LogChannel, LOG_WSTRING("Failed to delete object " << obj_ref->identifier << " from Print."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +86,14 @@ int CLI::run(int argc, char **argv) {
|
|||||||
// create a static (full) print config to be used in our logic
|
// create a static (full) print config to be used in our logic
|
||||||
this->full_print_config.apply(this->print_config);
|
this->full_print_config.apply(this->print_config);
|
||||||
|
|
||||||
|
// validate config
|
||||||
|
try {
|
||||||
|
this->full_print_config.validate();
|
||||||
|
} catch (InvalidOptionException &e) {
|
||||||
|
boost::nowide::cerr << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// read input file(s) if any
|
// read input file(s) if any
|
||||||
for (auto const &file : input_files) {
|
for (auto const &file : input_files) {
|
||||||
Model model;
|
Model model;
|
||||||
@ -271,6 +279,7 @@ int CLI::run(int argc, char **argv) {
|
|||||||
print.status_cb = [](int ln, const std::string& msg) {
|
print.status_cb = [](int ln, const std::string& msg) {
|
||||||
boost::nowide::cout << msg << std::endl;
|
boost::nowide::cout << msg << std::endl;
|
||||||
};
|
};
|
||||||
|
print.apply_config(this->print_config);
|
||||||
print.center = !this->config.has("center")
|
print.center = !this->config.has("center")
|
||||||
&& !this->config.has("align_xy")
|
&& !this->config.has("align_xy")
|
||||||
&& !this->config.getBool("dont_arrange");
|
&& !this->config.getBool("dont_arrange");
|
||||||
@ -282,7 +291,12 @@ int CLI::run(int argc, char **argv) {
|
|||||||
std::chrono::time_point<clock_> t0{ clock_::now() };
|
std::chrono::time_point<clock_> t0{ clock_::now() };
|
||||||
|
|
||||||
const std::string outfile = this->output_filepath(model, IO::Gcode);
|
const std::string outfile = this->output_filepath(model, IO::Gcode);
|
||||||
print.export_gcode(outfile);
|
try {
|
||||||
|
print.export_gcode(outfile);
|
||||||
|
} catch (InvalidPrintException &e) {
|
||||||
|
boost::nowide::cerr << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
boost::nowide::cout << "G-code exported to " << outfile << std::endl;
|
boost::nowide::cout << "G-code exported to " << outfile << std::endl;
|
||||||
|
|
||||||
// output some statistics
|
// output some statistics
|
||||||
|
@ -265,7 +265,7 @@ ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys &opt_
|
|||||||
ConfigOption* my_opt = this->option(opt_key, true);
|
ConfigOption* my_opt = this->option(opt_key, true);
|
||||||
if (opt_key.size() == 0) continue;
|
if (opt_key.size() == 0) continue;
|
||||||
if (my_opt == NULL) {
|
if (my_opt == NULL) {
|
||||||
if (ignore_nonexistent == false) throw UnknownOptionException();
|
if (ignore_nonexistent == false) throw UnknownOptionException(opt_key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (default_nonexistent && !other.has(opt_key)) {
|
if (default_nonexistent && !other.has(opt_key)) {
|
||||||
@ -328,7 +328,7 @@ ConfigBase::set_deserialize(t_config_option_key opt_key, std::string str, bool a
|
|||||||
if (optdef != NULL) break;
|
if (optdef != NULL) break;
|
||||||
}
|
}
|
||||||
if (optdef == NULL)
|
if (optdef == NULL)
|
||||||
throw UnknownOptionException();
|
throw UnknownOptionException(opt_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optdef->shortcut.empty()) {
|
if (!optdef->shortcut.empty()) {
|
||||||
@ -472,6 +472,35 @@ ConfigBase::save(const std::string &file) const
|
|||||||
c.close();
|
c.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConfigBase::validate() const
|
||||||
|
{
|
||||||
|
for (auto &opt_key : this->keys()) {
|
||||||
|
// get option definition
|
||||||
|
const ConfigOptionDef* def = this->def->get(opt_key);
|
||||||
|
assert(def != nullptr);
|
||||||
|
|
||||||
|
if (def->type == coInt) {
|
||||||
|
auto &value = this->opt<ConfigOptionInt>(opt_key)->value;
|
||||||
|
if (value < def->min || value > def->max)
|
||||||
|
throw InvalidOptionException(opt_key);
|
||||||
|
} else if (def->type == coFloat) {
|
||||||
|
auto &value = this->opt<ConfigOptionFloat>(opt_key)->value;
|
||||||
|
if (value < def->min || value > def->max)
|
||||||
|
throw InvalidOptionException(opt_key);
|
||||||
|
} else if (def->type == coInts) {
|
||||||
|
for (auto &value : this->opt<ConfigOptionInts>(opt_key)->values)
|
||||||
|
if (value < def->min || value > def->max)
|
||||||
|
throw InvalidOptionException(opt_key);
|
||||||
|
} else if (def->type == coFloats) {
|
||||||
|
for (auto &value : this->opt<ConfigOptionFloats>(opt_key)->values)
|
||||||
|
if (value < def->min || value > def->max)
|
||||||
|
throw InvalidOptionException(opt_key);
|
||||||
|
}
|
||||||
|
// TODO: validate coFloatOrPercent (semantics of min/max are ambiguous for it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DynamicConfig& DynamicConfig::operator= (DynamicConfig other)
|
DynamicConfig& DynamicConfig::operator= (DynamicConfig other)
|
||||||
{
|
{
|
||||||
this->swap(other);
|
this->swap(other);
|
||||||
|
@ -732,6 +732,7 @@ class ConfigBase
|
|||||||
void setenv_();
|
void setenv_();
|
||||||
void load(const std::string &file);
|
void load(const std::string &file);
|
||||||
void save(const std::string &file) const;
|
void save(const std::string &file) const;
|
||||||
|
void validate() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Configuration store with dynamic number of configuration values.
|
/// Configuration store with dynamic number of configuration values.
|
||||||
@ -775,7 +776,25 @@ class StaticConfig : public virtual ConfigBase
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
|
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
|
||||||
class UnknownOptionException : public std::exception {};
|
class ConfigOptionException : public std::exception {
|
||||||
|
public:
|
||||||
|
t_config_option_key opt_key;
|
||||||
|
ConfigOptionException(t_config_option_key _opt_key)
|
||||||
|
: opt_key(_opt_key) {};
|
||||||
|
};
|
||||||
|
class UnknownOptionException : public ConfigOptionException {
|
||||||
|
using ConfigOptionException::ConfigOptionException;
|
||||||
|
};
|
||||||
|
class InvalidOptionException : public ConfigOptionException {
|
||||||
|
using ConfigOptionException::ConfigOptionException;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual const char* what() const noexcept {
|
||||||
|
std::string s("Invalid value for option: ");
|
||||||
|
s += this->opt_key;
|
||||||
|
return s.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ Print::delete_object(size_t idx)
|
|||||||
{
|
{
|
||||||
PrintObjectPtrs::iterator i = this->objects.begin() + idx;
|
PrintObjectPtrs::iterator i = this->objects.begin() + idx;
|
||||||
if (i >= this->objects.end())
|
if (i >= this->objects.end())
|
||||||
throw InvalidObjectException();
|
throw std::out_of_range("Object not found");
|
||||||
|
|
||||||
// before deleting object, invalidate all of its steps in order to
|
// before deleting object, invalidate all of its steps in order to
|
||||||
// invalidate all of the dependent ones in Print
|
// invalidate all of the dependent ones in Print
|
||||||
@ -858,7 +858,7 @@ bool Print::has_skirt() const
|
|||||||
|| this->has_infinite_skirt();
|
|| this->has_infinite_skirt();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
void
|
||||||
Print::validate() const
|
Print::validate() const
|
||||||
{
|
{
|
||||||
if (this->config.complete_objects) {
|
if (this->config.complete_objects) {
|
||||||
@ -896,7 +896,7 @@ Print::validate() const
|
|||||||
Polygon p = convex_hull;
|
Polygon p = convex_hull;
|
||||||
p.translate(*copy);
|
p.translate(*copy);
|
||||||
if (!intersection(a, p).empty())
|
if (!intersection(a, p).empty())
|
||||||
return "Some objects are too close; your extruder will collide with them.";
|
throw InvalidPrintException{"Some objects are too close; your extruder will collide with them."};
|
||||||
|
|
||||||
a = union_(a, p);
|
a = union_(a, p);
|
||||||
}
|
}
|
||||||
@ -915,7 +915,7 @@ Print::validate() const
|
|||||||
// it will be printed as last one so its height doesn't matter
|
// it will be printed as last one so its height doesn't matter
|
||||||
object_height.pop_back();
|
object_height.pop_back();
|
||||||
if (!object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value))
|
if (!object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value))
|
||||||
return "Some objects are too tall and cannot be printed without extruder collisions.";
|
throw InvalidPrintException{"Some objects are too tall and cannot be printed without extruder collisions."};
|
||||||
}
|
}
|
||||||
} // end if (this->config.complete_objects)
|
} // end if (this->config.complete_objects)
|
||||||
|
|
||||||
@ -923,15 +923,13 @@ Print::validate() const
|
|||||||
size_t total_copies_count = 0;
|
size_t total_copies_count = 0;
|
||||||
FOREACH_OBJECT(this, i_object) total_copies_count += (*i_object)->copies().size();
|
FOREACH_OBJECT(this, i_object) total_copies_count += (*i_object)->copies().size();
|
||||||
if (total_copies_count > 1 && !this->config.complete_objects.getBool())
|
if (total_copies_count > 1 && !this->config.complete_objects.getBool())
|
||||||
return "The Spiral Vase option can only be used when printing a single object.";
|
throw InvalidPrintException{"The Spiral Vase option can only be used when printing a single object."};
|
||||||
if (this->regions.size() > 1)
|
if (this->regions.size() > 1)
|
||||||
return "The Spiral Vase option can only be used when printing single material objects.";
|
throw InvalidPrintException{"The Spiral Vase option can only be used when printing single material objects."};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->extruders().empty())
|
if (this->extruders().empty())
|
||||||
return "The supplied settings will cause an empty print.";
|
throw InvalidPrintException{"The supplied settings will cause an empty print."};
|
||||||
|
|
||||||
return std::string();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the bounding box of objects placed in copies position
|
// the bounding box of objects placed in copies position
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
#include "Flow.hpp"
|
#include "Flow.hpp"
|
||||||
@ -19,13 +21,11 @@
|
|||||||
#include "LayerHeightSpline.hpp"
|
#include "LayerHeightSpline.hpp"
|
||||||
#include "SupportMaterial.hpp"
|
#include "SupportMaterial.hpp"
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class InvalidObjectException : public std::exception {};
|
class InvalidPrintException : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
class Print;
|
class Print;
|
||||||
class PrintObject;
|
class PrintObject;
|
||||||
@ -292,8 +292,8 @@ class Print
|
|||||||
bool apply_config(DynamicPrintConfig config);
|
bool apply_config(DynamicPrintConfig config);
|
||||||
bool has_infinite_skirt() const;
|
bool has_infinite_skirt() const;
|
||||||
bool has_skirt() const;
|
bool has_skirt() const;
|
||||||
// Returns an empty string if valid, otherwise returns an error message.
|
// Throws exceptions if print is not valid.
|
||||||
std::string validate() const;
|
void validate() const;
|
||||||
BoundingBox bounding_box() const;
|
BoundingBox bounding_box() const;
|
||||||
BoundingBox total_bounding_box() const;
|
BoundingBox total_bounding_box() const;
|
||||||
double skirt_first_layer_height() const;
|
double skirt_first_layer_height() const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user