Complete the C++ CLI; remove the #ifndef SLIC3RXS guards and fix CI by removing std::initializer_lists

This commit is contained in:
Alessandro Ranellucci 2018-11-21 09:17:32 +01:00 committed by Joseph Lenox
parent 11a6601c4a
commit f0f36cb935
15 changed files with 325 additions and 366 deletions

View File

@ -147,6 +147,8 @@ src/libslic3r/PrintGCode.cpp
src/libslic3r/PrintGCode.hpp src/libslic3r/PrintGCode.hpp
src/libslic3r/PrintObject.cpp src/libslic3r/PrintObject.cpp
src/libslic3r/PrintRegion.cpp src/libslic3r/PrintRegion.cpp
src/libslic3r/SimplePrint.cpp
src/libslic3r/SimplePrint.hpp
src/libslic3r/SLAPrint.cpp src/libslic3r/SLAPrint.cpp
src/libslic3r/SLAPrint.hpp src/libslic3r/SLAPrint.hpp
src/libslic3r/SlicingAdaptive.cpp src/libslic3r/SlicingAdaptive.cpp

View File

@ -1,4 +1,3 @@
#ifndef SLIC3RXS
#include "Config.hpp" #include "Config.hpp"
#include "Log.hpp" #include "Log.hpp"
@ -22,7 +21,7 @@ Config::new_from_defaults(std::initializer_list<std::string> init)
std::shared_ptr<Config> std::shared_ptr<Config>
Config::new_from_defaults(t_config_option_keys init) Config::new_from_defaults(t_config_option_keys init)
{ {
auto my_config(std::make_shared<Config>()); std::shared_ptr<Config> my_config(std::make_shared<Config>());
for (auto& opt_key : init) { for (auto& opt_key : init) {
if (print_config_def.has(opt_key)) { if (print_config_def.has(opt_key)) {
const std::string value { print_config_def.get(opt_key).default_value->serialize() }; const std::string value { print_config_def.get(opt_key).default_value->serialize() };
@ -33,30 +32,25 @@ Config::new_from_defaults(t_config_option_keys init)
return my_config; return my_config;
} }
std::shared_ptr<Config>
new_from_cli(const int& argc, const char* argv[])
{
return std::make_shared<Config>();
}
std::shared_ptr<Config> std::shared_ptr<Config>
Config::new_from_ini(const std::string& inifile) Config::new_from_ini(const std::string& inifile)
{ {
auto my_config(std::make_shared<Config>()); std::shared_ptr<Config> my_config(std::make_shared<Config>());
my_config->read_ini(inifile); my_config->read_ini(inifile);
return my_config; return my_config;
} }
// TODO: this should be merged into ConfigBase::validate()
bool bool
Config::validate() Config::validate()
{ {
// general validation // general validation
for (auto k : this->_config.keys()) { for (auto k : this->_config.keys()) {
if (print_config_def.options.count(k) == 0) continue; // skip over keys that aren't in the master list if (print_config_def.options.count(k) == 0) continue; // skip over keys that aren't in the master list
const auto& opt {print_config_def.options.at(k)}; const ConfigOptionDef& opt { print_config_def.options.at(k) };
if (opt.cli == "" || std::regex_search(opt.cli, _match_info, _cli_pattern) == false) continue; if (opt.cli == "" || std::regex_search(opt.cli, _match_info, _cli_pattern) == false) continue;
auto type {_match_info.str(1)}; std::string type { _match_info.str(1) };
std::vector<std::string> values; std::vector<std::string> values;
if (std::regex_search(type, _match_info, std::regex("@$"))) { if (std::regex_search(type, _match_info, std::regex("@$"))) {
type = std::regex_replace(type, std::regex("@$"), std::string("")); // strip off the @ for later; type = std::regex_replace(type, std::regex("@$"), std::string("")); // strip off the @ for later;
@ -66,7 +60,7 @@ Config::validate()
} catch (std::bad_cast& e) { } catch (std::bad_cast& e) {
throw InvalidOptionType((std::string("(cast failure) Invalid value for ") + std::string(k)).c_str()); throw InvalidOptionType((std::string("(cast failure) Invalid value for ") + std::string(k)).c_str());
} }
auto tmp_str {tmp_opt->vserialize()}; const std::vector<std::string> tmp_str { tmp_opt->vserialize() };
values.insert(values.end(), tmp_str.begin(), tmp_str.end()); values.insert(values.end(), tmp_str.begin(), tmp_str.end());
} else { } else {
Slic3r::Log::debug("Config::validate", std::string("Not an array")); Slic3r::Log::debug("Config::validate", std::string("Not an array"));
@ -91,28 +85,28 @@ void
Config::set(const t_config_option_key& opt_key, const std::string& value) Config::set(const t_config_option_key& opt_key, const std::string& value)
{ {
try { try {
const auto& def {print_config_def.options.at(opt_key)}; const auto& def = print_config_def.options.at(opt_key);
switch (def.type) { switch (def.type) {
case coInt: case coInt:
{ {
auto* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))}; ConfigOptionInt* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))};
ptr->value = std::stoi(value); ptr->value = std::stoi(value);
} break; } break;
case coInts: case coInts:
{ {
auto* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))}; ConfigOptionInts* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))};
if (!ptr->deserialize(value, true) ) { if (!ptr->deserialize(value, true) ) {
throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value.")); throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value."));
} }
} break; } break;
case coFloat: case coFloat:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloat* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))};
ptr->setFloat(std::stod(value)); ptr->setFloat(std::stod(value));
} break; } break;
case coFloatOrPercent: case coFloatOrPercent:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloatOrPercent* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))};
const size_t perc = value.find("%"); const size_t perc = value.find("%");
ptr->percent = (perc != std::string::npos); ptr->percent = (perc != std::string::npos);
if (ptr->percent) { if (ptr->percent) {
@ -125,21 +119,21 @@ Config::set(const t_config_option_key& opt_key, const std::string& value)
} break; } break;
case coFloats: case coFloats:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloats* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))};
if (!ptr->deserialize(value, true) ) { if (!ptr->deserialize(value, true) ) {
throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value.")); throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value."));
} }
} break; } break;
case coString: case coString:
{ {
auto* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))}; ConfigOptionString* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))};
if (!ptr->deserialize(value) ) { if (!ptr->deserialize(value) ) {
throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value.")); throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value."));
} }
} break; } break;
case coBool: case coBool:
{ {
auto* ptr {dynamic_cast<ConfigOptionBool*>(this->_config.optptr(opt_key, true))}; ConfigOptionBool* ptr {dynamic_cast<ConfigOptionBool*>(this->_config.optptr(opt_key, true))};
ptr->deserialize(value); ptr->deserialize(value);
} break; } break;
default: default:
@ -156,42 +150,42 @@ void
Config::set(const t_config_option_key& opt_key, const bool value) Config::set(const t_config_option_key& opt_key, const bool value)
{ {
try { try {
const auto& def {print_config_def.options.at(opt_key)}; const auto& def = print_config_def.options.at(opt_key);
switch (def.type) { switch (def.type) {
case coBool: case coBool:
{ {
auto* ptr {dynamic_cast<ConfigOptionBool*>(this->_config.optptr(opt_key, true))}; ConfigOptionBool* ptr {dynamic_cast<ConfigOptionBool*>(this->_config.optptr(opt_key, true))};
ptr->value = value; ptr->value = value;
} break; } break;
case coInt: case coInt:
{ {
auto* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))}; ConfigOptionInt* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))};
ptr->setInt(value); ptr->setInt(value);
} break; } break;
case coInts: case coInts:
{ {
auto* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))}; ConfigOptionInts* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))};
ptr->deserialize(std::to_string(value), true); ptr->deserialize(std::to_string(value), true);
} break; } break;
case coFloat: case coFloat:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloat* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))};
ptr->setFloat(value); ptr->setFloat(value);
} break; } break;
case coFloatOrPercent: case coFloatOrPercent:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloatOrPercent* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))};
ptr->setFloat(value); ptr->setFloat(value);
ptr->percent = false; ptr->percent = false;
} break; } break;
case coFloats: case coFloats:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloats* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))};
ptr->deserialize(std::to_string(value), true); ptr->deserialize(std::to_string(value), true);
} break; } break;
case coString: case coString:
{ {
auto* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))}; ConfigOptionString* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))};
if (!ptr->deserialize(std::to_string(value)) ) { if (!ptr->deserialize(std::to_string(value)) ) {
throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value.")); throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value."));
} }
@ -209,42 +203,42 @@ void
Config::set(const t_config_option_key& opt_key, const int value) Config::set(const t_config_option_key& opt_key, const int value)
{ {
try { try {
const auto& def {print_config_def.options.at(opt_key)}; const auto& def = print_config_def.options.at(opt_key);
switch (def.type) { switch (def.type) {
case coBool: case coBool:
{ {
auto* ptr {dynamic_cast<ConfigOptionBool*>(this->_config.optptr(opt_key, true))}; ConfigOptionBool* ptr {dynamic_cast<ConfigOptionBool*>(this->_config.optptr(opt_key, true))};
ptr->value = (value != 0); ptr->value = (value != 0);
} break; } break;
case coInt: case coInt:
{ {
auto* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))}; ConfigOptionInt* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))};
ptr->setInt(value); ptr->setInt(value);
} break; } break;
case coInts: case coInts:
{ {
auto* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))}; ConfigOptionInts* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))};
ptr->deserialize(std::to_string(value), true); ptr->deserialize(std::to_string(value), true);
} break; } break;
case coFloat: case coFloat:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloat* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))};
ptr->setFloat(value); ptr->setFloat(value);
} break; } break;
case coFloatOrPercent: case coFloatOrPercent:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloatOrPercent* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))};
ptr->setFloat(value); ptr->setFloat(value);
ptr->percent = false; ptr->percent = false;
} break; } break;
case coFloats: case coFloats:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloats* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))};
ptr->deserialize(std::to_string(value), true); ptr->deserialize(std::to_string(value), true);
} break; } break;
case coString: case coString:
{ {
auto* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))}; ConfigOptionString* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))};
if (!ptr->deserialize(std::to_string(value)) ) { if (!ptr->deserialize(std::to_string(value)) ) {
throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value.")); throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value."));
} }
@ -262,37 +256,37 @@ void
Config::set(const t_config_option_key& opt_key, const double value) Config::set(const t_config_option_key& opt_key, const double value)
{ {
try { try {
const auto& def {print_config_def.options.at(opt_key)}; const auto& def = print_config_def.options.at(opt_key);
switch (def.type) { switch (def.type) {
case coInt: case coInt:
{ {
auto* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))}; ConfigOptionInt* ptr {dynamic_cast<ConfigOptionInt*>(this->_config.optptr(opt_key, true))};
ptr->setInt(std::round(value)); ptr->setInt(std::round(value));
} break; } break;
case coInts: case coInts:
{ {
auto* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))}; ConfigOptionInts* ptr {dynamic_cast<ConfigOptionInts*>(this->_config.optptr(opt_key, true))};
ptr->deserialize(std::to_string(std::round(value)), true); ptr->deserialize(std::to_string(std::round(value)), true);
} break; } break;
case coFloat: case coFloat:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloat* ptr {dynamic_cast<ConfigOptionFloat*>(this->_config.optptr(opt_key, true))};
ptr->setFloat(value); ptr->setFloat(value);
} break; } break;
case coFloatOrPercent: case coFloatOrPercent:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloatOrPercent* ptr {dynamic_cast<ConfigOptionFloatOrPercent*>(this->_config.optptr(opt_key, true))};
ptr->setFloat(value); ptr->setFloat(value);
ptr->percent = false; ptr->percent = false;
} break; } break;
case coFloats: case coFloats:
{ {
auto* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))}; ConfigOptionFloats* ptr {dynamic_cast<ConfigOptionFloats*>(this->_config.optptr(opt_key, true))};
ptr->deserialize(std::to_string(value), true); ptr->deserialize(std::to_string(value), true);
} break; } break;
case coString: case coString:
{ {
auto* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))}; ConfigOptionString* ptr {dynamic_cast<ConfigOptionString*>(this->_config.optptr(opt_key, true))};
if (!ptr->deserialize(std::to_string(value)) ) { if (!ptr->deserialize(std::to_string(value)) ) {
throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value.")); throw InvalidOptionValue(std::string(opt_key) + std::string(" set with invalid value."));
} }
@ -355,7 +349,3 @@ is_valid_float(const std::string& type, const ConfigOptionDef& opt, const std::s
Config::Config() : _config(DynamicPrintConfig()) {}; Config::Config() : _config(DynamicPrintConfig()) {};
} // namespace Slic3r } // namespace Slic3r
#endif // SLIC3RXS

View File

@ -1,5 +1,3 @@
#ifndef SLIC3RXS
#ifndef CONFIG_HPP #ifndef CONFIG_HPP
#define CONFIG_HPP #define CONFIG_HPP
@ -47,9 +45,6 @@ public:
/// Factory method to construct a Config with specific default values loaded. /// Factory method to construct a Config with specific default values loaded.
static std::shared_ptr<Config> new_from_defaults(t_config_option_keys init); static std::shared_ptr<Config> new_from_defaults(t_config_option_keys init);
/// Factory method to construct a Config from CLI options.
static std::shared_ptr<Config> new_from_cli(const int& argc, const char* argv[]);
/// Factory method to construct a Config from an ini file. /// Factory method to construct a Config from an ini file.
static std::shared_ptr<Config> new_from_ini(const std::string& inifile); static std::shared_ptr<Config> new_from_ini(const std::string& inifile);
@ -156,5 +151,3 @@ bool is_valid_float(const std::string& type, const ConfigOptionDef& opt, const s
} // namespace Slic3r } // namespace Slic3r
#endif // CONFIG_HPP #endif // CONFIG_HPP
#endif // SLIC3RXS

View File

@ -378,7 +378,7 @@ ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys &opt_
continue; continue;
} }
if (default_nonexistent && !other.has(opt_key)) { if (default_nonexistent && !other.has(opt_key)) {
auto* def_opt = this->def->get(opt_key)->default_value->clone(); auto* def_opt = this->def->get(opt_key).default_value->clone();
// not the most efficient way, but easier than casting pointers to subclasses // not the most efficient way, but easier than casting pointers to subclasses
bool res = my_opt->deserialize( def_opt->serialize() ); bool res = my_opt->deserialize( def_opt->serialize() );
if (!res) { if (!res) {
@ -434,11 +434,11 @@ ConfigBase::set_deserialize(t_config_option_key opt_key, std::string str, bool a
} }
} }
} }
if (!this->def->has(opt_key)) { if (!this->def->has(opt_key))
throw UnknownOptionException(opt_key); throw UnknownOptionException(opt_key);
const ConfigOptionDef& optdef = this->def->options.at(opt_key); const ConfigOptionDef& optdef = this->def->options.at(opt_key);
if (!optdef.shortcut.empty()) if (!optdef.shortcut.empty()) {
for (const t_config_option_key& shortcut : optdef.shortcut) for (const t_config_option_key& shortcut : optdef.shortcut)
if (!this->set_deserialize(shortcut, str)) if (!this->set_deserialize(shortcut, str))
return false; return false;

View File

@ -103,8 +103,6 @@ Print::delete_object(size_t idx)
// TODO: purge unused regions // TODO: purge unused regions
} }
#ifndef SLIC3RXS
void void
Print::process() Print::process()
{ {
@ -176,11 +174,11 @@ Print::make_skirt()
// $skirt_height_z in this case is the highest possible skirt height for safety. // $skirt_height_z in this case is the highest possible skirt height for safety.
double skirt_height_z {-1.0}; double skirt_height_z {-1.0};
for (const auto& object : this->objects) { for (const auto& object : this->objects) {
size_t skirt_height { const size_t skirt_height {
this->has_infinite_skirt() ? object->layer_count() : this->has_infinite_skirt() ? object->layer_count() :
std::min(size_t(this->config.skirt_height()), object->layer_count()) std::min(size_t(this->config.skirt_height()), object->layer_count())
}; };
auto* highest_layer {object->get_layer(skirt_height - 1)}; const Layer* highest_layer { object->get_layer(skirt_height - 1) };
skirt_height_z = std::max(skirt_height_z, highest_layer->print_z); skirt_height_z = std::max(skirt_height_z, highest_layer->print_z);
} }
@ -303,8 +301,6 @@ Print::make_skirt()
this->state.set_done(psSkirt); this->state.set_done(psSkirt);
} }
#endif // SLIC3RXS
void void
Print::reload_object(size_t idx) Print::reload_object(size_t idx)
{ {
@ -714,8 +710,6 @@ Print::add_model_object(ModelObject* model_object, int idx)
} }
} }
#ifndef SLIC3RXS
void void
Print::export_gcode(std::ostream& output, bool quiet) Print::export_gcode(std::ostream& output, bool quiet)
{ {
@ -724,9 +718,8 @@ Print::export_gcode(std::ostream& output, bool quiet)
if (this->status_cb != nullptr) if (this->status_cb != nullptr)
this->status_cb(90, "Exporting G-Code..."); this->status_cb(90, "Exporting G-Code...");
auto export_handler {Slic3r::PrintGCode(*this, output)}; Slic3r::PrintGCode(*this, output).output();
export_handler.output();
} }
void void
@ -777,13 +770,12 @@ Print::export_gcode(std::string outfile, bool quiet)
} }
} }
#ifndef SLIC3RXS
bool bool
Print::apply_config(config_ptr config) { Print::apply_config(config_ptr config) {
// dereference the stored pointer and pass the resulting data to apply_config() // dereference the stored pointer and pass the resulting data to apply_config()
return this->apply_config(config->config()); return this->apply_config(config->config());
} }
#endif #endif
bool bool
@ -934,12 +926,19 @@ Print::validate() const
object->model_object()->instances.front()->transform_polygon(&convex_hull); object->model_object()->instances.front()->transform_polygon(&convex_hull);
// grow convex hull with the clearance margin // grow convex hull with the clearance margin
convex_hull = offset(convex_hull, scale_(this->config.extruder_clearance_radius.value)/2, 1, jtRound, scale_(0.1)).front(); convex_hull = offset(
convex_hull,
// safety_offset in intersection() is not enough for preventing false positives
scale_(this->config.extruder_clearance_radius.value)/2 - scale_(0.01),
CLIPPER_OFFSET_SCALE,
jtRound, scale_(0.1)
).front();
// now we check that no instance of convex_hull intersects any of the previously checked object instances // now we check that no instance of convex_hull intersects any of the previously checked object instances
for (Points::const_iterator copy = object->_shifted_copies.begin(); copy != object->_shifted_copies.end(); ++copy) { for (Points::const_iterator copy = object->_shifted_copies.begin(); copy != object->_shifted_copies.end(); ++copy) {
Polygon p = convex_hull; Polygon p = convex_hull;
p.translate(*copy); p.translate(*copy);
if (!intersection(a, p).empty()) if (!intersection(a, p).empty())
throw InvalidPrintException{"Some objects are too close; your extruder will collide with them."}; throw InvalidPrintException{"Some objects are too close; your extruder will collide with them."};

View File

@ -113,7 +113,7 @@ class PrintObject
// TODO: Fill* fill_maker => (is => 'lazy'); // TODO: Fill* fill_maker => (is => 'lazy');
PrintState<PrintObjectStep> state; PrintState<PrintObjectStep> state;
Print* print(); Print* print() { return this->_print; };
ModelObject* model_object() { return this->_model_object; }; ModelObject* model_object() { return this->_model_object; };
const ModelObject& model_object() const { return *(this->_model_object); }; const ModelObject& model_object() const { return *(this->_model_object); };
@ -167,8 +167,6 @@ class PrintObject
void _make_perimeters(); void _make_perimeters();
void _infill(); void _infill();
#ifndef SLIC3RXS
/// Initialize and generate support material. /// Initialize and generate support material.
void generate_support_material(); void generate_support_material();
@ -200,7 +198,7 @@ class PrintObject
/// Idempotence of this method is guaranteed by the fact that we don't remove things from /// Idempotence of this method is guaranteed by the fact that we don't remove things from
/// fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries. /// fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
void clip_fill_surfaces(); void clip_fill_surfaces();
#endif // SLIC3RXS
private: private:
Print* _print; Print* _print;
ModelObject* _model_object; ModelObject* _model_object;
@ -211,12 +209,10 @@ class PrintObject
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox); PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
~PrintObject(); ~PrintObject();
#ifndef SLIC3RXS
/// Outer loop of logic for horizontal shell discovery /// Outer loop of logic for horizontal shell discovery
void _discover_external_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id); void _discover_external_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id);
/// Inner loop of logic for horizontal shell discovery /// Inner loop of logic for horizontal shell discovery
void _discover_neighbor_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id, const SurfaceType& type, Polygons& solid, const size_t& solid_layers); void _discover_neighbor_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id, const SurfaceType& type, Polygons& solid, const size_t& solid_layers);
#endif // SLIC3RXS
}; };
@ -233,13 +229,13 @@ class Print
PrintObjectPtrs objects; PrintObjectPtrs objects;
PrintRegionPtrs regions; PrintRegionPtrs regions;
PlaceholderParser placeholder_parser; PlaceholderParser placeholder_parser;
#ifndef SLIC3RXS
std::function<void(int, const std::string&)> status_cb {nullptr}; std::function<void(int, const std::string&)> status_cb {nullptr};
/// Function pointer for the UI side to call post-processing scripts. /// Function pointer for the UI side to call post-processing scripts.
/// Vector is assumed to be the executable script and all arguments. /// Vector is assumed to be the executable script and all arguments.
std::function<void(std::vector<std::string>)> post_process_cb {nullptr}; std::function<void(std::vector<std::string>)> post_process_cb {nullptr};
#endif
double total_used_filament, total_extruded_volume, total_cost, total_weight; double total_used_filament, total_extruded_volume, total_cost, total_weight;
std::map<size_t,float> filament_stats; std::map<size_t,float> filament_stats;
PrintState<PrintStep> state; PrintState<PrintStep> state;
@ -263,7 +259,6 @@ class Print
const PrintRegion* get_region(size_t idx) const { return this->regions.at(idx); }; const PrintRegion* get_region(size_t idx) const { return this->regions.at(idx); };
PrintRegion* add_region(); PrintRegion* add_region();
#ifndef SLIC3RXS
/// Triggers the rest of the print process /// Triggers the rest of the print process
void process(); void process();
@ -275,8 +270,6 @@ class Print
/// commands a gcode export to a temporary file and return its name /// commands a gcode export to a temporary file and return its name
std::string export_gcode(bool quiet = false); std::string export_gcode(bool quiet = false);
#endif // SLIC3RXS
// methods for handling state // methods for handling state
bool invalidate_state_by_config(const PrintConfigBase &config); bool invalidate_state_by_config(const PrintConfigBase &config);
@ -301,14 +294,12 @@ class Print
Flow skirt_flow() const; Flow skirt_flow() const;
void _make_brim(); void _make_brim();
#ifndef SLIC3RXS
/// Generates a skirt around the union of all of /// Generates a skirt around the union of all of
/// the objects in the print. /// the objects in the print.
void make_skirt(); void make_skirt();
/// Generates a brim around all of the objects in the print. /// Generates a brim around all of the objects in the print.
void make_brim(); void make_brim();
#endif // SLIC3RXS
std::set<size_t> object_extruders() const; std::set<size_t> object_extruders() const;

View File

@ -2029,7 +2029,7 @@ CLITransformConfigDef::CLITransformConfigDef()
def = this->add("repair", coBool); def = this->add("repair", coBool);
def->label = __TRANS("Repair"); def->label = __TRANS("Repair");
def->tooltip = __TRANS("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->tooltip = __TRANS("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->cli = "repair";
def = this->add("rotate", coFloat); def = this->add("rotate", coFloat);

View File

@ -1,4 +1,3 @@
#ifndef SLIC3RXS
#include "PrintGCode.hpp" #include "PrintGCode.hpp"
#include "PrintConfig.hpp" #include "PrintConfig.hpp"
@ -9,12 +8,6 @@ namespace Slic3r {
void void
PrintGCode::output() PrintGCode::output()
{ {
auto& gcodegen {this->_gcodegen};
auto& fh {this->fh};
auto& print {this->_print};
const auto& config {this->config};
const auto extruders {print.extruders()};
// Write information about the generator. // Write information about the generator.
time_t rawtime; tm * timeinfo; time_t rawtime; tm * timeinfo;
time(&rawtime); time(&rawtime);
@ -25,16 +18,16 @@ PrintGCode::output()
fh << "; Git Commit: " << BUILD_COMMIT << "\n\n"; fh << "; Git Commit: " << BUILD_COMMIT << "\n\n";
// Writes notes (content of all Settings tabs -> Notes) // Writes notes (content of all Settings tabs -> Notes)
fh << gcodegen.notes(); fh << _gcodegen.notes();
// Write some terse information on the slicing parameters. // Write some terse information on the slicing parameters.
auto& first_object {*(this->objects.at(0))}; PrintObject& first_object { *this->objects.at(0) };
auto layer_height {first_object.config.layer_height.getFloat()}; const auto layer_height = first_object.config.layer_height.getFloat();
for (auto* region : print.regions) { for (auto* region : _print.regions) {
{ {
auto flow {region->flow(frExternalPerimeter, layer_height, false, false, -1, first_object)}; const Flow flow { region->flow(frExternalPerimeter, layer_height, false, false, -1, first_object) };
auto vol_speed {flow.mm3_per_mm() * region->config.get_abs_value("external_perimeter_speed")}; auto vol_speed = flow.mm3_per_mm() * region->config.get_abs_value("external_perimeter_speed");
if (config.max_volumetric_speed.getInt() > 0) if (config.max_volumetric_speed.getInt() > 0)
vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat()); vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat());
fh << "; external perimeters extrusion width = "; fh << "; external perimeters extrusion width = ";
@ -42,8 +35,8 @@ PrintGCode::output()
fh << "(" << vol_speed << "mm^3/s)\n"; fh << "(" << vol_speed << "mm^3/s)\n";
} }
{ {
auto flow {region->flow(frPerimeter, layer_height, false, false, -1, first_object)}; const Flow flow { region->flow(frPerimeter, layer_height, false, false, -1, first_object) };
auto vol_speed {flow.mm3_per_mm() * region->config.get_abs_value("perimeter_speed")}; auto vol_speed = flow.mm3_per_mm() * region->config.get_abs_value("perimeter_speed");
if (config.max_volumetric_speed.getInt() > 0) if (config.max_volumetric_speed.getInt() > 0)
vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat()); vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat());
fh << "; perimeters extrusion width = "; fh << "; perimeters extrusion width = ";
@ -51,8 +44,8 @@ PrintGCode::output()
fh << "(" << vol_speed << "mm^3/s)\n"; fh << "(" << vol_speed << "mm^3/s)\n";
} }
{ {
auto flow {region->flow(frInfill, layer_height, false, false, -1, first_object)}; const Flow flow { region->flow(frInfill, layer_height, false, false, -1, first_object) };
auto vol_speed {flow.mm3_per_mm() * region->config.get_abs_value("infill_speed")}; auto vol_speed = flow.mm3_per_mm() * region->config.get_abs_value("infill_speed");
if (config.max_volumetric_speed.getInt() > 0) if (config.max_volumetric_speed.getInt() > 0)
vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat()); vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat());
fh << "; infill extrusion width = "; fh << "; infill extrusion width = ";
@ -60,8 +53,8 @@ PrintGCode::output()
fh << "(" << vol_speed << "mm^3/s)\n"; fh << "(" << vol_speed << "mm^3/s)\n";
} }
{ {
auto flow {region->flow(frSolidInfill, layer_height, false, false, -1, first_object)}; const Flow flow { region->flow(frSolidInfill, layer_height, false, false, -1, first_object) };
auto vol_speed {flow.mm3_per_mm() * region->config.get_abs_value("solid_infill_speed")}; auto vol_speed = flow.mm3_per_mm() * region->config.get_abs_value("solid_infill_speed");
if (config.max_volumetric_speed.getInt() > 0) if (config.max_volumetric_speed.getInt() > 0)
vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat()); vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat());
fh << "; solid infill extrusion width = "; fh << "; solid infill extrusion width = ";
@ -69,26 +62,26 @@ PrintGCode::output()
fh << "(" << vol_speed << "mm^3/s)\n"; fh << "(" << vol_speed << "mm^3/s)\n";
} }
{ {
auto flow {region->flow(frTopSolidInfill, layer_height, false, false, -1, first_object)}; const Flow flow { region->flow(frTopSolidInfill, layer_height, false, false, -1, first_object) };
auto vol_speed {flow.mm3_per_mm() * region->config.get_abs_value("top_solid_infill_speed")}; auto vol_speed = flow.mm3_per_mm() * region->config.get_abs_value("top_solid_infill_speed");
if (config.max_volumetric_speed.getInt() > 0) if (config.max_volumetric_speed.getInt() > 0)
vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat()); vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat());
fh << "; top solid infill extrusion width = "; fh << "; top solid infill extrusion width = ";
fh << std::fixed << std::setprecision(2) << flow.width << "mm "; fh << std::fixed << std::setprecision(2) << flow.width << "mm ";
fh << "(" << vol_speed << "mm^3/s)\n"; fh << "(" << vol_speed << "mm^3/s)\n";
} }
if (print.has_support_material()) { if (_print.has_support_material()) {
auto flow {first_object._support_material_flow()}; const Flow flow { first_object._support_material_flow() };
auto vol_speed {flow.mm3_per_mm() * first_object.config.get_abs_value("support_material_speed")}; auto vol_speed = flow.mm3_per_mm() * first_object.config.get_abs_value("support_material_speed");
if (config.max_volumetric_speed.getInt() > 0) if (config.max_volumetric_speed.getInt() > 0)
vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat()); vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat());
fh << "; support material extrusion width = "; fh << "; support material extrusion width = ";
fh << std::fixed << std::setprecision(2) << flow.width << "mm "; fh << std::fixed << std::setprecision(2) << flow.width << "mm ";
fh << "(" << vol_speed << "mm^3/s)\n"; fh << "(" << vol_speed << "mm^3/s)\n";
} }
if (print.config.first_layer_extrusion_width.getFloat() > 0) { if (_print.config.first_layer_extrusion_width.getFloat() > 0) {
auto flow {region->flow(frPerimeter, layer_height, false, false, -1, first_object)}; const Flow flow { region->flow(frPerimeter, layer_height, false, false, -1, first_object) };
// auto vol_speed {flow.mm3_per_mm() * print.config.get_abs_value("first_layer_speed")}; // auto vol_speed = flow.mm3_per_mm() * _print.config.get_abs_value("first_layer_speed");
// if (config.max_volumetric_speed.getInt() > 0) // if (config.max_volumetric_speed.getInt() > 0)
// vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat()); // vol_speed = std::min(vol_speed, config.max_volumetric_speed.getFloat());
fh << "; first layer extrusion width = "; fh << "; first layer extrusion width = ";
@ -99,29 +92,29 @@ PrintGCode::output()
fh << std::endl; fh << std::endl;
} }
// Prepare the helper object for replacing placeholders in custom G-Code and output filename // Prepare the helper object for replacing placeholders in custom G-Code and output filename
print.placeholder_parser.update_timestamp(); _print.placeholder_parser.update_timestamp();
// GCode sets this automatically when change_layer() is called, but needed for skirt/brim as well // GCode sets this automatically when change_layer() is called, but needed for skirt/brim as well
gcodegen.first_layer = true; _gcodegen.first_layer = true;
// disable fan // disable fan
if (config.cooling.getBool() && config.disable_fan_first_layers.getInt() > 0) { if (config.cooling.getBool() && config.disable_fan_first_layers.getInt() > 0) {
fh << gcodegen.writer.set_fan(0,1) << "\n"; fh << _gcodegen.writer.set_fan(0,1) << "\n";
} }
// set bed temperature // set bed temperature
auto temp{config.first_layer_bed_temperature.getFloat()}; const auto temp = config.first_layer_bed_temperature.getFloat();
if (config.has_heatbed && temp > 0 && std::regex_search(config.start_gcode.getString(), bed_temp_regex)) { if (config.has_heatbed && temp > 0 && std::regex_search(config.start_gcode.getString(), bed_temp_regex)) {
fh << gcodegen.writer.set_bed_temperature(temp, 1); fh << _gcodegen.writer.set_bed_temperature(temp, 1);
} }
// Set extruder(s) temperature before and after start gcode. // Set extruder(s) temperature before and after start gcode.
auto include_start_extruder_temp {!std::regex_search(config.start_gcode.getString(), ex_temp_regex)}; auto include_start_extruder_temp = !std::regex_search(config.start_gcode.getString(), ex_temp_regex);
for(const auto& start_gcode : config.start_filament_gcode.values) { for(const auto& start_gcode : config.start_filament_gcode.values) {
include_start_extruder_temp = include_start_extruder_temp && !std::regex_search(start_gcode, ex_temp_regex); include_start_extruder_temp = include_start_extruder_temp && !std::regex_search(start_gcode, ex_temp_regex);
} }
auto include_end_extruder_temp {!std::regex_search(config.end_gcode.getString(), ex_temp_regex)}; auto include_end_extruder_temp = !std::regex_search(config.end_gcode.getString(), ex_temp_regex);
for(const auto& end_gcode : config.end_filament_gcode.values) { for(const auto& end_gcode : config.end_filament_gcode.values) {
include_end_extruder_temp = include_end_extruder_temp && !std::regex_search(end_gcode, ex_temp_regex); include_end_extruder_temp = include_end_extruder_temp && !std::regex_search(end_gcode, ex_temp_regex);
} }
@ -129,12 +122,12 @@ PrintGCode::output()
if (include_start_extruder_temp) this->_print_first_layer_temperature(0); if (include_start_extruder_temp) this->_print_first_layer_temperature(0);
// Apply gcode math to start gcode // Apply gcode math to start gcode
fh << apply_math(gcodegen.placeholder_parser->process(config.start_gcode.value)); fh << apply_math(_gcodegen.placeholder_parser->process(config.start_gcode.value));
{ {
auto filament_extruder {0U}; auto filament_extruder = 0U;
for(const auto& start_gcode : config.start_filament_gcode.values) { for(const auto& start_gcode : config.start_filament_gcode.values) {
gcodegen.placeholder_parser->set("filament_extruder_id", filament_extruder++); _gcodegen.placeholder_parser->set("filament_extruder_id", filament_extruder++);
fh << apply_math(gcodegen.placeholder_parser->process(start_gcode)); fh << apply_math(_gcodegen.placeholder_parser->process(start_gcode));
} }
} }
@ -142,7 +135,7 @@ PrintGCode::output()
// Set other general things (preamble) // Set other general things (preamble)
fh << gcodegen.preamble(); fh << _gcodegen.preamble();
// initialize motion planner for object-to-object travel moves // initialize motion planner for object-to-object travel moves
if (config.avoid_crossing_perimeters.getBool()) { if (config.avoid_crossing_perimeters.getBool()) {
@ -153,7 +146,7 @@ PrintGCode::output()
Polygons polygons {}; Polygons polygons {};
// Add polygons that aren't just thin walls. // Add polygons that aren't just thin walls.
for (auto layer : object->layers) { for (auto layer : object->layers) {
const auto& slice {ExPolygons(layer->slices)}; const ExPolygons& slice { layer->slices };
std::for_each(slice.cbegin(), slice.cend(), [&polygons] (const ExPolygon& a) { polygons.emplace_back(a.contour); }); std::for_each(slice.cbegin(), slice.cend(), [&polygons] (const ExPolygon& a) { polygons.emplace_back(a.contour); });
} }
@ -166,39 +159,70 @@ PrintGCode::output()
} }
} }
gcodegen.avoid_crossing_perimeters.init_external_mp(union_ex(islands_p)); _gcodegen.avoid_crossing_perimeters.init_external_mp(union_ex(islands_p));
} }
const auto extruders = _print.extruders();
// Calculate wiping points if needed. // Calculate wiping points if needed.
if (config.ooze_prevention && extruders.size() > 1) { if (config.ooze_prevention && extruders.size() > 1) {
/*
TODO: PORT THIS!
my @skirt_points = map @$_, map @$_, @{$self->print->skirt};
if (@skirt_points) {
my $outer_skirt = convex_hull(\@skirt_points);
my @skirts = ();
foreach my $extruder_id (@extruders) {
my $extruder_offset = $self->config->get_at('extruder_offset', $extruder_id);
push @skirts, my $s = $outer_skirt->clone;
$s->translate(-scale($extruder_offset->x), -scale($extruder_offset->y)); #)
}
my $convex_hull = convex_hull([ map @$_, @skirts ]);
$gcodegen->ooze_prevention->set_enable(1);
$gcodegen->ooze_prevention->set_standby_points(
[ map @{$_->equally_spaced_points(scale 10)}, @{offset([$convex_hull], scale 3)} ]
);
if (0) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output(
"ooze_prevention.svg",
red_polygons => \@skirts,
polygons => [$outer_skirt],
points => $gcodegen->ooze_prevention->standby_points,
);
}
}
*/
} }
// Set initial extruder only after custom start gcode // Set initial extruder only after custom start gcode
fh << gcodegen.set_extruder(*(extruders.begin())); fh << _gcodegen.set_extruder( *(extruders.begin()) );
// Do all objects for each layer. // Do all objects for each layer.
if (config.complete_objects) { if (config.complete_objects) {
// print objects from the smallest to the tallest to avoid collisions // print objects from the smallest to the tallest to avoid collisions
// when moving onto next object starting point // when moving onto next object starting point
std::sort(print.objects.begin(), print.objects.end(), [] (const PrintObject* a, const PrintObject* b) { std::sort(_print.objects.begin(), _print.objects.end(), [] (const PrintObject* a, const PrintObject* b) {
return (a->config.sequential_print_priority < a->config.sequential_print_priority) || (a->size.z < b->size.z); return (a->config.sequential_print_priority < a->config.sequential_print_priority) || (a->size.z < b->size.z);
}); });
size_t finished_objects {0}; size_t finished_objects {0};
for (size_t obj_idx {0}; obj_idx < print.objects.size(); ++obj_idx) { for (size_t obj_idx {0}; obj_idx < _print.objects.size(); ++obj_idx) {
PrintObject& object {*(this->objects.at(obj_idx))}; PrintObject& object {*(this->objects.at(obj_idx))};
for (const Point& copy : object._shifted_copies) { for (const Point& copy : object._shifted_copies) {
if (finished_objects > 0) { if (finished_objects > 0) {
gcodegen.set_origin(Pointf::new_unscale(copy)); _gcodegen.set_origin(Pointf::new_unscale(copy));
gcodegen.enable_cooling_markers = false; _gcodegen.enable_cooling_markers = false;
gcodegen.avoid_crossing_perimeters.use_external_mp_once = true; _gcodegen.avoid_crossing_perimeters.use_external_mp_once = true;
fh << gcodegen.retract(); fh << _gcodegen.retract();
fh << gcodegen.travel_to(Point(0,0), erNone, "move to origin position for next object"); fh << _gcodegen.travel_to(Point(0,0), erNone, "move to origin position for next object");
gcodegen.enable_cooling_markers = true; _gcodegen.enable_cooling_markers = true;
// disable motion planner when traveling to first object point // disable motion planner when traveling to first object point
gcodegen.avoid_crossing_perimeters.disable_once = true; _gcodegen.avoid_crossing_perimeters.disable_once = true;
} }
std::vector<Layer*> layers; std::vector<Layer*> layers;
layers.reserve(object.layers.size() + object.support_layers.size()); layers.reserve(object.layers.size() + object.support_layers.size());
@ -218,7 +242,7 @@ PrintGCode::output()
config.has_heatbed && config.has_heatbed &&
std::regex_search(config.between_objects_gcode.getString(), bed_temp_regex)) std::regex_search(config.between_objects_gcode.getString(), bed_temp_regex))
{ {
fh << gcodegen.writer.set_bed_temperature(config.first_layer_bed_temperature); fh << _gcodegen.writer.set_bed_temperature(config.first_layer_bed_temperature);
} }
if (std::regex_search(config.between_objects_gcode.getString(), ex_temp_regex)) { if (std::regex_search(config.between_objects_gcode.getString(), ex_temp_regex)) {
_print_first_layer_temperature(false); _print_first_layer_temperature(false);
@ -242,8 +266,8 @@ PrintGCode::output()
std::vector<size_t> z; std::vector<size_t> z;
z.reserve(100); // preallocate with 100 layers z.reserve(100); // preallocate with 100 layers
std::map<coord_t, std::map<size_t, LayerPtrs > > layers {}; std::map<coord_t, std::map<size_t, LayerPtrs > > layers {};
for (size_t idx = 0U; idx < print.objects.size(); ++idx) { for (size_t idx = 0U; idx < _print.objects.size(); ++idx) {
const auto& object {*(objects.at(idx))}; const PrintObject& object { *objects.at(idx) };
// sort layers by Z into buckets // sort layers by Z into buckets
for (Layer* layer : object.layers) { for (Layer* layer : object.layers) {
if (layers.count(scale_(layer->print_z)) == 0) { // initialize bucket if empty if (layers.count(scale_(layer->print_z)) == 0) { // initialize bucket if empty
@ -272,47 +296,47 @@ PrintGCode::output()
this->process_layer(idx, layer, layer->object()->_shifted_copies); this->process_layer(idx, layer, layer->object()->_shifted_copies);
} }
} }
gcodegen.placeholder_parser->set("layer_z", unscale(print_z)); _gcodegen.placeholder_parser->set("layer_z", unscale(print_z));
gcodegen.placeholder_parser->set("layer_num", gcodegen.layer_index); _gcodegen.placeholder_parser->set("layer_num", _gcodegen.layer_index);
} }
this->flush_filters(); this->flush_filters();
} }
// Write end commands to file. // Write end commands to file.
fh << gcodegen.retract(); // TODO: process this retract through PressureRegulator in order to discharge fully fh << _gcodegen.retract(); // TODO: process this retract through PressureRegulator in order to discharge fully
{ {
auto filament_extruder {0U}; auto filament_extruder = 0U;
for(const auto& end_gcode : config.end_filament_gcode.values) { for(const auto& end_gcode : config.end_filament_gcode.values) {
gcodegen.placeholder_parser->set("filament_extruder_id", filament_extruder++); _gcodegen.placeholder_parser->set("filament_extruder_id", filament_extruder++);
fh << apply_math(gcodegen.placeholder_parser->process(end_gcode)); fh << apply_math(_gcodegen.placeholder_parser->process(end_gcode));
} }
} }
fh << apply_math(gcodegen.placeholder_parser->process(config.end_gcode)); fh << apply_math(_gcodegen.placeholder_parser->process(config.end_gcode));
// set bed temperature // set bed temperature
if (config.has_heatbed && temp > 0 && std::regex_search(config.end_gcode.getString(), bed_temp_regex)) { if (config.has_heatbed && temp > 0 && std::regex_search(config.end_gcode.getString(), bed_temp_regex)) {
fh << gcodegen.writer.set_bed_temperature(0, 0); fh << _gcodegen.writer.set_bed_temperature(0, 0);
} }
// Get filament stats // Get filament stats
print.filament_stats.clear(); _print.filament_stats.clear();
print.total_used_filament = 0.0; _print.total_used_filament = 0.0;
print.total_extruded_volume = 0.0; _print.total_extruded_volume = 0.0;
print.total_weight = 0.0; _print.total_weight = 0.0;
print.total_cost = 0.0; _print.total_cost = 0.0;
for (auto extruder_pair : gcodegen.writer.extruders) { for (auto extruder_pair : _gcodegen.writer.extruders) {
const auto& extruder {extruder_pair.second}; const Extruder& extruder { extruder_pair.second };
auto used_material {extruder.used_filament()}; const auto used_material = extruder.used_filament();
auto extruded_volume {extruder.extruded_volume()}; const auto extruded_volume = extruder.extruded_volume();
auto material_weight {extruded_volume * extruder.filament_density() / 1000.0}; const auto material_weight = extruded_volume * extruder.filament_density() / 1000.0;
auto material_cost { material_weight * (extruder.filament_cost() / 1000.0)}; const auto material_cost = material_weight * (extruder.filament_cost() / 1000.0);
print.filament_stats[extruder.id] = used_material; _print.filament_stats[extruder.id] = used_material;
fh << "; material used = "; fh << "; material used = ";
fh << std::fixed << std::setprecision(2) << used_material << "mm "; fh << std::fixed << std::setprecision(2) << used_material << "mm ";
@ -321,28 +345,28 @@ PrintGCode::output()
<< used_material << "cm3)\n"; << used_material << "cm3)\n";
if (material_weight > 0) { if (material_weight > 0) {
print.total_weight += material_weight; _print.total_weight += material_weight;
fh << "; material used = " fh << "; material used = "
<< std::fixed << std::setprecision(2) << material_weight << "g\n"; << std::fixed << std::setprecision(2) << material_weight << "g\n";
if (material_cost > 0) { if (material_cost > 0) {
print.total_cost += material_cost; _print.total_cost += material_cost;
fh << "; material cost = " fh << "; material cost = "
<< std::fixed << std::setprecision(2) << material_weight << "g\n"; << std::fixed << std::setprecision(2) << material_weight << "g\n";
} }
} }
print.total_used_filament += used_material; _print.total_used_filament += used_material;
print.total_extruded_volume += extruded_volume; _print.total_extruded_volume += extruded_volume;
} }
fh << "; total filament cost = " fh << "; total filament cost = "
<< std::fixed << std::setprecision(2) << print.total_cost << "\n"; << std::fixed << std::setprecision(2) << _print.total_cost << "\n";
// Append full config // Append full config
fh << std::endl; fh << std::endl;
// print config // print config
_print_config(print.config); _print_config(_print.config);
_print_config(print.default_object_config); _print_config(_print.default_object_config);
_print_config(print.default_region_config); _print_config(_print.default_region_config);
} }
std::string std::string
@ -355,17 +379,14 @@ void
PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies) PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
{ {
std::string gcode {""}; std::string gcode {""};
auto& gcodegen {this->_gcodegen};
const auto& print {this->_print};
const auto& config {this->config};
const auto& obj {*(layer->object())}; const PrintObject& obj { *layer->object() };
gcodegen.config.apply(obj.config, true); _gcodegen.config.apply(obj.config, true);
// check for usage of spiralvase logic. // check for usage of spiralvase logic.
this->_spiral_vase.enable = ( this->_spiral_vase.enable = (
layer->id() > 0 layer->id() > 0
&& (print.config.skirts == 0 || (layer->id() >= print.config.skirt_height && !print.has_infinite_skirt())) && (_print.config.skirts == 0 || (layer->id() >= _print.config.skirt_height && !_print.has_infinite_skirt()))
&& std::find_if(layer->regions.cbegin(), layer->regions.cend(), [layer] (const LayerRegion* l) && std::find_if(layer->regions.cbegin(), layer->regions.cend(), [layer] (const LayerRegion* l)
{ return l->region()->config.bottom_solid_layers > layer->id() { return l->region()->config.bottom_solid_layers > layer->id()
|| l->perimeters.items_count() > 1 || l->perimeters.items_count() > 1
@ -382,9 +403,9 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
{ {
// get the minimum cross-section used in the layer. // get the minimum cross-section used in the layer.
std::vector<double> mm3_per_mm; std::vector<double> mm3_per_mm;
for (auto region_id = 0U; region_id < print.regions.size(); ++region_id) { for (auto region_id = 0U; region_id < _print.regions.size(); ++region_id) {
const auto& region {print.regions.at(region_id)}; const PrintRegion* region = _print.get_region(region_id);
const auto& layerm {layer->get_region(region_id)}; const LayerRegion* layerm = layer->get_region(region_id);
if (!(region->config.get_abs_value("perimeter_speed") > 0 && if (!(region->config.get_abs_value("perimeter_speed") > 0 &&
region->config.get_abs_value("small_perimeter_speed") > 0 && region->config.get_abs_value("small_perimeter_speed") > 0 &&
@ -417,53 +438,53 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
// TODO make the definition of "too thin" based on a config somewhere // TODO make the definition of "too thin" based on a config somewhere
mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [] (const double& vol) { return vol <= 0.01;} ), mm3_per_mm.end()); mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [] (const double& vol) { return vol <= 0.01;} ), mm3_per_mm.end());
if (mm3_per_mm.size() > 0) { if (mm3_per_mm.size() > 0) {
const auto min_mm3_per_mm {*(std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()))}; const double min_mm3_per_mm { *(std::min_element(mm3_per_mm.begin(), mm3_per_mm.end())) };
// In order to honor max_print_speed we need to find a target volumetric // In order to honor max_print_speed we need to find a target volumetric
// speed that we can use throughout the print. So we define this target // speed that we can use throughout the _print. So we define this target
// volumetric speed as the volumetric speed produced by printing the // volumetric speed as the volumetric speed produced by printing the
// smallest cross-section at the maximum speed: any larger cross-section // smallest cross-section at the maximum speed: any larger cross-section
// will need slower feedrates. // will need slower feedrates.
auto volumetric_speed {min_mm3_per_mm * config.max_print_speed}; double volumetric_speed { min_mm3_per_mm * config.max_print_speed };
if (config.max_volumetric_speed > 0) { if (config.max_volumetric_speed > 0) {
volumetric_speed = std::min(volumetric_speed, config.max_volumetric_speed.getFloat()); volumetric_speed = std::min(volumetric_speed, config.max_volumetric_speed.getFloat());
} }
gcodegen.volumetric_speed = volumetric_speed; _gcodegen.volumetric_speed = volumetric_speed;
} }
} }
// set the second layer + temp // set the second layer + temp
if (!this->_second_layer_things_done && layer->id() == 1) { if (!this->_second_layer_things_done && layer->id() == 1) {
for (const auto& extruder_ref : gcodegen.writer.extruders) { for (const auto& extruder_ref : _gcodegen.writer.extruders) {
const auto& extruder { extruder_ref.second }; const Extruder& extruder { extruder_ref.second };
auto temp { config.temperature.get_at(extruder.id) }; auto temp = config.temperature.get_at(extruder.id);
if (temp > 0 && temp != config.first_layer_temperature.get_at(extruder.id) ) if (temp > 0 && temp != config.first_layer_temperature.get_at(extruder.id) )
gcode += gcodegen.writer.set_temperature(temp, 0, extruder.id); gcode += _gcodegen.writer.set_temperature(temp, 0, extruder.id);
} }
if (config.has_heatbed && print.config.first_layer_bed_temperature > 0 && print.config.bed_temperature != print.config.first_layer_bed_temperature) { if (config.has_heatbed && _print.config.first_layer_bed_temperature > 0 && _print.config.bed_temperature != _print.config.first_layer_bed_temperature) {
gcode += gcodegen.writer.set_bed_temperature(print.config.bed_temperature); gcode += _gcodegen.writer.set_bed_temperature(_print.config.bed_temperature);
} }
this->_second_layer_things_done = true; this->_second_layer_things_done = true;
} }
// set new layer - this will change Z and force a retraction if retract_layer_change is enabled // set new layer - this will change Z and force a retraction if retract_layer_change is enabled
if (print.config.before_layer_gcode.getString().size() > 0) { if (_print.config.before_layer_gcode.getString().size() > 0) {
auto pp {*(gcodegen.placeholder_parser)}; PlaceholderParser pp { *_gcodegen.placeholder_parser };
pp.set("layer_num", gcodegen.layer_index); pp.set("layer_num", _gcodegen.layer_index);
pp.set("layer_z", layer->print_z); pp.set("layer_z", layer->print_z);
pp.set("current_retraction", gcodegen.writer.extruder()->retracted); pp.set("current_retraction", _gcodegen.writer.extruder()->retracted);
gcode += apply_math(pp.process(print.config.before_layer_gcode.getString())); gcode += apply_math(pp.process(_print.config.before_layer_gcode.getString()));
gcode += "\n"; gcode += "\n";
} }
gcode += gcodegen.change_layer(*layer); gcode += _gcodegen.change_layer(*layer);
if (print.config.layer_gcode.getString().size() > 0) { if (_print.config.layer_gcode.getString().size() > 0) {
auto pp {*(gcodegen.placeholder_parser)}; PlaceholderParser pp { *_gcodegen.placeholder_parser };
pp.set("layer_num", gcodegen.layer_index); pp.set("layer_num", _gcodegen.layer_index);
pp.set("layer_z", layer->print_z); pp.set("layer_z", layer->print_z);
pp.set("current_retraction", gcodegen.writer.extruder()->retracted); pp.set("current_retraction", _gcodegen.writer.extruder()->retracted);
gcode += apply_math(pp.process(print.config.layer_gcode.getString())); gcode += apply_math(pp.process(_print.config.layer_gcode.getString()));
gcode += "\n"; gcode += "\n";
} }
@ -471,73 +492,73 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
// extrude skirt along raft layers and normal obj layers // extrude skirt along raft layers and normal obj layers
// (not along interlaced support material layers) // (not along interlaced support material layers)
if (layer->id() < static_cast<size_t>(obj.config.raft_layers) if (layer->id() < static_cast<size_t>(obj.config.raft_layers)
|| ((print.has_infinite_skirt() || _skirt_done.size() == 0 || (_skirt_done.rbegin())->first < print.config.skirt_height) || ((_print.has_infinite_skirt() || _skirt_done.size() == 0 || (_skirt_done.rbegin())->first < _print.config.skirt_height)
&& _skirt_done.count(scale_(layer->print_z)) == 0 && _skirt_done.count(scale_(layer->print_z)) == 0
&& typeid(layer) != typeid(SupportLayer*)) ) { && typeid(layer) != typeid(SupportLayer*)) ) {
gcodegen.set_origin(Pointf(0,0)); _gcodegen.set_origin(Pointf(0,0));
gcodegen.avoid_crossing_perimeters.use_external_mp = true; _gcodegen.avoid_crossing_perimeters.use_external_mp = true;
/// data load /// data load
std::vector<size_t> extruder_ids; std::vector<size_t> extruder_ids;
extruder_ids.reserve(gcodegen.writer.extruders.size()); extruder_ids.reserve(_gcodegen.writer.extruders.size());
std::transform(gcodegen.writer.extruders.cbegin(), gcodegen.writer.extruders.cend(), std::back_inserter(extruder_ids), std::transform(_gcodegen.writer.extruders.cbegin(), _gcodegen.writer.extruders.cend(), std::back_inserter(extruder_ids),
[] (const std::pair<unsigned int, Extruder>& z) -> std::size_t { return z.second.id; } ); [] (const std::pair<unsigned int, Extruder>& z) -> std::size_t { return z.second.id; } );
gcode += gcodegen.set_extruder(extruder_ids.at(0)); gcode += _gcodegen.set_extruder(extruder_ids.at(0));
// skip skirt if a large brim // skip skirt if a large brim
if (print.has_infinite_skirt() || layer->id() < static_cast<size_t>(print.config.skirt_height)) { if (_print.has_infinite_skirt() || layer->id() < static_cast<size_t>(_print.config.skirt_height)) {
const auto& skirt_flow {print.skirt_flow()}; const Flow skirt_flow { _print.skirt_flow() };
// distribute skirt loops across all extruders in layer 0 // distribute skirt loops across all extruders in layer 0
auto skirt_loops {print.skirt.flatten().entities}; const auto skirt_loops = _print.skirt.flatten().entities;
for (size_t i = 0; i < skirt_loops.size(); ++i) { for (size_t i = 0; i < skirt_loops.size(); ++i) {
// when printing layers > 0 ignore 'min_skirt_length' and // when printing layers > 0 ignore 'min_skirt_length' and
// just use the 'skirts' setting; also just use the current extruder // just use the 'skirts' setting; also just use the current extruder
if (layer->id() > 0 && i >= static_cast<size_t>(print.config.skirts)) break; if (layer->id() > 0 && i >= static_cast<size_t>(_print.config.skirts)) break;
const auto extruder_id { extruder_ids.at((i / extruder_ids.size()) % extruder_ids.size()) }; const size_t extruder_id { extruder_ids.at((i / extruder_ids.size()) % extruder_ids.size()) };
if (layer->id() == 0) if (layer->id() == 0)
gcode += gcodegen.set_extruder(extruder_id); gcode += _gcodegen.set_extruder(extruder_id);
// adjust flow according to layer height // adjust flow according to layer height
auto& loop {*(dynamic_cast<ExtrusionLoop*>(skirt_loops.at(i)))}; auto& loop = *dynamic_cast<ExtrusionLoop*>(skirt_loops.at(i));
{ {
Flow layer_skirt_flow(skirt_flow); Flow layer_skirt_flow(skirt_flow);
layer_skirt_flow.height = layer->height; layer_skirt_flow.height = layer->height;
auto mm3_per_mm {layer_skirt_flow.mm3_per_mm()}; const auto mm3_per_mm = layer_skirt_flow.mm3_per_mm();
for (auto& path : loop.paths) { for (auto& path : loop.paths) {
path.height = layer->height; path.height = layer->height;
path.mm3_per_mm = mm3_per_mm; path.mm3_per_mm = mm3_per_mm;
} }
} }
gcode += gcodegen.extrude(loop, "skirt", obj.config.support_material_speed); gcode += _gcodegen.extrude(loop, "skirt", obj.config.support_material_speed);
} }
} }
this->_skirt_done[scale_(layer->print_z)] = true; this->_skirt_done[scale_(layer->print_z)] = true;
gcodegen.avoid_crossing_perimeters.use_external_mp = false; _gcodegen.avoid_crossing_perimeters.use_external_mp = false;
if (layer->id() == 0) gcodegen.avoid_crossing_perimeters.disable_once = true; if (layer->id() == 0) _gcodegen.avoid_crossing_perimeters.disable_once = true;
} }
// extrude brim // extrude brim
if (this->_brim_done) { if (this->_brim_done) {
gcode += gcodegen.set_extruder(print.brim_extruder() - 1); gcode += _gcodegen.set_extruder(_print.brim_extruder() - 1);
gcodegen.set_origin(Pointf(0,0)); _gcodegen.set_origin(Pointf(0,0));
gcodegen.avoid_crossing_perimeters.use_external_mp = true; _gcodegen.avoid_crossing_perimeters.use_external_mp = true;
for (const auto& b : print.brim.entities) { for (const auto& b : _print.brim.entities) {
gcode += gcodegen.extrude(*b, "brim", obj.config.get_abs_value("support_material_speed")); gcode += _gcodegen.extrude(*b, "brim", obj.config.get_abs_value("support_material_speed"));
} }
this->_brim_done = true; this->_brim_done = true;
gcodegen.avoid_crossing_perimeters.use_external_mp = false; _gcodegen.avoid_crossing_perimeters.use_external_mp = false;
// allow a straight travel move to the first object point // allow a straight travel move to the first object point
gcodegen.avoid_crossing_perimeters.disable_once = true; _gcodegen.avoid_crossing_perimeters.disable_once = true;
} }
auto copy_idx = 0U; auto copy_idx = 0U;
@ -548,10 +569,10 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
// when starting a new object, use the external motion planner for the first travel move // when starting a new object, use the external motion planner for the first travel move
if (this->_last_obj_copy.first != copy && this->_last_obj_copy.second ) if (this->_last_obj_copy.first != copy && this->_last_obj_copy.second )
gcodegen.avoid_crossing_perimeters.use_external_mp = true; _gcodegen.avoid_crossing_perimeters.use_external_mp = true;
this->_last_obj_copy.first = copy; this->_last_obj_copy.first = copy;
this->_last_obj_copy.second = true; this->_last_obj_copy.second = true;
gcodegen.set_origin(Pointf::new_unscale(copy)); _gcodegen.set_origin(Pointf::new_unscale(copy));
// extrude support material before other things because it might use a lower Z // extrude support material before other things because it might use a lower Z
// and also because we avoid travelling on other things when printing it // and also because we avoid travelling on other things when printing it
@ -559,17 +580,17 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
const SupportLayer* slayer = dynamic_cast<const SupportLayer*>(layer); const SupportLayer* slayer = dynamic_cast<const SupportLayer*>(layer);
ExtrusionEntityCollection paths; ExtrusionEntityCollection paths;
if (slayer->support_interface_fills.size() > 0) { if (slayer->support_interface_fills.size() > 0) {
gcode += gcodegen.set_extruder(obj.config.support_material_interface_extruder - 1); gcode += _gcodegen.set_extruder(obj.config.support_material_interface_extruder - 1);
slayer->support_interface_fills.chained_path_from(gcodegen.last_pos(), &paths, false); slayer->support_interface_fills.chained_path_from(_gcodegen.last_pos(), &paths, false);
for (const auto& path : paths) { for (const auto& path : paths) {
gcode += gcodegen.extrude(*path, "support material interface", obj.config.get_abs_value("support_material_interface_speed")); gcode += _gcodegen.extrude(*path, "support material interface", obj.config.get_abs_value("support_material_interface_speed"));
} }
} }
if (slayer->support_fills.size() > 0) { if (slayer->support_fills.size() > 0) {
gcode += gcodegen.set_extruder(obj.config.support_material_extruder - 1); gcode += _gcodegen.set_extruder(obj.config.support_material_extruder - 1);
slayer->support_fills.chained_path_from(gcodegen.last_pos(), &paths, false); slayer->support_fills.chained_path_from(_gcodegen.last_pos(), &paths, false);
for (const auto& path : paths) { for (const auto& path : paths) {
gcode += gcodegen.extrude(*path, "support material", obj.config.get_abs_value("support_material_speed")); gcode += _gcodegen.extrude(*path, "support material", obj.config.get_abs_value("support_material_speed"));
} }
} }
} }
@ -594,25 +615,25 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
// cache bounding boxes of layer slices // cache bounding boxes of layer slices
std::vector<BoundingBox> layer_slices_bb; std::vector<BoundingBox> layer_slices_bb;
std::transform(layer->slices.cbegin(), layer->slices.cend(), std::back_inserter(layer_slices_bb), [] (const ExPolygon& s)-> BoundingBox { return s.bounding_box(); }); std::transform(layer->slices.cbegin(), layer->slices.cend(), std::back_inserter(layer_slices_bb), [] (const ExPolygon& s)-> BoundingBox { return s.bounding_box(); });
auto point_inside_surface { [&layer_slices_bb, &layer] (size_t i, Point point) -> bool { auto point_inside_surface = [&layer_slices_bb, &layer] (size_t i, Point point) -> bool {
const auto& bbox {layer_slices_bb.at(i)}; const BoundingBox& bbox { layer_slices_bb.at(i) };
return bbox.contains(point) && layer->slices.at(i).contour.contains(point); return bbox.contains(point) && layer->slices.at(i).contour.contains(point);
}}; };
const auto n_slices {layer->slices.size()}; const size_t n_slices { layer->slices.size() };
for (auto region_id = 0U; region_id < print.regions.size(); ++region_id) { for (auto region_id = 0U; region_id < _print.regions.size(); ++region_id) {
const LayerRegion* layerm; const LayerRegion* layerm;
try { try {
layerm = layer->get_region(region_id); // we promise to be good and not give this to anyone who will modify it layerm = layer->get_region(region_id); // we promise to be good and not give this to anyone who will modify it
} catch (std::out_of_range &e) { } catch (std::out_of_range &e) {
continue; // if no regions, bail; continue; // if no regions, bail;
} }
auto* region {print.get_region(region_id)}; const PrintRegion* region { _print.get_region(region_id) };
// process perimeters // process perimeters
{ {
auto extruder_id = region->config.perimeter_extruder-1; auto extruder_id = region->config.perimeter_extruder-1;
// Casting away const just to avoid double dereferences // Casting away const just to avoid double dereferences
for(auto* perimeter_coll : layerm->perimeters.flatten().entities) { for(const auto* perimeter_coll : layerm->perimeters.flatten().entities) {
if(perimeter_coll->length() == 0) continue; // this shouldn't happen but first_point() would fail if(perimeter_coll->length() == 0) continue; // this shouldn't happen but first_point() would fail
@ -654,10 +675,10 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
// tweak extruder ordering to save toolchanges // tweak extruder ordering to save toolchanges
auto last_extruder = gcodegen.writer.extruder()->id; auto last_extruder = _gcodegen.writer.extruder()->id;
if (by_extruder.count(last_extruder)) { if (by_extruder.count(last_extruder)) {
for(auto &island : by_extruder[last_extruder]) { for(auto &island : by_extruder[last_extruder]) {
if (print.config.infill_first()) { if (_print.config.infill_first()) {
gcode += this->_extrude_infill(std::get<1>(island.second)); gcode += this->_extrude_infill(std::get<1>(island.second));
gcode += this->_extrude_perimeters(std::get<0>(island.second)); gcode += this->_extrude_perimeters(std::get<0>(island.second));
} else { } else {
@ -668,9 +689,9 @@ PrintGCode::process_layer(size_t idx, const Layer* layer, const Points& copies)
} }
for(auto &pair : by_extruder) { for(auto &pair : by_extruder) {
if(pair.first == last_extruder)continue; if(pair.first == last_extruder)continue;
gcode += gcodegen.set_extruder(pair.first); gcode += _gcodegen.set_extruder(pair.first);
for(auto &island : pair.second) { for(auto &island : pair.second) {
if (print.config.infill_first()) { if (_print.config.infill_first()) {
gcode += this->_extrude_infill(std::get<1>(island.second)); gcode += this->_extrude_infill(std::get<1>(island.second));
gcode += this->_extrude_perimeters(std::get<0>(island.second)); gcode += this->_extrude_perimeters(std::get<0>(island.second));
} else { } else {
@ -733,16 +754,10 @@ PrintGCode::_extrude_infill(std::map<size_t,ExtrusionEntityCollection> &by_regio
void void
PrintGCode::_print_first_layer_temperature(bool wait) PrintGCode::_print_first_layer_temperature(bool wait)
{ {
auto& gcodegen {this->_gcodegen}; for (auto& t : _print.extruders()) {
auto& fh {this->fh}; auto temp = config.first_layer_temperature.get_at(t);
const auto& print {this->_print};
const auto& config {this->config};
const auto extruders {print.extruders()};
for (auto& t : extruders) {
auto temp { config.first_layer_temperature.get_at(t) };
if (config.ooze_prevention.value) temp += config.standby_temperature_delta.value; if (config.ooze_prevention.value) temp += config.standby_temperature_delta.value;
if (temp > 0) fh << gcodegen.writer.set_temperature(temp, wait, t); if (temp > 0) fh << _gcodegen.writer.set_temperature(temp, wait, t);
} }
} }
@ -758,9 +773,9 @@ PrintGCode::_print_config(const ConfigBase& config)
PrintGCode::PrintGCode(Slic3r::Print& print, std::ostream& _fh) : PrintGCode::PrintGCode(Slic3r::Print& print, std::ostream& _fh) :
_print(print), _print(print),
config(print.config), config(_print.config),
_gcodegen(Slic3r::GCode()), _gcodegen(Slic3r::GCode()),
objects(print.objects), objects(_print.objects),
fh(_fh), fh(_fh),
_cooling_buffer(Slic3r::CoolingBuffer(this->_gcodegen)), _cooling_buffer(Slic3r::CoolingBuffer(this->_gcodegen)),
_spiral_vase(Slic3r::SpiralVase(this->config)) _spiral_vase(Slic3r::SpiralVase(this->config))
@ -771,16 +786,16 @@ PrintGCode::PrintGCode(Slic3r::Print& print, std::ostream& _fh) :
} else { } else {
layer_count = std::accumulate(objects.cbegin(), objects.cend(), layer_count, [](const size_t& ret, const PrintObject* obj){ return ret + obj->total_layer_count(); }); layer_count = std::accumulate(objects.cbegin(), objects.cend(), layer_count, [](const size_t& ret, const PrintObject* obj){ return ret + obj->total_layer_count(); });
} }
_gcodegen.placeholder_parser = &(print.placeholder_parser); // initialize _gcodegen.placeholder_parser = &(_print.placeholder_parser); // initialize
_gcodegen.layer_count = layer_count; _gcodegen.layer_count = layer_count;
_gcodegen.enable_cooling_markers = true; _gcodegen.enable_cooling_markers = true;
_gcodegen.apply_print_config(config); _gcodegen.apply_print_config(config);
if (config.spiral_vase) _spiral_vase.enable = true; if (config.spiral_vase) _spiral_vase.enable = true;
auto extruders {print.extruders()}; const auto extruders = _print.extruders();
_gcodegen.set_extruders(extruders.cbegin(), extruders.cend()); _gcodegen.set_extruders(extruders.cbegin(), extruders.cend());
} }
} // namespace Slic3r } // namespace Slic3r
#endif //SLIC3RXS

View File

@ -1,4 +1,3 @@
#ifndef SLIC3RXS
#ifndef slic3r_PrintGCode_hpp #ifndef slic3r_PrintGCode_hpp
#define slic3r_PrintGCode_hpp #define slic3r_PrintGCode_hpp
@ -77,4 +76,3 @@ private:
} // namespace Slic3r } // namespace Slic3r
#endif // slic3r_PrintGCode_hpp #endif // slic3r_PrintGCode_hpp
#endif // SLIC3RXS

View File

@ -38,12 +38,6 @@ PrintObject::~PrintObject()
{ {
} }
Print*
PrintObject::print()
{
return this->_print;
}
Points Points
PrintObject::copies() const PrintObject::copies() const
{ {
@ -952,7 +946,6 @@ PrintObject::_slice_region(size_t region_id, std::vector<float> z, bool modifier
return layers; return layers;
} }
#ifndef SLIC3RXS
void void
PrintObject::make_perimeters() PrintObject::make_perimeters()
{ {
@ -966,28 +959,22 @@ PrintObject::make_perimeters()
void void
PrintObject::slice() PrintObject::slice()
{ {
auto* print {this->print()};
if (this->state.is_done(posSlice)) return; if (this->state.is_done(posSlice)) return;
this->state.set_started(posSlice); this->state.set_started(posSlice);
if (print->status_cb != nullptr) { if (_print->status_cb != nullptr) {
print->status_cb(10, "Processing triangulated mesh"); _print->status_cb(10, "Processing triangulated mesh");
} }
this->_slice(); this->_slice();
// detect slicing errors // detect slicing errors
bool warning_thrown = false; if (std::any_of(this->layers.cbegin(), this->layers.cend(),
for (size_t i = 0U; i < this->layer_count(); ++i) { [](const Layer* l){ return l->slicing_errors; }))
auto* layer {this->get_layer(i)}; Slic3r::Log::warn("PrintObject") << "The model has overlapping or self-intersecting facets. "
if (!layer->slicing_errors) continue; << "I tried to repair it, however you might want to check "
if (!warning_thrown) { << "the results or repair the input file and retry.\n";
Slic3r::Log::warn("PrintObject") << "The model has overlapping or self-intersecting facets. "
<< "I tried to repair it, however you might want to check "
<< "the results or repair the input file and retry.\n";
warning_thrown = true;
}
}
if (this->layers.size() == 0) { if (this->layers.size() == 0) {
Slic3r::Log::error("PrintObject") << "slice(): " << "No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n"; Slic3r::Log::error("PrintObject") << "slice(): " << "No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n";
return; // make this throw an exception instead? return; // make this throw an exception instead?
@ -998,7 +985,6 @@ PrintObject::slice()
this->state.set_done(posSlice); this->state.set_done(posSlice);
} }
#endif // SLIC3RXS
void void
PrintObject::_make_perimeters() PrintObject::_make_perimeters()
{ {
@ -1142,7 +1128,6 @@ PrintObject::_infill()
this->state.set_done(posInfill); this->state.set_done(posInfill);
} }
#ifndef SLIC3RXS
void void
PrintObject::prepare_infill() PrintObject::prepare_infill()
{ {
@ -1304,8 +1289,6 @@ PrintObject::infill()
this->_infill(); this->_infill();
} }
#endif //SLIC3RXS
SupportMaterial * SupportMaterial *
PrintObject::_support_material() PrintObject::_support_material()
{ {
@ -1357,12 +1340,10 @@ PrintObject::_support_material_flow(FlowRole role)
return support_flow; return support_flow;
} }
#ifndef SLIC3RXS
void void
PrintObject::generate_support_material() PrintObject::generate_support_material()
{ {
auto* print { this->_print };
const auto& config { this->config };
//prereqs //prereqs
this->slice(); this->slice();
if (this->state.is_done(posSupportMaterial)) { return; } if (this->state.is_done(posSupportMaterial)) { return; }
@ -1379,8 +1360,8 @@ PrintObject::generate_support_material()
this->state.set_done(posSupportMaterial); this->state.set_done(posSupportMaterial);
return; return;
} }
if (print->status_cb != nullptr) if (_print->status_cb != nullptr)
print->status_cb(85, "Generating support material"); _print->status_cb(85, "Generating support material");
this->_support_material()->generate(this); this->_support_material()->generate(this);
@ -1388,8 +1369,8 @@ PrintObject::generate_support_material()
std::stringstream stats {""}; std::stringstream stats {""};
if (print->status_cb != nullptr) if (_print->status_cb != nullptr)
print->status_cb(85, stats.str().c_str()); _print->status_cb(85, stats.str().c_str());
} }
@ -1397,15 +1378,14 @@ PrintObject::generate_support_material()
void void
PrintObject::discover_horizontal_shells() PrintObject::discover_horizontal_shells()
{ {
auto* print {this->print()}; for (size_t region_id = 0U; region_id < _print->regions.size(); ++region_id) {
for (size_t region_id = 0U; region_id < print->regions.size(); ++region_id) {
for (size_t i = 0; i < this->layer_count(); ++i) { for (size_t i = 0; i < this->layer_count(); ++i) {
auto* layerm {this->get_layer(i)->regions.at(region_id)}; auto* layerm = this->get_layer(i)->get_region(region_id);
const auto& region_config {layerm->region()->config}; const auto& region_config = layerm->region()->config;
if (region_config.solid_infill_every_layers() > 0 && region_config.fill_density() > 0 if (region_config.solid_infill_every_layers() > 0 && region_config.fill_density() > 0
&& (i % region_config.solid_infill_every_layers()) == 0) { && (i % region_config.solid_infill_every_layers()) == 0) {
const auto type {region_config.fill_density() == 100 ? stInternalSolid : stInternalBridge }; const auto type = region_config.fill_density() == 100 ? stInternalSolid : stInternalBridge;
// set the surface type to internal for the types // set the surface type to internal for the types
std::for_each(layerm->fill_surfaces.begin(), layerm->fill_surfaces.end(), [type] (Surface& s) { s.surface_type = (s.surface_type == type ? stInternal : s.surface_type); }); std::for_each(layerm->fill_surfaces.begin(), layerm->fill_surfaces.end(), [type] (Surface& s) { s.surface_type = (s.surface_type == type ? stInternal : s.surface_type); });
} }
@ -1417,7 +1397,7 @@ PrintObject::discover_horizontal_shells()
void void
PrintObject::_discover_external_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id) PrintObject::_discover_external_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id)
{ {
const auto& region_config {layerm->region()->config}; const auto& region_config = layerm->region()->config;
for (auto& type : { stTop, stBottom, stBottomBridge }) { for (auto& type : { stTop, stBottom, stBottomBridge }) {
// find slices of current type for current layer // find slices of current type for current layer
// use slices instead of fill_surfaces because they also include the perimeter area // use slices instead of fill_surfaces because they also include the perimeter area
@ -1430,7 +1410,7 @@ PrintObject::_discover_external_horizontal_shells(LayerRegion* layerm, const siz
// too much solid infill inside nearly-vertical slopes. // too much solid infill inside nearly-vertical slopes.
Polygons solid; Polygons solid;
auto tmp {layerm->slices.filter_by_type(type)}; auto tmp = layerm->slices.filter_by_type(type);
polygons_append(solid, tmp); polygons_append(solid, tmp);
tmp.clear(); tmp.clear();
tmp = layerm->fill_surfaces.filter_by_type(type); tmp = layerm->fill_surfaces.filter_by_type(type);
@ -1438,11 +1418,11 @@ PrintObject::_discover_external_horizontal_shells(LayerRegion* layerm, const siz
if (solid.size() == 0) continue; if (solid.size() == 0) continue;
auto solid_layers { type == stTop ? region_config.top_solid_layers() : region_config.bottom_solid_layers() }; auto solid_layers = type == stTop ? region_config.top_solid_layers() : region_config.bottom_solid_layers();
if (region_config.min_top_bottom_shell_thickness() > 0) { if (region_config.min_top_bottom_shell_thickness() > 0) {
auto current_shell_thick { static_cast<coordf_t>(solid_layers) * this->get_layer(i)->height }; auto current_shell_thick = static_cast<coordf_t>(solid_layers) * this->get_layer(i)->height;
const auto& min_shell_thick { region_config.min_top_bottom_shell_thickness() }; const auto min_shell_thick = region_config.min_top_bottom_shell_thickness();
while (std::abs(min_shell_thick - current_shell_thick) > Slic3r::Geometry::epsilon) { while (std::abs(min_shell_thick - current_shell_thick) > Slic3r::Geometry::epsilon) {
solid_layers++; solid_layers++;
current_shell_thick = static_cast<coordf_t>(solid_layers) * this->get_layer(i)->height; current_shell_thick = static_cast<coordf_t>(solid_layers) * this->get_layer(i)->height;
@ -1455,19 +1435,19 @@ PrintObject::_discover_external_horizontal_shells(LayerRegion* layerm, const siz
void void
PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id, const SurfaceType& type, Polygons& solid, const size_t& solid_layers) PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id, const SurfaceType& type, Polygons& solid, const size_t& solid_layers)
{ {
const auto& region_config {layerm->region()->config}; const auto& region_config = layerm->region()->config;
for (int n = (type == stTop ? i-1 : i+1); std::abs(n-int(i)) < solid_layers; (type == stTop ? n-- : n++)) { for (int n = (type == stTop ? i-1 : i+1); std::abs(n-int(i)) < solid_layers; (type == stTop ? n-- : n++)) {
if (n < 0 || static_cast<size_t>(n) >= this->layer_count()) continue; if (n < 0 || static_cast<size_t>(n) >= this->layer_count()) continue;
auto* neighbor_layerm { this->get_layer(n)->regions.at(region_id) }; LayerRegion* neighbor_layerm { this->get_layer(n)->get_region(region_id) };
// make a copy so we can use them even after clearing the original collection // make a copy so we can use them even after clearing the original collection
auto neighbor_fill_surfaces{ SurfaceCollection(neighbor_layerm->fill_surfaces) }; SurfaceCollection neighbor_fill_surfaces{ neighbor_layerm->fill_surfaces };
// find intersection between neighbor and current layer's surfaces // find intersection between neighbor and current layer's surfaces
// intersections have contours and holes // intersections have contours and holes
Polygons filtered_poly; Polygons filtered_poly;
polygons_append(filtered_poly, neighbor_fill_surfaces.filter_by_type({stInternal, stInternalSolid})); polygons_append(filtered_poly, neighbor_fill_surfaces.filter_by_type({stInternal, stInternalSolid}));
auto new_internal_solid { intersection(solid, filtered_poly , 1 ) }; auto new_internal_solid = intersection(solid, filtered_poly , 1 );
if (new_internal_solid.size() == 0) { if (new_internal_solid.size() == 0) {
// No internal solid needed on this layer. In order to decide whether to continue // No internal solid needed on this layer. In order to decide whether to continue
// searching on the next neighbor (thus enforcing the configured number of solid // searching on the next neighbor (thus enforcing the configured number of solid
@ -1490,8 +1470,8 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz
// than a perimeter width, since it's probably just crossing a sloping wall // than a perimeter width, since it's probably just crossing a sloping wall
// and it's not wanted in a hollow print even if it would make sense when // and it's not wanted in a hollow print even if it would make sense when
// obeying the solid shell count option strictly (DWIM!) // obeying the solid shell count option strictly (DWIM!)
auto margin { neighbor_layerm->flow(frExternalPerimeter).scaled_width()}; const auto margin = neighbor_layerm->flow(frExternalPerimeter).scaled_width();
auto too_narrow { diff(new_internal_solid, offset2(new_internal_solid, -margin, +margin, CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 5), 1)}; const auto too_narrow = diff(new_internal_solid, offset2(new_internal_solid, -margin, +margin, CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 5), 1);
if (too_narrow.size() > 0) if (too_narrow.size() > 0)
new_internal_solid = solid = diff(new_internal_solid, too_narrow); new_internal_solid = solid = diff(new_internal_solid, too_narrow);
} }
@ -1499,16 +1479,16 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz
// make sure the new internal solid is wide enough, as it might get collapsed // make sure the new internal solid is wide enough, as it might get collapsed
// when spacing is added in Slic3r::Fill // when spacing is added in Slic3r::Fill
{ {
auto margin {3 * layerm->flow(frSolidInfill).scaled_width()}; const auto margin = 3 * layerm->flow(frSolidInfill).scaled_width();
// we use a higher miterLimit here to handle areas with acute angles // we use a higher miterLimit here to handle areas with acute angles
// in those cases, the default miterLimit would cut the corner and we'd // in those cases, the default miterLimit would cut the corner and we'd
// get a triangle in $too_narrow; if we grow it below then the shell // get a triangle in $too_narrow; if we grow it below then the shell
// would have a different shape from the external surface and we'd still // would have a different shape from the external surface and we'd still
// have the same angle, so the next shell would be grown even more and so on. // have the same angle, so the next shell would be grown even more and so on.
auto too_narrow { diff(new_internal_solid, offset2(new_internal_solid, -margin, +margin, CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 5), 1) }; const auto too_narrow = diff(new_internal_solid, offset2(new_internal_solid, -margin, +margin, CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 5), 1);
if (too_narrow.size() > 0) { if (!too_narrow.empty()) {
// grow the collapsing parts and add the extra area to the neighbor layer // grow the collapsing parts and add the extra area to the neighbor layer
// as well as to our original surfaces so that we support this // as well as to our original surfaces so that we support this
// additional area in the next shell too // additional area in the next shell too
@ -1518,16 +1498,16 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz
for (auto& s : neighbor_fill_surfaces) { for (auto& s : neighbor_fill_surfaces) {
if (s.is_internal() && !s.is_bridge()) tmp_internal.emplace_back(Polygon(s.expolygon)); if (s.is_internal() && !s.is_bridge()) tmp_internal.emplace_back(Polygon(s.expolygon));
} }
auto grown {intersection( const auto grown = intersection(
offset(too_narrow, +margin), offset(too_narrow, +margin),
// Discard bridges as they are grown for anchoring and we cant // Discard bridges as they are grown for anchoring and we cant
// remove such anchors. (This may happen when a bridge is being // remove such anchors. (This may happen when a bridge is being
// anchored onto a wall where little space remains after the bridge // anchored onto a wall where little space remains after the bridge
// is grown, and that little space is an internal solid shell so // is grown, and that little space is an internal solid shell so
// it triggers this too_narrow logic.) // it triggers this too_narrow logic.)
tmp_internal) tmp_internal
}; );
new_internal_solid = solid = diff(new_internal_solid, too_narrow); new_internal_solid = solid = diff(grown, new_internal_solid);
} }
} }
// internal-solid are the union of the existing internal-solid surfaces // internal-solid are the union of the existing internal-solid surfaces
@ -1535,11 +1515,11 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz
Polygons tmp_internal { to_polygons(neighbor_fill_surfaces.filter_by_type(stInternalSolid)) }; Polygons tmp_internal { to_polygons(neighbor_fill_surfaces.filter_by_type(stInternalSolid)) };
polygons_append(tmp_internal, neighbor_fill_surfaces.surfaces); polygons_append(tmp_internal, neighbor_fill_surfaces.surfaces);
auto internal_solid {union_ex(tmp_internal)}; const auto internal_solid = union_ex(tmp_internal);
// subtract intersections from layer surfaces to get resulting internal surfaces // subtract intersections from layer surfaces to get resulting internal surfaces
tmp_internal = to_polygons(neighbor_fill_surfaces.filter_by_type(stInternal)); tmp_internal = to_polygons(neighbor_fill_surfaces.filter_by_type(stInternal));
auto internal { diff_ex(tmp_internal, to_polygons(internal_solid), 1) }; const auto internal = diff_ex(tmp_internal, to_polygons(internal_solid), 1);
// assign resulting internal surfaces to layer // assign resulting internal surfaces to layer
neighbor_fill_surfaces.clear(); neighbor_fill_surfaces.clear();
@ -1563,7 +1543,7 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz
both_solids.insert(both_solids.end(), internal_solid.begin(), internal_solid.end()); both_solids.insert(both_solids.end(), internal_solid.begin(), internal_solid.end());
both_solids.insert(both_solids.end(), internal.begin(), internal.end()); both_solids.insert(both_solids.end(), internal.begin(), internal.end());
auto solid_surfaces { diff_ex(pp, to_polygons(both_solids), 1) }; const auto solid_surfaces = diff_ex(pp, to_polygons(both_solids), 1);
for (auto exp : solid_surfaces) for (auto exp : solid_surfaces)
neighbor_fill_surfaces.surfaces.emplace_back(Surface(s.surface_type, exp)); neighbor_fill_surfaces.surfaces.emplace_back(Surface(s.surface_type, exp));
} }
@ -1645,5 +1625,4 @@ PrintObject::clip_fill_surfaces()
} }
} }
#endif // SLIC3RXS
} }

View File

@ -12,7 +12,6 @@ class SimplePrint {
bool center{true}; bool center{true};
std::function<void(int, const std::string&)> status_cb {nullptr}; std::function<void(int, const std::string&)> status_cb {nullptr};
bool apply_config(config_ptr config) { return this->_print.apply_config(config); }
bool apply_config(DynamicPrintConfig config) { return this->_print.apply_config(config); } bool apply_config(DynamicPrintConfig config) { return this->_print.apply_config(config); }
double total_used_filament() const { return this->_print.total_used_filament; } double total_used_filament() const { return this->_print.total_used_filament; }
double total_extruded_volume() const { return this->_print.total_extruded_volume; } double total_extruded_volume() const { return this->_print.total_extruded_volume; }

View File

@ -108,7 +108,6 @@ void TriangleMesh::clone(const TriangleMesh& other) {
} }
} }
#ifndef SLIC3RXS
TriangleMesh::TriangleMesh(TriangleMesh&& other) { TriangleMesh::TriangleMesh(TriangleMesh&& other) {
this->repaired = std::move(other.repaired); this->repaired = std::move(other.repaired);
this->stl = std::move(other.stl); this->stl = std::move(other.stl);
@ -123,7 +122,6 @@ TriangleMesh& TriangleMesh::operator= (TriangleMesh&& other)
return *this; return *this;
} }
#endif
void void
TriangleMesh::swap(TriangleMesh &other) TriangleMesh::swap(TriangleMesh &other)
@ -399,8 +397,6 @@ void TriangleMesh::rotate(double angle, const Point& center)
this->translate(+center.x, +center.y, 0); this->translate(+center.x, +center.y, 0);
} }
#ifndef SLIC3RXS
Pointf3s TriangleMesh::vertices() Pointf3s TriangleMesh::vertices()
{ {
Pointf3s tmp {}; Pointf3s tmp {};
@ -408,7 +404,7 @@ Pointf3s TriangleMesh::vertices()
if (this->stl.v_shared == nullptr) if (this->stl.v_shared == nullptr)
stl_generate_shared_vertices(&stl); // build the list of vertices stl_generate_shared_vertices(&stl); // build the list of vertices
for (auto i = 0; i < this->stl.stats.shared_vertices; i++) { for (auto i = 0; i < this->stl.stats.shared_vertices; i++) {
const auto& v {this->stl.v_shared[i]}; const stl_vertex& v { this->stl.v_shared[i] };
tmp.emplace_back(Pointf3(v.x, v.y, v.z)); tmp.emplace_back(Pointf3(v.x, v.y, v.z));
} }
} else { } else {
@ -424,7 +420,7 @@ Point3s TriangleMesh::facets()
if (this->stl.v_shared == nullptr) if (this->stl.v_shared == nullptr)
stl_generate_shared_vertices(&stl); // build the list of vertices stl_generate_shared_vertices(&stl); // build the list of vertices
for (auto i = 0; i < stl.stats.number_of_facets; i++) { for (auto i = 0; i < stl.stats.number_of_facets; i++) {
const auto& v {stl.v_indices[i]}; const v_indices_struct& v { stl.v_indices[i] };
tmp.emplace_back(Point3(v.vertex[0], v.vertex[1], v.vertex[2])); tmp.emplace_back(Point3(v.vertex[0], v.vertex[1], v.vertex[2]));
} }
} else { } else {
@ -438,7 +434,7 @@ Pointf3s TriangleMesh::normals() const
Pointf3s tmp {}; Pointf3s tmp {};
if (this->repaired) { if (this->repaired) {
for (auto i = 0; i < stl.stats.number_of_facets; i++) { for (auto i = 0; i < stl.stats.number_of_facets; i++) {
const auto& n {stl.facet_start[i].normal}; const auto& n = stl.facet_start[i].normal;
tmp.emplace_back(Pointf3(n.x, n.y, n.z)); tmp.emplace_back(Pointf3(n.x, n.y, n.z));
} }
} else { } else {
@ -449,7 +445,7 @@ Pointf3s TriangleMesh::normals() const
Pointf3 TriangleMesh::size() const Pointf3 TriangleMesh::size() const
{ {
const auto& sz {stl.stats.size}; const auto& sz = stl.stats.size;
return Pointf3(sz.x, sz.y, sz.z); return Pointf3(sz.x, sz.y, sz.z);
} }
@ -513,10 +509,6 @@ void TriangleMesh::cut(Axis axis, double z, TriangleMesh* upper, TriangleMesh* l
} }
} }
#endif // SLIC3RXS
TriangleMeshPtrs TriangleMeshPtrs
TriangleMesh::split() const TriangleMesh::split() const
{ {

View File

@ -47,11 +47,10 @@ class TriangleMesh
/// copy assignment /// copy assignment
TriangleMesh& operator= (const TriangleMesh& other); TriangleMesh& operator= (const TriangleMesh& other);
#ifndef SLIC3RXS
/// Move assignment /// Move assignment
TriangleMesh& operator= (TriangleMesh&& other); TriangleMesh& operator= (TriangleMesh&& other);
TriangleMesh(TriangleMesh&& other); TriangleMesh(TriangleMesh&& other);
#endif
void swap(TriangleMesh &other); void swap(TriangleMesh &other);
~TriangleMesh(); ~TriangleMesh();
void ReadSTLFile(const std::string &input_file); void ReadSTLFile(const std::string &input_file);
@ -99,9 +98,7 @@ class TriangleMesh
void extrude_tin(float offset); void extrude_tin(float offset);
void require_shared_vertices(); void require_shared_vertices();
void reverse_normals(); void reverse_normals();
#ifndef SLIC3RXS // Don't build these functions when also building the Perl interface.
/// Return a copy of the vertex array defining this mesh. /// Return a copy of the vertex array defining this mesh.
Pointf3s vertices(); Pointf3s vertices();
@ -127,8 +124,6 @@ class TriangleMesh
/// Perform a cut of the mesh and put the output in upper and lower /// Perform a cut of the mesh and put the output in upper and lower
void cut(Axis axis, double z, TriangleMesh* upper, TriangleMesh* lower); void cut(Axis axis, double z, TriangleMesh* upper, TriangleMesh* lower);
#endif // SLIC3RXS
/// Generate a mesh representing a cube with dimensions (x, y, z), with one corner at (0,0,0). /// Generate a mesh representing a cube with dimensions (x, y, z), with one corner at (0,0,0).
static TriangleMesh make_cube(double x, double y, double z); static TriangleMesh make_cube(double x, double y, double z);

View File

@ -79,8 +79,8 @@ ConfigBase__get(ConfigBase* THIS, const t_config_option_key &opt_key) {
ConfigOption* opt = THIS->option(opt_key); ConfigOption* opt = THIS->option(opt_key);
if (opt == NULL) return &PL_sv_undef; if (opt == NULL) return &PL_sv_undef;
const ConfigOptionDef* def = THIS->def->get(opt_key); const ConfigOptionDef& def = THIS->def->get(opt_key);
return ConfigOption_to_SV(*opt, *def); return ConfigOption_to_SV(*opt, def);
} }
SV* SV*
@ -153,22 +153,22 @@ ConfigBase__get_at(ConfigBase* THIS, const t_config_option_key &opt_key, size_t
ConfigOption* opt = THIS->option(opt_key); ConfigOption* opt = THIS->option(opt_key);
if (opt == NULL) return &PL_sv_undef; if (opt == NULL) return &PL_sv_undef;
const ConfigOptionDef* def = THIS->def->get(opt_key); const ConfigOptionDef& def = THIS->def->get(opt_key);
if (def->type == coFloats) { if (def.type == coFloats) {
ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt); ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt);
return newSVnv(optv->get_at(i)); return newSVnv(optv->get_at(i));
} else if (def->type == coInts) { } else if (def.type == coInts) {
ConfigOptionInts* optv = dynamic_cast<ConfigOptionInts*>(opt); ConfigOptionInts* optv = dynamic_cast<ConfigOptionInts*>(opt);
return newSViv(optv->get_at(i)); return newSViv(optv->get_at(i));
} else if (def->type == coStrings) { } else if (def.type == coStrings) {
ConfigOptionStrings* optv = dynamic_cast<ConfigOptionStrings*>(opt); ConfigOptionStrings* optv = dynamic_cast<ConfigOptionStrings*>(opt);
// we don't serialize() because that would escape newlines // we don't serialize() because that would escape newlines
std::string val = optv->get_at(i); std::string val = optv->get_at(i);
return newSVpvn_utf8(val.c_str(), val.length(), true); return newSVpvn_utf8(val.c_str(), val.length(), true);
} else if (def->type == coPoints) { } else if (def.type == coPoints) {
ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt); ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt);
return perl_to_SV_clone_ref(optv->get_at(i)); return perl_to_SV_clone_ref(optv->get_at(i));
} else if (def->type == coBools) { } else if (def.type == coBools) {
ConfigOptionBools* optv = dynamic_cast<ConfigOptionBools*>(opt); ConfigOptionBools* optv = dynamic_cast<ConfigOptionBools*>(opt);
return newSViv(optv->get_at(i) ? 1 : 0); return newSViv(optv->get_at(i) ? 1 : 0);
} else { } else {
@ -181,12 +181,12 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
ConfigOption* opt = THIS->option(opt_key, true); ConfigOption* opt = THIS->option(opt_key, true);
if (opt == NULL) CONFESS("Trying to set non-existing option"); if (opt == NULL) CONFESS("Trying to set non-existing option");
const ConfigOptionDef* def = THIS->def->get(opt_key); const ConfigOptionDef& def = THIS->def->get(opt_key);
if (def->type == coFloat) { if (def.type == coFloat) {
if (!looks_like_number(value)) return false; if (!looks_like_number(value)) return false;
ConfigOptionFloat* optv = dynamic_cast<ConfigOptionFloat*>(opt); ConfigOptionFloat* optv = dynamic_cast<ConfigOptionFloat*>(opt);
optv->value = SvNV(value); optv->value = SvNV(value);
} else if (def->type == coFloats) { } else if (def.type == coFloats) {
ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt); ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt);
std::vector<double> values; std::vector<double> values;
AV* av = (AV*)SvRV(value); AV* av = (AV*)SvRV(value);
@ -197,11 +197,11 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
values.push_back(SvNV(*elem)); values.push_back(SvNV(*elem));
} }
optv->values = values; optv->values = values;
} else if (def->type == coInt) { } else if (def.type == coInt) {
if (!looks_like_number(value)) return false; if (!looks_like_number(value)) return false;
ConfigOptionInt* optv = dynamic_cast<ConfigOptionInt*>(opt); ConfigOptionInt* optv = dynamic_cast<ConfigOptionInt*>(opt);
optv->value = SvIV(value); optv->value = SvIV(value);
} else if (def->type == coInts) { } else if (def.type == coInts) {
ConfigOptionInts* optv = dynamic_cast<ConfigOptionInts*>(opt); ConfigOptionInts* optv = dynamic_cast<ConfigOptionInts*>(opt);
std::vector<int> values; std::vector<int> values;
AV* av = (AV*)SvRV(value); AV* av = (AV*)SvRV(value);
@ -212,10 +212,10 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
values.push_back(SvIV(*elem)); values.push_back(SvIV(*elem));
} }
optv->values = values; optv->values = values;
} else if (def->type == coString) { } else if (def.type == coString) {
ConfigOptionString* optv = dynamic_cast<ConfigOptionString*>(opt); ConfigOptionString* optv = dynamic_cast<ConfigOptionString*>(opt);
optv->value = std::string(SvPV_nolen(value), SvCUR(value)); optv->value = std::string(SvPV_nolen(value), SvCUR(value));
} else if (def->type == coStrings) { } else if (def.type == coStrings) {
ConfigOptionStrings* optv = dynamic_cast<ConfigOptionStrings*>(opt); ConfigOptionStrings* optv = dynamic_cast<ConfigOptionStrings*>(opt);
optv->values.clear(); optv->values.clear();
AV* av = (AV*)SvRV(value); AV* av = (AV*)SvRV(value);
@ -225,13 +225,13 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
if (elem == NULL) return false; if (elem == NULL) return false;
optv->values.push_back(std::string(SvPV_nolen(*elem), SvCUR(*elem))); optv->values.push_back(std::string(SvPV_nolen(*elem), SvCUR(*elem)));
} }
} else if (def->type == coPoint) { } else if (def.type == coPoint) {
ConfigOptionPoint* optv = dynamic_cast<ConfigOptionPoint*>(opt); ConfigOptionPoint* optv = dynamic_cast<ConfigOptionPoint*>(opt);
return from_SV_check(value, &optv->value); return from_SV_check(value, &optv->value);
} else if(def->type == coPoint3){ } else if(def.type == coPoint3){
ConfigOptionPoint3* optv = dynamic_cast<ConfigOptionPoint3*>(opt); ConfigOptionPoint3* optv = dynamic_cast<ConfigOptionPoint3*>(opt);
return from_SV_check(value, &optv->value); return from_SV_check(value, &optv->value);
} else if (def->type == coPoints) { } else if (def.type == coPoints) {
ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt); ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt);
std::vector<Pointf> values; std::vector<Pointf> values;
AV* av = (AV*)SvRV(value); AV* av = (AV*)SvRV(value);
@ -243,10 +243,10 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
values.push_back(point); values.push_back(point);
} }
optv->values = values; optv->values = values;
} else if (def->type == coBool) { } else if (def.type == coBool) {
ConfigOptionBool* optv = dynamic_cast<ConfigOptionBool*>(opt); ConfigOptionBool* optv = dynamic_cast<ConfigOptionBool*>(opt);
optv->value = SvTRUE(value); optv->value = SvTRUE(value);
} else if (def->type == coBools) { } else if (def.type == coBools) {
ConfigOptionBools* optv = dynamic_cast<ConfigOptionBools*>(opt); ConfigOptionBools* optv = dynamic_cast<ConfigOptionBools*>(opt);
optv->values.clear(); optv->values.clear();
AV* av = (AV*)SvRV(value); AV* av = (AV*)SvRV(value);
@ -287,9 +287,9 @@ ConfigBase__set_ifndef(ConfigBase* THIS, const t_config_option_key &opt_key, SV*
bool bool
StaticConfig__set(StaticConfig* THIS, const t_config_option_key &opt_key, SV* value) { StaticConfig__set(StaticConfig* THIS, const t_config_option_key &opt_key, SV* value) {
const ConfigOptionDef* optdef = THIS->def->get(opt_key); const ConfigOptionDef& optdef = THIS->def->get(opt_key);
if (!optdef->shortcut.empty()) { if (!optdef.shortcut.empty()) {
for (std::vector<t_config_option_key>::const_iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) { for (std::vector<t_config_option_key>::const_iterator it = optdef.shortcut.begin(); it != optdef.shortcut.end(); ++it) {
if (!StaticConfig__set(THIS, *it, value)) return false; if (!StaticConfig__set(THIS, *it, value)) return false;
} }
return true; return true;

View File

@ -269,7 +269,13 @@ _constant()
bool has_infinite_skirt(); bool has_infinite_skirt();
bool has_skirt(); bool has_skirt();
std::string _validate() std::string _validate()
%code%{ RETVAL = THIS->validate(); %}; %code%{
try {
THIS->validate();
} catch (std::exception &e) {
RETVAL = e.what();
}
%};
Clone<BoundingBox> bounding_box(); Clone<BoundingBox> bounding_box();
Clone<BoundingBox> total_bounding_box(); Clone<BoundingBox> total_bounding_box();
double skirt_first_layer_height(); double skirt_first_layer_height();