Validate CLI config options against min/max

This commit is contained in:
Alessandro Ranellucci 2018-11-17 18:02:15 +01:00 committed by Joseph Lenox
parent bb29661a90
commit a1464a737e
6 changed files with 82 additions and 22 deletions

View File

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

View File

@ -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);
try {
print.export_gcode(outfile); 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

View File

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

View File

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

View File

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

View File

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