Enabled the C++ fillers for all infills, not just the supports.
Made sure the C++ fillers are instantiated at the worker threads, where there are being released. Extended the FillRectilinear2 to calculate the contour / line intersection with exact arithmetics, improved robustness and added error handling and error reporting, if the contours to be filled are not correct.
This commit is contained in:
parent
f788f50b5a
commit
9e4edcd8ec
@ -223,7 +223,9 @@ sub thread_cleanup {
|
|||||||
*Slic3r::ExtrusionPath::Collection::DESTROY = sub {};
|
*Slic3r::ExtrusionPath::Collection::DESTROY = sub {};
|
||||||
*Slic3r::ExtrusionSimulator::DESTROY = sub {};
|
*Slic3r::ExtrusionSimulator::DESTROY = sub {};
|
||||||
*Slic3r::Flow::DESTROY = sub {};
|
*Slic3r::Flow::DESTROY = sub {};
|
||||||
*Slic3r::Filler::DESTROY = sub {};
|
# Fillers are only being allocated in worker threads, which are not going to be forked.
|
||||||
|
# Therefore the Filler instances shall be released at the end of the thread.
|
||||||
|
# *Slic3r::Filler::DESTROY = sub {};
|
||||||
*Slic3r::GCode::DESTROY = sub {};
|
*Slic3r::GCode::DESTROY = sub {};
|
||||||
*Slic3r::GCode::AvoidCrossingPerimeters::DESTROY = sub {};
|
*Slic3r::GCode::AvoidCrossingPerimeters::DESTROY = sub {};
|
||||||
*Slic3r::GCode::OozePrevention::DESTROY = sub {};
|
*Slic3r::GCode::OozePrevention::DESTROY = sub {};
|
||||||
|
@ -36,7 +36,9 @@ sub make_fill {
|
|||||||
|
|
||||||
foreach my $layerm (@{$self->regions}) {
|
foreach my $layerm (@{$self->regions}) {
|
||||||
$layerm->fills->clear;
|
$layerm->fills->clear;
|
||||||
$layerm->fills->append($_) for $self->object->fill_maker->make_fill($layerm);
|
# Fearlessly enable the C++ fillers.
|
||||||
|
$layerm->fills->append($_) for $self->object->fill_maker2->make_fill($layerm);
|
||||||
|
# $layerm->fills->append($_) for $self->object->fill_maker->make_fill($layerm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,11 +647,6 @@ sub generate_toolpaths {
|
|||||||
$pattern = 'honeycomb';
|
$pattern = 'honeycomb';
|
||||||
}
|
}
|
||||||
|
|
||||||
my %fillers = (
|
|
||||||
interface => $object->fill_maker2->filler('rectilinear'),
|
|
||||||
support => $object->fill_maker2->filler($pattern),
|
|
||||||
);
|
|
||||||
|
|
||||||
my $interface_angle = $self->object_config->support_material_angle + 90;
|
my $interface_angle = $self->object_config->support_material_angle + 90;
|
||||||
my $interface_spacing = $self->object_config->support_material_interface_spacing + $interface_flow->spacing;
|
my $interface_spacing = $self->object_config->support_material_interface_spacing + $interface_flow->spacing;
|
||||||
my $interface_density = $interface_spacing == 0 ? 1 : $interface_flow->spacing / $interface_spacing;
|
my $interface_density = $interface_spacing == 0 ? 1 : $interface_flow->spacing / $interface_spacing;
|
||||||
@ -763,6 +758,13 @@ sub generate_toolpaths {
|
|||||||
$layer->support_interface_fills->append(@loops);
|
$layer->support_interface_fills->append(@loops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Allocate the fillers exclusively in the worker threads! Don't allocate them at the main thread,
|
||||||
|
# as Perl copies the C++ pointers by default, so then the C++ objects are shared between threads!
|
||||||
|
my %fillers = (
|
||||||
|
interface => $object->fill_maker2->filler('rectilinear'),
|
||||||
|
support => $object->fill_maker2->filler($pattern),
|
||||||
|
);
|
||||||
|
|
||||||
# interface and contact infill
|
# interface and contact infill
|
||||||
if (@$interface || @$contact_infill) {
|
if (@$interface || @$contact_infill) {
|
||||||
$fillers{interface}->set_angle($interface_angle);
|
$fillers{interface}->set_angle($interface_angle);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -16,6 +15,12 @@
|
|||||||
|
|
||||||
// #define SLIC3R_DEBUG
|
// #define SLIC3R_DEBUG
|
||||||
|
|
||||||
|
// Make assert active if SLIC3R_DEBUG
|
||||||
|
#ifdef SLIC3R_DEBUG
|
||||||
|
#undef NDEBUG
|
||||||
|
#endif
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
#include "SVG.hpp"
|
#include "SVG.hpp"
|
||||||
#endif
|
#endif
|
||||||
@ -190,7 +195,8 @@ public:
|
|||||||
SegmentIntersection() :
|
SegmentIntersection() :
|
||||||
iContour(0),
|
iContour(0),
|
||||||
iSegment(0),
|
iSegment(0),
|
||||||
pos(0),
|
pos_p(0),
|
||||||
|
pos_q(1),
|
||||||
type(UNKNOWN),
|
type(UNKNOWN),
|
||||||
consumed_vertical_up(false),
|
consumed_vertical_up(false),
|
||||||
consumed_perimeter_right(false)
|
consumed_perimeter_right(false)
|
||||||
@ -200,8 +206,20 @@ public:
|
|||||||
size_t iContour;
|
size_t iContour;
|
||||||
// Index of a segment in iContour, with which this vertical line intersects.
|
// Index of a segment in iContour, with which this vertical line intersects.
|
||||||
size_t iSegment;
|
size_t iSegment;
|
||||||
// y position of the intersection.
|
// y position of the intersection, ratinal number.
|
||||||
coord_t pos;
|
int64_t pos_p;
|
||||||
|
uint32_t pos_q;
|
||||||
|
|
||||||
|
coord_t pos() const {
|
||||||
|
// Division rounds both positive and negative down to zero.
|
||||||
|
// Add half of q for an arithmetic rounding effect.
|
||||||
|
int64_t p = pos_p;
|
||||||
|
if (p < 0)
|
||||||
|
p -= int64_t(pos_q>>1);
|
||||||
|
else
|
||||||
|
p += int64_t(pos_q>>1);
|
||||||
|
return coord_t(p / int64_t(pos_q));
|
||||||
|
}
|
||||||
|
|
||||||
// Kind of intersection. With the original contour, or with the inner offestted contour?
|
// Kind of intersection. With the original contour, or with the inner offestted contour?
|
||||||
// A vertical segment will be at least intersected by OUTER_LOW, OUTER_HIGH,
|
// A vertical segment will be at least intersected by OUTER_LOW, OUTER_HIGH,
|
||||||
@ -232,8 +250,89 @@ public:
|
|||||||
bool is_low () const { return type == INNER_LOW || type == OUTER_LOW; }
|
bool is_low () const { return type == INNER_LOW || type == OUTER_LOW; }
|
||||||
bool is_high () const { return type == INNER_HIGH || type == OUTER_HIGH; }
|
bool is_high () const { return type == INNER_HIGH || type == OUTER_HIGH; }
|
||||||
|
|
||||||
|
// Compare two y intersection points given by rational numbers.
|
||||||
|
// Note that the rational number is given as pos_p/pos_q, where pos_p is int64 and pos_q is uint32.
|
||||||
|
// This function calculates pos_p * other.pos_q < other.pos_p * pos_q as a 48bit number.
|
||||||
|
// We don't use 128bit intrinsic data types as these are usually not supported by 32bit compilers and
|
||||||
|
// we don't need the full 128bit precision anyway.
|
||||||
bool operator<(const SegmentIntersection &other) const
|
bool operator<(const SegmentIntersection &other) const
|
||||||
{ return pos < other.pos; }
|
{
|
||||||
|
assert(pos_q > 0);
|
||||||
|
assert(other.pos_q > 0);
|
||||||
|
if (pos_p == 0 || other.pos_p == 0) {
|
||||||
|
// Because the denominators are positive and one of the nominators is zero,
|
||||||
|
// following simple statement holds.
|
||||||
|
return pos_p < other.pos_p;
|
||||||
|
} else {
|
||||||
|
// None of the nominators is zero.
|
||||||
|
char sign1 = (pos_p > 0) ? 1 : -1;
|
||||||
|
char sign2 = (other.pos_p > 0) ? 1 : -1;
|
||||||
|
char signs = sign1 * sign2;
|
||||||
|
assert(signs == 1 || signs == -1);
|
||||||
|
if (signs < 0) {
|
||||||
|
// The nominators have different signs.
|
||||||
|
return sign1 < 0;
|
||||||
|
} else {
|
||||||
|
// The nominators have the same sign.
|
||||||
|
// Absolute values
|
||||||
|
uint64_t p1, p2;
|
||||||
|
if (sign1 > 0) {
|
||||||
|
p1 = uint64_t(pos_p);
|
||||||
|
p2 = uint64_t(other.pos_p);
|
||||||
|
} else {
|
||||||
|
p1 = uint64_t(- pos_p);
|
||||||
|
p2 = uint64_t(- other.pos_p);
|
||||||
|
};
|
||||||
|
// Multiply low and high 32bit words of p1 by other_pos.q
|
||||||
|
// 32bit x 32bit => 64bit
|
||||||
|
// l_hi and l_lo overlap by 32 bits.
|
||||||
|
uint64_t l_hi = (p1 >> 32) * uint64_t(other.pos_q);
|
||||||
|
uint64_t l_lo = (p1 & 0xffffffffll) * uint64_t(other.pos_q);
|
||||||
|
l_hi += (l_lo >> 32);
|
||||||
|
uint64_t r_hi = (p2 >> 32) * uint64_t(pos_q);
|
||||||
|
uint64_t r_lo = (p2 & 0xffffffffll) * uint64_t(pos_q);
|
||||||
|
r_hi += (r_lo >> 32);
|
||||||
|
// Compare the high 64 bits.
|
||||||
|
if (l_hi == r_hi) {
|
||||||
|
// Compare the low 32 bits.
|
||||||
|
l_lo &= 0xffffffffll;
|
||||||
|
r_lo &= 0xffffffffll;
|
||||||
|
return (sign1 < 0) ? (l_lo > r_lo) : (l_lo < r_lo);
|
||||||
|
}
|
||||||
|
return (sign1 < 0) ? (l_hi > r_hi) : (l_hi < r_hi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const SegmentIntersection &other) const
|
||||||
|
{
|
||||||
|
assert(pos_q > 0);
|
||||||
|
assert(other.pos_q > 0);
|
||||||
|
if (pos_p == 0 || other.pos_p == 0) {
|
||||||
|
// Because the denominators are positive and one of the nominators is zero,
|
||||||
|
// following simple statement holds.
|
||||||
|
return pos_p == other.pos_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// None of the nominators is zero, none of the denominators is zero.
|
||||||
|
bool positive = pos_p > 0;
|
||||||
|
if (positive != (other.pos_p > 0))
|
||||||
|
return false;
|
||||||
|
// The nominators have the same sign.
|
||||||
|
// Absolute values
|
||||||
|
uint64_t p1 = positive ? uint64_t(pos_p) : uint64_t(- pos_p);
|
||||||
|
uint64_t p2 = positive ? uint64_t(other.pos_p) : uint64_t(- other.pos_p);
|
||||||
|
// Multiply low and high 32bit words of p1 by other_pos.q
|
||||||
|
// 32bit x 32bit => 64bit
|
||||||
|
// l_hi and l_lo overlap by 32 bits.
|
||||||
|
uint64_t l_lo = (p1 & 0xffffffffll) * uint64_t(other.pos_q);
|
||||||
|
uint64_t r_lo = (p2 & 0xffffffffll) * uint64_t(pos_q);
|
||||||
|
if (l_lo != r_lo)
|
||||||
|
return false;
|
||||||
|
uint64_t l_hi = (p1 >> 32) * uint64_t(other.pos_q);
|
||||||
|
uint64_t r_hi = (p2 >> 32) * uint64_t(pos_q);
|
||||||
|
return l_hi + (l_lo >> 32) == r_hi + (r_lo >> 32);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A vertical line with intersection points with polygons.
|
// A vertical line with intersection points with polygons.
|
||||||
@ -260,8 +359,9 @@ public:
|
|||||||
coord_t aoffset2)
|
coord_t aoffset2)
|
||||||
{
|
{
|
||||||
// Copy and rotate the source polygons.
|
// Copy and rotate the source polygons.
|
||||||
polygons_src = (Polygons)expolygon;
|
polygons_src = expolygon;
|
||||||
for (Polygons::iterator it = polygons_src.begin(); it != polygons_src.end(); ++ it)
|
polygons_src.contour.rotate(angle);
|
||||||
|
for (Polygons::iterator it = polygons_src.holes.begin(); it != polygons_src.holes.end(); ++ it)
|
||||||
it->rotate(angle);
|
it->rotate(angle);
|
||||||
|
|
||||||
double mitterLimit = 3.;
|
double mitterLimit = 3.;
|
||||||
@ -271,14 +371,22 @@ public:
|
|||||||
myassert(aoffset1 < 0);
|
myassert(aoffset1 < 0);
|
||||||
myassert(aoffset2 < 0);
|
myassert(aoffset2 < 0);
|
||||||
myassert(aoffset2 < aoffset1);
|
myassert(aoffset2 < aoffset1);
|
||||||
|
bool sticks_removed = remove_sticks(polygons_src);
|
||||||
|
// if (sticks_removed) printf("Sticks removed!\n");
|
||||||
polygons_outer = offset(polygons_src, aoffset1,
|
polygons_outer = offset(polygons_src, aoffset1,
|
||||||
CLIPPER_OFFSET_SCALE,
|
CLIPPER_OFFSET_SCALE,
|
||||||
ClipperLib::jtMiter,
|
ClipperLib::jtMiter,
|
||||||
mitterLimit);
|
mitterLimit);
|
||||||
polygons_inner = offset(polygons_src, aoffset2,
|
polygons_inner = offset(polygons_outer, aoffset2 - aoffset1,
|
||||||
CLIPPER_OFFSET_SCALE,
|
CLIPPER_OFFSET_SCALE,
|
||||||
ClipperLib::jtMiter,
|
ClipperLib::jtMiter,
|
||||||
mitterLimit);
|
mitterLimit);
|
||||||
|
// Filter out contours with zero area or small area, contours with 2 points only.
|
||||||
|
const double min_area_threshold = 0.01 * aoffset2 * aoffset2;
|
||||||
|
remove_small(polygons_outer, min_area_threshold);
|
||||||
|
remove_small(polygons_inner, min_area_threshold);
|
||||||
|
remove_sticks(polygons_outer);
|
||||||
|
remove_sticks(polygons_inner);
|
||||||
n_contours_outer = polygons_outer.size();
|
n_contours_outer = polygons_outer.size();
|
||||||
n_contours_inner = polygons_inner.size();
|
n_contours_inner = polygons_inner.size();
|
||||||
n_contours = n_contours_outer + n_contours_inner;
|
n_contours = n_contours_outer + n_contours_inner;
|
||||||
@ -304,13 +412,21 @@ public:
|
|||||||
bool is_contour_ccw(size_t idx) const { return polygons_ccw[idx]; }
|
bool is_contour_ccw(size_t idx) const { return polygons_ccw[idx]; }
|
||||||
|
|
||||||
BoundingBox bounding_box_src() const
|
BoundingBox bounding_box_src() const
|
||||||
{ return _bounding_box_polygons(polygons_src); }
|
{ return get_extents(polygons_src); }
|
||||||
BoundingBox bounding_box_outer() const
|
BoundingBox bounding_box_outer() const
|
||||||
{ return _bounding_box_polygons(polygons_outer); }
|
{ return get_extents(polygons_outer); }
|
||||||
BoundingBox bounding_box_inner() const
|
BoundingBox bounding_box_inner() const
|
||||||
{ return _bounding_box_polygons(polygons_inner); }
|
{ return get_extents(polygons_inner); }
|
||||||
|
|
||||||
Polygons polygons_src;
|
#ifdef SLIC3R_DEBUG
|
||||||
|
void export_to_svg(Slic3r::SVG &svg) {
|
||||||
|
svg.draw_outline(polygons_src, "black");
|
||||||
|
svg.draw_outline(polygons_outer, "green");
|
||||||
|
svg.draw_outline(polygons_inner, "brown");
|
||||||
|
}
|
||||||
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
|
||||||
|
ExPolygon polygons_src;
|
||||||
Polygons polygons_outer;
|
Polygons polygons_outer;
|
||||||
Polygons polygons_inner;
|
Polygons polygons_inner;
|
||||||
|
|
||||||
@ -321,16 +437,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
// For each polygon of polygons_inner, remember its orientation.
|
// For each polygon of polygons_inner, remember its orientation.
|
||||||
std::vector<unsigned char> polygons_ccw;
|
std::vector<unsigned char> polygons_ccw;
|
||||||
|
|
||||||
static BoundingBox _bounding_box_polygons(const Polygons &poly) {
|
|
||||||
BoundingBox bbox;
|
|
||||||
if (! poly.empty()) {
|
|
||||||
bbox = poly.front().bounding_box();
|
|
||||||
for (size_t i = 1; i < poly.size(); ++ i)
|
|
||||||
bbox.merge(poly[i]);
|
|
||||||
}
|
|
||||||
return bbox;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int distance_of_segmens(const Polygon &poly, size_t seg1, size_t seg2, bool forward)
|
static inline int distance_of_segmens(const Polygon &poly, size_t seg1, size_t seg2, bool forward)
|
||||||
@ -536,8 +642,8 @@ static inline coordf_t measure_perimeter_prev_next_segment_length(
|
|||||||
myassert(itsct.is_inner());
|
myassert(itsct.is_inner());
|
||||||
const bool forward = itsct.is_low() == dir_is_next;
|
const bool forward = itsct.is_low() == dir_is_next;
|
||||||
|
|
||||||
Point p1(il.pos, itsct.pos);
|
Point p1(il.pos, itsct.pos());
|
||||||
Point p2(il2.pos, itsct2.pos);
|
Point p2(il2.pos, itsct2.pos());
|
||||||
return forward ?
|
return forward ?
|
||||||
segment_length(poly, itsct .iSegment, p1, itsct2.iSegment, p2) :
|
segment_length(poly, itsct .iSegment, p1, itsct2.iSegment, p2) :
|
||||||
segment_length(poly, itsct2.iSegment, p2, itsct .iSegment, p1);
|
segment_length(poly, itsct2.iSegment, p2, itsct .iSegment, p1);
|
||||||
@ -604,7 +710,7 @@ static inline void emit_perimeter_prev_next_segment(
|
|||||||
else
|
else
|
||||||
polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
|
polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
|
||||||
// Append the last point.
|
// Append the last point.
|
||||||
out.points.push_back(Point(il2.pos, itsct2.pos));
|
out.points.push_back(Point(il2.pos, itsct2.pos()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the points of a perimeter segment when going from iIntersection to iIntersection2.
|
// Append the points of a perimeter segment when going from iIntersection to iIntersection2.
|
||||||
@ -636,7 +742,7 @@ static inline void emit_perimeter_segment_on_vertical_line(
|
|||||||
else
|
else
|
||||||
polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
|
polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
|
||||||
// Append the last point.
|
// Append the last point.
|
||||||
out.points.push_back(Point(il.pos, itsct2.pos));
|
out.points.push_back(Point(il.pos, itsct2.pos()));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DirectionMask
|
enum DirectionMask
|
||||||
@ -645,7 +751,7 @@ enum DirectionMask
|
|||||||
DIR_BACKWARD = 2
|
DIR_BACKWARD = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, Polylines &polylines_out)
|
bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, Polylines &polylines_out)
|
||||||
{
|
{
|
||||||
// At the end, only the new polylines will be rotated back.
|
// At the end, only the new polylines will be rotated back.
|
||||||
size_t n_polylines_out_initial = polylines_out.size();
|
size_t n_polylines_out_initial = polylines_out.size();
|
||||||
@ -672,7 +778,7 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
scale_(- 0.5 * this->spacing));
|
scale_(- 0.5 * this->spacing));
|
||||||
if (poly_with_offset.n_contours_inner == 0) {
|
if (poly_with_offset.n_contours_inner == 0) {
|
||||||
//FIXME maybe one shall trigger the gap fill here?
|
//FIXME maybe one shall trigger the gap fill here?
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox bounding_box = poly_with_offset.bounding_box_outer();
|
BoundingBox bounding_box = poly_with_offset.bounding_box_outer();
|
||||||
@ -696,27 +802,13 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
coord_t x0 = bounding_box.min.x + this->_line_spacing;
|
coord_t x0 = bounding_box.min.x + this->_line_spacing;
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
char path[2048];
|
|
||||||
static int iRun = 0;
|
static int iRun = 0;
|
||||||
sprintf(path, "out/FillRectilinear2-%d.svg", iRun);
|
|
||||||
BoundingBox bbox_svg = poly_with_offset.bounding_box_outer();
|
BoundingBox bbox_svg = poly_with_offset.bounding_box_outer();
|
||||||
::Slic3r::SVG svg(path, bbox_svg); // , scale_(1.));
|
::Slic3r::SVG svg(debug_out_path("FillRectilinear2-%d.svg", iRun), bbox_svg); // , scale_(1.));
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_src.size(); ++ i)
|
poly_with_offset.export_to_svg(svg);
|
||||||
svg.draw(poly_with_offset.polygons_src[i].lines());
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_outer.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_outer[i].lines(), "green");
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_inner.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_inner[i].lines(), "brown");
|
|
||||||
{
|
{
|
||||||
char path2[2048];
|
::Slic3r::SVG svg(debug_out_path("FillRectilinear2-initial-%d.svg", iRun), bbox_svg); // , scale_(1.));
|
||||||
sprintf(path2, "out/FillRectilinear2-initial-%d.svg", iRun);
|
poly_with_offset.export_to_svg(svg);
|
||||||
::Slic3r::SVG svg(path2, bbox_svg); // , scale_(1.));
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_src.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_src[i].lines());
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_outer.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_outer[i].lines(), "green");
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_inner.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_inner[i].lines(), "brown");
|
|
||||||
}
|
}
|
||||||
iRun ++;
|
iRun ++;
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
@ -756,39 +848,42 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
continue;
|
continue;
|
||||||
myassert(il >= 0 && il < segs.size());
|
myassert(il >= 0 && il < segs.size());
|
||||||
myassert(ir >= 0 && ir < segs.size());
|
myassert(ir >= 0 && ir < segs.size());
|
||||||
if (l == r) {
|
for (int i = il; i <= ir; ++ i) {
|
||||||
// The segment is vertical.
|
coord_t this_x = segs[i].pos;
|
||||||
// Don't insert vertical segments at all.
|
assert(this_x == i * this->_line_spacing + x0);
|
||||||
// If the contour is not degenerate, then this vertical line will be crossed
|
|
||||||
// by the non-vertical segments preceding resp. succeeding this vertical segment.
|
|
||||||
/*
|
|
||||||
SegmentIntersection is;
|
SegmentIntersection is;
|
||||||
is.iContour = iContour;
|
is.iContour = iContour;
|
||||||
is.iSegment = iSegment;
|
is.iSegment = iSegment;
|
||||||
is.pos = p1.y;
|
myassert(l <= this_x);
|
||||||
segs[il].intersections.push_back(is);
|
myassert(r >= this_x);
|
||||||
is.pos = p2.y;
|
// Calculate the intersection position in y axis. x is known.
|
||||||
segs[il].intersections.push_back(is);
|
if (p1.x == this_x) {
|
||||||
*/
|
if (p2.x == this_x) {
|
||||||
|
// Ignore strictly vertical segments.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int i = il; i <= ir; ++ i) {
|
is.pos_p = p1.y;
|
||||||
SegmentIntersection is;
|
is.pos_q = 1;
|
||||||
is.iContour = iContour;
|
} else if (p2.x == this_x) {
|
||||||
is.iSegment = iSegment;
|
is.pos_p = p2.y;
|
||||||
myassert(l <= segs[i].pos);
|
is.pos_q = 1;
|
||||||
myassert(r >= segs[i].pos);
|
} else {
|
||||||
// Calculate the intersection position in y axis. x is known.
|
// First calculate the intersection parameter 't' as a rational number with non negative denominator.
|
||||||
double t = double(segs[i].pos - p1.x) / double(p2.x - p1.x);
|
if (p2.x > p1.x) {
|
||||||
myassert(t > -0.000001 && t < 1.000001);
|
is.pos_p = this_x - p1.x;
|
||||||
t = clamp(0., 1., t);
|
is.pos_q = p2.x - p1.x;
|
||||||
coord_t lo = p1.y;
|
} else {
|
||||||
coord_t hi = p2.y;
|
is.pos_p = p1.x - this_x;
|
||||||
if (lo > hi)
|
is.pos_q = p1.x - p2.x;
|
||||||
std::swap(lo, hi);
|
}
|
||||||
is.pos = p1.y + coord_t(t * double(p2.y - p1.y));
|
myassert(is.pos_p >= 0 && is.pos_p <= is.pos_q);
|
||||||
myassert(is.pos > lo - 0.000001 && is.pos < hi + 0.000001);
|
// Make an intersection point from the 't'.
|
||||||
is.pos = clamp(lo, hi, is.pos);
|
is.pos_p *= int64_t(p2.y - p1.y);
|
||||||
|
is.pos_p += p1.y * int64_t(is.pos_q);
|
||||||
|
}
|
||||||
|
// +-1 to take rounding into account.
|
||||||
|
myassert(is.pos() + 1 >= std::min(p1.y, p2.y));
|
||||||
|
myassert(is.pos() <= std::max(p1.y, p2.y) + 1);
|
||||||
segs[i].intersections.push_back(is);
|
segs[i].intersections.push_back(is);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -797,9 +892,10 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
// Sort the intersections along their segments, specify the intersection types.
|
// Sort the intersections along their segments, specify the intersection types.
|
||||||
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
||||||
SegmentedIntersectionLine &sil = segs[i_seg];
|
SegmentedIntersectionLine &sil = segs[i_seg];
|
||||||
// Sort the intersection points. This needs to be verified, because the intersection points were calculated
|
// Sort the intersection points using exact rational arithmetic.
|
||||||
// using imprecise arithmetics.
|
|
||||||
std::sort(sil.intersections.begin(), sil.intersections.end());
|
std::sort(sil.intersections.begin(), sil.intersections.end());
|
||||||
|
|
||||||
|
#if 0
|
||||||
// Verify the order, bubble sort the intersections until sorted.
|
// Verify the order, bubble sort the intersections until sorted.
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
do {
|
do {
|
||||||
@ -888,12 +984,20 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
if (swap) {
|
if (swap) {
|
||||||
// Swap the intersection points, but keep the original positions, so they stay sorted by the y axis.
|
// Swap the intersection points, but keep the original positions, so they stay sorted by the y axis.
|
||||||
std::swap(sil.intersections[i-1], sil.intersections[i]);
|
std::swap(sil.intersections[i-1], sil.intersections[i]);
|
||||||
std::swap(sil.intersections[i-1].pos, sil.intersections[i].pos);
|
std::swap(sil.intersections[i-1].pos_p, sil.intersections[i].pos_p);
|
||||||
|
std::swap(sil.intersections[i-1].pos_q, sil.intersections[i].pos_q);
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (modified);
|
} while (modified);
|
||||||
// Assign the intersection types.
|
#endif
|
||||||
|
|
||||||
|
// Assign the intersection types, remove duplicate or overlapping intersection points.
|
||||||
|
// When a loop vertex touches a vertical line, intersection point is generated for both segments.
|
||||||
|
// If such two segments are oriented equally, then one of them is removed.
|
||||||
|
// Otherwise the vertex is tangential to the vertical line and both segments are removed.
|
||||||
|
// The same rule applies, if the loop is pinched into a single point and this point touches the vertical line:
|
||||||
|
// The loop has a zero vertical size at the vertical line, therefore the intersection point is removed.
|
||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
for (size_t i = 0; i < sil.intersections.size(); ++ i) {
|
for (size_t i = 0; i < sil.intersections.size(); ++ i) {
|
||||||
// What is the orientation of the segment at the intersection point?
|
// What is the orientation of the segment at the intersection point?
|
||||||
@ -909,75 +1013,75 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
(low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) :
|
(low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) :
|
||||||
(low ? SegmentIntersection::INNER_LOW : SegmentIntersection::INNER_HIGH);
|
(low ? SegmentIntersection::INNER_LOW : SegmentIntersection::INNER_HIGH);
|
||||||
if (j > 0 &&
|
if (j > 0 &&
|
||||||
sil.intersections[i].pos == sil.intersections[j-1].pos &&
|
sil.intersections[i].pos() == sil.intersections[j-1].pos() &&
|
||||||
sil.intersections[i].type == sil.intersections[j-1].type &&
|
|
||||||
sil.intersections[i].iContour == sil.intersections[j-1].iContour) {
|
sil.intersections[i].iContour == sil.intersections[j-1].iContour) {
|
||||||
|
if (sil.intersections[i].type == sil.intersections[j-1].type) {
|
||||||
// This has to be a corner point crossing the vertical line.
|
// This has to be a corner point crossing the vertical line.
|
||||||
// Remove the second intersection point.
|
// Remove the second intersection point.
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
||||||
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
||||||
myassert(iSegment == iPrev2 || iSegment2 == iPrev);
|
myassert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
} else {
|
||||||
|
// This is a loop returning to the same point.
|
||||||
|
// It may as well be a vertex of a loop touching this vertical line.
|
||||||
|
// Remove both the lines.
|
||||||
|
-- j;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (j < i)
|
if (j < i)
|
||||||
sil.intersections[j] = sil.intersections[i];
|
sil.intersections[j] = sil.intersections[i];
|
||||||
++ j;
|
++ j;
|
||||||
}
|
}
|
||||||
|
//FIXME solve a degenerate case, where there is a vertical segment on this vertical line and the contour
|
||||||
|
// follows from left to right or vice versa, leading to low,low or high,high intersections.
|
||||||
}
|
}
|
||||||
// Shrink the list of intersections, if any of the intersection was removed during the classification.
|
// Shrink the list of intersections, if any of the intersection was removed during the classification.
|
||||||
if (j < sil.intersections.size())
|
if (j < sil.intersections.size())
|
||||||
sil.intersections.erase(sil.intersections.begin() + j, sil.intersections.end());
|
sil.intersections.erase(sil.intersections.begin() + j, sil.intersections.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
// Verify the segments. If something is wrong, give up.
|
||||||
// Verify the segments & paint them.
|
#define ASSERT_OR_RETURN(CONDITION) do { assert(CONDITION); if (CONDITION) return false; } while (0)
|
||||||
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
||||||
SegmentedIntersectionLine &sil = segs[i_seg];
|
SegmentedIntersectionLine &sil = segs[i_seg];
|
||||||
// The intersection points have to be even.
|
// The intersection points have to be even.
|
||||||
myassert((sil.intersections.size() & 1) == 0);
|
ASSERT_OR_RETURN((sil.intersections.size() & 1) == 0);
|
||||||
for (size_t i = 0; i < sil.intersections.size();) {
|
for (size_t i = 0; i < sil.intersections.size();) {
|
||||||
// An intersection segment crossing the bigger contour may cross the inner offsetted contour even number of times.
|
// An intersection segment crossing the bigger contour may cross the inner offsetted contour even number of times.
|
||||||
myassert(sil.intersections[i].type == SegmentIntersection::OUTER_LOW);
|
ASSERT_OR_RETURN(sil.intersections[i].type == SegmentIntersection::OUTER_LOW);
|
||||||
|
size_t j = i + 1;
|
||||||
|
ASSERT_OR_RETURN(j < sil.intersections.size());
|
||||||
|
ASSERT_OR_RETURN(sil.intersections[j].type == SegmentIntersection::INNER_LOW || sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
|
||||||
|
for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++ j) ;
|
||||||
|
ASSERT_OR_RETURN(j < sil.intersections.size());
|
||||||
|
ASSERT_OR_RETURN((j & 1) == 1);
|
||||||
|
ASSERT_OR_RETURN(sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
|
||||||
|
ASSERT_OR_RETURN(i + 1 == j || sil.intersections[j - 1].type == SegmentIntersection::INNER_HIGH);
|
||||||
|
i = j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef ASSERT_OR_RETURN
|
||||||
|
|
||||||
|
#ifdef SLIC3R_DEBUG
|
||||||
|
// Paint the segments and finalize the SVG file.
|
||||||
|
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
||||||
|
SegmentedIntersectionLine &sil = segs[i_seg];
|
||||||
|
for (size_t i = 0; i < sil.intersections.size();) {
|
||||||
size_t j = i + 1;
|
size_t j = i + 1;
|
||||||
myassert(j < sil.intersections.size());
|
|
||||||
myassert(sil.intersections[j].type == SegmentIntersection::INNER_LOW || sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
|
|
||||||
for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++ j) ;
|
for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++ j) ;
|
||||||
myassert(j < sil.intersections.size());
|
|
||||||
myassert((j & 1) == 1);
|
|
||||||
myassert(sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
|
|
||||||
myassert(i + 1 == j || sil.intersections[j - 1].type == SegmentIntersection::INNER_HIGH);
|
|
||||||
if (i + 1 == j) {
|
if (i + 1 == j) {
|
||||||
svg.draw(Line(Point(sil.pos, sil.intersections[i].pos), Point(sil.pos, sil.intersections[j].pos)), "blue");
|
svg.draw(Line(Point(sil.pos, sil.intersections[i].pos()), Point(sil.pos, sil.intersections[j].pos())), "blue");
|
||||||
} else {
|
} else {
|
||||||
svg.draw(Line(Point(sil.pos, sil.intersections[i].pos), Point(sil.pos, sil.intersections[i+1].pos)), "green");
|
svg.draw(Line(Point(sil.pos, sil.intersections[i].pos()), Point(sil.pos, sil.intersections[i+1].pos())), "green");
|
||||||
svg.draw(Line(Point(sil.pos, sil.intersections[i+1].pos), Point(sil.pos, sil.intersections[j-1].pos)), (j - i + 1 > 4) ? "yellow" : "magenta");
|
svg.draw(Line(Point(sil.pos, sil.intersections[i+1].pos()), Point(sil.pos, sil.intersections[j-1].pos())), (j - i + 1 > 4) ? "yellow" : "magenta");
|
||||||
svg.draw(Line(Point(sil.pos, sil.intersections[j-1].pos), Point(sil.pos, sil.intersections[j].pos)), "green");
|
svg.draw(Line(Point(sil.pos, sil.intersections[j-1].pos()), Point(sil.pos, sil.intersections[j].pos())), "green");
|
||||||
}
|
}
|
||||||
i = j + 1;
|
i = j + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
svg.Close();
|
svg.Close();
|
||||||
|
|
||||||
// Verify the segments & paint them.
|
|
||||||
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
|
||||||
SegmentedIntersectionLine &sil = segs[i_seg];
|
|
||||||
// The intersection points have to be even.
|
|
||||||
myassert((sil.intersections.size() & 1) == 0);
|
|
||||||
for (size_t i = 0; i < sil.intersections.size();) {
|
|
||||||
// An intersection segment crossing the bigger contour may cross the inner offsetted contour even number of times.
|
|
||||||
myassert(sil.intersections[i].type == SegmentIntersection::OUTER_LOW);
|
|
||||||
size_t j = i + 1;
|
|
||||||
myassert(j < sil.intersections.size());
|
|
||||||
myassert(sil.intersections[j].type == SegmentIntersection::INNER_LOW || sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
|
|
||||||
for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++ j) ;
|
|
||||||
myassert(j < sil.intersections.size());
|
|
||||||
myassert((j & 1) == 1);
|
|
||||||
myassert(sil.intersections[j].type == SegmentIntersection::OUTER_HIGH);
|
|
||||||
myassert(i + 1 == j || sil.intersections[j - 1].type == SegmentIntersection::INNER_HIGH);
|
|
||||||
i = j + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
|
||||||
// Mark an outer only chord as consumed, so there will be no tiny pieces emitted.
|
// Mark an outer only chord as consumed, so there will be no tiny pieces emitted.
|
||||||
@ -992,7 +1096,9 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
|
|
||||||
// Now construct a graph.
|
// Now construct a graph.
|
||||||
// Find the first point.
|
// Find the first point.
|
||||||
//FIXME ideally one would plan the initial point to be closest to the current print head position.
|
// Naively one would expect to achieve best results by chaining the paths by the shortest distance,
|
||||||
|
// but that procedure does not create the longest continuous paths.
|
||||||
|
// A simple "sweep left to right" procedure achieves better results.
|
||||||
size_t i_vline = 0;
|
size_t i_vline = 0;
|
||||||
size_t i_intersection = size_t(-1);
|
size_t i_intersection = size_t(-1);
|
||||||
// Follow the line, connect the lines into a graph.
|
// Follow the line, connect the lines into a graph.
|
||||||
@ -1020,7 +1126,7 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
intrsctn.consumed_vertical_up :
|
intrsctn.consumed_vertical_up :
|
||||||
seg.intersections[i-1].consumed_vertical_up;
|
seg.intersections[i-1].consumed_vertical_up;
|
||||||
if (! consumed) {
|
if (! consumed) {
|
||||||
coordf_t dist2 = sqr(coordf_t(pointLast.x - seg.pos)) + sqr(coordf_t(pointLast.y - intrsctn.pos));
|
coordf_t dist2 = sqr(coordf_t(pointLast.x - seg.pos)) + sqr(coordf_t(pointLast.y - intrsctn.pos()));
|
||||||
if (dist2 < dist2min) {
|
if (dist2 < dist2min) {
|
||||||
dist2min = dist2;
|
dist2min = dist2;
|
||||||
i_vline = i_vline2;
|
i_vline = i_vline2;
|
||||||
@ -1044,7 +1150,7 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
polylines_out.push_back(Polyline());
|
polylines_out.push_back(Polyline());
|
||||||
polyline_current = &polylines_out.back();
|
polyline_current = &polylines_out.back();
|
||||||
// Emit the first point of a path.
|
// Emit the first point of a path.
|
||||||
pointLast = Point(segs[i_vline].pos, segs[i_vline].intersections[i_intersection].pos);
|
pointLast = Point(segs[i_vline].pos, segs[i_vline].intersections[i_intersection].pos());
|
||||||
polyline_current->points.push_back(pointLast);
|
polyline_current->points.push_back(pointLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1190,7 +1296,7 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
(distNext < distPrev) :
|
(distNext < distPrev) :
|
||||||
intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
|
intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
|
||||||
myassert(intrsctn->is_inner());
|
myassert(intrsctn->is_inner());
|
||||||
polyline_current->points.push_back(Point(seg.pos, intrsctn->pos));
|
polyline_current->points.push_back(Point(seg.pos, intrsctn->pos()));
|
||||||
emit_perimeter_prev_next_segment(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, take_next ? iNext : iPrev, *polyline_current, take_next);
|
emit_perimeter_prev_next_segment(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, take_next ? iNext : iPrev, *polyline_current, take_next);
|
||||||
// Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
|
// Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
|
||||||
if (iPrev != -1)
|
if (iPrev != -1)
|
||||||
@ -1241,7 +1347,7 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
distance_of_segmens(poly, intrsctn->iSegment, iSegNext, false)) :
|
distance_of_segmens(poly, intrsctn->iSegment, iSegNext, false)) :
|
||||||
(vert_seg_dir_valid_mask == DIR_FORWARD);
|
(vert_seg_dir_valid_mask == DIR_FORWARD);
|
||||||
// Consume the connecting contour and the next segment.
|
// Consume the connecting contour and the next segment.
|
||||||
polyline_current->points.push_back(Point(seg.pos, intrsctn->pos));
|
polyline_current->points.push_back(Point(seg.pos, intrsctn->pos()));
|
||||||
emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iNext, *polyline_current, dir_forward);
|
emit_perimeter_segment_on_vertical_line(poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iNext, *polyline_current, dir_forward);
|
||||||
// Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
|
// Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
|
||||||
// If there are any outer intersection points skipped (bypassed) by the contour,
|
// If there are any outer intersection points skipped (bypassed) by the contour,
|
||||||
@ -1277,7 +1383,7 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
// reset the current vertical line to pick a new starting point in the next round.
|
// reset the current vertical line to pick a new starting point in the next round.
|
||||||
myassert(intrsctn->is_outer());
|
myassert(intrsctn->is_outer());
|
||||||
myassert(intrsctn->is_high() == going_up);
|
myassert(intrsctn->is_high() == going_up);
|
||||||
pointLast = Point(seg.pos, intrsctn->pos);
|
pointLast = Point(seg.pos, intrsctn->pos());
|
||||||
polyline_current->points.push_back(pointLast);
|
polyline_current->points.push_back(pointLast);
|
||||||
// Handle duplicate points and zero length segments.
|
// Handle duplicate points and zero length segments.
|
||||||
polyline_current->remove_duplicate_points();
|
polyline_current->remove_duplicate_points();
|
||||||
@ -1296,30 +1402,15 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
sprintf(path, "out\\FillRectilinear2-final-%03d.svg", iRun);
|
::Slic3r::SVG svg(debug_out_path("FillRectilinear2-final-%03d.svg", iRun), bbox_svg); // , scale_(1.));
|
||||||
::Slic3r::SVG svg(path, bbox_svg); // , scale_(1.));
|
poly_with_offset.export_to_svg(svg);
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_src.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_src[i].lines());
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_outer.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_outer[i].lines(), "green");
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_inner.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_inner[i].lines(), "brown");
|
|
||||||
for (size_t i = n_polylines_out_initial; i < polylines_out.size(); ++ i)
|
for (size_t i = n_polylines_out_initial; i < polylines_out.size(); ++ i)
|
||||||
svg.draw(polylines_out[i].lines(), "black");
|
svg.draw(polylines_out[i].lines(), "black");
|
||||||
svg.Close();
|
|
||||||
}
|
}
|
||||||
// Paint a picture per polyline. This makes it easier to discover the order of the polylines and their overlap.
|
// Paint a picture per polyline. This makes it easier to discover the order of the polylines and their overlap.
|
||||||
for (size_t i_polyline = n_polylines_out_initial; i_polyline < polylines_out.size(); ++ i_polyline) {
|
for (size_t i_polyline = n_polylines_out_initial; i_polyline < polylines_out.size(); ++ i_polyline) {
|
||||||
sprintf(path, "out\\FillRectilinear2-final-%03d-%03d.svg", iRun, i_polyline);
|
::Slic3r::SVG svg(debug_out_path("FillRectilinear2-final-%03d-%03d.svg", iRun, i_polyline), bbox_svg); // , scale_(1.));
|
||||||
::Slic3r::SVG svg(path, bbox_svg); // , scale_(1.));
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_src.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_src[i].lines());
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_outer.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_outer[i].lines(), "green");
|
|
||||||
for (size_t i = 0; i < poly_with_offset.polygons_inner.size(); ++ i)
|
|
||||||
svg.draw(poly_with_offset.polygons_inner[i].lines(), "brown");
|
|
||||||
svg.draw(polylines_out[i_polyline].lines(), "black");
|
svg.draw(polylines_out[i_polyline].lines(), "black");
|
||||||
svg.Close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
@ -1340,20 +1431,26 @@ void FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
for (Polylines::iterator it = polylines_out.begin(); it != polylines_out.end(); ++ it)
|
for (Polylines::iterator it = polylines_out.begin(); it != polylines_out.end(); ++ it)
|
||||||
myassert(! it->has_duplicate_points());
|
myassert(! it->has_duplicate_points());
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParams ¶ms)
|
Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||||
{
|
{
|
||||||
Polylines polylines_out;
|
Polylines polylines_out;
|
||||||
fill_surface_by_lines(surface, params, 0.f, polylines_out);
|
if (! fill_surface_by_lines(surface, params, 0.f, polylines_out)) {
|
||||||
|
printf("FillRectilinear2::fill_surface() failed to fill a region.\n");
|
||||||
|
}
|
||||||
return polylines_out;
|
return polylines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Polylines FillGrid2::fill_surface(const Surface *surface, const FillParams ¶ms)
|
Polylines FillGrid2::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||||
{
|
{
|
||||||
Polylines polylines_out;
|
Polylines polylines_out;
|
||||||
fill_surface_by_lines(surface, params, 0.f, polylines_out);
|
if (! fill_surface_by_lines(surface, params, 0.f, polylines_out) ||
|
||||||
fill_surface_by_lines(surface, params, float(M_PI / 2.), polylines_out);
|
! fill_surface_by_lines(surface, params, float(M_PI / 2.), polylines_out)) {
|
||||||
|
printf("FillRectilinear2::fill_surface() failed to fill a region.\n");
|
||||||
|
}
|
||||||
return polylines_out;
|
return polylines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ public:
|
|||||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, Polylines &polylines_out);
|
bool fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, Polylines &polylines_out);
|
||||||
|
|
||||||
coord_t _min_spacing;
|
coord_t _min_spacing;
|
||||||
coord_t _line_spacing;
|
coord_t _line_spacing;
|
||||||
|
@ -406,7 +406,7 @@ bool remove_small(Polygons &polys, double min_area)
|
|||||||
bool modified = false;
|
bool modified = false;
|
||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
for (size_t i = 0; i < polys.size(); ++ i) {
|
for (size_t i = 0; i < polys.size(); ++ i) {
|
||||||
if (polys[i].area() >= min_area) {
|
if (std::abs(polys[i].area()) >= min_area) {
|
||||||
if (j < i)
|
if (j < i)
|
||||||
std::swap(polys[i].points, polys[j].points);
|
std::swap(polys[i].points, polys[j].points);
|
||||||
++ j;
|
++ j;
|
||||||
|
@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
SVG::SVG(const char* filename)
|
bool SVG::open(const char* afilename)
|
||||||
: arrows(false), fill("grey"), stroke("black"), filename(filename), flipY(false)
|
|
||||||
{
|
{
|
||||||
this->f = fopen(filename, "w");
|
this->filename = afilename;
|
||||||
|
this->f = fopen(afilename, "w");
|
||||||
|
if (this->f == NULL)
|
||||||
|
return false;
|
||||||
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"
|
||||||
@ -17,12 +19,17 @@ SVG::SVG(const char* filename)
|
|||||||
" <polyline fill=\"darkblue\" points=\"0,0 10,5 0,10 1,5\" />\n"
|
" <polyline fill=\"darkblue\" points=\"0,0 10,5 0,10 1,5\" />\n"
|
||||||
" </marker>\n"
|
" </marker>\n"
|
||||||
);
|
);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SVG::SVG(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset, bool aflipY)
|
bool SVG::open(const char* afilename, 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");
|
this->filename = afilename;
|
||||||
|
this->origin = bbox.min - Point(bbox_offset, bbox_offset);
|
||||||
|
this->flipY = aflipY;
|
||||||
|
this->f = ::fopen(afilename, "w");
|
||||||
|
if (f == NULL)
|
||||||
|
return false;
|
||||||
float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset);
|
float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset);
|
||||||
float h = COORD(bbox.max.y - bbox.min.y + 2 * bbox_offset);
|
float h = COORD(bbox.max.y - bbox.min.y + 2 * bbox_offset);
|
||||||
fprintf(this->f,
|
fprintf(this->f,
|
||||||
@ -33,6 +40,7 @@ SVG::SVG(const char* filename, const BoundingBox &bbox, const coord_t bbox_offse
|
|||||||
" <polyline fill=\"darkblue\" points=\"0,0 10,5 0,10 1,5\" />\n"
|
" <polyline fill=\"darkblue\" points=\"0,0 10,5 0,10 1,5\" />\n"
|
||||||
" </marker>\n",
|
" </marker>\n",
|
||||||
h, w);
|
h, w);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -18,10 +18,27 @@ class SVG
|
|||||||
Point origin;
|
Point origin;
|
||||||
bool flipY;
|
bool flipY;
|
||||||
|
|
||||||
SVG(const char* filename);
|
SVG(const char* afilename) :
|
||||||
SVG(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false);
|
arrows(false), fill("grey"), stroke("black"), filename(afilename), flipY(false)
|
||||||
|
{ open(filename); }
|
||||||
|
SVG(const char* afilename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) :
|
||||||
|
arrows(false), fill("grey"), stroke("black"), filename(afilename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY)
|
||||||
|
{ open(filename, bbox, bbox_offset, aflipY); }
|
||||||
|
SVG(const std::string &filename) :
|
||||||
|
arrows(false), fill("grey"), stroke("black"), filename(filename), flipY(false)
|
||||||
|
{ open(filename); }
|
||||||
|
SVG(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) :
|
||||||
|
arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY)
|
||||||
|
{ open(filename, bbox, bbox_offset, aflipY); }
|
||||||
~SVG() { if (f != NULL) Close(); }
|
~SVG() { if (f != NULL) Close(); }
|
||||||
|
|
||||||
|
bool open(const char* filename);
|
||||||
|
bool open(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false);
|
||||||
|
bool open(const std::string &filename)
|
||||||
|
{ return open(filename.c_str()); }
|
||||||
|
bool open(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false)
|
||||||
|
{ return open(filename.c_str(), bbox, bbox_offset, flipY); }
|
||||||
|
|
||||||
void draw(const Line &line, std::string stroke = "black", coordf_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, 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 Lines &lines, std::string stroke = "black", coordf_t stroke_width = 0);
|
||||||
|
@ -144,7 +144,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_object_1st_layer_gap = m_soluble_interface ? 0 : m_object_config->support_material_contact_distance;
|
m_object_1st_layer_gap = m_soluble_interface ? 0. : m_object_config->support_material_contact_distance.value;
|
||||||
m_object_1st_layer_print_z = m_raft_height + m_object_1st_layer_gap + m_object_1st_layer_height;
|
m_object_1st_layer_print_z = m_raft_height + m_object_1st_layer_gap + m_object_1st_layer_height;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define slic3r_SupportMaterial_hpp_
|
#define slic3r_SupportMaterial_hpp_
|
||||||
|
|
||||||
#include "Flow.hpp"
|
#include "Flow.hpp"
|
||||||
|
#include "PrintConfig.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#define SLIC3R_VERSION "1.3.0-dev"
|
#define SLIC3R_VERSION "1.3.0-dev"
|
||||||
|
|
||||||
@ -63,6 +64,18 @@ void confess_at(const char *file, int line, const char *func, const char *pat, .
|
|||||||
#define SLIC3R_CPPVER 0
|
#define SLIC3R_CPPVER 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_FILE_PREFIX "out/"
|
||||||
|
|
||||||
|
inline std::string debug_out_path(const char *name, ...)
|
||||||
|
{
|
||||||
|
char buffer[2048];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, name);
|
||||||
|
vsprintf(buffer, name, args);
|
||||||
|
va_end(args);
|
||||||
|
return std::string(DEBUG_FILE_PREFIX) + std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
// Write slices as SVG images into out directory during the 2D processing of the slices.
|
// Write slices as SVG images into out directory during the 2D processing of the slices.
|
||||||
// #define SLIC3R_DEBUG_SLICE_PROCESSING
|
// #define SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user