New Rectilinear implementation based on @bubnikv's work. Faster, more robust, follows perimeters better, makes more continuous lines. Also includes the new Triangles, Stars, Cubic patterns. Line pattern was removed

This commit is contained in:
Alessandro Ranellucci 2016-12-12 01:38:48 +01:00
parent 540d632bbb
commit a881f755a1
21 changed files with 666 additions and 240 deletions

View File

@ -2,7 +2,7 @@ use Test::More;
use strict; use strict;
use warnings; use warnings;
plan tests => 43; plan tests => 92;
BEGIN { BEGIN {
use FindBin; use FindBin;
@ -11,8 +11,8 @@ BEGIN {
use List::Util qw(first sum); use List::Util qw(first sum);
use Slic3r; use Slic3r;
use Slic3r::Geometry qw(PI X Y scale unscale convex_hull); use Slic3r::Geometry qw(PI X Y scaled_epsilon scale unscale convex_hull);
use Slic3r::Geometry::Clipper qw(union diff diff_ex offset offset2_ex); use Slic3r::Geometry::Clipper qw(union diff diff_ex offset offset2_ex diff_pl);
use Slic3r::Surface qw(:types); use Slic3r::Surface qw(:types);
use Slic3r::Test; use Slic3r::Test;
@ -26,6 +26,67 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
is $surface_width % $distance, 0, 'adjusted solid distance'; is $surface_width % $distance, 0, 'adjusted solid distance';
} }
{
my $filler = Slic3r::Filler->new_from_type('rectilinear');
$filler->set_angle(-(PI)/2);
$filler->set_spacing(5);
$filler->set_dont_adjust(1);
$filler->set_endpoints_overlap(0);
my $test = sub {
my ($expolygon) = @_;
my $surface = Slic3r::Surface->new(
surface_type => S_TYPE_TOP,
expolygon => $expolygon,
);
return $filler->fill_surface($surface);
};
# square
$filler->set_density($filler->spacing / 50);
for my $i (0..3) {
# check that it works regardless of the points order
my @points = ([0,0], [100,0], [100,100], [0,100]);
@points = (@points[$i..$#points], @points[0..($i-1)]);
my $paths = $test->(my $e = Slic3r::ExPolygon->new([ scale_points @points ]));
is(scalar @$paths, 1, 'one continuous path') or done_testing, exit;
ok abs($paths->[0]->length - scale(3*100 + 2*50)) - scaled_epsilon, 'path has expected length';
}
# diamond with endpoints on grid
{
my $paths = $test->(my $e = Slic3r::ExPolygon->new([ scale_points [0,0], [100,0], [150,50], [100,100], [0,100], [-50,50] ]));
is(scalar @$paths, 1, 'one continuous path') or done_testing, exit;
}
# square with hole
for my $angle (-(PI/2), -(PI/4), -(PI), PI/2, PI) {
for my $spacing (25, 5, 7.5, 8.5) {
$filler->set_density($filler->spacing / $spacing);
$filler->set_angle($angle);
my $paths = $test->(my $e = Slic3r::ExPolygon->new(
[ scale_points [0,0], [100,0], [100,100], [0,100] ],
[ scale_points reverse [25,25], [75,25], [75,75], [25,75] ],
));
if (0) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output(
"fill.svg",
no_arrows => 1,
expolygons => [$e],
polylines => $paths,
);
}
ok(@$paths >= 2 && @$paths <= 3, '2 or 3 continuous paths') or done_testing, exit;
ok(!@{diff_pl($paths->arrayref, offset(\@$e, +scaled_epsilon*10))},
'paths don\'t cross hole') or done_testing, exit;
}
}
}
{ {
my $expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,50], [0,50] ]); my $expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,50], [0,50] ]);
my $filler = Slic3r::Filler->new_from_type('rectilinear'); my $filler = Slic3r::Filler->new_from_type('rectilinear');
@ -41,6 +102,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
nozzle_diameter => 0.50, nozzle_diameter => 0.50,
); );
$filler->set_spacing($flow->spacing); $filler->set_spacing($flow->spacing);
$filler->set_density(1);
foreach my $angle (0, 45) { foreach my $angle (0, 45) {
$surface->expolygon->rotate(Slic3r::Geometry::deg2rad($angle), [0,0]); $surface->expolygon->rotate(Slic3r::Geometry::deg2rad($angle), [0,0]);
my $paths = $filler->fill_surface($surface, layer_height => 0.4, density => 0.4); my $paths = $filler->fill_surface($surface, layer_height => 0.4, density => 0.4);
@ -55,6 +117,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
my $filler = Slic3r::Filler->new_from_type('rectilinear'); my $filler = Slic3r::Filler->new_from_type('rectilinear');
$filler->set_bounding_box($expolygon->bounding_box); $filler->set_bounding_box($expolygon->bounding_box);
$filler->set_angle($angle // 0); $filler->set_angle($angle // 0);
$filler->set_dont_adjust(0);
my $surface = Slic3r::Surface->new( my $surface = Slic3r::Surface->new(
surface_type => S_TYPE_BOTTOM, surface_type => S_TYPE_BOTTOM,
expolygon => $expolygon, expolygon => $expolygon,

View File

@ -24,12 +24,9 @@ Fill::new_from_type(const InfillPattern type)
case ip3DHoneycomb: return new Fill3DHoneycomb(); case ip3DHoneycomb: return new Fill3DHoneycomb();
case ipRectilinear: return new FillRectilinear(); case ipRectilinear: return new FillRectilinear();
case ipLine: return new FillLine();
case ipGrid: return new FillGrid();
case ipAlignedRectilinear: return new FillAlignedRectilinear(); case ipAlignedRectilinear: return new FillAlignedRectilinear();
case ipGrid: return new FillGrid();
case ipRectilinear2: return new FillRectilinear2();
case ipGrid2: return new FillGrid2();
case ipTriangles: return new FillTriangles(); case ipTriangles: return new FillTriangles();
case ipStars: return new FillStars(); case ipStars: return new FillStars();
case ipCubic: return new FillCubic(); case ipCubic: return new FillCubic();
@ -80,26 +77,27 @@ Fill::adjust_solid_spacing(const coord_t width, const coord_t distance)
{ {
assert(width >= 0); assert(width >= 0);
assert(distance > 0); assert(distance > 0);
// floor(width / distance) const int number_of_intervals = floor(width / distance);
coord_t number_of_intervals = floor(width / distance); if (number_of_intervals == 0) return distance;
coord_t distance_new = (number_of_intervals == 0)
? distance coord_t distance_new = (width / number_of_intervals);
: (width / number_of_intervals);
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance); const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
assert(factor > 1. - 1e-5); assert(factor > 1. - 1e-5);
// How much could the extrusion width be increased? By 20%. // How much could the extrusion width be increased? By 20%.
const coordf_t factor_max = 1.2; const coordf_t factor_max = 1.2;
if (factor > factor_max) if (false && factor > factor_max)
distance_new = floor((double)distance * factor_max + 0.5); distance_new = floor((double)distance * factor_max + 0.5);
assert((distance_new * number_of_intervals) <= width);
return distance_new; return distance_new;
} }
// Returns orientation of the infill and the reference point of the infill pattern. // Returns orientation of the infill and the reference point of the infill pattern.
// For a normal print, the reference point is the center of a bounding box of the STL. // For a normal print, the reference point is the center of a bounding box of the STL.
std::pair<float, Point> Fill::direction_t
Fill::_infill_direction(const Surface &surface) const Fill::_infill_direction(const Surface &surface) const
{ {
// set infill angle // set infill angle
@ -133,7 +131,7 @@ Fill::_infill_direction(const Surface &surface) const
} }
out_angle += float(M_PI/2.); out_angle += float(M_PI/2.);
return std::pair<float, Point>(out_angle, out_shift); return direction_t(out_angle, out_shift);
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -29,6 +29,9 @@ public:
// in unscaled coordinates // in unscaled coordinates
coordf_t spacing; coordf_t spacing;
// overlap over spacing for extrusion endpoints
float endpoints_overlap;
// in radians, ccw, 0 = East // in radians, ccw, 0 = East
float angle; float angle;
@ -80,6 +83,7 @@ protected:
layer_id(size_t(-1)), layer_id(size_t(-1)),
z(0.f), z(0.f),
spacing(0.f), spacing(0.f),
endpoints_overlap(0.3f),
angle(0), angle(0),
link_max_length(0), link_max_length(0),
loop_clipping(0), loop_clipping(0),
@ -89,10 +93,12 @@ protected:
complete(false) complete(false)
{}; {};
typedef std::pair<float, Point> direction_t;
// The expolygon may be modified by the method to avoid a copy. // The expolygon may be modified by the method to avoid a copy.
virtual void _fill_surface_single( virtual void _fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out) {}; Polylines* polylines_out) {};
@ -101,7 +107,7 @@ protected:
return (idx % 2) == 0 ? (M_PI/2.) : 0; return (idx % 2) == 0 ? (M_PI/2.) : 0;
}; };
std::pair<float, Point> _infill_direction(const Surface &surface) const; direction_t _infill_direction(const Surface &surface) const;
}; };
} // namespace Slic3r } // namespace Slic3r

View File

@ -150,7 +150,7 @@ makeGrid(coord_t z, coord_t gridSize, size_t gridWidth, size_t gridHeight, size_
void void
Fill3DHoneycomb::_fill_surface_single( Fill3DHoneycomb::_fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out) Polylines* polylines_out)
{ {

View File

@ -21,7 +21,7 @@ public:
protected: protected:
virtual void _fill_surface_single( virtual void _fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out); Polylines* polylines_out);
}; };

View File

@ -9,7 +9,7 @@ namespace Slic3r {
void void
FillConcentric::_fill_surface_single( FillConcentric::_fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out) Polylines* polylines_out)
{ {

View File

@ -14,7 +14,7 @@ protected:
virtual Fill* clone() const { return new FillConcentric(*this); }; virtual Fill* clone() const { return new FillConcentric(*this); };
virtual void _fill_surface_single( virtual void _fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out); Polylines* polylines_out);

View File

@ -9,7 +9,7 @@ namespace Slic3r {
void void
FillHoneycomb::_fill_surface_single( FillHoneycomb::_fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out) Polylines* polylines_out)
{ {

View File

@ -18,7 +18,7 @@ protected:
virtual Fill* clone() const { return new FillHoneycomb(*this); }; virtual Fill* clone() const { return new FillHoneycomb(*this); };
virtual void _fill_surface_single( virtual void _fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out Polylines* polylines_out
); );

View File

@ -8,7 +8,7 @@ namespace Slic3r {
void FillPlanePath::_fill_surface_single( void FillPlanePath::_fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out) Polylines* polylines_out)
{ {

View File

@ -21,7 +21,7 @@ public:
protected: protected:
virtual void _fill_surface_single( virtual void _fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out); Polylines* polylines_out);

View File

@ -2,138 +2,471 @@
#include "../ExPolygon.hpp" #include "../ExPolygon.hpp"
#include "../PolylineCollection.hpp" #include "../PolylineCollection.hpp"
#include "../Surface.hpp" #include "../Surface.hpp"
#include <algorithm>
#include <cmath>
#include "FillRectilinear.hpp" #include "FillRectilinear.hpp"
//#define DEBUG_RECTILINEAR
#ifdef DEBUG_RECTILINEAR
#include "../SVG.hpp"
#endif
namespace Slic3r { namespace Slic3r {
void FillRectilinear::_fill_surface_single( void
unsigned int thickness_layers, FillRectilinear::_fill_single_direction(ExPolygon expolygon,
const std::pair<float, Point> &direction, const direction_t &direction, coord_t x_shift, Polylines* out)
ExPolygon &expolygon,
Polylines* polylines_out)
{ {
assert(this->density > 0.0001f && this->density <= 1.f);
// rotate polygons so that we can work with vertical lines here // rotate polygons so that we can work with vertical lines here
expolygon.rotate(-direction.first); expolygon.rotate(-direction.first);
this->_min_spacing = scale_(this->spacing); assert(this->density > 0.0001f && this->density <= 1.f);
this->_line_spacing = coord_t(coordf_t(this->_min_spacing) / this->density); const coord_t min_spacing = scale_(this->spacing);
this->_diagonal_distance = this->_line_spacing * 2; coord_t line_spacing = (double) min_spacing / this->density;
this->_line_oscillation = this->_line_spacing - this->_min_spacing; // only for Line infill
// We ignore this->bounding_box because it doesn't matter; we're doing align_to_grid below. // We ignore this->bounding_box because it doesn't matter; we're doing align_to_grid below.
BoundingBox bounding_box = expolygon.contour.bounding_box(); BoundingBox bounding_box = expolygon.contour.bounding_box();
// Due to integer rounding, rotated polygons might not preserve verticality
// (i.e. when rotating by PI/2 two points having the same x coordinate
// they might get different y coordinates), thus the first line will be skipped.
bounding_box.offset(-1);
// define flow spacing according to requested density // define flow spacing according to requested density
if (this->density > 0.9999f && !this->dont_adjust) { if (this->density > 0.9999f && !this->dont_adjust) {
this->_line_spacing = this->adjust_solid_spacing(bounding_box.size().x, this->_line_spacing); line_spacing = this->adjust_solid_spacing(bounding_box.size().x, line_spacing);
this->spacing = unscale(this->_line_spacing); this->spacing = unscale(line_spacing);
} else { } else {
// extend bounding box so that our pattern will be aligned with other layers // extend bounding box so that our pattern will be aligned with other layers
// Transform the reference point to the rotated coordinate system. // Transform the reference point to the rotated coordinate system.
Point p = direction.second.rotated(-direction.first);
p.x -= x_shift > 0 ? x_shift : (x_shift + line_spacing);
bounding_box.min.align_to_grid( bounding_box.min.align_to_grid(
Point(this->_line_spacing, this->_line_spacing), Point(line_spacing, line_spacing),
direction.second.rotated(-direction.first) p
); );
} }
// generate the basic pattern
const coord_t x_max = bounding_box.max.x + SCALED_EPSILON;
Lines lines;
for (coord_t x = bounding_box.min.x; x <= x_max; x += this->_line_spacing)
lines.push_back(this->_line(lines.size(), x, bounding_box.min.y, bounding_box.max.y));
if (this->_horizontal_lines()) {
const coord_t y_max = bounding_box.max.y + SCALED_EPSILON;
for (coord_t y = bounding_box.min.y; y <= y_max; y += this->_line_spacing)
lines.push_back(Line(Point(bounding_box.min.x, y), Point(bounding_box.max.x, y)));
}
// clip paths against a slightly larger expolygon, so that the first and last paths
// are kept even if the expolygon has vertical sides
// the minimum offset for preventing edge lines from being clipped is SCALED_EPSILON;
// however we use a larger offset to support expolygons with slightly skewed sides and
// not perfectly straight
Polylines polylines = intersection_pl( // Find all the polygons points intersecting the rectilinear vertical lines and store
to_polylines(lines), // them in an std::map<> (grid) which orders them automatically by x and y.
offset(expolygon, scale_(0.02)), // For each intersection point we store its position (upper/lower): upper means it's
false // the upper endpoint of an intersection line, and vice versa.
); // Whenever between two intersection points we find vertices of the original polygon,
// store them in the 'skipped' member of the latter point.
// FIXME Vojtech: This is only performed for horizontal lines, not for the vertical lines!
const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
// How much to extend an infill path from expolygon outside? grid_t grid;
const coord_t extra = coord_t(floor(this->_min_spacing * INFILL_OVERLAP_OVER_SPACING + 0.5f)); {
for (Polylines::iterator it_polyline = polylines.begin(); const Polygons polygons = expolygon;
it_polyline != polylines.end(); ++ it_polyline) { for (Polygons::const_iterator polygon = polygons.begin(); polygon != polygons.end(); ++polygon) {
Point *first_point = &it_polyline->points.front(); const Points &points = polygon->points;
Point *last_point = &it_polyline->points.back();
if (first_point->y > last_point->y) // This vector holds the original polygon vertices found after the last intersection
std::swap(first_point, last_point); // point. We'll flush it as soon as we find the next intersection point.
first_point->y -= extra; Points skipped_points;
last_point->y += extra;
} // This vector holds the coordinates of the intersection points found while
// looping through the polygon.
size_t n_polylines_out_old = polylines_out->size(); Points ips;
// connect lines for (Points::const_iterator p = points.begin(); p != points.end(); ++p) {
if (!this->dont_connect && !polylines.empty()) { // prevent calling leftmost_point() on empty collections const Point &prev = p == points.begin() ? *(points.end()-1) : *(p-1);
// offset the expolygon by max(min_spacing/2, extra) const Point &next = p == points.end()-1 ? *points.begin() : *(p+1);
ExPolygon expolygon_off; const Point &next2 = p == (points.end()-2) ? *points.begin()
{ : p == (points.end()-1) ? *(points.begin()+1) : *(p+2);
ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing/2);
if (!expolygons_off.empty()) { // Does the p-next line belong to an intersection line?
// When expanding a polygon, the number of islands could only shrink. if (p->x == next.x && ((p->x - bounding_box.min.x) % line_spacing) == 0) {
// Therefore the offset_ex shall generate exactly one expanded island if (p->y == next.y) continue; // skip coinciding points
// for one input island. vertical_t &v = grid[p->x];
assert(expolygons_off.size() == 1);
std::swap(expolygon_off, expolygons_off.front()); // Detect line direction.
} IntersectionPoint::ipType p_type = IntersectionPoint::ipTypeLower;
} IntersectionPoint::ipType n_type = IntersectionPoint::ipTypeUpper;
Polylines chained = PolylineCollection::chained_path_from( if (p->y > next.y) std::swap(p_type, n_type); // line goes downwards
STDMOVE(polylines),
PolylineCollection::leftmost_point(polylines), // Do we already have 'p' in our grid?
false // reverse allowed vertical_t::iterator pit = v.find(p->y);
); if (pit != v.end()) {
bool first = true; // Yes, we have it. If its not of the same type, it means it's
for (Polylines::iterator it_polyline = chained.begin(); it_polyline != chained.end(); ++ it_polyline) { // an intermediate point of a longer line. We store this information
if (!first) { // for now and we'll remove it later.
// Try to connect the lines. if (pit->second.type != p_type)
Points &pts_end = polylines_out->back().points; pit->second.type = IntersectionPoint::ipTypeMiddle;
const Point &first_point = it_polyline->points.front(); } else {
const Point &last_point = pts_end.back(); // Store the point.
// Distance in X, Y. IntersectionPoint ip(p->x, p->y, p_type);
const Vector distance = first_point.vector_to(last_point); v[p->y] = ip;
// TODO: we should also check that both points are on a fill_boundary to avoid ips.push_back(ip);
// connecting paths on the boundaries of internal regions }
if (this->_can_connect(std::abs(distance.x), std::abs(distance.y))
&& expolygon_off.contains(Line(last_point, first_point))) { // Do we already have 'next' in our grid?
// Append the polyline. pit = v.find(next.y);
append_to(pts_end, it_polyline->points); if (pit != v.end()) {
// Yes, we have it. If its not of the same type, it means it's
// an intermediate point of a longer line. We store this information
// for now and we'll remove it later.
if (pit->second.type != n_type)
pit->second.type = IntersectionPoint::ipTypeMiddle;
} else {
// Store the point.
IntersectionPoint ip(next.x, next.y, n_type);
v[next.y] = ip;
ips.push_back(ip);
}
continue; continue;
} }
// We're going to look for intersection points within this line.
// First, let's sort its x coordinates regardless of the original line direction.
const coord_t min_x = std::min(p->x, next.x);
const coord_t max_x = std::max(p->x, next.x);
// Now find the leftmost intersection point belonging to the line.
const coord_t min_x2 = bounding_box.min.x + ceil((double) (min_x - bounding_box.min.x) / (double)line_spacing) * (double)line_spacing;
assert(min_x2 >= min_x);
// In case this coordinate does not belong to this line, we have no intersection points.
if (min_x2 > max_x) {
// Store the two skipped points and move on.
skipped_points.push_back(*p);
skipped_points.push_back(next);
continue;
}
// Find the rightmost intersection point belonging to the line.
const coord_t max_x2 = bounding_box.min.x + floor((double) (max_x - bounding_box.min.x) / (double) line_spacing) * (double)line_spacing;
assert(max_x2 <= max_x);
// We're now going past the first point, so save it.
if (p->x < min_x2)
skipped_points.push_back(*p);
// Now loop through those intersection points according the original direction
// of the line (because we need to store them in this order).
const bool line_goes_right = next.x > p->x;
for (coord_t x = line_goes_right ? min_x2 : max_x2;
x >= min_x && x <= max_x;
x += line_goes_right ? +line_spacing : -line_spacing) {
// Is this intersection an endpoint of the original line *and* is the
// intersection just a tangent point? If so, just skip it.
if (x == p->x && ((prev.x > x && next.x > x) || (prev.x < x && next.x < x))) {
skipped_points.push_back(*p);
continue;
}
if (x == next.x && ((p->x > x && next2.x > x) || (p->x < x && next2.x < x))) {
skipped_points.push_back(next);
continue;
}
// Calculate the y coordinate of this intersection.
IntersectionPoint ip(
x,
p->y + double(next.y - p->y) * double(x - p->x) / double(next.x - p->x),
line_goes_right ? IntersectionPoint::ipTypeLower : IntersectionPoint::ipTypeUpper
);
vertical_t &v = grid[ip.x];
// Did we already find this point?
// (We might have found it as the endpoint of a vertical line.)
{
vertical_t::iterator pit = v.find(ip.y);
if (pit != v.end()) {
// Yes, we have it. If its not of the same type, it means it's
// an intermediate point of a longer line. We store this information
// for now and we'll remove it later.
if (pit->second.type != ip.type)
pit->second.type = IntersectionPoint::ipTypeMiddle;
continue;
}
}
// Store the skipped polygon vertices along with this point.
ip.skipped = skipped_points;
skipped_points.clear();
#ifdef DEBUG_RECTILINEAR
printf("NEW POINT at %f,%f\n", unscale(ip.x), unscale(ip.y));
for (Points::const_iterator it = ip.skipped.begin(); it != ip.skipped.end(); ++it)
printf(" skipped: %f,%f\n", unscale(it->x), unscale(it->y));
#endif
// Store the point.
v[ip.y] = ip;
ips.push_back(ip);
}
// We're now going past the final point, so save it.
if (next.x > max_x2)
skipped_points.push_back(next);
}
if (!this->dont_connect) {
// We'll now build connections between the vertical intersection lines.
// Each intersection point will be connected to the first intersection point
// found along the original polygon having a greater x coordinate (or the same
// x coordinate: think about two vertical intersection lines having the same x
// separated by a hole polygon: we'll connect them with the hole portion).
// We will sweep only from left to right, so we only need to build connections
// in this direction.
for (Points::const_iterator it = ips.begin(); it != ips.end(); ++it) {
IntersectionPoint &ip = grid[it->x][it->y];
IntersectionPoint &next = it == ips.end()-1 ? grid[ips.begin()->x][ips.begin()->y] : grid[(it+1)->x][(it+1)->y];
#ifdef DEBUG_RECTILINEAR
printf("CONNECTING %f,%f to %f,%f\n",
unscale(ip.x), unscale(ip.y),
unscale(next.x), unscale(next.y)
);
#endif
// We didn't flush the skipped_points vector after completing the loop above:
// it now contains the polygon vertices between the last and the first
// intersection points.
if (it == ips.begin())
ip.skipped.insert(ip.skipped.begin(), skipped_points.begin(), skipped_points.end());
if (ip.x <= next.x) {
// Link 'ip' to 'next' --->
if (ip.next.empty()) {
ip.next = next.skipped;
ip.next.push_back(next);
}
} else if (next.x < ip.x) {
// Link 'next' to 'ip' --->
if (next.next.empty()) {
next.next = next.skipped;
std::reverse(next.next.begin(), next.next.end());
next.next.push_back(ip);
}
}
}
}
// Do some cleanup: remove the 'skipped' points we used for building
// connections and also remove the middle intersection points.
for (Points::const_iterator it = ips.begin(); it != ips.end(); ++it) {
vertical_t &v = grid[it->x];
IntersectionPoint &ip = v[it->y];
ip.skipped.clear();
if (ip.type == IntersectionPoint::ipTypeMiddle)
v.erase(it->y);
} }
// The lines cannot be connected.
#if SLIC3R_CPPVER >= 11
polylines_out->push_back(std::move(*it_polyline));
#else
polylines_out->push_back(Polyline());
std::swap(polylines_out->back(), *it_polyline);
#endif
first = false;
} }
} }
// paths must be rotated back #ifdef DEBUG_RECTILINEAR
for (Polylines::iterator it = polylines_out->begin() + n_polylines_out_old; SVG svg("grid.svg");
it != polylines_out->end(); ++ it) { svg.draw(expolygon);
// No need to translate, the absolute position is irrelevant.
// it->translate(- direction.second.x, - direction.second.y); printf("GRID:\n");
it->rotate(direction.first); for (grid_t::const_iterator it = grid.begin(); it != grid.end(); ++it) {
printf("x = %f:\n", unscale(it->first));
for (vertical_t::const_iterator v = it->second.begin(); v != it->second.end(); ++v) {
const IntersectionPoint &ip = v->second;
printf(" y = %f (%s, next = %f,%f, extra = %zu)\n", unscale(v->first),
ip.type == IntersectionPoint::ipTypeLower ? "lower"
: ip.type == IntersectionPoint::ipTypeMiddle ? "middle" : "upper",
(ip.next.empty() ? -1 : unscale(ip.next.back().x)),
(ip.next.empty() ? -1 : unscale(ip.next.back().y)),
(ip.next.empty() ? 0 : ip.next.size()-1)
);
svg.draw(ip, ip.type == IntersectionPoint::ipTypeLower ? "blue"
: ip.type == IntersectionPoint::ipTypeMiddle ? "yellow" : "red");
}
} }
printf("\n");
svg.Close();
#endif
// Calculate the extension of the vertical endpoints according to the configured value.
const coord_t extra_y = floor((double)min_spacing * this->endpoints_overlap + 0.5f);
// Store the number of polygons already existing in the output container.
const size_t n_polylines_out_old = out->size();
// Loop until we have no more vertical lines available.
while (!grid.empty()) {
// Get the first x coordinate.
vertical_t &v = grid.begin()->second;
// If this x coordinate does not have any y coordinate, remove it.
if (v.empty()) {
grid.erase(grid.begin());
continue;
}
// We expect every x coordinate to contain an even number of y coordinates
// because they are the endpoints of vertical intersection lines:
// lower/upper, lower/upper etc.
assert(v.size() % 2 == 0);
// Get the first lower point.
vertical_t::iterator it = v.begin(); // minimum x,y
IntersectionPoint p = it->second;
assert(p.type == IntersectionPoint::ipTypeLower);
// Start our polyline.
Polyline polyline;
polyline.append(p);
polyline.points.back().y -= extra_y;
while (true) {
// Complete the vertical line by finding the corresponding upper or lower point.
if (p.type == IntersectionPoint::ipTypeUpper) {
// find first point along c.x with y < c.y
assert(it != grid[p.x].begin());
--it;
} else {
// find first point along c.x with y > c.y
++it;
assert(it != grid[p.x].end());
}
// Append the point to our polyline.
IntersectionPoint b = it->second;
assert(b.type != p.type);
polyline.append(b);
polyline.points.back().y += extra_y * (b.type == IntersectionPoint::ipTypeUpper ? 1 : -1);
// Remove the two endpoints of this vertical line from the grid.
{
vertical_t &v = grid[p.x];
v.erase(p.y);
v.erase(it);
if (v.empty()) grid.erase(p.x);
}
// Do we have a connection starting from here?
// If not, stop the polyline.
if (b.next.empty())
break;
// If we have a connection, append it to the polyline.
// We apply the y extension to the whole connection line. This works well when
// the connection is straight and horizontal, but doesn't work well when the
// connection is articulated and also has vertical parts.
{
const size_t n = polyline.points.size();
polyline.append(b.next);
for (Points::iterator pit = polyline.points.begin()+n; pit != polyline.points.end(); ++pit)
pit->y += extra_y * (b.type == IntersectionPoint::ipTypeUpper ? 1 : -1);
}
// Is the final point still available?
if (grid.count(b.next.back().x) == 0
|| grid[b.next.back().x].count(b.next.back().y) == 0)
// We already used this point or we might have removed this
// point while building the grid because it's collinear (middle); in either
// cases the connection line from the previous one is legit and worth having.
break;
// Retrieve the intersection point. The next loop will find the correspondent
// endpoint of the vertical line.
it = grid[ b.next.back().x ].find(b.next.back().y);
p = it->second;
// If the connection brought us to another x coordinate, we expect the point
// type to be the same.
assert((p.type == b.type && p.x > b.x)
|| (p.type != b.type && p.x == b.x));
}
// Yay, we have a polyline!
if (polyline.is_valid())
out->push_back(polyline);
}
// paths must be rotated back
for (Polylines::iterator it = out->begin() + n_polylines_out_old;
it != out->end(); ++it)
it->rotate(direction.first);
}
void FillRectilinear::_fill_surface_single(
unsigned int thickness_layers,
const direction_t &direction,
ExPolygon &expolygon,
Polylines* out)
{
this->_fill_single_direction(expolygon, direction, 0, out);
}
void FillGrid::_fill_surface_single(
unsigned int thickness_layers,
const direction_t &direction,
ExPolygon &expolygon,
Polylines* out)
{
FillGrid fill2 = *this;
fill2.density /= 2.;
direction_t direction2 = direction;
direction2.first += PI/2;
fill2._fill_single_direction(expolygon, direction, 0, out);
fill2._fill_single_direction(expolygon, direction2, 0, out);
}
void FillTriangles::_fill_surface_single(
unsigned int thickness_layers,
const direction_t &direction,
ExPolygon &expolygon,
Polylines* out)
{
FillTriangles fill2 = *this;
fill2.density /= 3.;
direction_t direction2 = direction;
fill2._fill_single_direction(expolygon, direction2, 0, out);
direction2.first += PI/3;
fill2._fill_single_direction(expolygon, direction2, 0, out);
direction2.first += PI/3;
fill2._fill_single_direction(expolygon, direction2, 0, out);
}
void FillStars::_fill_surface_single(
unsigned int thickness_layers,
const direction_t &direction,
ExPolygon &expolygon,
Polylines* out)
{
FillStars fill2 = *this;
fill2.density /= 3.;
direction_t direction2 = direction;
fill2._fill_single_direction(expolygon, direction2, 0, out);
direction2.first += PI/3;
fill2._fill_single_direction(expolygon, direction2, 0, out);
direction2.first += PI/3;
const coord_t x_shift = 0.5 * scale_(fill2.spacing) / fill2.density;
fill2._fill_single_direction(expolygon, direction2, x_shift, out);
}
void FillCubic::_fill_surface_single(
unsigned int thickness_layers,
const direction_t &direction,
ExPolygon &expolygon,
Polylines* out)
{
FillCubic fill2 = *this;
fill2.density /= 3.;
direction_t direction2 = direction;
const coord_t range = scale_(this->spacing / this->density);
const coord_t x_shift = abs(( (coord_t)(scale_(this->z) + range) % (coord_t)(range * 2)) - range);
fill2._fill_single_direction(expolygon, direction2, -x_shift, out);
direction2.first += PI/3;
fill2._fill_single_direction(expolygon, direction2, +x_shift, out);
direction2.first += PI/3;
fill2._fill_single_direction(expolygon, direction2, -x_shift, out);
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -16,61 +16,33 @@ public:
protected: protected:
virtual void _fill_surface_single( virtual void _fill_surface_single(
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const direction_t &direction,
ExPolygon &expolygon, ExPolygon &expolygon,
Polylines* polylines_out); Polylines* polylines_out);
coord_t _min_spacing; void _fill_single_direction(ExPolygon expolygon, const direction_t &direction,
coord_t _line_spacing; coord_t x_shift, Polylines* out);
// distance threshold for allowing the horizontal infill lines to be connected into a continuous path
coord_t _diagonal_distance; struct IntersectionPoint : Point {
// only for line infill enum ipType { ipTypeLower, ipTypeUpper, ipTypeMiddle };
coord_t _line_oscillation; ipType type;
// Enabled for the grid infill, disabled for the rectilinear and line infill. // skipped contains the polygon points accumulated between the previous intersection
virtual bool _horizontal_lines() const { return false; }; // point and the current one, in the original polygon winding order (does not contain
// either points)
virtual Line _line(int i, coord_t x, coord_t y_min, coord_t y_max) const Points skipped;
{ return Line(Point(x, y_min), Point(x, y_max)); };
// next contains a polygon portion connecting this point to the first intersection
virtual bool _can_connect(coord_t dist_X, coord_t dist_Y) { // point found following the polygon in any direction but having:
return dist_X <= this->_diagonal_distance // x > this->x || (x == this->x && y > this->y)
&& dist_Y <= this->_diagonal_distance; // (it doesn't contain *this but it contains the target intersection point)
Points next;
IntersectionPoint() : Point() {};
IntersectionPoint(coord_t x, coord_t y, ipType _type) : Point(x,y), type(_type) {};
}; };
}; typedef std::map<coord_t,IntersectionPoint> vertical_t; // <y,point>
typedef std::map<coord_t,vertical_t> grid_t; // <x,<y,point>>
class FillLine : public FillRectilinear
{
public:
virtual Fill* clone() const { return new FillLine(*this); };
virtual ~FillLine() {}
protected:
virtual Line _line(int i, coord_t x, coord_t y_min, coord_t y_max) const {
coord_t osc = (i & 1) ? this->_line_oscillation : 0;
return Line(Point(x - osc, y_min), Point(x + osc, y_max));
};
virtual bool _can_connect(coord_t dist_X, coord_t dist_Y)
{
coord_t TOLERANCE = 10 * SCALED_EPSILON;
return (dist_X >= (this->_line_spacing - this->_line_oscillation) - TOLERANCE)
&& (dist_X <= (this->_line_spacing + this->_line_oscillation) + TOLERANCE)
&& (dist_Y <= this->_diagonal_distance);
};
};
class FillGrid : public FillRectilinear
{
public:
virtual Fill* clone() const { return new FillGrid(*this); };
virtual ~FillGrid() {}
protected:
// The grid fill will keep the angle constant between the layers,; see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
// Flag for Slic3r::Fill::Rectilinear to fill both directions.
virtual bool _horizontal_lines() const { return true; };
}; };
class FillAlignedRectilinear : public FillRectilinear class FillAlignedRectilinear : public FillRectilinear
@ -84,6 +56,74 @@ protected:
virtual float _layer_angle(size_t idx) const { return 0.f; }; virtual float _layer_angle(size_t idx) const { return 0.f; };
}; };
class FillGrid : public FillRectilinear
{
public:
virtual Fill* clone() const { return new FillGrid(*this); };
virtual ~FillGrid() {}
protected:
// The grid fill will keep the angle constant between the layers,; see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
virtual void _fill_surface_single(
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines* polylines_out);
};
class FillTriangles : public FillRectilinear
{
public:
virtual Fill* clone() const { return new FillTriangles(*this); };
virtual ~FillTriangles() {}
protected:
// The grid fill will keep the angle constant between the layers,; see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
virtual void _fill_surface_single(
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines* polylines_out);
};
class FillStars : public FillRectilinear
{
public:
virtual Fill* clone() const { return new FillStars(*this); };
virtual ~FillStars() {}
protected:
// The grid fill will keep the angle constant between the layers,; see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
virtual void _fill_surface_single(
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines* polylines_out);
};
class FillCubic : public FillRectilinear
{
public:
virtual Fill* clone() const { return new FillCubic(*this); };
virtual ~FillCubic() {}
protected:
// The grid fill will keep the angle constant between the layers,; see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
virtual void _fill_surface_single(
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines* polylines_out);
};
}; // namespace Slic3r }; // namespace Slic3r
#endif // slic3r_FillRectilinear_hpp_ #endif // slic3r_FillRectilinear_hpp_

View File

@ -16,7 +16,7 @@
// #define SLIC3R_DEBUG // #define SLIC3R_DEBUG
// Make assert active if SLIC3R_DEBUG // Make assert active if SLIC3R_DEBUG
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
#undef NDEBUG #undef NDEBUG
#include "SVG.hpp" #include "SVG.hpp"
#endif #endif
@ -116,7 +116,7 @@ static inline bool is_ccw(const Polygon &poly)
// therefore the point p1 lies on poly.points[seg1-1], poly.points[seg1] etc. // therefore the point p1 lies on poly.points[seg1-1], poly.points[seg1] etc.
static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Point &p1, size_t seg2, const Point &p2) static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Point &p1, size_t seg2, const Point &p2)
{ {
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
// Verify that p1 lies on seg1. This is difficult to verify precisely, // Verify that p1 lies on seg1. This is difficult to verify precisely,
// but at least verify, that p1 lies in the bounding box of seg1. // but at least verify, that p1 lies in the bounding box of seg1.
for (size_t i = 0; i < 2; ++ i) { for (size_t i = 0; i < 2; ++ i) {
@ -409,7 +409,7 @@ 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]; }
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
void export_to_svg(Slic3r::SVG &svg) { void export_to_svg(Slic3r::SVG &svg) {
//svg.draw_outline(polygons_src, "black"); //svg.draw_outline(polygons_src, "black");
//svg.draw_outline(polygons_outer, "green"); //svg.draw_outline(polygons_outer, "green");
@ -846,7 +846,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
myassert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f); myassert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
// Rotate polygons so that we can work with vertical lines here // Rotate polygons so that we can work with vertical lines here
std::pair<float, Point> rotate_vector = this->_infill_direction(*surface); direction_t rotate_vector = this->_infill_direction(*surface);
rotate_vector.first += angleBase; rotate_vector.first += angleBase;
myassert(this->density > 0.0001f && this->density <= 1.f); myassert(this->density > 0.0001f && this->density <= 1.f);
@ -889,7 +889,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
size_t n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing; size_t n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing;
coord_t x0 = bounding_box.min.x + (line_spacing + SCALED_EPSILON) / 2; coord_t x0 = bounding_box.min.x + (line_spacing + SCALED_EPSILON) / 2;
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
static int iRun = 0; static int iRun = 0;
BoundingBox bbox_svg(to_points(poly_with_offset.polygons_outer)); BoundingBox bbox_svg(to_points(poly_with_offset.polygons_outer));
//::Slic3r::SVG svg(debug_out_path("FillRectilinear2-%d.svg", iRun), bbox_svg); // , scale_(1.)); //::Slic3r::SVG svg(debug_out_path("FillRectilinear2-%d.svg", iRun), bbox_svg); // , scale_(1.));
@ -1002,7 +1002,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
// The same segment, it has to be vertical. // The same segment, it has to be vertical.
myassert(iPrev1 == iPrev2); myassert(iPrev1 == iPrev2);
swap = contour1[iPrev1].y > contour1[iContour1].y; swap = contour1[iPrev1].y > contour1[iContour1].y;
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
if (swap) if (swap)
printf("Swapping when single vertical segment\n"); printf("Swapping when single vertical segment\n");
#endif #endif
@ -1018,7 +1018,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
const Point *b = &contour1[iSegment1]; const Point *b = &contour1[iSegment1];
const Point *c = &contour2[iPrev2]; const Point *c = &contour2[iPrev2];
const Point *d = &contour2[iSegment2]; const Point *d = &contour2[iSegment2];
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
const Point x1(sil.pos, sil.intersections[i-1].pos); const Point x1(sil.pos, sil.intersections[i-1].pos);
const Point x2(sil.pos, sil.intersections[i ].pos); const Point x2(sil.pos, sil.intersections[i ].pos);
bool successive = false; bool successive = false;
@ -1045,11 +1045,11 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
myassert(iSegment1 == iPrev2 || iPrev1 == iSegment2); myassert(iSegment1 == iPrev2 || iPrev1 == iSegment2);
std::swap(c, d); std::swap(c, d);
myassert(a != c && b != c); myassert(a != c && b != c);
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
successive = true; successive = true;
#endif /* SLIC3R_DEBUG */ #endif /* SLIC3R_DEBUG */
} }
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
else if (b == d) { else if (b == d) {
// The segments iSegment1 and iSegment2 are directly connected. // The segments iSegment1 and iSegment2 are directly connected.
myassert(iContour1 == iContour2); myassert(iContour1 == iContour2);
@ -1061,7 +1061,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
Orientation o = orient(*a, *b, *c); Orientation o = orient(*a, *b, *c);
myassert(o != ORIENTATION_COLINEAR); myassert(o != ORIENTATION_COLINEAR);
swap = upper_more_left != (o == ORIENTATION_CW); swap = upper_more_left != (o == ORIENTATION_CW);
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
if (swap) if (swap)
printf(successive ? printf(successive ?
"Swapping when iContour1 == iContour2 and successive segments\n" : "Swapping when iContour1 == iContour2 and successive segments\n" :
@ -1106,7 +1106,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
if (sil.intersections[i].type == sil.intersections[j-1].type) { 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_DEBUG2
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);
@ -1152,7 +1152,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
} }
#undef ASSERT_OR_RETURN #undef ASSERT_OR_RETURN
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
// Paint the segments and finalize the SVG file. // Paint the segments and finalize the SVG file.
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];
@ -1519,7 +1519,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
polyline_current = NULL; polyline_current = NULL;
} }
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
{ {
{ {
//::Slic3r::SVG svg(debug_out_path("FillRectilinear2-final-%03d.svg", iRun), bbox_svg); // , scale_(1.)); //::Slic3r::SVG svg(debug_out_path("FillRectilinear2-final-%03d.svg", iRun), bbox_svg); // , scale_(1.));
@ -1546,7 +1546,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, float angle
it->remove_duplicate_points(); it->remove_duplicate_points();
} }
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG2
// Verify, that there are no duplicate points in the sequence. // Verify, that there are no duplicate points in the sequence.
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());
@ -1577,10 +1577,10 @@ Polylines FillGrid2::fill_surface(const Surface &surface)
return polylines_out; return polylines_out;
} }
Polylines FillTriangles::fill_surface(const Surface &surface) Polylines FillTriangles2::fill_surface(const Surface &surface)
{ {
// Each linear fill covers 1/3 of the target coverage. // Each linear fill covers 1/3 of the target coverage.
FillTriangles fill2 = *this; FillTriangles2 fill2 = *this;
fill2.density *= 0.333333333f; fill2.density *= 0.333333333f;
Polylines polylines_out; Polylines polylines_out;
if (! fill2.fill_surface_by_lines(&surface, 0.f, 0., polylines_out) || if (! fill2.fill_surface_by_lines(&surface, 0.f, 0., polylines_out) ||
@ -1591,10 +1591,10 @@ Polylines FillTriangles::fill_surface(const Surface &surface)
return polylines_out; return polylines_out;
} }
Polylines FillStars::fill_surface(const Surface &surface) Polylines FillStars2::fill_surface(const Surface &surface)
{ {
// Each linear fill covers 1/3 of the target coverage. // Each linear fill covers 1/3 of the target coverage.
FillStars fill2 = *this; FillStars2 fill2 = *this;
fill2.density *= 0.333333333f; fill2.density *= 0.333333333f;
Polylines polylines_out; Polylines polylines_out;
if (! fill2.fill_surface_by_lines(&surface, 0.f, 0., polylines_out) || if (! fill2.fill_surface_by_lines(&surface, 0.f, 0., polylines_out) ||
@ -1605,10 +1605,10 @@ Polylines FillStars::fill_surface(const Surface &surface)
return polylines_out; return polylines_out;
} }
Polylines FillCubic::fill_surface(const Surface &surface) Polylines FillCubic2::fill_surface(const Surface &surface)
{ {
// Each linear fill covers 1/3 of the target coverage. // Each linear fill covers 1/3 of the target coverage.
FillCubic fill2 = *this; FillCubic2 fill2 = *this;
fill2.density *= 0.333333333f; fill2.density *= 0.333333333f;
Polylines polylines_out; Polylines polylines_out;
if (! fill2.fill_surface_by_lines(&surface, 0.f, z, polylines_out) || if (! fill2.fill_surface_by_lines(&surface, 0.f, z, polylines_out) ||

View File

@ -32,11 +32,11 @@ protected:
virtual float _layer_angle(size_t idx) const { return 0.f; } virtual float _layer_angle(size_t idx) const { return 0.f; }
}; };
class FillTriangles : public FillRectilinear2 class FillTriangles2 : public FillRectilinear2
{ {
public: public:
virtual Fill* clone() const { return new FillTriangles(*this); }; virtual Fill* clone() const { return new FillTriangles2(*this); };
virtual ~FillTriangles() {} virtual ~FillTriangles2() {}
virtual Polylines fill_surface(const Surface &surface); virtual Polylines fill_surface(const Surface &surface);
protected: protected:
@ -44,11 +44,11 @@ protected:
virtual float _layer_angle(size_t idx) const { return 0.f; } virtual float _layer_angle(size_t idx) const { return 0.f; }
}; };
class FillStars : public FillRectilinear2 class FillStars2 : public FillRectilinear2
{ {
public: public:
virtual Fill* clone() const { return new FillStars(*this); }; virtual Fill* clone() const { return new FillStars2(*this); };
virtual ~FillStars() {} virtual ~FillStars2() {}
virtual Polylines fill_surface(const Surface &surface); virtual Polylines fill_surface(const Surface &surface);
protected: protected:
@ -56,11 +56,11 @@ protected:
virtual float _layer_angle(size_t idx) const { return 0.f; } virtual float _layer_angle(size_t idx) const { return 0.f; }
}; };
class FillCubic : public FillRectilinear2 class FillCubic2 : public FillRectilinear2
{ {
public: public:
virtual Fill* clone() const { return new FillCubic(*this); }; virtual Fill* clone() const { return new FillCubic2(*this); };
virtual ~FillCubic() {} virtual ~FillCubic2() {}
virtual Polylines fill_surface(const Surface &surface); virtual Polylines fill_surface(const Surface &surface);
protected: protected:

View File

@ -549,25 +549,6 @@ MedialAxis::build(ThickPolylines* polylines)
// append polyline to result // append polyline to result
polylines->push_back(polyline); polylines->push_back(polyline);
} }
#ifdef SLIC3R_DEBUG
{
char path[2048];
static int iRun = 0;
sprintf(path, "out/MedialAxis-%d.svg", iRun ++);
//dump_voronoi_to_svg(this->lines, this->vd, polylines, path);
printf("Thick lines: ");
for (ThickPolylines::const_iterator it = polylines->begin(); it != polylines->end(); ++ it) {
ThickLines lines = it->thicklines();
for (ThickLines::const_iterator it2 = lines.begin(); it2 != lines.end(); ++ it2) {
printf("%f,%f ", it2->a_width, it2->b_width);
}
}
printf("\n");
}
#endif /* SLIC3R_DEBUG */
} }
void void

View File

@ -18,6 +18,12 @@ Point::operator==(const Point& rhs) const
return this->coincides_with(rhs); return this->coincides_with(rhs);
} }
bool
Point::operator<(const Point& rhs) const
{
return this->x < rhs.x || this->y < rhs.y;
}
std::string std::string
Point::wkt() const Point::wkt() const
{ {

View File

@ -37,6 +37,7 @@ class Point
return Point(scale_(x), scale_(y)); return Point(scale_(x), scale_(y));
}; };
bool operator==(const Point& rhs) const; bool operator==(const Point& rhs) const;
bool operator<(const Point& rhs) const;
std::string wkt() const; std::string wkt() const;
std::string dump_perl() const; std::string dump_perl() const;
void scale(double factor); void scale(double factor);

View File

@ -391,9 +391,6 @@ PrintConfigDef::PrintConfigDef()
def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear");
def->enum_values.push_back("alignedrectilinear"); def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("grid"); def->enum_values.push_back("grid");
def->enum_values.push_back("line");
def->enum_values.push_back("rectilinear2");
def->enum_values.push_back("grid2");
def->enum_values.push_back("triangles"); def->enum_values.push_back("triangles");
def->enum_values.push_back("stars"); def->enum_values.push_back("stars");
def->enum_values.push_back("cubic"); def->enum_values.push_back("cubic");
@ -406,9 +403,6 @@ PrintConfigDef::PrintConfigDef()
def->enum_labels.push_back("Rectilinear"); def->enum_labels.push_back("Rectilinear");
def->enum_labels.push_back("Aligned Rectilinear"); def->enum_labels.push_back("Aligned Rectilinear");
def->enum_labels.push_back("Grid"); def->enum_labels.push_back("Grid");
def->enum_labels.push_back("Line");
def->enum_labels.push_back("Rectilinear 2");
def->enum_labels.push_back("Grid 2");
def->enum_labels.push_back("Triangles"); def->enum_labels.push_back("Triangles");
def->enum_labels.push_back("Stars"); def->enum_labels.push_back("Stars");
def->enum_labels.push_back("Cubic"); def->enum_labels.push_back("Cubic");
@ -418,7 +412,7 @@ PrintConfigDef::PrintConfigDef()
def->enum_labels.push_back("Hilbert Curve"); def->enum_labels.push_back("Hilbert Curve");
def->enum_labels.push_back("Archimedean Chords"); def->enum_labels.push_back("Archimedean Chords");
def->enum_labels.push_back("Octagram Spiral"); def->enum_labels.push_back("Octagram Spiral");
def->default_value = new ConfigOptionEnum<InfillPattern>(ipHoneycomb); def->default_value = new ConfigOptionEnum<InfillPattern>(ipStars);
def = this->add("first_layer_acceleration", coFloat); def = this->add("first_layer_acceleration", coFloat);
def->label = "First layer"; def->label = "First layer";

View File

@ -30,8 +30,8 @@ enum GCodeFlavor {
}; };
enum InfillPattern { enum InfillPattern {
ipRectilinear, ipGrid, ipLine, ipAlignedRectilinear, ipRectilinear, ipGrid, ipAlignedRectilinear,
ipRectilinear2, ipGrid2, ipTriangles, ipStars, ipCubic, ipTriangles, ipStars, ipCubic,
ipConcentric, ipHoneycomb, ip3DHoneycomb, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
}; };
@ -63,9 +63,6 @@ template<> inline t_config_enum_values ConfigOptionEnum<InfillPattern>::get_enum
keys_map["rectilinear"] = ipRectilinear; keys_map["rectilinear"] = ipRectilinear;
keys_map["alignedrectilinear"] = ipAlignedRectilinear; keys_map["alignedrectilinear"] = ipAlignedRectilinear;
keys_map["grid"] = ipGrid; keys_map["grid"] = ipGrid;
keys_map["line"] = ipLine;
keys_map["rectilinear2"] = ipRectilinear2;
keys_map["grid2"] = ipGrid2;
keys_map["triangles"] = ipTriangles; keys_map["triangles"] = ipTriangles;
keys_map["stars"] = ipStars; keys_map["stars"] = ipStars;
keys_map["cubic"] = ipCubic; keys_map["cubic"] = ipCubic;

View File

@ -13,10 +13,17 @@
void set_bounding_box(BoundingBox *bbox) void set_bounding_box(BoundingBox *bbox)
%code{% THIS->fill->bounding_box = *bbox; %}; %code{% THIS->fill->bounding_box = *bbox; %};
void set_spacing(coordf_t spacing) void set_spacing(coordf_t spacing)
%code{% THIS->fill->spacing = spacing; %}; %code{% THIS->fill->spacing = spacing; %};
coordf_t spacing() coordf_t spacing()
%code{% RETVAL = THIS->fill->spacing; %}; %code{% RETVAL = THIS->fill->spacing; %};
void set_endpoints_overlap(float overlap)
%code{% THIS->fill->endpoints_overlap = overlap; %};
float endpoints_overlap()
%code{% RETVAL = THIS->fill->endpoints_overlap; %};
void set_layer_id(size_t layer_id) void set_layer_id(size_t layer_id)
%code{% THIS->fill->layer_id = layer_id; %}; %code{% THIS->fill->layer_id = layer_id; %};
void set_z(coordf_t z) void set_z(coordf_t z)