Ported from the playground branch. Various documentation and optimization.

This commit is contained in:
bubnikv 2016-09-13 13:30:00 +02:00
parent a5b7f14dfa
commit 620c6c7378
38 changed files with 586 additions and 92 deletions

View File

@ -68,6 +68,26 @@ BoundingBox::polygon() const
return p; return p;
} }
BoundingBox BoundingBox::rotated(double angle) const
{
BoundingBox out;
out.merge(this->min.rotated(angle));
out.merge(this->max.rotated(angle));
out.merge(Point(this->min.x, this->max.y).rotated(angle));
out.merge(Point(this->max.x, this->min.y).rotated(angle));
return out;
}
BoundingBox BoundingBox::rotated(double angle, const Point &center) const
{
BoundingBox out;
out.merge(this->min.rotated(angle, center));
out.merge(this->max.rotated(angle, center));
out.merge(Point(this->min.x, this->max.y).rotated(angle, center));
out.merge(Point(this->max.x, this->min.y).rotated(angle, center));
return out;
}
template <class PointClass> void template <class PointClass> void
BoundingBoxBase<PointClass>::scale(double factor) BoundingBoxBase<PointClass>::scale(double factor)
{ {
@ -163,6 +183,26 @@ BoundingBox3Base<PointClass>::size() const
} }
template Pointf3 BoundingBox3Base<Pointf3>::size() const; template Pointf3 BoundingBox3Base<Pointf3>::size() const;
template <class PointClass> double
BoundingBoxBase<PointClass>::radius() const
{
double x = this->max.x - this->min.x;
double y = this->max.y - this->min.y;
return 0.5 * sqrt(x*x+y*y);
}
template double BoundingBoxBase<Point>::radius() const;
template double BoundingBoxBase<Pointf>::radius() const;
template <class PointClass> double
BoundingBox3Base<PointClass>::radius() const
{
double x = this->max.x - this->min.x;
double y = this->max.y - this->min.y;
double z = this->max.z - this->min.z;
return 0.5 * sqrt(x*x+y*y+z*z);
}
template double BoundingBox3Base<Pointf3>::radius() const;
template <class PointClass> void template <class PointClass> void
BoundingBoxBase<PointClass>::translate(coordf_t x, coordf_t y) BoundingBoxBase<PointClass>::translate(coordf_t x, coordf_t y)
{ {

View File

@ -28,6 +28,7 @@ class BoundingBoxBase
void merge(const BoundingBoxBase<PointClass> &bb); void merge(const BoundingBoxBase<PointClass> &bb);
void scale(double factor); void scale(double factor);
PointClass size() const; PointClass size() const;
double radius() const;
void translate(coordf_t x, coordf_t y); void translate(coordf_t x, coordf_t y);
void offset(coordf_t delta); void offset(coordf_t delta);
PointClass center() const; PointClass center() const;
@ -44,6 +45,7 @@ class BoundingBox3Base : public BoundingBoxBase<PointClass>
void merge(const std::vector<PointClass> &points); void merge(const std::vector<PointClass> &points);
void merge(const BoundingBox3Base<PointClass> &bb); void merge(const BoundingBox3Base<PointClass> &bb);
PointClass size() const; PointClass size() const;
double radius() const;
void translate(coordf_t x, coordf_t y, coordf_t z); void translate(coordf_t x, coordf_t y, coordf_t z);
void offset(coordf_t delta); void offset(coordf_t delta);
PointClass center() const; PointClass center() const;
@ -54,6 +56,10 @@ class BoundingBox : public BoundingBoxBase<Point>
public: public:
void polygon(Polygon* polygon) const; void polygon(Polygon* polygon) const;
Polygon polygon() const; Polygon polygon() const;
BoundingBox rotated(double angle) const;
BoundingBox rotated(double angle, const Point &center) const;
void rotate(double angle) { (*this) = this->rotated(angle); }
void rotate(double angle, const Point &center) { (*this) = this->rotated(angle, center); }
BoundingBox() : BoundingBoxBase<Point>() {}; BoundingBox() : BoundingBoxBase<Point>() {};
BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {}; BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {};
@ -100,7 +106,9 @@ inline bool empty(const BoundingBoxBase<VT> &bb)
template<typename VT> template<typename VT>
inline bool empty(const BoundingBox3Base<VT> &bb) inline bool empty(const BoundingBox3Base<VT> &bb)
{ {
return bb.min.x > bb.max.x || bb.min.y > bb.max.y || bb.min.z > bb.max.z;} return bb.min.x > bb.max.x || bb.min.y > bb.max.y || bb.min.z > bb.max.z;
} }
} // namespace Slic3r
#endif #endif

View File

@ -1,6 +1,12 @@
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "Geometry.hpp" #include "Geometry.hpp"
// #define CLIPPER_UTILS_DEBUG
#ifdef CLIPPER_UTILS_DEBUG
#include "SVG.hpp"
#endif /* CLIPPER_UTILS_DEBUG */
namespace Slic3r { namespace Slic3r {
//----------------------------------------------------------- //-----------------------------------------------------------
@ -226,6 +232,19 @@ void
offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1, offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
#ifdef CLIPPER_UTILS_DEBUG
BoundingBox bbox = get_extents(polygons);
coordf_t stroke_width = scale_(0.005);
static int iRun = 0;
++ iRun;
char path[2048];
sprintf(path, "out\\offset2-%d.svg", iRun);
bool flipY = false;
SVG svg(path, bbox, scale_(1.), flipY);
for (Slic3r::Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++ it)
svg.draw(it->lines(), "gray", stroke_width);
#endif /* CLIPPER_UTILS_DEBUG */
// read input // read input
ClipperLib::Paths input; ClipperLib::Paths input;
Slic3rMultiPoints_to_ClipperPaths(polygons, &input); Slic3rMultiPoints_to_ClipperPaths(polygons, &input);
@ -245,12 +264,18 @@ offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
ClipperLib::Paths output1; ClipperLib::Paths output1;
co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); co.AddPaths(input, joinType, ClipperLib::etClosedPolygon);
co.Execute(output1, (delta1*scale)); co.Execute(output1, (delta1*scale));
#ifdef CLIPPER_UTILS_DEBUG
svg.draw(output1, 1./CLIPPER_OFFSET_SCALE, "red", stroke_width);
#endif /* CLIPPER_UTILS_DEBUG */
// perform second offset // perform second offset
co.Clear(); co.Clear();
co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon); co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon);
co.Execute(*retval, (delta2*scale)); co.Execute(*retval, (delta2*scale));
#ifdef CLIPPER_UTILS_DEBUG
svg.draw(*retval, 1./CLIPPER_OFFSET_SCALE, "green", stroke_width);
#endif /* CLIPPER_UTILS_DEBUG */
// unscale output // unscale output
scaleClipperPolygons(*retval, 1/scale); scaleClipperPolygons(*retval, 1/scale);
} }

View File

@ -14,6 +14,11 @@ using ClipperLib::jtSquare;
namespace Slic3r { namespace Slic3r {
// Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library.
//FIXME Vojtech: Better to use a power of 2 coefficient and to use bit shifts for scaling.
// How about 2^17=131072?
// By the way, is the scalling needed at all? Cura runs all the computation with a fixed point precision of 1um, while Slic3r scales to 1nm,
// further scaling by 10e5 brings us to
#define CLIPPER_OFFSET_SCALE 100000.0 #define CLIPPER_OFFSET_SCALE 100000.0
//----------------------------------------------------------- //-----------------------------------------------------------

View File

@ -39,8 +39,8 @@ ConfigDef::add(const t_config_option_key &opt_key, ConfigOptionType type)
const ConfigOptionDef* const ConfigOptionDef*
ConfigDef::get(const t_config_option_key &opt_key) const ConfigDef::get(const t_config_option_key &opt_key) const
{ {
if (this->options.count(opt_key) == 0) return NULL; t_optiondef_map::iterator it = const_cast<ConfigDef*>(this)->options.find(opt_key);
return &const_cast<ConfigDef*>(this)->options[opt_key]; return (it == this->options.end()) ? NULL : &it->second;
} }
bool bool
@ -113,6 +113,8 @@ ConfigBase::set_deserialize(const t_config_option_key &opt_key, std::string str)
return opt->deserialize(str); return opt->deserialize(str);
} }
// Return an absolute value of a possibly relative config variable.
// For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height.
double double
ConfigBase::get_abs_value(const t_config_option_key &opt_key) { ConfigBase::get_abs_value(const t_config_option_key &opt_key) {
ConfigOption* opt = this->option(opt_key, false); ConfigOption* opt = this->option(opt_key, false);
@ -130,6 +132,8 @@ ConfigBase::get_abs_value(const t_config_option_key &opt_key) {
} }
} }
// Return an absolute value of a possibly relative config variable.
// For example, return absolute infill extrusion width, either from an absolute value, or relative to a provided value.
double double
ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) { ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) {
// get stored option value // get stored option value
@ -180,6 +184,7 @@ DynamicConfig& DynamicConfig::operator= (DynamicConfig other)
void void
DynamicConfig::swap(DynamicConfig &other) DynamicConfig::swap(DynamicConfig &other)
{ {
std::swap(this->def, other.def);
std::swap(this->options, other.options); std::swap(this->options, other.options);
} }
@ -197,7 +202,8 @@ DynamicConfig::DynamicConfig (const DynamicConfig& other) {
ConfigOption* ConfigOption*
DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) { DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) {
if (this->options.count(opt_key) == 0) { t_options_map::iterator it = options.find(opt_key);
if (it == options.end()) {
if (create) { if (create) {
const ConfigOptionDef* optdef = this->def->get(opt_key); const ConfigOptionDef* optdef = this->def->get(opt_key);
assert(optdef != NULL); assert(optdef != NULL);
@ -239,7 +245,7 @@ DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) {
return NULL; return NULL;
} }
} }
return this->options[opt_key]; return it->second;
} }
template<class T> template<class T>
@ -273,7 +279,6 @@ StaticConfig::set_defaults()
t_config_option_keys keys = this->keys(); t_config_option_keys keys = this->keys();
for (t_config_option_keys::const_iterator it = keys.begin(); it != keys.end(); ++it) { for (t_config_option_keys::const_iterator it = keys.begin(); it != keys.end(); ++it) {
const ConfigOptionDef* def = this->def->get(*it); const ConfigOptionDef* def = this->def->get(*it);
if (def->default_value != NULL) if (def->default_value != NULL)
this->option(*it)->set(*def->default_value); this->option(*it)->set(*def->default_value);
} }

View File

@ -14,9 +14,11 @@
namespace Slic3r { namespace Slic3r {
// Name of the configuration option.
typedef std::string t_config_option_key; typedef std::string t_config_option_key;
typedef std::vector<std::string> t_config_option_keys; typedef std::vector<std::string> t_config_option_keys;
// A generic value of a configuration option.
class ConfigOption { class ConfigOption {
public: public:
virtual ~ConfigOption() {}; virtual ~ConfigOption() {};
@ -31,6 +33,7 @@ class ConfigOption {
friend bool operator!= (const ConfigOption &a, const ConfigOption &b); friend bool operator!= (const ConfigOption &a, const ConfigOption &b);
}; };
// Value of a single valued option (bool, int, float, string, point, enum)
template <class T> template <class T>
class ConfigOptionSingle : public ConfigOption { class ConfigOptionSingle : public ConfigOption {
public: public:
@ -44,12 +47,14 @@ class ConfigOptionSingle : public ConfigOption {
}; };
}; };
// Value of a vector valued option (bools, ints, floats, strings, points)
class ConfigOptionVectorBase : public ConfigOption { class ConfigOptionVectorBase : public ConfigOption {
public: public:
virtual ~ConfigOptionVectorBase() {}; virtual ~ConfigOptionVectorBase() {};
virtual std::vector<std::string> vserialize() const = 0; virtual std::vector<std::string> vserialize() const = 0;
}; };
// Value of a vector valued option (bools, ints, floats, strings, points), template
template <class T> template <class T>
class ConfigOptionVector : public ConfigOptionVectorBase class ConfigOptionVector : public ConfigOptionVectorBase
{ {
@ -436,6 +441,7 @@ class ConfigOptionBools : public ConfigOptionVector<bool>
}; };
}; };
// Map from an enum name to an enum integer value.
typedef std::map<std::string,int> t_config_enum_values; typedef std::map<std::string,int> t_config_enum_values;
template <class T> template <class T>
@ -461,11 +467,14 @@ class ConfigOptionEnum : public ConfigOptionSingle<T>
return true; return true;
}; };
// Map from an enum name to an enum integer value.
//FIXME The map is called often, it shall be initialized statically.
static t_config_enum_values get_enum_values(); static t_config_enum_values get_enum_values();
}; };
/* We use this one in DynamicConfig objects, otherwise it's better to use // Generic enum configuration value.
the specialized ConfigOptionEnum<T> containers. */ // We use this one in DynamicConfig objects when creating a config value object for ConfigOptionType == coEnum.
// In the StaticConfig, it is better to use the specialized ConfigOptionEnum<T> containers.
class ConfigOptionEnumGeneric : public ConfigOptionInt class ConfigOptionEnumGeneric : public ConfigOptionInt
{ {
public: public:
@ -485,57 +494,117 @@ class ConfigOptionEnumGeneric : public ConfigOptionInt
}; };
}; };
// Type of a configuration value.
enum ConfigOptionType { enum ConfigOptionType {
coNone, coNone,
// single float
coFloat, coFloat,
// vector of floats
coFloats, coFloats,
// single int
coInt, coInt,
// vector of ints
coInts, coInts,
// single string
coString, coString,
// vector of strings
coStrings, coStrings,
// percent value. Currently only used for infill.
coPercent, coPercent,
// a fraction or an absolute value
coFloatOrPercent, coFloatOrPercent,
// single 2d point. Currently not used.
coPoint, coPoint,
// vector of 2d points. Currently used for the definition of the print bed and for the extruder offsets.
coPoints, coPoints,
// single boolean value
coBool, coBool,
// vector of boolean values
coBools, coBools,
// a generic enum
coEnum, coEnum,
}; };
// Definition of a configuration value for the purpose of GUI presentation, editing, value mapping and config file handling.
class ConfigOptionDef class ConfigOptionDef
{ {
public: public:
// What type? bool, int, string etc.
ConfigOptionType type; ConfigOptionType type;
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
ConfigOption* default_value; ConfigOption* default_value;
// Usually empty.
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
// "select_open" - to open a selection dialog (currently only a serial port selection).
std::string gui_type; std::string gui_type;
// Usually empty. Otherwise "serialized" or "show_value"
// The flags may be combined.
// "serialized" - vector valued option is entered in a single edit field. Values are separated by a semicolon.
// "show_value" - even if enum_values / enum_labels are set, still display the value, not the enum label.
std::string gui_flags; std::string gui_flags;
// Label of the GUI input field.
// In case the GUI input fields are grouped in some views, the label defines a short label of a grouped value,
// while full_label contains a label of a stand-alone field.
// The full label is shown, when adding an override parameter for an object or a modified object.
std::string label; std::string label;
std::string full_label; std::string full_label;
// Category of a configuration field, from the GUI perspective.
// One of: "Layers and Perimeters", "Infill", "Support material", "Speed", "Extruders", "Advanced", "Extrusion Width"
std::string category; std::string category;
// A tooltip text shown in the GUI.
std::string tooltip; std::string tooltip;
// Text right from the input field, usually a unit of measurement.
std::string sidetext; std::string sidetext;
// Format of this parameter on a command line.
std::string cli; std::string cli;
// Set for type == coFloatOrPercent.
// It provides a link to a configuration value, of which this option provides a ratio.
// For example,
// For example external_perimeter_speed may be defined as a fraction of perimeter_speed.
t_config_option_key ratio_over; t_config_option_key ratio_over;
// True for multiline strings.
bool multiline; bool multiline;
// For text input: If true, the GUI text box spans the complete page width.
bool full_width; bool full_width;
// Not editable. Currently only used for the display of the number of threads.
bool readonly; bool readonly;
// Height of a multiline GUI text box.
int height; int height;
// Optional width of an input field.
int width; int width;
// <min, max> limit of a numeric input.
// If not set, the <min, max> is set to <INT_MIN, INT_MAX>
// By setting min=0, only nonnegative input is allowed.
int min; int min;
int max; int max;
// Legacy names for this configuration option.
// Used when parsing legacy configuration file.
std::vector<t_config_option_key> aliases; std::vector<t_config_option_key> aliases;
// Sometimes a single value may well define multiple values in a "beginner" mode.
// Currently used for aliasing "solid_layers" to "top_solid_layers", "bottom_solid_layers".
std::vector<t_config_option_key> shortcut; std::vector<t_config_option_key> shortcut;
// Definition of values / labels for a combo box.
// Mostly used for enums (when type == coEnum), but may be used for ints resp. floats, if gui_type is set to "i_enum_open" resp. "f_enum_open".
std::vector<std::string> enum_values; std::vector<std::string> enum_values;
std::vector<std::string> enum_labels; std::vector<std::string> enum_labels;
// For enums (when type == coEnum). Maps enum_values to enums.
// Initialized by ConfigOptionEnum<xxx>::get_enum_values()
t_config_enum_values enum_keys_map; t_config_enum_values enum_keys_map;
ConfigOptionDef() : type(coNone), default_value(NULL), ConfigOptionDef() : type(coNone), default_value(NULL),
multiline(false), full_width(false), readonly(false), multiline(false), full_width(false), readonly(false),
height(-1), width(-1), min(INT_MIN), max(INT_MAX) {}; height(-1), width(-1), min(INT_MIN), max(INT_MAX) {};
}; };
// Map from a config option name to its definition.
// The definition does not carry an actual value of the config option, only its constant default value.
// t_config_option_key is std::string
typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map; typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map;
// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
// The configuration definition is static: It does not carry the actual configuration values,
// but it carries the defaults of the configuration values.
class ConfigDef class ConfigDef
{ {
public: public:
@ -545,9 +614,14 @@ class ConfigDef
const ConfigOptionDef* get(const t_config_option_key &opt_key) const; const ConfigOptionDef* get(const t_config_option_key &opt_key) const;
}; };
// An abstract configuration store.
class ConfigBase class ConfigBase
{ {
public: public:
// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
// The configuration definition is static: It does not carry the actual configuration values,
// but it carries the defaults of the configuration values.
// ConfigBase does not own ConfigDef, it only references it.
const ConfigDef* def; const ConfigDef* def;
ConfigBase() : def(NULL) {}; ConfigBase() : def(NULL) {};
@ -562,11 +636,14 @@ class ConfigBase
t_config_option_keys diff(ConfigBase &other); t_config_option_keys diff(ConfigBase &other);
std::string serialize(const t_config_option_key &opt_key) const; std::string serialize(const t_config_option_key &opt_key) const;
bool set_deserialize(const t_config_option_key &opt_key, std::string str); bool set_deserialize(const t_config_option_key &opt_key, std::string str);
double get_abs_value(const t_config_option_key &opt_key); double get_abs_value(const t_config_option_key &opt_key);
double get_abs_value(const t_config_option_key &opt_key, double ratio_over); double get_abs_value(const t_config_option_key &opt_key, double ratio_over);
void setenv_(); void setenv_();
}; };
// Configuration store with dynamic number of configuration values.
// In Slic3r, the dynamic config is mostly used at the user interface layer.
class DynamicConfig : public virtual ConfigBase class DynamicConfig : public virtual ConfigBase
{ {
public: public:
@ -585,13 +662,20 @@ class DynamicConfig : public virtual ConfigBase
t_options_map options; t_options_map options;
}; };
// Configuration store with a static definition of configuration values.
// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
// because the configuration values could be accessed directly.
class StaticConfig : public virtual ConfigBase class StaticConfig : public virtual ConfigBase
{ {
public: public:
StaticConfig() : ConfigBase() {}; StaticConfig() : ConfigBase() {};
// Gets list of config option names for each config option of this->def, which has a static counter-part defined by the derived object
// and which could be resolved by this->optptr(key) call.
t_config_option_keys keys() const; t_config_option_keys keys() const;
//virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0; // Set all statically defined config options to their defaults defined by this->def.
void set_defaults(); void set_defaults();
// The derived class has to implement optptr to resolve a static configuration value.
// virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0;
}; };
} }

View File

@ -514,4 +514,20 @@ ExPolygon::dump_perl() const
return ret.str(); return ret.str();
} }
BoundingBox get_extents(const ExPolygon &expolygon)
{
return get_extents(expolygon.contour);
} }
BoundingBox get_extents(const ExPolygons &expolygons)
{
BoundingBox bbox;
if (! expolygons.empty()) {
bbox = get_extents(expolygons.front());
for (size_t i = 1; i < expolygons.size(); ++ i)
bbox.merge(get_extents(expolygons[i]));
}
return bbox;
}
} // namespace Slic3r

View File

@ -72,7 +72,10 @@ inline Polygons to_polygons(ExPolygons &&src)
} }
#endif #endif
} extern BoundingBox get_extents(const ExPolygon &expolygon);
extern BoundingBox get_extents(const ExPolygons &expolygons);
} // namespace Slic3r
// start Boost // start Boost
#include <boost/polygon/polygon.hpp> #include <boost/polygon/polygon.hpp>

View File

@ -128,4 +128,9 @@ ExPolygonCollection::append(const ExPolygons &expp)
this->expolygons.insert(this->expolygons.end(), expp.begin(), expp.end()); this->expolygons.insert(this->expolygons.end(), expp.begin(), expp.end());
} }
BoundingBox get_extents(const ExPolygonCollection &expolygon)
{
return get_extents(expolygon.expolygons);
}
} }

View File

@ -34,6 +34,8 @@ class ExPolygonCollection
void append(const ExPolygons &expolygons); void append(const ExPolygons &expolygons);
}; };
extern BoundingBox get_extents(const ExPolygonCollection &expolygon);
} }
#endif #endif

View File

@ -1,7 +1,7 @@
// Optimize the extrusion simulator to the bones. // Optimize the extrusion simulator to the bones.
#pragma GCC optimize ("O3") //#pragma GCC optimize ("O3")
#undef SLIC3R_DEBUG //#undef SLIC3R_DEBUG
#define NDEBUG //#define NDEBUG
#include <cmath> #include <cmath>
#include <cassert> #include <cassert>
@ -640,7 +640,7 @@ struct Cell
// Height of the covered part in excess to the expected layer height. // Height of the covered part in excess to the expected layer height.
float excess_height; float excess_height;
bool operator<(const Cell &c2) { bool operator<(const Cell &c2) const {
return this->excess_height < c2.excess_height; return this->excess_height < c2.excess_height;
} }
}; };

View File

@ -2,7 +2,6 @@
#define slic3r_ExtrusionSimulator_hpp_ #define slic3r_ExtrusionSimulator_hpp_
#include "libslic3r.h" #include "libslic3r.h"
#include "Config.hpp"
#include "ExtrusionEntity.hpp" #include "ExtrusionEntity.hpp"
#include "BoundingBox.hpp" #include "BoundingBox.hpp"

View File

@ -23,6 +23,10 @@
// We want our version of assert. // We want our version of assert.
#include "../libslic3r.h" #include "../libslic3r.h"
#ifndef myassert
#define myassert assert
#endif
namespace Slic3r { namespace Slic3r {
#ifndef clamp #ifndef clamp

View File

@ -78,6 +78,9 @@ class GCode {
Wipe wipe; Wipe wipe;
AvoidCrossingPerimeters avoid_crossing_perimeters; AvoidCrossingPerimeters avoid_crossing_perimeters;
bool enable_loop_clipping; bool enable_loop_clipping;
// If enabled, the G-code generator will put following comments at the ends
// of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END
// Those comments are received and consumed (removed from the G-code) by the CoolingBuffer.pm Perl module.
bool enable_cooling_markers; bool enable_cooling_markers;
// Markers for the Pressure Equalizer to recognize the extrusion type. // Markers for the Pressure Equalizer to recognize the extrusion type.
// The Pressure Equalizer removes the markers from the final G-code. // The Pressure Equalizer removes the markers from the final G-code.
@ -89,6 +92,10 @@ class GCode {
// Distance Field structure to // Distance Field structure to
EdgeGrid::Grid *_lower_layer_edge_grid; EdgeGrid::Grid *_lower_layer_edge_grid;
bool first_layer; // this flag triggers first layer speeds bool first_layer; // this flag triggers first layer speeds
// Used by the CoolingBuffer.pm Perl module to calculate time spent per layer change.
// This value is not quite precise. First it only accouts for extrusion moves and travel moves,
// it does not account for wipe, retract / unretract moves.
// second it does not account for the velocity profiles of the printer.
float elapsed_time; // seconds float elapsed_time; // seconds
double volumetric_speed; double volumetric_speed;
// Support for the extrusion role markers. Which marker is active? // Support for the extrusion role markers. Which marker is active?

View File

@ -162,6 +162,10 @@ Layer::any_bottom_region_slice_contains(const T &item) const
} }
template bool Layer::any_bottom_region_slice_contains<Polyline>(const Polyline &item) const; template bool Layer::any_bottom_region_slice_contains<Polyline>(const Polyline &item) const;
// Here the perimeters are created cummulatively for all layer regions sharing the same parameters influencing the perimeters.
// The perimeter paths and the thin fills (ExtrusionEntityCollection) are assigned to the first compatible layer region.
// The resulting fill surface is split back among the originating regions.
void void
Layer::make_perimeters() Layer::make_perimeters()
{ {

View File

@ -77,6 +77,7 @@ LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection*
); );
if (this->layer()->lower_layer != NULL) if (this->layer()->lower_layer != NULL)
// Cummulative sum of polygons over all the regions.
g.lower_slices = &this->layer()->lower_layer->slices; g.lower_slices = &this->layer()->lower_layer->slices;
g.layer_id = this->layer()->id(); g.layer_id = this->layer()->id();

View File

@ -772,7 +772,7 @@ ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
void void
ModelInstance::transform_polygon(Polygon* polygon) const ModelInstance::transform_polygon(Polygon* polygon) const
{ {
polygon->rotate(this->rotation, Point(0,0)); // rotate around polygon origin polygon->rotate(this->rotation); // rotate around polygon origin
polygon->scale(this->scaling_factor); // scale around polygon origin polygon->scale(this->scaling_factor); // scale around polygon origin
} }

View File

@ -27,10 +27,18 @@ typedef std::vector<ModelObject*> ModelObjectPtrs;
typedef std::vector<ModelVolume*> ModelVolumePtrs; typedef std::vector<ModelVolume*> ModelVolumePtrs;
typedef std::vector<ModelInstance*> ModelInstancePtrs; typedef std::vector<ModelInstance*> ModelInstancePtrs;
// The print bed content.
// Description of a triangular model with multiple materials, multiple instances with various affine transformations
// and with multiple modifier meshes.
// A model groups multiple objects, each object having possibly multiple instances,
// all objects may share mutliple materials.
class Model class Model
{ {
public: public:
// Materials are owned by a model and referenced by objects through t_model_material_id.
// Single material may be shared by multiple models.
ModelMaterialMap materials; ModelMaterialMap materials;
// Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation).
ModelObjectPtrs objects; ModelObjectPtrs objects;
Model(); Model();
@ -63,34 +71,48 @@ class Model
void duplicate_objects_grid(size_t x, size_t y, coordf_t dist); void duplicate_objects_grid(size_t x, size_t y, coordf_t dist);
}; };
// Material, which may be shared across multiple ModelObjects of a single Model.
class ModelMaterial class ModelMaterial
{ {
friend class Model; friend class Model;
public: public:
// Attributes are defined by the AMF file format, but they don't seem to be used by Slic3r for any purpose.
t_model_material_attributes attributes; t_model_material_attributes attributes;
// Dynamic configuration storage for the object specific configuration values, overriding the global configuration.
DynamicPrintConfig config; DynamicPrintConfig config;
Model* get_model() const { return this->model; }; Model* get_model() const { return this->model; };
void apply(const t_model_material_attributes &attributes); void apply(const t_model_material_attributes &attributes);
private: private:
// Parent, owning this material.
Model* model; Model* model;
ModelMaterial(Model *model); ModelMaterial(Model *model);
ModelMaterial(Model *model, const ModelMaterial &other); ModelMaterial(Model *model, const ModelMaterial &other);
}; };
// A printable object, possibly having multiple print volumes (each with its own set of parameters and materials),
// and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials.
// Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed,
// different rotation and different uniform scaling.
class ModelObject class ModelObject
{ {
friend class Model; friend class Model;
public: public:
std::string name; std::string name;
std::string input_file; std::string input_file;
// Instances of this ModelObject. Each instance defines a shift on the print bed, rotation around the Z axis and a uniform scaling.
// Instances are owned by this ModelObject.
ModelInstancePtrs instances; ModelInstancePtrs instances;
// Printable and modifier volumes, each with its material ID and a set of override parameters.
// ModelVolumes are owned by this ModelObject.
ModelVolumePtrs volumes; ModelVolumePtrs volumes;
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
DynamicPrintConfig config; DynamicPrintConfig config;
// Variation of a layer thickness for spans of Z coordinates.
t_layer_height_ranges layer_height_ranges; t_layer_height_ranges layer_height_ranges;
/* This vector accumulates the total translation applied to the object by the /* This vector accumulates the total translation applied to the object by the
center_around_origin() method. Callers might want to apply the same translation center_around_origin() method. Callers might want to apply the same translation
to new volumes before adding them to this object in order to preserve alignment to new volumes before adding them to this object in order to preserve alignment
@ -134,7 +156,8 @@ class ModelObject
void split(ModelObjectPtrs* new_objects); void split(ModelObjectPtrs* new_objects);
void update_bounding_box(); // this is a private method but we expose it until we need to expose it via XS void update_bounding_box(); // this is a private method but we expose it until we need to expose it via XS
private: private:
// Parent object, owning this ModelObject.
Model* model; Model* model;
ModelObject(Model *model); ModelObject(Model *model);
@ -144,15 +167,22 @@ class ModelObject
~ModelObject(); ~ModelObject();
}; };
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
// ModelVolume instances are owned by a ModelObject.
class ModelVolume class ModelVolume
{ {
friend class ModelObject; friend class ModelObject;
public: public:
std::string name; std::string name;
// The triangular model.
TriangleMesh mesh; TriangleMesh mesh;
// Configuration parameters specific to an object model geometry or a modifier volume,
// overriding the global Slic3r settings and the ModelObject settings.
DynamicPrintConfig config; DynamicPrintConfig config;
// Is it an object to be printed, or a modifier volume?
bool modifier; bool modifier;
// A parent object owning this modifier volume.
ModelObject* get_object() const { return this->object; }; ModelObject* get_object() const { return this->object; };
t_model_material_id material_id() const; t_model_material_id material_id() const;
void material_id(t_model_material_id material_id); void material_id(t_model_material_id material_id);
@ -161,7 +191,8 @@ class ModelVolume
ModelMaterial* assign_unique_material(); ModelMaterial* assign_unique_material();
private: private:
// Parent object owning this ModelVolume.
ModelObject* object; ModelObject* object;
t_model_material_id _material_id; t_model_material_id _material_id;
@ -169,19 +200,25 @@ class ModelVolume
ModelVolume(ModelObject *object, const ModelVolume &other); ModelVolume(ModelObject *object, const ModelVolume &other);
}; };
// A single instance of a ModelObject.
// Knows the affine transformation of an object.
class ModelInstance class ModelInstance
{ {
friend class ModelObject; friend class ModelObject;
public: public:
double rotation; // in radians around mesh center point double rotation; // Rotation around the Z axis, in radians around mesh center point
double scaling_factor; double scaling_factor;
Pointf offset; // in unscaled coordinates Pointf offset; // in unscaled coordinates
ModelObject* get_object() const { return this->object; }; ModelObject* get_object() const { return this->object; };
// To be called on an external mesh
void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const; void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const;
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
void transform_polygon(Polygon* polygon) const; void transform_polygon(Polygon* polygon) const;
private: private:
// Parent object, owning this instance.
ModelObject* object; ModelObject* object;
ModelInstance(ModelObject *object); ModelInstance(ModelObject *object);

View File

@ -33,8 +33,8 @@ MultiPoint::translate(const Point &vector)
void void
MultiPoint::rotate(double angle) MultiPoint::rotate(double angle)
{ {
double s = sin(angle); double s = sin(angle);
double c = cos(angle); double c = cos(angle);
for (Points::iterator it = points.begin(); it != points.end(); ++it) { for (Points::iterator it = points.begin(); it != points.end(); ++it) {
double cur_x = (double)it->x; double cur_x = (double)it->x;
double cur_y = (double)it->y; double cur_y = (double)it->y;
@ -46,8 +46,13 @@ MultiPoint::rotate(double angle)
void void
MultiPoint::rotate(double angle, const Point &center) MultiPoint::rotate(double angle, const Point &center)
{ {
double s = sin(angle);
double c = cos(angle);
for (Points::iterator it = points.begin(); it != points.end(); ++it) { for (Points::iterator it = points.begin(); it != points.end(); ++it) {
(*it).rotate(angle, center); double dx = double(it->x - center.x);
double dy = double(it->y - center.y);
it->x = (coord_t)round(double(center.x) + c * dx - s * dy);
it->y = (coord_t)round(double(center.y) + c * dy + s * dx);
} }
} }
@ -202,4 +207,9 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
return results; return results;
} }
BoundingBox get_extents(const MultiPoint &mp)
{
return mp.bounding_box();
}
} }

View File

@ -47,6 +47,8 @@ class MultiPoint
static Points _douglas_peucker(const Points &points, const double tolerance); static Points _douglas_peucker(const Points &points, const double tolerance);
}; };
} extern BoundingBox get_extents(const MultiPoint &mp);
} // namespace Slic3r
#endif #endif

View File

@ -533,12 +533,6 @@ PerimeterGenerator::_variable_width(const ThickPolylines &polylines, ExtrusionRo
return coll; return coll;
} }
bool
PerimeterGeneratorLoop::is_external() const
{
return this->depth == 0;
}
bool bool
PerimeterGeneratorLoop::is_internal_contour() const PerimeterGeneratorLoop::is_internal_contour() const
{ {

View File

@ -11,25 +11,33 @@
namespace Slic3r { namespace Slic3r {
class PerimeterGeneratorLoop; // Hierarchy of perimeters.
typedef std::vector<PerimeterGeneratorLoop> PerimeterGeneratorLoops;
class PerimeterGeneratorLoop { class PerimeterGeneratorLoop {
public: public:
// Polygon of this contour.
Polygon polygon; Polygon polygon;
// Is it a contour or a hole?
// Contours are CCW oriented, holes are CW oriented.
bool is_contour; bool is_contour;
// Depth in the hierarchy. External perimeter has depth = 0. An external perimeter could be both a contour and a hole.
unsigned short depth; unsigned short depth;
// Children contour, may be both CCW and CW oriented (outer contours or holes).
std::vector<PerimeterGeneratorLoop> children; std::vector<PerimeterGeneratorLoop> children;
PerimeterGeneratorLoop(Polygon polygon, unsigned short depth) PerimeterGeneratorLoop(Polygon polygon, unsigned short depth)
: polygon(polygon), is_contour(false), depth(depth) : polygon(polygon), is_contour(false), depth(depth)
{}; {};
bool is_external() const; // External perimeter. It may be CCW or CW oriented (outer contour or hole contour).
bool is_external() const { return this->depth == 0; }
// An island, which may have holes, but it does not have another internal island.
bool is_internal_contour() const; bool is_internal_contour() const;
}; };
typedef std::vector<PerimeterGeneratorLoop> PerimeterGeneratorLoops;
class PerimeterGenerator { class PerimeterGenerator {
public: public:
// Inputs:
const SurfaceCollection* slices; const SurfaceCollection* slices;
const ExPolygonCollection* lower_slices; const ExPolygonCollection* lower_slices;
double layer_height; double layer_height;
@ -41,14 +49,26 @@ class PerimeterGenerator {
PrintRegionConfig* config; PrintRegionConfig* config;
PrintObjectConfig* object_config; PrintObjectConfig* object_config;
PrintConfig* print_config; PrintConfig* print_config;
// Outputs:
ExtrusionEntityCollection* loops; ExtrusionEntityCollection* loops;
ExtrusionEntityCollection* gap_fill; ExtrusionEntityCollection* gap_fill;
SurfaceCollection* fill_surfaces; SurfaceCollection* fill_surfaces;
PerimeterGenerator(const SurfaceCollection* slices, double layer_height, Flow flow, PerimeterGenerator(
PrintRegionConfig* config, PrintObjectConfig* object_config, // Input:
PrintConfig* print_config, ExtrusionEntityCollection* loops, const SurfaceCollection* slices,
ExtrusionEntityCollection* gap_fill, SurfaceCollection* fill_surfaces) double layer_height,
Flow flow,
PrintRegionConfig* config,
PrintObjectConfig* object_config,
PrintConfig* print_config,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection* loops,
// Gaps without the thin walls
ExtrusionEntityCollection* gap_fill,
// Infills without the gap fills
SurfaceCollection* fill_surfaces)
: slices(slices), lower_slices(NULL), layer_height(layer_height), : slices(slices), lower_slices(NULL), layer_height(layer_height),
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow), layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
overhang_flow(flow), solid_infill_flow(flow), overhang_flow(flow), solid_infill_flow(flow),

View File

@ -94,6 +94,12 @@ Point::nearest_point_index(const Points &points) const
return this->nearest_point_index(p); return this->nearest_point_index(p);
} }
template<typename T>
inline T sqr(const T x)
{
return x * x;
}
int int
Point::nearest_point_index(const PointConstPtrs &points) const Point::nearest_point_index(const PointConstPtrs &points) const
{ {
@ -103,12 +109,12 @@ Point::nearest_point_index(const PointConstPtrs &points) const
for (PointConstPtrs::const_iterator it = points.begin(); it != points.end(); ++it) { for (PointConstPtrs::const_iterator it = points.begin(); it != points.end(); ++it) {
/* If the X distance of the candidate is > than the total distance of the /* If the X distance of the candidate is > than the total distance of the
best previous candidate, we know we don't want it */ best previous candidate, we know we don't want it */
double d = pow(this->x - (*it)->x, 2); double d = sqr<double>(this->x - (*it)->x);
if (distance != -1 && d > distance) continue; if (distance != -1 && d > distance) continue;
/* If the Y distance of the candidate is > than the total distance of the /* If the Y distance of the candidate is > than the total distance of the
best previous candidate, we know we don't want it */ best previous candidate, we know we don't want it */
d += pow(this->y - (*it)->y, 2); d += sqr<double>(this->y - (*it)->y);
if (distance != -1 && d > distance) continue; if (distance != -1 && d > distance) continue;
idx = it - points.begin(); idx = it - points.begin();
@ -129,10 +135,10 @@ Point::nearest_waypoint_index(const Points &points, const Point &dest) const
for (Points::const_iterator p = points.begin(); p != points.end(); ++p) { for (Points::const_iterator p = points.begin(); p != points.end(); ++p) {
// distance from this to candidate // distance from this to candidate
double d = pow(this->x - p->x, 2) + pow(this->y - p->y, 2); double d = sqr<double>(this->x - p->x) + sqr<double>(this->y - p->y);
// distance from candidate to dest // distance from candidate to dest
d += pow(p->x - dest.x, 2) + pow(p->y - dest.y, 2); d += sqr<double>(p->x - dest.x) + sqr<double>(p->y - dest.y);
// if the total distance is greater than current min distance, ignore it // if the total distance is greater than current min distance, ignore it
if (distance != -1 && d > distance) continue; if (distance != -1 && d > distance) continue;
@ -278,8 +284,10 @@ Point::projection_onto(const Line &line) const
If theta is outside the interval [0,1], then one of the Line_Segment's endpoints If theta is outside the interval [0,1], then one of the Line_Segment's endpoints
must be closest to calling Point. must be closest to calling Point.
*/ */
double theta = ( (double)(line.b.x - this->x)*(double)(line.b.x - line.a.x) + (double)(line.b.y- this->y)*(double)(line.b.y - line.a.y) ) double lx = (double)(line.b.x - line.a.x);
/ ( (double)pow(line.b.x - line.a.x, 2) + (double)pow(line.b.y - line.a.y, 2) ); double ly = (double)(line.b.y - line.a.y);
double theta = ( (double)(line.b.x - this->x)*lx + (double)(line.b.y- this->y)*ly )
/ ( sqr<double>(lx) + sqr<double>(ly) );
if (0.0 <= theta && theta <= 1.0) if (0.0 <= theta && theta <= 1.0)
return theta * line.a + (1.0-theta) * line.b; return theta * line.a + (1.0-theta) * line.b;

View File

@ -44,6 +44,8 @@ class Point
void translate(const Vector &vector); void translate(const Vector &vector);
void rotate(double angle); void rotate(double angle);
void rotate(double angle, const Point &center); void rotate(double angle, const Point &center);
Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; }
Point rotated(double angle, const Point &center) const { Point res(*this); res.rotate(angle, center); return res; }
bool coincides_with(const Point &point) const { return this->x == point.x && this->y == point.y; } bool coincides_with(const Point &point) const { return this->x == point.x && this->y == point.y; }
bool coincides_with_epsilon(const Point &point) const; bool coincides_with_epsilon(const Point &point) const;
int nearest_point_index(const Points &points) const; int nearest_point_index(const Points &points) const;

View File

@ -1,3 +1,4 @@
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "Polygon.hpp" #include "Polygon.hpp"
#include "Polyline.hpp" #include "Polyline.hpp"
@ -59,6 +60,7 @@ Polygon::split_at_vertex(const Point &point) const
return Polyline(); return Polyline();
} }
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
Polyline Polyline
Polygon::split_at_index(int index) const Polygon::split_at_index(int index) const
{ {
@ -71,6 +73,7 @@ Polygon::split_at_index(int index) const
return polyline; return polyline;
} }
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
Polyline Polyline
Polygon::split_at_first_point() const Polygon::split_at_first_point() const
{ {
@ -131,6 +134,8 @@ Polygon::is_valid() const
return this->points.size() >= 3; return this->points.size() >= 3;
} }
// Does an unoriented polygon contain a point?
// Tested by counting intersections along a horizontal line.
bool bool
Polygon::contains(const Point &point) const Polygon::contains(const Point &point) const
{ {
@ -139,9 +144,20 @@ Polygon::contains(const Point &point) const
Points::const_iterator i = this->points.begin(); Points::const_iterator i = this->points.begin();
Points::const_iterator j = this->points.end() - 1; Points::const_iterator j = this->points.end() - 1;
for (; i != this->points.end(); j = i++) { for (; i != this->points.end(); j = i++) {
//FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point.y well.
// Does the ray with y == point.y intersect this line segment?
#if 1
if ( ((i->y > point.y) != (j->y > point.y)) if ( ((i->y > point.y) != (j->y > point.y))
&& ((double)point.x < (double)(j->x - i->x) * (double)(point.y - i->y) / (double)(j->y - i->y) + (double)i->x) ) && ((double)point.x < (double)(j->x - i->x) * (double)(point.y - i->y) / (double)(j->y - i->y) + (double)i->x) )
result = !result; result = !result;
#else
if ((i->y > point.y) != (j->y > point.y)) {
// Orientation predicated relative to i-th point.
double orient = (double)(point.x - i->x) * (double)(j->y - i->y) - (double)(point.y - i->y) * (double)(j->x - i->x);
if ((i->y > j->y) ? (orient > 0.) : (orient < 0.))
result = !result;
}
#endif
} }
return result; return result;
} }
@ -265,4 +281,20 @@ Polygon::convex_points(double angle) const
return points; return points;
} }
BoundingBox get_extents(const Polygon &poly)
{
return poly.bounding_box();
}
BoundingBox get_extents(const Polygons &polygons)
{
BoundingBox bb;
if (! polygons.empty()) {
bb = polygons.front().bounding_box();
for (size_t i = 1; i < polygons.size(); ++ i)
bb.merge(polygons[i]);
}
return bb;
}
} }

View File

@ -25,7 +25,9 @@ class Polygon : public MultiPoint {
Point last_point() const; Point last_point() const;
virtual Lines lines() const; virtual Lines lines() const;
Polyline split_at_vertex(const Point &point) const; Polyline split_at_vertex(const Point &point) const;
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
Polyline split_at_index(int index) const; Polyline split_at_index(int index) const;
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
Polyline split_at_first_point() const; Polyline split_at_first_point() const;
Points equally_spaced_points(double distance) const; Points equally_spaced_points(double distance) const;
double area() const; double area() const;
@ -34,6 +36,8 @@ class Polygon : public MultiPoint {
bool make_counter_clockwise(); bool make_counter_clockwise();
bool make_clockwise(); bool make_clockwise();
bool is_valid() const; bool is_valid() const;
// Does an unoriented polygon contain a point?
// Tested by counting intersections along a horizontal line.
bool contains(const Point &point) const; bool contains(const Point &point) const;
Polygons simplify(double tolerance) const; Polygons simplify(double tolerance) const;
void simplify(double tolerance, Polygons &polygons) const; void simplify(double tolerance, Polygons &polygons) const;
@ -44,6 +48,9 @@ class Polygon : public MultiPoint {
Points convex_points(double angle = PI) const; Points convex_points(double angle = PI) const;
}; };
extern BoundingBox get_extents(const Polygon &poly);
extern BoundingBox get_extents(const Polygons &polygons);
} }
// start Boost // start Boost

View File

@ -639,7 +639,7 @@ Print::validate() const
if (!object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value)) if (!object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value))
throw PrintValidationException("Some objects are too tall and cannot be printed without extruder collisions."); throw PrintValidationException("Some objects are too tall and cannot be printed without extruder collisions.");
} }
} } // end if (this->config.complete_objects)
if (this->config.spiral_vase) { if (this->config.spiral_vase) {
size_t total_copies_count = 0; size_t total_copies_count = 0;
@ -837,6 +837,7 @@ Print::auto_assign_extruders(ModelObject* model_object) const
size_t extruders = this->config.nozzle_diameter.values.size(); size_t extruders = this->config.nozzle_diameter.values.size();
for (ModelVolumePtrs::const_iterator v = model_object->volumes.begin(); v != model_object->volumes.end(); ++v) { for (ModelVolumePtrs::const_iterator v = model_object->volumes.begin(); v != model_object->volumes.end(); ++v) {
if (!(*v)->material_id().empty()) { if (!(*v)->material_id().empty()) {
//FIXME Vojtech: This assigns an extruder ID even to a modifier volume, if it has a material assigned.
size_t extruder_id = (v - model_object->volumes.begin()) + 1; size_t extruder_id = (v - model_object->volumes.begin()) + 1;
if (!(*v)->config.has("extruder")) if (!(*v)->config.has("extruder"))
(*v)->config.opt<ConfigOptionInt>("extruder", true)->value = extruder_id; (*v)->config.opt<ConfigOptionInt>("extruder", true)->value = extruder_id;

View File

@ -20,7 +20,7 @@ class Print;
class PrintObject; class PrintObject;
class ModelObject; class ModelObject;
// Print step IDs for keeping track of the print state.
enum PrintStep { enum PrintStep {
psSkirt, psBrim, psSkirt, psBrim,
}; };
@ -34,6 +34,7 @@ class PrintValidationException : public std::runtime_error {
PrintValidationException(const std::string &error) : std::runtime_error(error) {}; PrintValidationException(const std::string &error) : std::runtime_error(error) {};
}; };
// To be instantiated over PrintStep or PrintObjectStep enums.
template <class StepType> template <class StepType>
class PrintState class PrintState
{ {
@ -120,6 +121,7 @@ class PrintObject
size_t layer_count() const; size_t layer_count() const;
void clear_layers(); void clear_layers();
Layer* get_layer(int idx); Layer* get_layer(int idx);
// print_z: top of the layer; slice_z: center of the layer.
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z); Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
void delete_layer(int idx); void delete_layer(int idx);
@ -152,6 +154,7 @@ class PrintObject
typedef std::vector<PrintObject*> PrintObjectPtrs; typedef std::vector<PrintObject*> PrintObjectPtrs;
typedef std::vector<PrintRegion*> PrintRegionPtrs; typedef std::vector<PrintRegion*> PrintRegionPtrs;
// The complete print tray with possibly multiple objects.
class Print class Print
{ {
public: public:

View File

@ -885,11 +885,37 @@ PrintConfigDef::PrintConfigDef()
def->enum_values.push_back("random"); def->enum_values.push_back("random");
def->enum_values.push_back("nearest"); def->enum_values.push_back("nearest");
def->enum_values.push_back("aligned"); def->enum_values.push_back("aligned");
// def->enum_values.push_back("preferred");
def->enum_labels.push_back("Random"); def->enum_labels.push_back("Random");
def->enum_labels.push_back("Nearest"); def->enum_labels.push_back("Nearest");
def->enum_labels.push_back("Aligned"); def->enum_labels.push_back("Aligned");
// def->enum_labels.push_back("Preferred Direction");
def->default_value = new ConfigOptionEnum<SeamPosition>(spAligned); def->default_value = new ConfigOptionEnum<SeamPosition>(spAligned);
#if 0
def = this->add("seam_preferred_direction", coFloat);
// def->gui_type = "slider";
def->label = "Direction";
def->sidetext = "°";
def->full_label = "Preferred direction of the seam";
def->tooltip = "Seam preferred direction";
def->cli = "seam-preferred-direction=f";
def->min = 0;
def->max = 360;
def->default_value = new ConfigOptionFloat(0);
def = this->add("seam_preferred_direction_jitter", coFloat);
// def->gui_type = "slider";
def->label = "Jitter";
def->sidetext = "°";
def->full_label = "Seam preferred direction jitter";
def->tooltip = "Preferred direction of the seam - jitter";
def->cli = "seam-preferred-direction-jitter=f";
def->min = 0;
def->max = 360;
def->default_value = new ConfigOptionFloat(30);
#endif
def = this->add("serial_port", coString); def = this->add("serial_port", coString);
def->gui_type = "select_open"; def->gui_type = "select_open";
def->label = ""; def->label = "";

View File

@ -1,3 +1,20 @@
// Configuration store of Slic3r.
//
// The configuration store is either static or dynamic.
// DynamicPrintConfig is used mainly at the user interface. while the StaticPrintConfig is used
// during the slicing and the g-code generation.
//
// The classes derived from StaticPrintConfig form a following hierarchy.
// Virtual inheritance is used for some of the parent objects.
//
// FullPrintConfig
// PrintObjectConfig
// PrintRegionConfig
// PrintConfig
// GCodeConfig
// HostConfig
//
#ifndef slic3r_PrintConfig_hpp_ #ifndef slic3r_PrintConfig_hpp_
#define slic3r_PrintConfig_hpp_ #define slic3r_PrintConfig_hpp_
@ -22,7 +39,7 @@ enum SupportMaterialPattern {
}; };
enum SeamPosition { enum SeamPosition {
spRandom, spNearest, spAligned spRandom, spNearest, spAligned //, spPreferred
}; };
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() { template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
@ -65,17 +82,23 @@ template<> inline t_config_enum_values ConfigOptionEnum<SeamPosition>::get_enum_
keys_map["random"] = spRandom; keys_map["random"] = spRandom;
keys_map["nearest"] = spNearest; keys_map["nearest"] = spNearest;
keys_map["aligned"] = spAligned; keys_map["aligned"] = spAligned;
// keys_map["preferred"] = spPreferred;
return keys_map; return keys_map;
} }
// Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs.
// Does not store the actual values, but defines default values.
class PrintConfigDef : public ConfigDef class PrintConfigDef : public ConfigDef
{ {
public: public:
PrintConfigDef(); PrintConfigDef();
}; };
// The one and only global definition of SLic3r configuration options.
// This definition is constant.
extern PrintConfigDef print_config_def; extern PrintConfigDef print_config_def;
// Slic3r configuration storage with print_config_def assigned.
class PrintConfigBase : public virtual ConfigBase class PrintConfigBase : public virtual ConfigBase
{ {
public: public:
@ -86,6 +109,12 @@ class PrintConfigBase : public virtual ConfigBase
double min_object_distance() const; double min_object_distance() const;
}; };
// Slic3r dynamic configuration, used to override the configuration
// per object, per modification volume or per printing material.
// The dynamic configuration is also used to store user modifications of the print global parameters,
// so the modified configuration values may be diffed against the active configuration
// to invalidate the proper slicing resp. g-code generation processing steps.
// This object is mapped to Perl as Slic3r::Config.
class DynamicPrintConfig : public PrintConfigBase, public DynamicConfig class DynamicPrintConfig : public PrintConfigBase, public DynamicConfig
{ {
public: public:
@ -93,12 +122,14 @@ class DynamicPrintConfig : public PrintConfigBase, public DynamicConfig
void normalize(); void normalize();
}; };
class StaticPrintConfig : public PrintConfigBase, public StaticConfig class StaticPrintConfig : public PrintConfigBase, public StaticConfig
{ {
public: public:
StaticPrintConfig() : PrintConfigBase(), StaticConfig() {}; StaticPrintConfig() : PrintConfigBase(), StaticConfig() {};
}; };
// This object is mapped to Perl as Slic3r::Config::PrintObject.
class PrintObjectConfig : public virtual StaticPrintConfig class PrintObjectConfig : public virtual StaticPrintConfig
{ {
public: public:
@ -110,6 +141,8 @@ class PrintObjectConfig : public virtual StaticPrintConfig
ConfigOptionFloat layer_height; ConfigOptionFloat layer_height;
ConfigOptionInt raft_layers; ConfigOptionInt raft_layers;
ConfigOptionEnum<SeamPosition> seam_position; ConfigOptionEnum<SeamPosition> seam_position;
// ConfigOptionFloat seam_preferred_direction;
// ConfigOptionFloat seam_preferred_direction_jitter;
ConfigOptionBool support_material; ConfigOptionBool support_material;
ConfigOptionInt support_material_angle; ConfigOptionInt support_material_angle;
ConfigOptionFloat support_material_contact_distance; ConfigOptionFloat support_material_contact_distance;
@ -130,7 +163,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
if (initialize) if (initialize)
this->set_defaults(); this->set_defaults();
} }
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(dont_support_bridges); OPT_PTR(dont_support_bridges);
OPT_PTR(extrusion_width); OPT_PTR(extrusion_width);
@ -140,6 +173,8 @@ class PrintObjectConfig : public virtual StaticPrintConfig
OPT_PTR(layer_height); OPT_PTR(layer_height);
OPT_PTR(raft_layers); OPT_PTR(raft_layers);
OPT_PTR(seam_position); OPT_PTR(seam_position);
// OPT_PTR(seam_preferred_direction);
// OPT_PTR(seam_preferred_direction_jitter);
OPT_PTR(support_material); OPT_PTR(support_material);
OPT_PTR(support_material_angle); OPT_PTR(support_material_angle);
OPT_PTR(support_material_contact_distance); OPT_PTR(support_material_contact_distance);
@ -160,6 +195,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
}; };
}; };
// This object is mapped to Perl as Slic3r::Config::PrintRegion.
class PrintRegionConfig : public virtual StaticPrintConfig class PrintRegionConfig : public virtual StaticPrintConfig
{ {
public: public:
@ -200,7 +236,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
if (initialize) if (initialize)
this->set_defaults(); this->set_defaults();
} }
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(bottom_solid_layers); OPT_PTR(bottom_solid_layers);
OPT_PTR(bridge_flow_ratio); OPT_PTR(bridge_flow_ratio);
@ -239,6 +275,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
}; };
}; };
// This object is mapped to Perl as Slic3r::Config::GCode.
class GCodeConfig : public virtual StaticPrintConfig class GCodeConfig : public virtual StaticPrintConfig
{ {
public: public:
@ -315,6 +352,7 @@ class GCodeConfig : public virtual StaticPrintConfig
}; };
}; };
// This object is mapped to Perl as Slic3r::Config::Print.
class PrintConfig : public GCodeConfig class PrintConfig : public GCodeConfig
{ {
public: public:
@ -373,7 +411,7 @@ class PrintConfig : public GCodeConfig
if (initialize) if (initialize)
this->set_defaults(); this->set_defaults();
} }
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(avoid_crossing_perimeters); OPT_PTR(avoid_crossing_perimeters);
OPT_PTR(bed_shape); OPT_PTR(bed_shape);
@ -446,7 +484,7 @@ class HostConfig : public virtual StaticPrintConfig
if (initialize) if (initialize)
this->set_defaults(); this->set_defaults();
} }
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(octoprint_host); OPT_PTR(octoprint_host);
OPT_PTR(octoprint_apikey); OPT_PTR(octoprint_apikey);
@ -457,6 +495,7 @@ class HostConfig : public virtual StaticPrintConfig
}; };
}; };
// This object is mapped to Perl as Slic3r::Config::Full.
class FullPrintConfig class FullPrintConfig
: public PrintObjectConfig, public PrintRegionConfig, public PrintConfig, public HostConfig : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig, public HostConfig
{ {

View File

@ -270,6 +270,8 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
steps.insert(posPerimeters); steps.insert(posPerimeters);
steps.insert(posInfill); steps.insert(posInfill);
} else if (*opt_key == "seam_position" } else if (*opt_key == "seam_position"
|| *opt_key == "seam_preferred_direction"
|| *opt_key == "seam_preferred_direction_jitter"
|| *opt_key == "support_material_speed" || *opt_key == "support_material_speed"
|| *opt_key == "bridge_speed" || *opt_key == "bridge_speed"
|| *opt_key == "external_perimeter_speed" || *opt_key == "external_perimeter_speed"

View File

@ -1,12 +1,12 @@
#include "SVG.hpp" #include "SVG.hpp"
#include <iostream> #include <iostream>
#define COORD(x) ((float)unscale(x)*10) #define COORD(x) ((float)unscale((x))*10)
namespace Slic3r { namespace Slic3r {
SVG::SVG(const char* filename) SVG::SVG(const char* filename)
: arrows(false), fill("grey"), stroke("black"), filename(filename) : arrows(false), fill("grey"), stroke("black"), filename(filename), flipY(false)
{ {
this->f = fopen(filename, "w"); this->f = fopen(filename, "w");
fprintf(this->f, fprintf(this->f,
@ -19,12 +19,12 @@ SVG::SVG(const char* filename)
); );
} }
SVG::SVG(const char* filename, const BoundingBox &bbox) SVG::SVG(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset, bool aflipY)
: arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min) : arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY)
{ {
this->f = fopen(filename, "w"); this->f = fopen(filename, "w");
float w = COORD(bbox.max.x - bbox.min.x); float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset);
float h = COORD(bbox.max.y - bbox.min.y); float h = COORD(bbox.max.y - bbox.min.y + 2 * bbox_offset);
fprintf(this->f, fprintf(this->f,
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
@ -36,7 +36,7 @@ SVG::SVG(const char* filename, const BoundingBox &bbox)
} }
void void
SVG::draw(const Line &line, std::string stroke, coord_t stroke_width) SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
{ {
fprintf(this->f, fprintf(this->f,
" <line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke: %s; stroke-width: %f\"", " <line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke: %s; stroke-width: %f\"",
@ -46,7 +46,7 @@ SVG::draw(const Line &line, std::string stroke, coord_t stroke_width)
fprintf(this->f, "/>\n"); fprintf(this->f, "/>\n");
} }
void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coord_t stroke_width) void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
{ {
Pointf dir(line.b.x-line.a.x, line.b.y-line.a.y); Pointf dir(line.b.x-line.a.x, line.b.y-line.a.y);
Pointf perp(-dir.y, dir.x); Pointf perp(-dir.y, dir.x);
@ -68,10 +68,10 @@ void SVG::draw(const ThickLine &line, const std::string &fill, const std::string
} }
void void
SVG::draw(const Lines &lines, std::string stroke) SVG::draw(const Lines &lines, std::string stroke, coordf_t stroke_width)
{ {
for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it) for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it)
this->draw(*it, stroke); this->draw(*it, stroke, stroke_width);
} }
void void
@ -91,7 +91,7 @@ SVG::draw(const ExPolygon &expolygon, std::string fill)
for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) { for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) {
d += this->get_path_d(*p, true) + " "; d += this->get_path_d(*p, true) + " ";
} }
this->path(d, true); this->path(d, true, 0);
} }
void void
@ -105,7 +105,7 @@ void
SVG::draw(const Polygon &polygon, std::string fill) SVG::draw(const Polygon &polygon, std::string fill)
{ {
this->fill = fill; this->fill = fill;
this->path(this->get_path_d(polygon, true), !fill.empty()); this->path(this->get_path_d(polygon, true), !fill.empty(), 0);
} }
void void
@ -116,34 +116,34 @@ SVG::draw(const Polygons &polygons, std::string fill)
} }
void void
SVG::draw(const Polyline &polyline, std::string stroke, coord_t stroke_width) SVG::draw(const Polyline &polyline, std::string stroke, coordf_t stroke_width)
{ {
this->stroke = stroke; this->stroke = stroke;
this->path(this->get_path_d(polyline, false), false, stroke_width); this->path(this->get_path_d(polyline, false), false, stroke_width);
} }
void void
SVG::draw(const Polylines &polylines, std::string stroke, coord_t stroke_width) SVG::draw(const Polylines &polylines, std::string stroke, coordf_t stroke_width)
{ {
for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
this->draw(*it, fill, stroke_width); this->draw(*it, fill, stroke_width);
} }
void SVG::draw(const ThickLines &thicklines, const std::string &fill, const std::string &stroke, coord_t stroke_width) void SVG::draw(const ThickLines &thicklines, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
{ {
for (ThickLines::const_iterator it = thicklines.begin(); it != thicklines.end(); ++it) for (ThickLines::const_iterator it = thicklines.begin(); it != thicklines.end(); ++it)
this->draw(*it, fill, stroke, stroke_width); this->draw(*it, fill, stroke, stroke_width);
} }
void void
SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coord_t stroke_width) SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coordf_t stroke_width)
{ {
for (ThickPolylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) for (ThickPolylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
this->draw((Polyline)*it, stroke, stroke_width); this->draw((Polyline)*it, stroke, stroke_width);
} }
void void
SVG::draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coord_t stroke_width) SVG::draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
{ {
for (ThickPolylines::const_iterator it = thickpolylines.begin(); it != thickpolylines.end(); ++ it) for (ThickPolylines::const_iterator it = thickpolylines.begin(); it != thickpolylines.end(); ++ it)
draw(it->thicklines(), fill, stroke, stroke_width); draw(it->thicklines(), fill, stroke, stroke_width);
@ -168,8 +168,36 @@ SVG::draw(const Points &points, std::string fill, coord_t radius)
this->draw(*it, fill, radius); this->draw(*it, fill, radius);
} }
void
SVG::draw(const ClipperLib::Path &polygon, double scale, std::string stroke, coordf_t stroke_width)
{
this->stroke = stroke;
this->path(this->get_path_d(polygon, scale, true), false, stroke_width);
}
void
SVG::draw(const ClipperLib::Paths &polygons, double scale, std::string stroke, coordf_t stroke_width)
{
for (ClipperLib::Paths::const_iterator it = polygons.begin(); it != polygons.end(); ++ it)
draw(*it, scale, stroke, stroke_width);
}
void
SVG::draw_outline(const Polygon &polygon, std::string stroke, coordf_t stroke_width)
{
this->stroke = stroke;
this->path(this->get_path_d(polygon, true), false, stroke_width);
}
void
SVG::draw_outline(const Polygons &polygons, std::string stroke, coordf_t stroke_width)
{
for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++ it)
draw_outline(*it, stroke, stroke_width);
}
void void
SVG::path(const std::string &d, bool fill, coord_t stroke_width) SVG::path(const std::string &d, bool fill, coordf_t stroke_width)
{ {
float lineWidth = 0.f; float lineWidth = 0.f;
if (! fill) if (! fill)
@ -199,6 +227,19 @@ SVG::get_path_d(const MultiPoint &mp, bool closed) const
return d.str(); return d.str();
} }
std::string
SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const
{
std::ostringstream d;
d << "M ";
for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) {
d << COORD(scale * p->X - origin.x) << " ";
d << COORD(scale * p->Y - origin.y) << " ";
}
if (closed) d << "z";
return d.str();
}
void void
SVG::Close() SVG::Close()
{ {

View File

@ -2,6 +2,7 @@
#define slic3r_SVG_hpp_ #define slic3r_SVG_hpp_
#include "libslic3r.h" #include "libslic3r.h"
#include "clipper.hpp"
#include "ExPolygon.hpp" #include "ExPolygon.hpp"
#include "Line.hpp" #include "Line.hpp"
#include "TriangleMesh.hpp" #include "TriangleMesh.hpp"
@ -14,34 +15,43 @@ class SVG
bool arrows; bool arrows;
std::string fill, stroke; std::string fill, stroke;
Point origin; Point origin;
bool flipY;
SVG(const char* filename); SVG(const char* filename);
SVG(const char* filename, const BoundingBox &bbox); SVG(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false);
~SVG() { if (f != NULL) Close(); } ~SVG() { if (f != NULL) Close(); }
void draw(const Line &line, std::string stroke = "black", coord_t stroke_width = 0); void draw(const Line &line, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coord_t stroke_width = 0); void draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width = 0);
void draw(const Lines &lines, std::string stroke = "black"); void draw(const Lines &lines, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const IntersectionLines &lines, std::string stroke = "black"); void draw(const IntersectionLines &lines, std::string stroke = "black");
void draw(const ExPolygon &expolygon, std::string fill = "grey"); void draw(const ExPolygon &expolygon, std::string fill = "grey");
void draw(const ExPolygons &expolygons, std::string fill = "grey"); void draw(const ExPolygons &expolygons, std::string fill = "grey");
void draw(const Polygon &polygon, std::string fill = "grey"); void draw(const Polygon &polygon, std::string fill = "grey");
void draw_outline(const Polygon &polygon, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const Polygons &polygons, std::string fill = "grey"); void draw(const Polygons &polygons, std::string fill = "grey");
void draw(const Polyline &polyline, std::string stroke = "black", coord_t stroke_width = 0); void draw_outline(const Polygons &polygons, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const Polylines &polylines, std::string stroke = "black", coord_t stroke_width = 0); void draw(const Polyline &polyline, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const ThickLines &thicklines, const std::string &fill = "lime", const std::string &stroke = "black", coord_t stroke_width = 0); void draw(const Polylines &polylines, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const ThickPolylines &polylines, const std::string &stroke = "black", coord_t stroke_width = 0); void draw(const ThickLines &thicklines, const std::string &fill = "lime", const std::string &stroke = "black", coordf_t stroke_width = 0);
void draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coord_t stroke_width); void draw(const ThickPolylines &polylines, const std::string &stroke = "black", coordf_t stroke_width = 0);
void draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coordf_t stroke_width);
void draw(const Point &point, std::string fill = "black", coord_t radius = 0); void draw(const Point &point, std::string fill = "black", coord_t radius = 0);
void draw(const Points &points, std::string fill = "black", coord_t radius = 0); void draw(const Points &points, std::string fill = "black", coord_t radius = 0);
// Support for rendering the ClipperLib paths
void draw(const ClipperLib::Path &polygon, double scale, std::string fill = "grey", coordf_t stroke_width = 0);
void draw(const ClipperLib::Paths &polygons, double scale, std::string fill = "grey", coordf_t stroke_width = 0);
void Close(); void Close();
private: private:
std::string filename; std::string filename;
FILE* f; FILE* f;
void path(const std::string &d, bool fill, coord_t stroke_width = 0); void path(const std::string &d, bool fill, coordf_t stroke_width);
std::string get_path_d(const MultiPoint &mp, bool closed = false) const; std::string get_path_d(const MultiPoint &mp, bool closed = false) const;
std::string get_path_d(const ClipperLib::Path &mp, double scale, bool closed = false) const;
}; };
} }

View File

@ -1,3 +1,4 @@
#include "BoundingBox.hpp"
#include "Surface.hpp" #include "Surface.hpp"
namespace Slic3r { namespace Slic3r {
@ -54,4 +55,31 @@ Surface::is_bridge() const
|| this->surface_type == stInternalBridge; || this->surface_type == stInternalBridge;
} }
BoundingBox get_extents(const Surface &surface)
{
return get_extents(surface.expolygon.contour);
}
BoundingBox get_extents(const Surfaces &surfaces)
{
BoundingBox bbox;
if (! surfaces.empty()) {
bbox = get_extents(surfaces.front());
for (size_t i = 1; i < surfaces.size(); ++ i)
bbox.merge(get_extents(surfaces[i]));
}
return bbox;
}
BoundingBox get_extents(const SurfacesPtr &surfaces)
{
BoundingBox bbox;
if (! surfaces.empty()) {
bbox = get_extents(*surfaces.front());
for (size_t i = 1; i < surfaces.size(); ++ i)
bbox.merge(get_extents(*surfaces[i]));
}
return bbox;
}
} }

View File

@ -34,6 +34,10 @@ class Surface
typedef std::vector<Surface> Surfaces; typedef std::vector<Surface> Surfaces;
typedef std::vector<Surface*> SurfacesPtr; typedef std::vector<Surface*> SurfacesPtr;
extern BoundingBox get_extents(const Surface &surface);
extern BoundingBox get_extents(const Surfaces &surfaces);
extern BoundingBox get_extents(const SurfacesPtr &surfaces);
} }
#endif #endif

View File

@ -8,12 +8,22 @@
#define SLIC3R_VERSION "1.3.0-dev" #define SLIC3R_VERSION "1.3.0-dev"
//FIXME This epsilon value is used for many non-related purposes:
// For a threshold of a squared Euclidean distance,
// for a trheshold in a difference of radians,
// for a threshold of a cross product of two non-normalized vectors etc.
#define EPSILON 1e-4 #define EPSILON 1e-4
// Scaling factor for a conversion from coord_t to coordf_t: 10e-6
// This scaling generates a following fixed point representation with for a 32bit integer:
// 0..4294mm with 1nm resolution
#define SCALING_FACTOR 0.000001 #define SCALING_FACTOR 0.000001
// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm.
#define RESOLUTION 0.0125 #define RESOLUTION 0.0125
#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR) #define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR)
#define PI 3.141592653589793238 #define PI 3.141592653589793238
// When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam.
#define LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER 0.15 #define LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER 0.15
// Maximum perimeter length for the loop to apply the small perimeter speed.
#define SMALL_PERIMETER_LENGTH (6.5 / SCALING_FACTOR) * 2 * PI #define SMALL_PERIMETER_LENGTH (6.5 / SCALING_FACTOR) * 2 * PI
#define INSET_OVERLAP_TOLERANCE 0.4 #define INSET_OVERLAP_TOLERANCE 0.4
#define EXTERNAL_INFILL_MARGIN 3 #define EXTERNAL_INFILL_MARGIN 3

View File

@ -19,13 +19,15 @@
Clone<Polygon> polygon(); Clone<Polygon> polygon();
Clone<Point> size(); Clone<Point> size();
Clone<Point> center(); Clone<Point> center();
double radius();
Clone<Point> min_point() %code{% RETVAL = THIS->min; %}; Clone<Point> min_point() %code{% RETVAL = THIS->min; %};
Clone<Point> max_point() %code{% RETVAL = THIS->max; %}; Clone<Point> max_point() %code{% RETVAL = THIS->max; %};
long x_min() %code{% RETVAL = THIS->min.x; %}; long x_min() %code{% RETVAL = THIS->min.x; %};
long x_max() %code{% RETVAL = THIS->max.x; %}; long x_max() %code{% RETVAL = THIS->max.x; %};
long y_min() %code{% RETVAL = THIS->min.y; %}; long y_min() %code{% RETVAL = THIS->min.y; %};
long y_max() %code{% RETVAL = THIS->max.y; %}; long y_max() %code{% RETVAL = THIS->max.y; %};
std::string serialize() %code{% char buf[2048]; sprintf(buf, "%d,%d;%d,%d", THIS->min.x, THIS->min.y, THIS->max.x, THIS->max.y); RETVAL = buf; %};
%{ %{
BoundingBox* BoundingBox*
@ -51,6 +53,7 @@ new_from_points(CLASS, points)
void translate(double x, double y); void translate(double x, double y);
Clone<Pointf> size(); Clone<Pointf> size();
Clone<Pointf> center(); Clone<Pointf> center();
double radius();
Clone<Pointf> min_point() %code{% RETVAL = THIS->min; %}; Clone<Pointf> min_point() %code{% RETVAL = THIS->min; %};
Clone<Pointf> max_point() %code{% RETVAL = THIS->max; %}; Clone<Pointf> max_point() %code{% RETVAL = THIS->max; %};
double x_min() %code{% RETVAL = THIS->min.x; %}; double x_min() %code{% RETVAL = THIS->min.x; %};
@ -61,7 +64,8 @@ new_from_points(CLASS, points)
void set_x_max(double val) %code{% THIS->max.x = val; %}; void set_x_max(double val) %code{% THIS->max.x = val; %};
void set_y_min(double val) %code{% THIS->min.y = val; %}; void set_y_min(double val) %code{% THIS->min.y = val; %};
void set_y_max(double val) %code{% THIS->max.y = val; %}; void set_y_max(double val) %code{% THIS->max.y = val; %};
std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf;%lf,%lf", THIS->min.x, THIS->min.y, THIS->max.x, THIS->max.y); RETVAL = buf; %};
%{ %{
BoundingBoxf* BoundingBoxf*
@ -87,6 +91,7 @@ new_from_points(CLASS, points)
void translate(double x, double y, double z); void translate(double x, double y, double z);
Clone<Pointf3> size(); Clone<Pointf3> size();
Clone<Pointf3> center(); Clone<Pointf3> center();
double radius();
Clone<Pointf3> min_point() %code{% RETVAL = THIS->min; %}; Clone<Pointf3> min_point() %code{% RETVAL = THIS->min; %};
Clone<Pointf3> max_point() %code{% RETVAL = THIS->max; %}; Clone<Pointf3> max_point() %code{% RETVAL = THIS->max; %};
double x_min() %code{% RETVAL = THIS->min.x; %}; double x_min() %code{% RETVAL = THIS->min.x; %};
@ -95,4 +100,5 @@ new_from_points(CLASS, points)
double y_max() %code{% RETVAL = THIS->max.y; %}; double y_max() %code{% RETVAL = THIS->max.y; %};
double z_min() %code{% RETVAL = THIS->min.z; %}; double z_min() %code{% RETVAL = THIS->min.z; %};
double z_max() %code{% RETVAL = THIS->max.z; %}; double z_max() %code{% RETVAL = THIS->max.z; %};
std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf;%lf,%lf,%lf", THIS->min.x, THIS->min.y, THIS->min.z, THIS->max.x, THIS->max.y, THIS->max.z); RETVAL = buf; %};
}; };

View File

@ -49,6 +49,7 @@
%code{% RETVAL = new Point(THIS->negative()); %}; %code{% RETVAL = new Point(THIS->negative()); %};
bool coincides_with_epsilon(Point* point) bool coincides_with_epsilon(Point* point)
%code{% RETVAL = THIS->coincides_with_epsilon(*point); %}; %code{% RETVAL = THIS->coincides_with_epsilon(*point); %};
std::string serialize() %code{% char buf[2048]; sprintf(buf, "%d,%d", THIS->x, THIS->y); RETVAL = buf; %};
%{ %{
@ -86,6 +87,7 @@ Point::coincides_with(point_sv)
%code{% RETVAL = THIS->y; %}; %code{% RETVAL = THIS->y; %};
long z() long z()
%code{% RETVAL = THIS->z; %}; %code{% RETVAL = THIS->z; %};
std::string serialize() %code{% char buf[2048]; sprintf(buf, "%d,%d,%d", THIS->x, THIS->y, THIS->z); RETVAL = buf; %};
}; };
%name{Slic3r::Pointf} class Pointf { %name{Slic3r::Pointf} class Pointf {
@ -113,6 +115,7 @@ Point::coincides_with(point_sv)
%code{% RETVAL = THIS->negative(); %}; %code{% RETVAL = THIS->negative(); %};
Clone<Pointf> vector_to(Pointf* point) Clone<Pointf> vector_to(Pointf* point)
%code{% RETVAL = THIS->vector_to(*point); %}; %code{% RETVAL = THIS->vector_to(*point); %};
std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf", THIS->x, THIS->y); RETVAL = buf; %};
}; };
%name{Slic3r::Pointf3} class Pointf3 { %name{Slic3r::Pointf3} class Pointf3 {
@ -140,4 +143,5 @@ Point::coincides_with(point_sv)
%code{% RETVAL = THIS->negative(); %}; %code{% RETVAL = THIS->negative(); %};
Clone<Pointf3> vector_to(Pointf3* point) Clone<Pointf3> vector_to(Pointf3* point)
%code{% RETVAL = THIS->vector_to(*point); %}; %code{% RETVAL = THIS->vector_to(*point); %};
std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf", THIS->x, THIS->y, THIS->z); RETVAL = buf; %};
}; };