Merge pull request #3610 from alexrj/new-rectilinear

New Rectilinear implementation
This commit is contained in:
Alessandro Ranellucci 2016-12-15 11:04:08 +01:00 committed by GitHub
commit 43c62d468c
22 changed files with 641 additions and 2011 deletions

View File

@ -50,7 +50,6 @@ add_library(libslic3r STATIC
${LIBDIR}/libslic3r/Fill/FillHoneycomb.cpp ${LIBDIR}/libslic3r/Fill/FillHoneycomb.cpp
${LIBDIR}/libslic3r/Fill/FillPlanePath.cpp ${LIBDIR}/libslic3r/Fill/FillPlanePath.cpp
${LIBDIR}/libslic3r/Fill/FillRectilinear.cpp ${LIBDIR}/libslic3r/Fill/FillRectilinear.cpp
${LIBDIR}/libslic3r/Fill/FillRectilinear2.cpp
${LIBDIR}/libslic3r/Flow.cpp ${LIBDIR}/libslic3r/Flow.cpp
${LIBDIR}/libslic3r/GCode.cpp ${LIBDIR}/libslic3r/GCode.cpp
${LIBDIR}/libslic3r/GCodeSender.cpp ${LIBDIR}/libslic3r/GCodeSender.cpp

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

@ -40,8 +40,6 @@ src/libslic3r/Fill/FillPlanePath.cpp
src/libslic3r/Fill/FillPlanePath.hpp src/libslic3r/Fill/FillPlanePath.hpp
src/libslic3r/Fill/FillRectilinear.cpp src/libslic3r/Fill/FillRectilinear.cpp
src/libslic3r/Fill/FillRectilinear.hpp src/libslic3r/Fill/FillRectilinear.hpp
src/libslic3r/Fill/FillRectilinear2.cpp
src/libslic3r/Fill/FillRectilinear2.hpp
src/libslic3r/Flow.cpp src/libslic3r/Flow.cpp
src/libslic3r/Flow.hpp src/libslic3r/Flow.hpp
src/libslic3r/GCode.cpp src/libslic3r/GCode.cpp

View File

@ -11,7 +11,6 @@
#include "Fill3DHoneycomb.hpp" #include "Fill3DHoneycomb.hpp"
#include "FillPlanePath.hpp" #include "FillPlanePath.hpp"
#include "FillRectilinear.hpp" #include "FillRectilinear.hpp"
#include "FillRectilinear2.hpp"
namespace Slic3r { namespace Slic3r {
@ -24,12 +23,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,11 +76,10 @@ 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);
@ -94,12 +89,14 @@ Fill::adjust_solid_spacing(const coord_t width, const coord_t distance)
if (factor > factor_max) if (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 +130,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,479 @@
#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 // Find all the polygons points intersecting the rectilinear vertical lines and store
const coord_t x_max = bounding_box.max.x + SCALED_EPSILON; // them in an std::map<> (grid) which orders them automatically by x and y.
Lines lines; // For each intersection point we store its position (upper/lower): upper means it's
for (coord_t x = bounding_box.min.x; x <= x_max; x += this->_line_spacing) // the upper endpoint of an intersection line, and vice versa.
lines.push_back(this->_line(lines.size(), x, bounding_box.min.y, bounding_box.max.y)); // Whenever between two intersection points we find vertices of the original polygon,
if (this->_horizontal_lines()) { // store them in the 'skipped' member of the latter point.
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 grid_t grid;
// 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(
to_polylines(lines),
offset(expolygon, scale_(0.02)),
false
);
// 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?
const coord_t extra = coord_t(floor(this->_min_spacing * INFILL_OVERLAP_OVER_SPACING + 0.5f));
for (Polylines::iterator it_polyline = polylines.begin();
it_polyline != polylines.end(); ++ it_polyline) {
Point *first_point = &it_polyline->points.front();
Point *last_point = &it_polyline->points.back();
if (first_point->y > last_point->y)
std::swap(first_point, last_point);
first_point->y -= extra;
last_point->y += extra;
}
size_t n_polylines_out_old = polylines_out->size();
// connect lines
if (!this->dont_connect && !polylines.empty()) { // prevent calling leftmost_point() on empty collections
// offset the expolygon by max(min_spacing/2, extra)
ExPolygon expolygon_off;
{ {
ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing/2); const Polygons polygons = expolygon;
if (!expolygons_off.empty()) { for (Polygons::const_iterator polygon = polygons.begin(); polygon != polygons.end(); ++polygon) {
// When expanding a polygon, the number of islands could only shrink. const Points &points = polygon->points;
// Therefore the offset_ex shall generate exactly one expanded island
// for one input island. // This vector holds the original polygon vertices found after the last intersection
assert(expolygons_off.size() == 1); // point. We'll flush it as soon as we find the next intersection point.
std::swap(expolygon_off, expolygons_off.front()); Points skipped_points;
// This vector holds the coordinates of the intersection points found while
// looping through the polygon.
Points ips;
for (Points::const_iterator p = points.begin(); p != points.end(); ++p) {
const Point &prev = p == points.begin() ? *(points.end()-1) : *(p-1);
const Point &next = p == points.end()-1 ? *points.begin() : *(p+1);
// Does the p-next line belong to an intersection line?
if (p->x == next.x && ((p->x - bounding_box.min.x) % line_spacing) == 0) {
if (p->y == next.y) continue; // skip coinciding points
vertical_t &v = grid[p->x];
// Detect line direction.
IntersectionPoint::ipType p_type = IntersectionPoint::ipTypeLower;
IntersectionPoint::ipType n_type = IntersectionPoint::ipTypeUpper;
if (p->y > next.y) std::swap(p_type, n_type); // line goes downwards
// Do we already have 'p' in our grid?
vertical_t::iterator pit = v.find(p->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 != p_type)
pit->second.type = IntersectionPoint::ipTypeMiddle;
} else {
// Store the point.
IntersectionPoint ip(p->x, p->y, p_type);
v[p->y] = ip;
ips.push_back(ip);
} }
// Do we already have 'next' in our grid?
pit = v.find(next.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 != 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);
} }
Polylines chained = PolylineCollection::chained_path_from( continue;
STDMOVE(polylines), }
PolylineCollection::leftmost_point(polylines),
false // reverse allowed // We're going to look for intersection points within this line.
); // First, let's sort its x coordinates regardless of the original line direction.
bool first = true; const coord_t min_x = std::min(p->x, next.x);
for (Polylines::iterator it_polyline = chained.begin(); it_polyline != chained.end(); ++ it_polyline) { const coord_t max_x = std::max(p->x, next.x);
if (!first) {
// Try to connect the lines. // Now find the leftmost intersection point belonging to the line.
Points &pts_end = polylines_out->back().points; const coord_t min_x2 = bounding_box.min.x + ceil((double) (min_x - bounding_box.min.x) / (double)line_spacing) * (double)line_spacing;
const Point &first_point = it_polyline->points.front(); assert(min_x2 >= min_x);
const Point &last_point = pts_end.back();
// Distance in X, Y. // In case this coordinate does not belong to this line, we have no intersection points.
const Vector distance = first_point.vector_to(last_point); if (min_x2 > max_x) {
// TODO: we should also check that both points are on a fill_boundary to avoid // Store the two skipped points and move on.
// connecting paths on the boundaries of internal regions skipped_points.push_back(*p);
if (this->_can_connect(std::abs(distance.x), std::abs(distance.y)) skipped_points.push_back(next);
&& expolygon_off.contains(Line(last_point, first_point))) { continue;
// Append the polyline. }
append_to(pts_end, it_polyline->points);
// 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.
const bool line_goes_right = next.x > p->x;
if (line_goes_right ? (p->x < min_x2) : (p->x > max_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).
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) {
const Point &next2 = p == (points.end()-2) ? *points.begin()
: p == (points.end()-1) ? *(points.begin()+1) : *(p+2);
if ((p->x > x && next2.x > x) || (p->x < x && next2.x < x)) {
skipped_points.push_back(next);
continue; continue;
} }
} }
// The lines cannot be connected.
#if SLIC3R_CPPVER >= 11 // Calculate the y coordinate of this intersection.
polylines_out->push_back(std::move(*it_polyline)); IntersectionPoint ip(
#else x,
polylines_out->push_back(Polyline()); p->y + double(next.y - p->y) * double(x - p->x) / double(next.x - p->x),
std::swap(polylines_out->back(), *it_polyline); line_goes_right ? IntersectionPoint::ipTypeLower : IntersectionPoint::ipTypeUpper
#endif );
first = false; 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 (line_goes_right ? (next.x > max_x2) : (next.x < min_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);
}
}
}
#ifdef DEBUG_RECTILINEAR
SVG svg("grid.svg");
svg.draw(expolygon);
printf("GRID:\n");
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.
{
// TODO: here's where we should check for overextrusion. We should only add
// connection points while they are not generating vertical lines within the
// extrusion thickness of the main vertical lines. We should also check whether
// a previous run of this method occupied this polygon portion (derived infill
// patterns doing multiple runs at different angles generate overlapping connections).
// In both cases, we should just stop the connection and break the polyline here.
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 // paths must be rotated back
for (Polylines::iterator it = polylines_out->begin() + n_polylines_out_old; for (Polylines::iterator it = out->begin() + n_polylines_out_old;
it != polylines_out->end(); ++ it) { it != out->end(); ++it)
// No need to translate, the absolute position is irrelevant.
// it->translate(- direction.second.x, - direction.second.y);
it->rotate(direction.first); 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;
// only for line infill
coord_t _line_oscillation;
// Enabled for the grid infill, disabled for the rectilinear and line infill. struct IntersectionPoint : Point {
virtual bool _horizontal_lines() const { return false; }; enum ipType { ipTypeLower, ipTypeUpper, ipTypeMiddle };
ipType type;
virtual Line _line(int i, coord_t x, coord_t y_min, coord_t y_max) const // skipped contains the polygon points accumulated between the previous intersection
{ return Line(Point(x, y_min), Point(x, y_max)); }; // point and the current one, in the original polygon winding order (does not contain
// either points)
Points skipped;
virtual bool _can_connect(coord_t dist_X, coord_t dist_Y) { // next contains a polygon portion connecting this point to the first intersection
return dist_X <= this->_diagonal_distance // point found following the polygon in any direction but having:
&& dist_Y <= this->_diagonal_distance; // x > this->x || (x == this->x && y > this->y)
// (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_

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +0,0 @@
#ifndef slic3r_FillRectilinear2_hpp_
#define slic3r_FillRectilinear2_hpp_
#include "../libslic3r.h"
#include "Fill.hpp"
namespace Slic3r {
class Surface;
class FillRectilinear2 : public Fill
{
public:
virtual Fill* clone() const { return new FillRectilinear2(*this); };
virtual ~FillRectilinear2() {}
virtual Polylines fill_surface(const Surface &surface);
protected:
bool fill_surface_by_lines(const Surface *surface, float angleBase, float pattern_shift, Polylines &polylines_out);
};
class FillGrid2 : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillGrid2(*this); };
virtual ~FillGrid2() {}
virtual Polylines fill_surface(const Surface &surface);
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; }
};
class FillTriangles : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillTriangles(*this); };
virtual ~FillTriangles() {}
virtual Polylines fill_surface(const Surface &surface);
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; }
};
class FillStars : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillStars(*this); };
virtual ~FillStars() {}
virtual Polylines fill_surface(const Surface &surface);
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; }
};
class FillCubic : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillCubic(*this); };
virtual ~FillCubic() {}
virtual Polylines fill_surface(const Surface &surface);
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; }
};
// Remove sticks (tentacles with zero area) from the polygon.
extern bool remove_sticks(Polygon &poly);
extern bool remove_sticks(Polygons &polys);
extern bool remove_sticks(ExPolygon &poly);
extern bool remove_small(Polygons &polys, double min_area);
}; // namespace Slic3r
#endif // slic3r_FillRectilinear2_hpp_

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

@ -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

@ -97,8 +97,8 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo
$config->set_deserialize('gcode_flavor', 'machinekit'); $config->set_deserialize('gcode_flavor', 'machinekit');
is $config->get('gcode_flavor'), 'machinekit', 'deserialize enum (gcode_flavor)'; is $config->get('gcode_flavor'), 'machinekit', 'deserialize enum (gcode_flavor)';
$config->set_deserialize('fill_pattern', 'line'); $config->set_deserialize('fill_pattern', 'stars');
is $config->get('fill_pattern'), 'line', 'deserialize enum (fill_pattern)'; is $config->get('fill_pattern'), 'stars', 'deserialize enum (fill_pattern)';
$config->set_deserialize('support_material_pattern', 'pillars'); $config->set_deserialize('support_material_pattern', 'pillars');
is $config->get('support_material_pattern'), 'pillars', 'deserialize enum (support_material_pattern)'; is $config->get('support_material_pattern'), 'pillars', 'deserialize enum (support_material_pattern)';
@ -199,12 +199,12 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo
{ {
my $config = Slic3r::Config->new; my $config = Slic3r::Config->new;
$config->set('fill_pattern', 'line'); $config->set('fill_pattern', 'stars');
my $config2 = Slic3r::Config->new; my $config2 = Slic3r::Config->new;
$config2->set('fill_pattern', 'hilbertcurve'); $config2->set('fill_pattern', 'hilbertcurve');
is $config->get('fill_pattern'), 'line', 'no interferences between DynamicConfig objects'; is $config->get('fill_pattern'), 'stars', 'no interferences between DynamicConfig objects';
} }
{ {

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)