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;
}
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
BoundingBoxBase<PointClass>::scale(double factor)
{
@ -163,6 +183,26 @@ BoundingBox3Base<PointClass>::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
BoundingBoxBase<PointClass>::translate(coordf_t x, coordf_t y)
{

View File

@ -28,6 +28,7 @@ class BoundingBoxBase
void merge(const BoundingBoxBase<PointClass> &bb);
void scale(double factor);
PointClass size() const;
double radius() const;
void translate(coordf_t x, coordf_t y);
void offset(coordf_t delta);
PointClass center() const;
@ -44,6 +45,7 @@ class BoundingBox3Base : public BoundingBoxBase<PointClass>
void merge(const std::vector<PointClass> &points);
void merge(const BoundingBox3Base<PointClass> &bb);
PointClass size() const;
double radius() const;
void translate(coordf_t x, coordf_t y, coordf_t z);
void offset(coordf_t delta);
PointClass center() const;
@ -54,6 +56,10 @@ class BoundingBox : public BoundingBoxBase<Point>
public:
void polygon(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(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {};
@ -100,7 +106,9 @@ inline bool empty(const BoundingBoxBase<VT> &bb)
template<typename VT>
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

View File

@ -1,6 +1,12 @@
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
// #define CLIPPER_UTILS_DEBUG
#ifdef CLIPPER_UTILS_DEBUG
#include "SVG.hpp"
#endif /* CLIPPER_UTILS_DEBUG */
namespace Slic3r {
//-----------------------------------------------------------
@ -226,6 +232,19 @@ void
offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1,
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
ClipperLib::Paths input;
Slic3rMultiPoints_to_ClipperPaths(polygons, &input);
@ -245,12 +264,18 @@ offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
ClipperLib::Paths output1;
co.AddPaths(input, joinType, ClipperLib::etClosedPolygon);
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
co.Clear();
co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon);
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
scaleClipperPolygons(*retval, 1/scale);
}

View File

@ -14,6 +14,11 @@ using ClipperLib::jtSquare;
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
//-----------------------------------------------------------

View File

@ -39,8 +39,8 @@ ConfigDef::add(const t_config_option_key &opt_key, ConfigOptionType type)
const ConfigOptionDef*
ConfigDef::get(const t_config_option_key &opt_key) const
{
if (this->options.count(opt_key) == 0) return NULL;
return &const_cast<ConfigDef*>(this)->options[opt_key];
t_optiondef_map::iterator it = const_cast<ConfigDef*>(this)->options.find(opt_key);
return (it == this->options.end()) ? NULL : &it->second;
}
bool
@ -113,6 +113,8 @@ ConfigBase::set_deserialize(const t_config_option_key &opt_key, std::string 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
ConfigBase::get_abs_value(const t_config_option_key &opt_key) {
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
ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) {
// get stored option value
@ -180,6 +184,7 @@ DynamicConfig& DynamicConfig::operator= (DynamicConfig other)
void
DynamicConfig::swap(DynamicConfig &other)
{
std::swap(this->def, other.def);
std::swap(this->options, other.options);
}
@ -197,7 +202,8 @@ DynamicConfig::DynamicConfig (const DynamicConfig& other) {
ConfigOption*
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) {
const ConfigOptionDef* optdef = this->def->get(opt_key);
assert(optdef != NULL);
@ -239,7 +245,7 @@ DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) {
return NULL;
}
}
return this->options[opt_key];
return it->second;
}
template<class T>
@ -273,7 +279,6 @@ StaticConfig::set_defaults()
t_config_option_keys keys = this->keys();
for (t_config_option_keys::const_iterator it = keys.begin(); it != keys.end(); ++it) {
const ConfigOptionDef* def = this->def->get(*it);
if (def->default_value != NULL)
this->option(*it)->set(*def->default_value);
}

View File

@ -14,9 +14,11 @@
namespace Slic3r {
// Name of the configuration option.
typedef std::string t_config_option_key;
typedef std::vector<std::string> t_config_option_keys;
// A generic value of a configuration option.
class ConfigOption {
public:
virtual ~ConfigOption() {};
@ -31,6 +33,7 @@ class ConfigOption {
friend bool operator!= (const ConfigOption &a, const ConfigOption &b);
};
// Value of a single valued option (bool, int, float, string, point, enum)
template <class T>
class ConfigOptionSingle : public ConfigOption {
public:
@ -44,12 +47,14 @@ class ConfigOptionSingle : public ConfigOption {
};
};
// Value of a vector valued option (bools, ints, floats, strings, points)
class ConfigOptionVectorBase : public ConfigOption {
public:
virtual ~ConfigOptionVectorBase() {};
virtual std::vector<std::string> vserialize() const = 0;
};
// Value of a vector valued option (bools, ints, floats, strings, points), template
template <class T>
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;
template <class T>
@ -461,11 +467,14 @@ class ConfigOptionEnum : public ConfigOptionSingle<T>
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();
};
/* We use this one in DynamicConfig objects, otherwise it's better to use
the specialized ConfigOptionEnum<T> containers. */
// Generic enum configuration value.
// 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
{
public:
@ -485,57 +494,117 @@ class ConfigOptionEnumGeneric : public ConfigOptionInt
};
};
// Type of a configuration value.
enum ConfigOptionType {
coNone,
// single float
coFloat,
// vector of floats
coFloats,
// single int
coInt,
// vector of ints
coInts,
// single string
coString,
// vector of strings
coStrings,
// percent value. Currently only used for infill.
coPercent,
// a fraction or an absolute value
coFloatOrPercent,
// single 2d point. Currently not used.
coPoint,
// vector of 2d points. Currently used for the definition of the print bed and for the extruder offsets.
coPoints,
// single boolean value
coBool,
// vector of boolean values
coBools,
// a generic enum
coEnum,
};
// Definition of a configuration value for the purpose of GUI presentation, editing, value mapping and config file handling.
class ConfigOptionDef
{
public:
// What type? bool, int, string etc.
ConfigOptionType type;
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
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;
// 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;
// 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 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;
// A tooltip text shown in the GUI.
std::string tooltip;
// Text right from the input field, usually a unit of measurement.
std::string sidetext;
// Format of this parameter on a command line.
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;
// True for multiline strings.
bool multiline;
// For text input: If true, the GUI text box spans the complete page width.
bool full_width;
// Not editable. Currently only used for the display of the number of threads.
bool readonly;
// Height of a multiline GUI text box.
int height;
// Optional width of an input field.
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 max;
// Legacy names for this configuration option.
// Used when parsing legacy configuration file.
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;
// 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_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;
ConfigOptionDef() : type(coNone), default_value(NULL),
multiline(false), full_width(false), readonly(false),
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;
// 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
{
public:
@ -545,9 +614,14 @@ class ConfigDef
const ConfigOptionDef* get(const t_config_option_key &opt_key) const;
};
// An abstract configuration store.
class ConfigBase
{
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;
ConfigBase() : def(NULL) {};
@ -562,11 +636,14 @@ class ConfigBase
t_config_option_keys diff(ConfigBase &other);
std::string serialize(const t_config_option_key &opt_key) const;
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 ratio_over);
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
{
public:
@ -585,13 +662,20 @@ class DynamicConfig : public virtual ConfigBase
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
{
public:
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;
//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();
// 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();
}
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
}
extern BoundingBox get_extents(const ExPolygon &expolygon);
extern BoundingBox get_extents(const ExPolygons &expolygons);
} // namespace Slic3r
// start Boost
#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());
}
BoundingBox get_extents(const ExPolygonCollection &expolygon)
{
return get_extents(expolygon.expolygons);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -78,6 +78,9 @@ class GCode {
Wipe wipe;
AvoidCrossingPerimeters avoid_crossing_perimeters;
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;
// Markers for the Pressure Equalizer to recognize the extrusion type.
// The Pressure Equalizer removes the markers from the final G-code.
@ -89,6 +92,10 @@ class GCode {
// Distance Field structure to
EdgeGrid::Grid *_lower_layer_edge_grid;
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
double volumetric_speed;
// 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;
// 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
Layer::make_perimeters()
{

View File

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

View File

@ -772,7 +772,7 @@ ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
void
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
}

View File

@ -27,10 +27,18 @@ typedef std::vector<ModelObject*> ModelObjectPtrs;
typedef std::vector<ModelVolume*> ModelVolumePtrs;
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
{
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;
// Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation).
ModelObjectPtrs objects;
Model();
@ -63,34 +71,48 @@ class Model
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
{
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;
// Dynamic configuration storage for the object specific configuration values, overriding the global configuration.
DynamicPrintConfig config;
Model* get_model() const { return this->model; };
void apply(const t_model_material_attributes &attributes);
private:
private:
// Parent, owning this material.
Model* model;
ModelMaterial(Model *model);
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
{
friend class Model;
public:
public:
std::string name;
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;
// Printable and modifier volumes, each with its material ID and a set of override parameters.
// ModelVolumes are owned by this ModelObject.
ModelVolumePtrs volumes;
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
DynamicPrintConfig config;
// Variation of a layer thickness for spans of Z coordinates.
t_layer_height_ranges layer_height_ranges;
/* This vector accumulates the total translation applied to the object by the
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
@ -134,7 +156,8 @@ class ModelObject
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
private:
private:
// Parent object, owning this ModelObject.
Model* model;
ModelObject(Model *model);
@ -144,15 +167,22 @@ class 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
{
friend class ModelObject;
public:
public:
std::string name;
// The triangular model.
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;
// Is it an object to be printed, or a modifier volume?
bool modifier;
// A parent object owning this modifier volume.
ModelObject* get_object() const { return this->object; };
t_model_material_id material_id() const;
void material_id(t_model_material_id material_id);
@ -161,7 +191,8 @@ class ModelVolume
ModelMaterial* assign_unique_material();
private:
private:
// Parent object owning this ModelVolume.
ModelObject* object;
t_model_material_id _material_id;
@ -169,19 +200,25 @@ class ModelVolume
ModelVolume(ModelObject *object, const ModelVolume &other);
};
// A single instance of a ModelObject.
// Knows the affine transformation of an object.
class ModelInstance
{
friend class ModelObject;
public:
double rotation; // in radians around mesh center point
public:
double rotation; // Rotation around the Z axis, in radians around mesh center point
double scaling_factor;
Pointf offset; // in unscaled coordinates
ModelObject* get_object() const { return this->object; };
// To be called on an external mesh
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;
private:
private:
// Parent object, owning this instance.
ModelObject* object;
ModelInstance(ModelObject *object);

View File

@ -33,8 +33,8 @@ MultiPoint::translate(const Point &vector)
void
MultiPoint::rotate(double angle)
{
double s = sin(angle);
double c = cos(angle);
double s = sin(angle);
double c = cos(angle);
for (Points::iterator it = points.begin(); it != points.end(); ++it) {
double cur_x = (double)it->x;
double cur_y = (double)it->y;
@ -46,8 +46,13 @@ MultiPoint::rotate(double angle)
void
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) {
(*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;
}
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);
};
}
extern BoundingBox get_extents(const MultiPoint &mp);
} // namespace Slic3r
#endif

View File

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

View File

@ -11,25 +11,33 @@
namespace Slic3r {
class PerimeterGeneratorLoop;
typedef std::vector<PerimeterGeneratorLoop> PerimeterGeneratorLoops;
// Hierarchy of perimeters.
class PerimeterGeneratorLoop {
public:
public:
// Polygon of this contour.
Polygon polygon;
// Is it a contour or a hole?
// Contours are CCW oriented, holes are CW oriented.
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;
// Children contour, may be both CCW and CW oriented (outer contours or holes).
std::vector<PerimeterGeneratorLoop> children;
PerimeterGeneratorLoop(Polygon polygon, unsigned short 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;
};
typedef std::vector<PerimeterGeneratorLoop> PerimeterGeneratorLoops;
class PerimeterGenerator {
public:
public:
// Inputs:
const SurfaceCollection* slices;
const ExPolygonCollection* lower_slices;
double layer_height;
@ -41,14 +49,26 @@ class PerimeterGenerator {
PrintRegionConfig* config;
PrintObjectConfig* object_config;
PrintConfig* print_config;
// Outputs:
ExtrusionEntityCollection* loops;
ExtrusionEntityCollection* gap_fill;
SurfaceCollection* fill_surfaces;
PerimeterGenerator(const SurfaceCollection* slices, double layer_height, Flow flow,
PrintRegionConfig* config, PrintObjectConfig* object_config,
PrintConfig* print_config, ExtrusionEntityCollection* loops,
ExtrusionEntityCollection* gap_fill, SurfaceCollection* fill_surfaces)
PerimeterGenerator(
// Input:
const SurfaceCollection* slices,
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),
layer_id(-1), perimeter_flow(flow), ext_perimeter_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);
}
template<typename T>
inline T sqr(const T x)
{
return x * x;
}
int
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) {
/* If the X distance of the candidate is > than the total distance of the
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 the Y distance of the candidate is > than the total distance of the
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;
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) {
// 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
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 (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
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)pow(line.b.x - line.a.x, 2) + (double)pow(line.b.y - line.a.y, 2) );
double lx = (double)(line.b.x - line.a.x);
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)
return theta * line.a + (1.0-theta) * line.b;

View File

@ -44,6 +44,8 @@ class Point
void translate(const Vector &vector);
void rotate(double angle);
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_epsilon(const Point &point) const;
int nearest_point_index(const Points &points) const;

View File

@ -1,3 +1,4 @@
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
#include "Polygon.hpp"
#include "Polyline.hpp"
@ -59,6 +60,7 @@ Polygon::split_at_vertex(const Point &point) const
return Polyline();
}
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
Polyline
Polygon::split_at_index(int index) const
{
@ -71,6 +73,7 @@ Polygon::split_at_index(int index) const
return polyline;
}
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
Polyline
Polygon::split_at_first_point() const
{
@ -131,6 +134,8 @@ Polygon::is_valid() const
return this->points.size() >= 3;
}
// Does an unoriented polygon contain a point?
// Tested by counting intersections along a horizontal line.
bool
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 j = this->points.end() - 1;
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))
&& ((double)point.x < (double)(j->x - i->x) * (double)(point.y - i->y) / (double)(j->y - i->y) + (double)i->x) )
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;
}
@ -265,4 +281,20 @@ Polygon::convex_points(double angle) const
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;
virtual Lines lines() 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;
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
Polyline split_at_first_point() const;
Points equally_spaced_points(double distance) const;
double area() const;
@ -34,6 +36,8 @@ class Polygon : public MultiPoint {
bool make_counter_clockwise();
bool make_clockwise();
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;
Polygons simplify(double tolerance) const;
void simplify(double tolerance, Polygons &polygons) const;
@ -44,6 +48,9 @@ class Polygon : public MultiPoint {
Points convex_points(double angle = PI) const;
};
extern BoundingBox get_extents(const Polygon &poly);
extern BoundingBox get_extents(const Polygons &polygons);
}
// 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))
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) {
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();
for (ModelVolumePtrs::const_iterator v = model_object->volumes.begin(); v != model_object->volumes.end(); ++v) {
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;
if (!(*v)->config.has("extruder"))
(*v)->config.opt<ConfigOptionInt>("extruder", true)->value = extruder_id;

View File

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

View File

@ -885,11 +885,37 @@ PrintConfigDef::PrintConfigDef()
def->enum_values.push_back("random");
def->enum_values.push_back("nearest");
def->enum_values.push_back("aligned");
// def->enum_values.push_back("preferred");
def->enum_labels.push_back("Random");
def->enum_labels.push_back("Nearest");
def->enum_labels.push_back("Aligned");
// def->enum_labels.push_back("Preferred Direction");
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->gui_type = "select_open";
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_
#define slic3r_PrintConfig_hpp_
@ -22,7 +39,7 @@ enum SupportMaterialPattern {
};
enum SeamPosition {
spRandom, spNearest, spAligned
spRandom, spNearest, spAligned //, spPreferred
};
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["nearest"] = spNearest;
keys_map["aligned"] = spAligned;
// keys_map["preferred"] = spPreferred;
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
{
public:
PrintConfigDef();
};
// The one and only global definition of SLic3r configuration options.
// This definition is constant.
extern PrintConfigDef print_config_def;
// Slic3r configuration storage with print_config_def assigned.
class PrintConfigBase : public virtual ConfigBase
{
public:
@ -86,6 +109,12 @@ class PrintConfigBase : public virtual ConfigBase
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
{
public:
@ -93,12 +122,14 @@ class DynamicPrintConfig : public PrintConfigBase, public DynamicConfig
void normalize();
};
class StaticPrintConfig : public PrintConfigBase, public StaticConfig
{
public:
StaticPrintConfig() : PrintConfigBase(), StaticConfig() {};
};
// This object is mapped to Perl as Slic3r::Config::PrintObject.
class PrintObjectConfig : public virtual StaticPrintConfig
{
public:
@ -110,6 +141,8 @@ class PrintObjectConfig : public virtual StaticPrintConfig
ConfigOptionFloat layer_height;
ConfigOptionInt raft_layers;
ConfigOptionEnum<SeamPosition> seam_position;
// ConfigOptionFloat seam_preferred_direction;
// ConfigOptionFloat seam_preferred_direction_jitter;
ConfigOptionBool support_material;
ConfigOptionInt support_material_angle;
ConfigOptionFloat support_material_contact_distance;
@ -130,7 +163,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
if (initialize)
this->set_defaults();
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(dont_support_bridges);
OPT_PTR(extrusion_width);
@ -140,6 +173,8 @@ class PrintObjectConfig : public virtual StaticPrintConfig
OPT_PTR(layer_height);
OPT_PTR(raft_layers);
OPT_PTR(seam_position);
// OPT_PTR(seam_preferred_direction);
// OPT_PTR(seam_preferred_direction_jitter);
OPT_PTR(support_material);
OPT_PTR(support_material_angle);
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
{
public:
@ -200,7 +236,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
if (initialize)
this->set_defaults();
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(bottom_solid_layers);
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
{
public:
@ -315,6 +352,7 @@ class GCodeConfig : public virtual StaticPrintConfig
};
};
// This object is mapped to Perl as Slic3r::Config::Print.
class PrintConfig : public GCodeConfig
{
public:
@ -373,7 +411,7 @@ class PrintConfig : public GCodeConfig
if (initialize)
this->set_defaults();
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(avoid_crossing_perimeters);
OPT_PTR(bed_shape);
@ -446,7 +484,7 @@ class HostConfig : public virtual StaticPrintConfig
if (initialize)
this->set_defaults();
}
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(octoprint_host);
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
: 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(posInfill);
} else if (*opt_key == "seam_position"
|| *opt_key == "seam_preferred_direction"
|| *opt_key == "seam_preferred_direction_jitter"
|| *opt_key == "support_material_speed"
|| *opt_key == "bridge_speed"
|| *opt_key == "external_perimeter_speed"

View File

@ -1,12 +1,12 @@
#include "SVG.hpp"
#include <iostream>
#define COORD(x) ((float)unscale(x)*10)
#define COORD(x) ((float)unscale((x))*10)
namespace Slic3r {
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");
fprintf(this->f,
@ -19,12 +19,12 @@ SVG::SVG(const char* filename)
);
}
SVG::SVG(const char* filename, const BoundingBox &bbox)
: arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min)
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 - Point(bbox_offset, bbox_offset)), flipY(aflipY)
{
this->f = fopen(filename, "w");
float w = COORD(bbox.max.x - bbox.min.x);
float h = COORD(bbox.max.y - bbox.min.y);
float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset);
float h = COORD(bbox.max.y - bbox.min.y + 2 * bbox_offset);
fprintf(this->f,
"<?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"
@ -36,7 +36,7 @@ SVG::SVG(const char* filename, const BoundingBox &bbox)
}
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,
" <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");
}
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 perp(-dir.y, dir.x);
@ -68,10 +68,10 @@ void SVG::draw(const ThickLine &line, const std::string &fill, const std::string
}
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)
this->draw(*it, stroke);
this->draw(*it, stroke, stroke_width);
}
void
@ -91,7 +91,7 @@ SVG::draw(const ExPolygon &expolygon, std::string fill)
for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) {
d += this->get_path_d(*p, true) + " ";
}
this->path(d, true);
this->path(d, true, 0);
}
void
@ -105,7 +105,7 @@ void
SVG::draw(const Polygon &polygon, std::string 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
@ -116,34 +116,34 @@ SVG::draw(const Polygons &polygons, std::string fill)
}
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->path(this->get_path_d(polyline, false), false, stroke_width);
}
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)
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)
this->draw(*it, fill, stroke, stroke_width);
}
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)
this->draw((Polyline)*it, stroke, stroke_width);
}
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)
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);
}
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
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;
if (! fill)
@ -199,6 +227,19 @@ SVG::get_path_d(const MultiPoint &mp, bool closed) const
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
SVG::Close()
{

View File

@ -2,6 +2,7 @@
#define slic3r_SVG_hpp_
#include "libslic3r.h"
#include "clipper.hpp"
#include "ExPolygon.hpp"
#include "Line.hpp"
#include "TriangleMesh.hpp"
@ -14,34 +15,43 @@ class SVG
bool arrows;
std::string fill, stroke;
Point origin;
bool flipY;
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(); }
void draw(const Line &line, std::string stroke = "black", coord_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 Lines &lines, std::string stroke = "black");
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, coordf_t stroke_width = 0);
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 ExPolygon &expolygon, std::string fill = "grey");
void draw(const ExPolygons &expolygons, 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 Polyline &polyline, std::string stroke = "black", coord_t stroke_width = 0);
void draw(const Polylines &polylines, std::string stroke = "black", coord_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 ThickPolylines &polylines, const std::string &stroke = "black", coord_t stroke_width = 0);
void draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coord_t stroke_width);
void draw_outline(const Polygons &polygons, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const Polyline &polyline, std::string stroke = "black", coordf_t stroke_width = 0);
void draw(const Polylines &polylines, std::string stroke = "black", coordf_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 &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 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();
private:
std::string filename;
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 ClipperLib::Path &mp, double scale, bool closed = false) const;
};
}

View File

@ -1,3 +1,4 @@
#include "BoundingBox.hpp"
#include "Surface.hpp"
namespace Slic3r {
@ -54,4 +55,31 @@ Surface::is_bridge() const
|| 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*> SurfacesPtr;
extern BoundingBox get_extents(const Surface &surface);
extern BoundingBox get_extents(const Surfaces &surfaces);
extern BoundingBox get_extents(const SurfacesPtr &surfaces);
}
#endif

View File

@ -8,12 +8,22 @@
#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
// 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
// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm.
#define RESOLUTION 0.0125
#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR)
#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
// Maximum perimeter length for the loop to apply the small perimeter speed.
#define SMALL_PERIMETER_LENGTH (6.5 / SCALING_FACTOR) * 2 * PI
#define INSET_OVERLAP_TOLERANCE 0.4
#define EXTERNAL_INFILL_MARGIN 3

View File

@ -19,13 +19,15 @@
Clone<Polygon> polygon();
Clone<Point> size();
Clone<Point> center();
double radius();
Clone<Point> min_point() %code{% RETVAL = THIS->min; %};
Clone<Point> max_point() %code{% RETVAL = THIS->max; %};
long x_min() %code{% RETVAL = THIS->min.x; %};
long x_max() %code{% RETVAL = THIS->max.x; %};
long y_min() %code{% RETVAL = THIS->min.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*
@ -51,6 +53,7 @@ new_from_points(CLASS, points)
void translate(double x, double y);
Clone<Pointf> size();
Clone<Pointf> center();
double radius();
Clone<Pointf> min_point() %code{% RETVAL = THIS->min; %};
Clone<Pointf> max_point() %code{% RETVAL = THIS->max; %};
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_y_min(double val) %code{% THIS->min.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*
@ -87,6 +91,7 @@ new_from_points(CLASS, points)
void translate(double x, double y, double z);
Clone<Pointf3> size();
Clone<Pointf3> center();
double radius();
Clone<Pointf3> min_point() %code{% RETVAL = THIS->min; %};
Clone<Pointf3> max_point() %code{% RETVAL = THIS->max; %};
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 z_min() %code{% RETVAL = THIS->min.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()); %};
bool coincides_with_epsilon(Point* 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; %};
long 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 {
@ -113,6 +115,7 @@ Point::coincides_with(point_sv)
%code{% RETVAL = THIS->negative(); %};
Clone<Pointf> vector_to(Pointf* 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 {
@ -140,4 +143,5 @@ Point::coincides_with(point_sv)
%code{% RETVAL = THIS->negative(); %};
Clone<Pointf3> vector_to(Pointf3* 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; %};
};