From 68acf19c09fde9085453d4bd41b13cc48a9a74bf Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 18 Oct 2016 10:22:34 +0200 Subject: [PATCH 1/3] New --scale-to-fit option in slic3r.cpp --- src/slic3r.cpp | 3 ++ xs/src/libslic3r/Config.cpp | 2 ++ xs/src/libslic3r/Config.hpp | 53 +++++++++++++++++++++++++++++--- xs/src/libslic3r/Model.cpp | 14 +++++++++ xs/src/libslic3r/Model.hpp | 2 ++ xs/src/libslic3r/PrintConfig.cpp | 6 ++++ xs/src/libslic3r/PrintConfig.hpp | 2 ++ xs/src/perlglue.cpp | 3 ++ xs/xsp/Config.xsp | 2 +- 9 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 8a75564cd..2ea600f4b 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -63,6 +63,9 @@ main(const int argc, const char **argv) // apply command line transform options for (ModelObjectPtrs::iterator o = model.objects.begin(); o != model.objects.end(); ++o) { + if (cli_config.scale_to_fit.is_positive_volume()) + (*o)->scale_to_fit(cli_config.scale_to_fit.value); + (*o)->scale(cli_config.scale.value); (*o)->rotate(cli_config.rotate.value, Z); } diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index 372b7b1b0..2426a491f 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -283,6 +283,8 @@ DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) { opt = new ConfigOptionFloatOrPercent (); } else if (optdef->type == coPoint) { opt = new ConfigOptionPoint (); + } else if (optdef->type == coPoint3) { + opt = new ConfigOptionPoint3 (); } else if (optdef->type == coPoints) { opt = new ConfigOptionPoints (); } else if (optdef->type == coBool) { diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index ff9762a2e..48c6bbd89 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "libslic3r.h" #include "Point.hpp" @@ -352,15 +354,55 @@ class ConfigOptionPoint : public ConfigOptionSingle }; bool deserialize(std::string str, bool append = false) { - std::istringstream iss(str); - iss >> this->value.x; - iss.ignore(std::numeric_limits::max(), ','); - iss.ignore(std::numeric_limits::max(), 'x'); - iss >> this->value.y; + std::vector tokens(2); + boost::split(tokens, str, boost::is_any_of(",x")); + try { + this->value.x = boost::lexical_cast(tokens[0]); + this->value.y = boost::lexical_cast(tokens[1]); + } catch (boost::bad_lexical_cast &e){ + std::cout << "Exception caught : " << e.what() << std::endl; + return false; + } return true; }; }; +class ConfigOptionPoint3 : public ConfigOptionSingle +{ + public: + ConfigOptionPoint3() : ConfigOptionSingle(Pointf3(0,0,0)) {}; + ConfigOptionPoint3(Pointf3 _value) : ConfigOptionSingle(_value) {}; + ConfigOptionPoint3* clone() const { return new ConfigOptionPoint3(this->value); }; + + std::string serialize() const { + std::ostringstream ss; + ss << this->value.x; + ss << ","; + ss << this->value.y; + ss << ","; + ss << this->value.z; + return ss.str(); + }; + + bool deserialize(std::string str, bool append = false) { + std::vector tokens(3); + boost::split(tokens, str, boost::is_any_of(",x")); + try { + this->value.x = boost::lexical_cast(tokens[0]); + this->value.y = boost::lexical_cast(tokens[1]); + this->value.z = boost::lexical_cast(tokens[2]); + } catch (boost::bad_lexical_cast &e){ + std::cout << "Exception caught : " << e.what() << std::endl; + return false; + } + return true; + }; + + bool is_positive_volume () { + return this->value.x > 0 && this->value.y > 0 && this->value.z > 0; + }; +}; + class ConfigOptionPoints : public ConfigOptionVector { public: @@ -526,6 +568,7 @@ enum ConfigOptionType { coPercent, coFloatOrPercent, coPoint, + coPoint3, coPoints, coBool, coBools, diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 6c4cbdfae..9175995bf 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -609,6 +609,20 @@ ModelObject::scale(const Pointf3 &versor) this->invalidate_bounding_box(); } +void +ModelObject::scale_to_fit(const Sizef3 &size) +{ + Sizef3 orig_size = this->bounding_box().size(); + float factor = fminf( + size.x / orig_size.x, + fminf( + size.y / orig_size.y, + size.z / orig_size.z + ) + ); + this->scale(factor); +} + void ModelObject::rotate(float angle, const Axis &axis) { diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 6d4ab1bfc..aeb784b0b 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -2,6 +2,7 @@ #define slic3r_Model_hpp_ #include "libslic3r.h" +#include "BoundingBox.hpp" #include "PrintConfig.hpp" #include "Layer.hpp" #include "Point.hpp" @@ -129,6 +130,7 @@ class ModelObject void translate(coordf_t x, coordf_t y, coordf_t z); void scale(float factor); void scale(const Pointf3 &versor); + void scale_to_fit(const Sizef3 &size); void rotate(float angle, const Axis &axis); void mirror(const Axis &axis); size_t materials_count() const; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 461981cda..8bf65dea6 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1412,6 +1412,12 @@ CLIConfigDef::CLIConfigDef() def->tooltip = "Scaling factor (default: 1)."; def->cli = "scale"; def->default_value = new ConfigOptionFloat(1); + + def = this->add("scale_to_fit", coPoint3); + def->label = "Scale to Fit"; + def->tooltip = "Scale to fit the given volume."; + def->cli = "scale-to-fit"; + def->default_value = new ConfigOptionPoint3(Pointf3(0,0,0)); } CLIConfigDef cli_config_def; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 762aa4c97..e943e058d 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -526,6 +526,7 @@ class CLIConfig ConfigOptionFloat rotate; ConfigOptionString save; ConfigOptionFloat scale; + ConfigOptionPoint3 scale_to_fit; CLIConfig() : ConfigBase(), StaticConfig() { this->def = &cli_config_def; @@ -542,6 +543,7 @@ class CLIConfig OPT_PTR(rotate); OPT_PTR(save); OPT_PTR(scale); + OPT_PTR(scale_to_fit); return NULL; }; diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index 55e00bc3a..d8621ac91 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -115,6 +115,9 @@ ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def) { } else if (def.type == coPoint) { const ConfigOptionPoint* optv = dynamic_cast(&opt); return perl_to_SV_clone_ref(optv->value); + } else if (def.type == coPoint3) { + const ConfigOptionPoint3* optv = dynamic_cast(&opt); + return perl_to_SV_clone_ref(optv->value); } else if (def.type == coPoints) { const ConfigOptionPoints* optv = dynamic_cast(&opt); AV* av = newAV(); diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp index 496269a73..056f1e1fd 100644 --- a/xs/xsp/Config.xsp +++ b/xs/xsp/Config.xsp @@ -118,7 +118,7 @@ print_config_def() opt_type = "s"; } else if (optdef->type == coStrings) { opt_type = "s@"; - } else if (optdef->type == coPoint || optdef->type == coPoints) { + } else if (optdef->type == coPoint || optdef->type == coPoint3 || optdef->type == coPoints) { opt_type = "point"; } else if (optdef->type == coBool || optdef->type == coBools) { opt_type = "bool"; From 56334c49acb125b8dd0c79844736a2c6d6a707ae Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 18 Oct 2016 14:25:25 +0200 Subject: [PATCH 2/3] Don't rescale mesh in POV export --- xs/src/libslic3r/IO.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/xs/src/libslic3r/IO.cpp b/xs/src/libslic3r/IO.cpp index 809a7b3bf..4a44cf23c 100644 --- a/xs/src/libslic3r/IO.cpp +++ b/xs/src/libslic3r/IO.cpp @@ -58,11 +58,6 @@ POV::write(TriangleMesh& mesh, std::string output_file) { TriangleMesh mesh2 = mesh; mesh2.center_around_origin(); - { - Sizef3 size = mesh2.bounding_box().size(); - coordf_t maxdim = fmax(size.x, fmax(size.y, size.y)); - mesh2.scale(10.0/maxdim); - } using namespace std; ofstream pov; From 8910b4970a18127199e29e71be5278b7abcbdad3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 19 Oct 2016 12:35:55 +0200 Subject: [PATCH 3/3] Added basic support material to SVG export --- xs/src/libslic3r/ClipperUtils.cpp | 29 ++++++++++++++++++++++ xs/src/libslic3r/ClipperUtils.hpp | 1 + xs/src/libslic3r/PrintConfig.hpp | 6 +++++ xs/src/libslic3r/SVGExport.cpp | 40 +++++++++++++++++++++++++++++-- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp index 3490118ee..69c8643f3 100644 --- a/xs/src/libslic3r/ClipperUtils.cpp +++ b/xs/src/libslic3r/ClipperUtils.cpp @@ -486,6 +486,17 @@ void diff(const SubjectType &subject, const Slic3r::ExPolygons &clip, ResultType } template void diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, Slic3r::ExPolygons* retval, bool safety_offset_); +template +void diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ResultType* retval, bool safety_offset_) +{ + Slic3r::Polygons pp; + for (Slic3r::ExPolygons::const_iterator ex = subject.begin(); ex != subject.end(); ++ex) { + Slic3r::Polygons ppp = *ex; + pp.insert(pp.end(), ppp.begin(), ppp.end()); + } + diff(pp, clip, retval, safety_offset_); +} + Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_) { @@ -504,6 +515,7 @@ diff_ex(const SubjectType &subject, const ClipType &clip, bool safety_offset_) } template Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_); template Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_); +template Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_); template void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_) @@ -596,6 +608,23 @@ void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, union_(pp, retval, safety_offset); } +Slic3r::Polygons +union_(const Slic3r::ExPolygons &subject1, const Slic3r::ExPolygons &subject2, bool safety_offset) +{ + Polygons pp; + for (Slic3r::ExPolygons::const_iterator it = subject1.begin(); it != subject1.end(); ++it) { + Polygons spp = *it; + pp.insert(pp.end(), spp.begin(), spp.end()); + } + for (Slic3r::ExPolygons::const_iterator it = subject2.begin(); it != subject2.end(); ++it) { + Polygons spp = *it; + pp.insert(pp.end(), spp.begin(), spp.end()); + } + Polygons retval; + union_(pp, &retval, safety_offset); + return retval; +} + void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree* retval, bool safety_offset_) { Slic3r::Polygons clip; diff --git a/xs/src/libslic3r/ClipperUtils.hpp b/xs/src/libslic3r/ClipperUtils.hpp index 4bc5ceb89..08697652c 100644 --- a/xs/src/libslic3r/ClipperUtils.hpp +++ b/xs/src/libslic3r/ClipperUtils.hpp @@ -129,6 +129,7 @@ Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, bool safety_offset Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject, bool safety_offset = false); void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, Slic3r::Polygons* retval, bool safety_offset = false); +Slic3r::Polygons union_(const Slic3r::ExPolygons &subject1, const Slic3r::ExPolygons &subject2, bool safety_offset = false); void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree* retval, bool safety_offset_ = false); void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool safety_offset_ = false); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index e943e058d..8aaebab35 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -490,6 +490,9 @@ class SVGExportConfig ConfigOptionFloat layer_height; ConfigOptionInt raft_layers; ConfigOptionFloat raft_offset; + ConfigOptionBool support_material; + ConfigOptionFloatOrPercent support_material_extrusion_width; + ConfigOptionFloat support_material_spacing; SVGExportConfig() : StaticPrintConfig() { this->set_defaults(); @@ -500,6 +503,9 @@ class SVGExportConfig OPT_PTR(layer_height); OPT_PTR(raft_layers); OPT_PTR(raft_offset); + OPT_PTR(support_material); + OPT_PTR(support_material_extrusion_width); + OPT_PTR(support_material_spacing); return NULL; }; diff --git a/xs/src/libslic3r/SVGExport.cpp b/xs/src/libslic3r/SVGExport.cpp index c34b5216e..a209977cf 100644 --- a/xs/src/libslic3r/SVGExport.cpp +++ b/xs/src/libslic3r/SVGExport.cpp @@ -17,6 +17,7 @@ SVGExport::writeSVG(const std::string &outputfile) bb.max.y += this->config.raft_offset.value; } this->mesh.translate(-bb.min.x, -bb.min.y, -bb.min.z); // align to origin + bb.translate(-bb.min.x, -bb.min.y, -bb.min.z); // align to origin const Sizef3 size = bb.size(); // if we are generating a raft, first_layer_height will not affect mesh slicing @@ -53,17 +54,47 @@ SVGExport::writeSVG(const std::string &outputfile) layer_z[i] += first_lh + lh * (this->config.raft_layers-1); } + // generate support material + std::vector support_material(layers.size()); + if (this->config.support_material) { + // generate a grid of points according to the configured spacing, + // covering the entire object bounding box + Points support_material_points; + for (coordf_t x = bb.min.x; x <= bb.max.x; x += this->config.support_material_spacing) { + for (coordf_t y = bb.min.y; y <= bb.max.y; y += this->config.support_material_spacing) { + support_material_points.push_back(Point(scale_(x), scale_(y))); + } + } + + // check overhangs, starting from the upper layer, and detect which points apply + // to each layer + ExPolygons overhangs; + for (int i = layer_z.size()-1; i >= 0; --i) { + overhangs = diff_ex(union_(overhangs, layers[i+1]), layers[i]); + for (Points::const_iterator it = support_material_points.begin(); it != support_material_points.end(); ++it) { + for (ExPolygons::const_iterator e = overhangs.begin(); e != overhangs.end(); ++e) { + if (e->contains(*it)) { + support_material[i].push_back(*it); + break; + } + } + } + } + } + + double support_material_radius = this->config.support_material_extrusion_width.get_abs_value(this->config.layer_height)/2; + FILE* f = fopen(outputfile.c_str(), "w"); fprintf(f, "\n" "\n" - "\n" + "\n" "\n" , size.x, size.y, SLIC3R_VERSION); for (size_t i = 0; i < layer_z.size(); ++i) { fprintf(f, "\t\n", i, layer_z[i]); - for (ExPolygons::const_iterator it = layers[i].begin(); it != layers[i].end(); ++it){ + for (ExPolygons::const_iterator it = layers[i].begin(); it != layers[i].end(); ++it) { std::string pd; Polygons pp = *it; for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp) { @@ -80,6 +111,11 @@ SVGExport::writeSVG(const std::string &outputfile) pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) ); } + for (Points::const_iterator it = support_material[i].begin(); it != support_material[i].end(); ++it) { + fprintf(f,"\t\t\n", + unscale(it->x), unscale(it->y), support_material_radius + ); + } fprintf(f,"\t\n"); } fprintf(f,"\n");