Merge branch 'master' into wipe_tower_improvements

This commit is contained in:
Lukas Matena 2018-03-09 15:10:15 +01:00
commit 1c6fa6660e
79 changed files with 34645 additions and 10116 deletions

View file

@ -26,6 +26,7 @@ enum ExtrusionRole {
erSupportMaterial,
erSupportMaterialInterface,
erWipeTower,
erCustom,
// Extrusion role for a collection with multiple extrusion roles.
erMixed,
};

View file

@ -8,6 +8,7 @@
#include "FillConcentric.hpp"
#include "FillHoneycomb.hpp"
#include "Fill3DHoneycomb.hpp"
#include "FillGyroid.hpp"
#include "FillPlanePath.hpp"
#include "FillRectilinear.hpp"
#include "FillRectilinear2.hpp"
@ -21,6 +22,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipConcentric: return new FillConcentric();
case ipHoneycomb: return new FillHoneycomb();
case ip3DHoneycomb: return new Fill3DHoneycomb();
case ipGyroid: return new FillGyroid();
case ipRectilinear: return new FillRectilinear2();
// case ipRectilinear: return new FillRectilinear();
case ipLine: return new FillLine();

View file

@ -0,0 +1,150 @@
#include "../ClipperUtils.hpp"
#include "../PolylineCollection.hpp"
#include "../Surface.hpp"
#include <cmath>
#include <algorithm>
#include <iostream>
#include "FillGyroid.hpp"
namespace Slic3r {
static inline Polyline make_wave_vertical(
double width, double height, double x0,
double segmentSize, double scaleFactor,
double z_cos, double z_sin, bool flip)
{
Polyline polyline;
polyline.points.emplace_back(Point(coord_t(clamp(0., width, x0) * scaleFactor), 0));
double phase_offset_sin = (z_cos < 0 ? M_PI : 0) + M_PI;
double phase_offset_cos = (z_cos < 0 ? M_PI : 0) + M_PI + (flip ? M_PI : 0.);
for (double y = 0.; y < height + segmentSize; y += segmentSize) {
y = std::min(y, height);
double a = sin(y + phase_offset_sin);
double b = - z_cos;
double res = z_sin * cos(y + phase_offset_cos);
double r = sqrt(sqr(a) + sqr(b));
double x = clamp(0., width, asin(a/r) + asin(res/r) + M_PI + x0);
polyline.points.emplace_back(convert_to<Point>(Pointf(x, y) * scaleFactor));
}
if (flip)
std::reverse(polyline.points.begin(), polyline.points.end());
return polyline;
}
static inline Polyline make_wave_horizontal(
double width, double height, double y0,
double segmentSize, double scaleFactor,
double z_cos, double z_sin, bool flip)
{
Polyline polyline;
polyline.points.emplace_back(Point(0, coord_t(clamp(0., height, y0) * scaleFactor)));
double phase_offset_sin = (z_sin < 0 ? M_PI : 0) + (flip ? 0 : M_PI);
double phase_offset_cos = z_sin < 0 ? M_PI : 0.;
for (double x=0.; x < width + segmentSize; x += segmentSize) {
x = std::min(x, width);
double a = cos(x + phase_offset_cos);
double b = - z_sin;
double res = z_cos * sin(x + phase_offset_sin);
double r = sqrt(sqr(a) + sqr(b));
double y = clamp(0., height, asin(a/r) + asin(res/r) + 0.5 * M_PI + y0);
polyline.points.emplace_back(convert_to<Point>(Pointf(x, y) * scaleFactor));
}
if (flip)
std::reverse(polyline.points.begin(), polyline.points.end());
return polyline;
}
static Polylines make_gyroid_waves(double gridZ, double density, double layer_width, double width, double height)
{
double scaleFactor = scale_(layer_width) / density;
double segmentSize = 0.5 * density;
//scale factor for 5% : 8 712 388
// 1z = 10^-6 mm ?
double z = gridZ / scaleFactor;
double z_sin = sin(z);
double z_cos = cos(z);
Polylines result;
if (abs(z_sin) <= abs(z_cos)) {
// Vertical wave
double x0 = M_PI * (int)((- 0.5 * M_PI) / M_PI - 1.);
bool flip = ((int)(x0 / M_PI + 1.) & 1) != 0;
for (; x0 < width - 0.5 * M_PI; x0 += M_PI, flip = ! flip)
result.emplace_back(make_wave_vertical(width, height, x0, segmentSize, scaleFactor, z_cos, z_sin, flip));
} else {
// Horizontal wave
bool flip = true;
for (double y0 = 0.; y0 < width; y0 += M_PI, flip = !flip)
result.emplace_back(make_wave_horizontal(width, height, y0, segmentSize, scaleFactor, z_cos, z_sin, flip));
}
return result;
}
void FillGyroid::_fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out)
{
// no rotation is supported for this infill pattern
BoundingBox bb = expolygon.contour.bounding_box();
coord_t distance = coord_t(scale_(this->spacing) / (params.density*this->scaling));
// align bounding box to a multiple of our grid module
bb.merge(_align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
// generate pattern
Polylines polylines = make_gyroid_waves(
scale_(this->z),
params.density*this->scaling,
this->spacing,
ceil(bb.size().x / distance) + 1.,
ceil(bb.size().y / distance) + 1.);
// move pattern in place
for (Polyline &polyline : polylines)
polyline.translate(bb.min.x, bb.min.y);
// clip pattern to boundaries
polylines = intersection_pl(polylines, (Polygons)expolygon);
// connect lines
if (! params.dont_connect && ! polylines.empty()) { // prevent calling leftmost_point() on empty collections
ExPolygon expolygon_off;
{
ExPolygons expolygons_off = offset_ex(expolygon, (float)SCALED_EPSILON);
if (! expolygons_off.empty()) {
// When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island.
assert(expolygons_off.size() == 1);
std::swap(expolygon_off, expolygons_off.front());
}
}
Polylines chained = PolylineCollection::chained_path_from(
std::move(polylines),
PolylineCollection::leftmost_point(polylines), false); // reverse allowed
bool first = true;
for (Polyline &polyline : chained) {
if (! first) {
// Try to connect the lines.
Points &pts_end = polylines_out.back().points;
const Point &first_point = polyline.points.front();
const Point &last_point = pts_end.back();
// TODO: we should also check that both points are on a fill_boundary to avoid
// connecting paths on the boundaries of internal regions
// TODO: avoid crossing current infill path
if (first_point.distance_to(last_point) <= 5 * distance &&
expolygon_off.contains(Line(last_point, first_point))) {
// Append the polyline.
pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end());
continue;
}
}
// The lines cannot be connected.
polylines_out.emplace_back(std::move(polyline));
first = false;
}
}
}
} // namespace Slic3r

View file

@ -0,0 +1,34 @@
#ifndef slic3r_FillGyroid_hpp_
#define slic3r_FillGyroid_hpp_
#include "../libslic3r.h"
#include "FillBase.hpp"
namespace Slic3r {
class FillGyroid : public Fill
{
public:
FillGyroid() {}
virtual Fill* clone() const { return new FillGyroid(*this); }
// require bridge flow since most of this pattern hangs in air
virtual bool use_bridge_flow() const { return true; }
protected:
// mult of density, to have a good %of weight for each density parameter
float scaling = 1.75;
virtual void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out);
};
} // namespace Slic3r
#endif // slic3r_FillGyroid_hpp_

View file

@ -587,6 +587,15 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
// Set extruder(s) temperature before and after start G-code.
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
if (m_enable_analyzer)
{
// adds tag for analyzer
char buf[32];
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
_writeln(file, buf);
}
// Write the custom start G-code
_writeln(file, start_gcode);
// Process filament-specific gcode in extruder order.
@ -770,6 +779,15 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// Write end commands to file.
_write(file, this->retract());
_write(file, m_writer.set_fan(false));
if (m_enable_analyzer)
{
// adds tag for analyzer
char buf[32];
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
_writeln(file, buf);
}
// Process filament-specific gcode in extruder order.
if (print.config.single_extruder_multi_material) {
// Process the end_filament_gcode for the active filament only.
@ -1384,18 +1402,13 @@ void GCode::apply_print_config(const PrintConfig &print_config)
void GCode::append_full_config(const Print& print, std::string& str)
{
char buff[4096];
const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config };
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) {
const StaticPrintConfig *cfg = configs[i];
for (const std::string &key : cfg->keys())
{
if (key != "compatible_printers")
{
sprintf(buff, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str());
str += buff;
}
str += "; " + key + " = " + cfg->serialize(key) + "\n";
}
}
}

View file

@ -150,7 +150,13 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi
{
// processes 'special' comments contained in line
if (_process_tags(line))
{
#if 0
// DEBUG ONLY: puts the line back into the gcode
m_process_output += line.raw() + "\n";
#endif
return;
}
// sets new start position/extrusion
_set_start_position(_get_end_position());

View file

@ -1,6 +1,8 @@
#include "Analyzer.hpp"
#include "PreviewData.hpp"
#include <float.h>
#include <wx/intl.h>
#include "slic3r/GUI/GUI.hpp"
namespace Slic3r {
@ -125,26 +127,28 @@ const GCodePreviewData::Color GCodePreviewData::Extrusion::Default_Extrusion_Rol
Color(0.0f, 0.5f, 0.0f, 1.0f), // erSupportMaterial
Color(0.0f, 0.0f, 0.5f, 1.0f), // erSupportMaterialInterface
Color(0.7f, 0.89f, 0.67f, 1.0f), // erWipeTower
Color(1.0f, 1.0f, 0.0f, 1.0f), // erCustom
Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed
};
// todo: merge with Slic3r::ExtrusionRole2String() from GCode.cpp
const std::string GCodePreviewData::Extrusion::Default_Extrusion_Role_Names[Num_Extrusion_Roles]
{
"None",
"Perimeter",
"External perimeter",
"Overhang perimeter",
"Internal infill",
"Solid infill",
"Top solid infill",
"Bridge infill",
"Gap fill",
"Skirt",
"Support material",
"Support material interface",
"Wipe tower",
"Mixed"
L("None"),
L("Perimeter"),
L("External perimeter"),
L("Overhang perimeter"),
L("Internal infill"),
L("Solid infill"),
L("Top solid infill"),
L("Bridge infill"),
L("Gap fill"),
L("Skirt"),
L("Support material"),
L("Support material interface"),
L("Wipe tower"),
L("Custom"),
L("Mixed")
};
const GCodePreviewData::Extrusion::EViewType GCodePreviewData::Extrusion::Default_View_Type = GCodePreviewData::Extrusion::FeatureType;
@ -323,15 +327,15 @@ std::string GCodePreviewData::get_legend_title() const
switch (extrusion.view_type)
{
case Extrusion::FeatureType:
return "Feature type";
return L("Feature type");
case Extrusion::Height:
return "Height (mm)";
return L("Height (mm)");
case Extrusion::Width:
return "Width (mm)";
return L("Width (mm)");
case Extrusion::Feedrate:
return "Speed (mm/s)";
return L("Speed (mm/s)");
case Extrusion::Tool:
return "Tool";
return L("Tool");
}
return "";
@ -360,10 +364,13 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
{
case Extrusion::FeatureType:
{
items.reserve(erMixed - erPerimeter + 1);
for (unsigned int i = (unsigned int)erPerimeter; i < (unsigned int)erMixed; ++i)
ExtrusionRole first_valid = erPerimeter;
ExtrusionRole last_valid = erCustom;
items.reserve(last_valid - first_valid + 1);
for (unsigned int i = (unsigned int)first_valid; i <= (unsigned int)last_valid; ++i)
{
items.emplace_back(extrusion.role_names[i], extrusion.role_colors[i]);
items.emplace_back(_CHB(extrusion.role_names[i].c_str()).data(), extrusion.role_colors[i]);
}
break;
@ -389,8 +396,8 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
items.reserve(tools_colors_count);
for (unsigned int i = 0; i < tools_colors_count; ++i)
{
char buf[32];
sprintf(buf, "Extruder %d", i + 1);
char buf[MIN_BUF_LENGTH_FOR_L];
sprintf(buf, _CHB(L("Extruder %d")), i + 1);
GCodePreviewData::Color color;
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));

View file

@ -19,6 +19,18 @@ static const float DEFAULT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE = 1.0f; // 100 per
static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
#if ENABLE_MOVE_STATS
static const std::string MOVE_TYPE_STR[Slic3r::GCodeTimeEstimator::Block::Num_Types] =
{
"Noop",
"Retract",
"Unretract",
"Tool_change",
"Move",
"Extrude"
};
#endif // ENABLE_MOVE_STATS
namespace Slic3r {
void GCodeTimeEstimator::Feedrates::reset()
@ -139,6 +151,14 @@ namespace Slic3r {
return (acceleration == 0.0f) ? 0.0f : (2.0f * acceleration * distance - sqr(initial_rate) + sqr(final_rate)) / (4.0f * acceleration);
}
#if ENABLE_MOVE_STATS
GCodeTimeEstimator::MoveStats::MoveStats()
: count(0)
, time(0.0f)
{
}
#endif // ENABLE_MOVE_STATS
GCodeTimeEstimator::GCodeTimeEstimator()
{
reset();
@ -155,6 +175,10 @@ namespace Slic3r {
_calculate_time();
#if ENABLE_MOVE_STATS
_log_moves_stats();
#endif // ENABLE_MOVE_STATS
_reset_blocks();
_reset();
}
@ -166,6 +190,10 @@ namespace Slic3r {
_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
_calculate_time();
#if ENABLE_MOVE_STATS
_log_moves_stats();
#endif // ENABLE_MOVE_STATS
_reset_blocks();
_reset();
}
@ -180,6 +208,10 @@ namespace Slic3r {
_parser.parse_line(line, action);
_calculate_time();
#if ENABLE_MOVE_STATS
_log_moves_stats();
#endif // ENABLE_MOVE_STATS
_reset_blocks();
_reset();
}
@ -208,6 +240,11 @@ namespace Slic3r {
{
PROFILE_FUNC();
_calculate_time();
#if ENABLE_MOVE_STATS
_log_moves_stats();
#endif // ENABLE_MOVE_STATS
_reset_blocks();
_reset();
}
@ -393,6 +430,9 @@ namespace Slic3r {
void GCodeTimeEstimator::reset()
{
_time = 0.0f;
#if ENABLE_MOVE_STATS
_moves_stats.clear();
#endif // ENABLE_MOVE_STATS
_reset_blocks();
_reset();
}
@ -448,9 +488,24 @@ namespace Slic3r {
for (const Block& block : _blocks)
{
#if ENABLE_MOVE_STATS
float block_time = 0.0f;
block_time += block.acceleration_time();
block_time += block.cruise_time();
block_time += block.deceleration_time();
_time += block_time;
MovesStatsMap::iterator it = _moves_stats.find(block.move_type);
if (it == _moves_stats.end())
it = _moves_stats.insert(MovesStatsMap::value_type(block.move_type, MoveStats())).first;
it->second.count += 1;
it->second.time += block_time;
#else
_time += block.acceleration_time();
_time += block.cruise_time();
_time += block.deceleration_time();
#endif // ENABLE_MOVE_STATS
}
}
@ -746,6 +801,28 @@ namespace Slic3r {
set_axis_position((EAxis)a, new_pos[a]);
}
#if ENABLE_MOVE_STATS
// detects block move type
block.move_type = Block::Noop;
if (block.delta_pos[E] < 0.0f)
{
if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f))
block.move_type = Block::Move;
else
block.move_type = Block::Retract;
}
else if (block.delta_pos[E] > 0.0f)
{
if ((block.delta_pos[X] == 0.0f) && (block.delta_pos[Y] == 0.0f) && (block.delta_pos[Z] == 0.0f))
block.move_type = Block::Unretract;
else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f))
block.move_type = Block::Extrude;
}
else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f))
block.move_type = Block::Move;
#endif // ENABLE_MOVE_STATS
// adds block to blocks list
_blocks.emplace_back(block);
}
@ -1064,4 +1141,24 @@ namespace Slic3r {
next->flags.recalculate = false;
}
}
#if ENABLE_MOVE_STATS
void GCodeTimeEstimator::_log_moves_stats() const
{
float moves_count = 0.0f;
for (const MovesStatsMap::value_type& move : _moves_stats)
{
moves_count += (float)move.second.count;
}
for (const MovesStatsMap::value_type& move : _moves_stats)
{
std::cout << MOVE_TYPE_STR[move.first];
std::cout << ": count " << move.second.count << " (" << 100.0f * (float)move.second.count / moves_count << "%)";
std::cout << " - time: " << move.second.time << "s (" << 100.0f * move.second.time / _time << "%)";
std::cout << std::endl;
}
std::cout << std::endl;
}
#endif // ENABLE_MOVE_STATS
}

View file

@ -5,6 +5,8 @@
#include "PrintConfig.hpp"
#include "GCodeReader.hpp"
#define ENABLE_MOVE_STATS 0
namespace Slic3r {
//
@ -74,6 +76,19 @@ namespace Slic3r {
public:
struct Block
{
#if ENABLE_MOVE_STATS
enum EMoveType : unsigned char
{
Noop,
Retract,
Unretract,
Tool_change,
Move,
Extrude,
Num_Types
};
#endif // ENABLE_MOVE_STATS
struct FeedrateProfile
{
float entry; // mm/s
@ -106,6 +121,10 @@ namespace Slic3r {
bool nominal_length;
};
#if ENABLE_MOVE_STATS
EMoveType move_type;
#endif // ENABLE_MOVE_STATS
Flags flags;
float delta_pos[Num_Axis]; // mm
@ -156,6 +175,18 @@ namespace Slic3r {
typedef std::vector<Block> BlocksList;
#if ENABLE_MOVE_STATS
struct MoveStats
{
unsigned int count;
float time;
MoveStats();
};
typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap;
#endif // ENABLE_MOVE_STATS
private:
GCodeReader _parser;
State _state;
@ -163,6 +194,9 @@ namespace Slic3r {
Feedrates _prev;
BlocksList _blocks;
float _time; // s
#if ENABLE_MOVE_STATS
MovesStatsMap _moves_stats;
#endif // ENABLE_MOVE_STATS
public:
GCodeTimeEstimator();
@ -318,6 +352,10 @@ namespace Slic3r {
void _planner_reverse_pass_kernel(Block& curr, Block& next);
void _recalculate_trapezoids();
#if ENABLE_MOVE_STATS
void _log_moves_stats() const;
#endif // ENABLE_MOVE_STATS
};
} /* namespace Slic3r */

View file

@ -12,6 +12,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/nowide/iostream.hpp>
#include <boost/algorithm/string/replace.hpp>
namespace Slic3r {
@ -91,7 +92,15 @@ Model Model::read_from_archive(const std::string &input_file, PresetBundle* bund
throw std::runtime_error("The supplied file couldn't be read because it's empty");
for (ModelObject *o : model.objects)
o->input_file = input_file;
{
if (boost::algorithm::iends_with(input_file, ".zip.amf"))
{
// we remove the .zip part of the extension to avoid it be added to filenames when exporting
o->input_file = boost::ireplace_last_copy(input_file, ".zip.", ".");
}
else
o->input_file = input_file;
}
if (add_default_instances)
model.add_default_instances();

File diff suppressed because it is too large Load diff

View file

@ -29,7 +29,7 @@ enum GCodeFlavor {
enum InfillPattern {
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
};
enum SupportMaterialPattern {
@ -73,6 +73,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enu
keys_map["concentric"] = ipConcentric;
keys_map["honeycomb"] = ipHoneycomb;
keys_map["3dhoneycomb"] = ip3DHoneycomb;
keys_map["gyroid"] = ipGyroid;
keys_map["hilbertcurve"] = ipHilbertCurve;
keys_map["archimedeanchords"] = ipArchimedeanChords;
keys_map["octagramspiral"] = ipOctagramSpiral;
@ -699,6 +700,7 @@ class HostConfig : public StaticPrintConfig
public:
ConfigOptionString octoprint_host;
ConfigOptionString octoprint_apikey;
ConfigOptionString octoprint_cafile;
ConfigOptionString serial_port;
ConfigOptionInt serial_speed;
@ -707,6 +709,7 @@ protected:
{
OPT_PTR(octoprint_host);
OPT_PTR(octoprint_apikey);
OPT_PTR(octoprint_cafile);
OPT_PTR(serial_port);
OPT_PTR(serial_speed);
}

View file

@ -198,9 +198,8 @@ TriangleMesh::repair() {
stl_clear_error(&stl);
}
// commenting out the following call fixes: #574, #413, #269, #262, #259, #230, #228, #206
// // normal_directions
// stl_fix_normal_directions(&stl);
// normal_directions
stl_fix_normal_directions(&stl);
// normal_values
stl_fix_normal_values(&stl);
@ -210,7 +209,7 @@ TriangleMesh::repair() {
// neighbors
stl_verify_neighbors(&stl);
this->repaired = true;
BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() finished";
@ -1187,40 +1186,46 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic
loops correctly in some edge cases when original model had overlapping facets
*/
std::vector<double> area;
std::vector<size_t> sorted_area; // vector of indices
for (Polygons::const_iterator loop = loops.begin(); loop != loops.end(); ++ loop) {
area.push_back(loop->area());
sorted_area.push_back(loop - loops.begin());
}
// outer first
std::sort(sorted_area.begin(), sorted_area.end(),
[&area](size_t a, size_t b) { return std::abs(area[a]) > std::abs(area[b]); });
/* The following lines are commented out because they can generate wrong polygons,
see for example issue #661 */
// we don't perform a safety offset now because it might reverse cw loops
Polygons p_slices;
for (std::vector<size_t>::const_iterator loop_idx = sorted_area.begin(); loop_idx != sorted_area.end(); ++ loop_idx) {
/* we rely on the already computed area to determine the winding order
of the loops, since the Orientation() function provided by Clipper
would do the same, thus repeating the calculation */
Polygons::const_iterator loop = loops.begin() + *loop_idx;
if (area[*loop_idx] > +EPSILON)
p_slices.push_back(*loop);
else if (area[*loop_idx] < -EPSILON)
//FIXME This is arbitrary and possibly very slow.
// If the hole is inside a polygon, then there is no need to diff.
// If the hole intersects a polygon boundary, then diff it, but then
// there is no guarantee of an ordering of the loops.
// Maybe we can test for the intersection before running the expensive diff algorithm?
p_slices = diff(p_slices, *loop);
}
//std::vector<double> area;
//std::vector<size_t> sorted_area; // vector of indices
//for (Polygons::const_iterator loop = loops.begin(); loop != loops.end(); ++ loop) {
// area.push_back(loop->area());
// sorted_area.push_back(loop - loops.begin());
//}
//
//// outer first
//std::sort(sorted_area.begin(), sorted_area.end(),
// [&area](size_t a, size_t b) { return std::abs(area[a]) > std::abs(area[b]); });
//// we don't perform a safety offset now because it might reverse cw loops
//Polygons p_slices;
//for (std::vector<size_t>::const_iterator loop_idx = sorted_area.begin(); loop_idx != sorted_area.end(); ++ loop_idx) {
// /* we rely on the already computed area to determine the winding order
// of the loops, since the Orientation() function provided by Clipper
// would do the same, thus repeating the calculation */
// Polygons::const_iterator loop = loops.begin() + *loop_idx;
// if (area[*loop_idx] > +EPSILON)
// p_slices.push_back(*loop);
// else if (area[*loop_idx] < -EPSILON)
// //FIXME This is arbitrary and possibly very slow.
// // If the hole is inside a polygon, then there is no need to diff.
// // If the hole intersects a polygon boundary, then diff it, but then
// // there is no guarantee of an ordering of the loops.
// // Maybe we can test for the intersection before running the expensive diff algorithm?
// p_slices = diff(p_slices, *loop);
//}
// perform a safety offset to merge very close facets (TODO: find test case for this)
double safety_offset = scale_(0.0499);
//FIXME see https://github.com/prusa3d/Slic3r/issues/520
// double safety_offset = scale_(0.0001);
ExPolygons ex_slices = offset2_ex(p_slices, +safety_offset, -safety_offset);
/* The following line is commented out because it can generate wrong polygons,
see for example issue #661 */
//ExPolygons ex_slices = offset2_ex(p_slices, +safety_offset, -safety_offset);
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
size_t holes_count = 0;
@ -1231,7 +1236,10 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic
#endif
// append to the supplied collection
expolygons_append(*slices, ex_slices);
/* Fix for issue #661 { */
expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset));
//expolygons_append(*slices, ex_slices);
/* } */
}
void TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const