mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-15 00:05:57 +08:00
Merge branch 'master' of https://github.com/alexrj/slic3r
This commit is contained in:
commit
9fedc425ac
@ -8,7 +8,7 @@ use Slic3r::ExtrusionPath ':roles';
|
|||||||
use Slic3r::Flow ':roles';
|
use Slic3r::Flow ':roles';
|
||||||
use Slic3r::Geometry qw(epsilon scale scaled_epsilon PI rad2deg deg2rad convex_hull);
|
use Slic3r::Geometry qw(epsilon scale scaled_epsilon PI rad2deg deg2rad convex_hull);
|
||||||
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
|
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
|
||||||
intersection_pl offset2_ex diff_pl);
|
intersection_pl offset2_ex diff_pl diff_ex);
|
||||||
use Slic3r::Surface ':types';
|
use Slic3r::Surface ':types';
|
||||||
|
|
||||||
has 'print_config' => (is => 'rw', required => 1);
|
has 'print_config' => (is => 'rw', required => 1);
|
||||||
@ -782,7 +782,7 @@ sub generate_toolpaths {
|
|||||||
my $base_flow = $_flow;
|
my $base_flow = $_flow;
|
||||||
|
|
||||||
# find centerline of the external loop/extrusions
|
# find centerline of the external loop/extrusions
|
||||||
my $to_infill = offset2_ex($base, +scaled_epsilon, -(scaled_epsilon + $_flow->scaled_width/2));
|
my $to_infill = offset2($base, +scaled_epsilon, -(scaled_epsilon + $_flow->scaled_width/2));
|
||||||
|
|
||||||
my @paths = ();
|
my @paths = ();
|
||||||
|
|
||||||
@ -796,6 +796,17 @@ sub generate_toolpaths {
|
|||||||
# use the proper spacing for first layer as we don't need to align
|
# use the proper spacing for first layer as we don't need to align
|
||||||
# its pattern to the other layers
|
# its pattern to the other layers
|
||||||
$filler->set_min_spacing($base_flow->spacing);
|
$filler->set_min_spacing($base_flow->spacing);
|
||||||
|
|
||||||
|
# subtract brim so that it goes around the object fully (and support gets its own brim)
|
||||||
|
if ($self->print_config->brim_width > 0) {
|
||||||
|
my $d = +scale $self->print_config->brim_width*2;
|
||||||
|
$to_infill = diff_ex(
|
||||||
|
$to_infill,
|
||||||
|
offset($object->get_layer(0)->slices->polygons, $d),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$to_infill = union_ex($to_infill);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
# draw a perimeter all around support infill
|
# draw a perimeter all around support infill
|
||||||
# TODO: use brim ordering algorithm
|
# TODO: use brim ordering algorithm
|
||||||
@ -806,10 +817,10 @@ sub generate_toolpaths {
|
|||||||
mm3_per_mm => $mm3_per_mm,
|
mm3_per_mm => $mm3_per_mm,
|
||||||
width => $_flow->width,
|
width => $_flow->width,
|
||||||
height => $layer->height,
|
height => $layer->height,
|
||||||
), map @$_, @$to_infill;
|
), @$to_infill;
|
||||||
|
|
||||||
# TODO: use offset2_ex()
|
# TODO: use offset2_ex()
|
||||||
$to_infill = offset_ex([ map @$_, @$to_infill ], -$_flow->scaled_spacing);
|
$to_infill = offset_ex($to_infill, -$_flow->scaled_spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $mm3_per_mm = $base_flow->mm3_per_mm;
|
my $mm3_per_mm = $base_flow->mm3_per_mm;
|
||||||
|
2
t/fill.t
2
t/fill.t
@ -22,7 +22,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
|
|||||||
{
|
{
|
||||||
my $print = Slic3r::Print->new;
|
my $print = Slic3r::Print->new;
|
||||||
my $surface_width = 250;
|
my $surface_width = 250;
|
||||||
my $distance = Slic3r::Filler::adjust_solid_spacing($surface_width, 47);
|
my $distance = Slic3r::Flow::solid_spacing($surface_width, 47);
|
||||||
is $distance, 50, 'adjusted solid distance';
|
is $distance, 50, 'adjusted solid distance';
|
||||||
is $surface_width % $distance, 0, 'adjusted solid distance';
|
is $surface_width % $distance, 0, 'adjusted solid distance';
|
||||||
}
|
}
|
||||||
|
@ -5,24 +5,6 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class BridgeDirectionComparator {
|
|
||||||
public:
|
|
||||||
std::map<double,double> dir_coverage; // angle => score
|
|
||||||
|
|
||||||
BridgeDirectionComparator(double _extrusion_width)
|
|
||||||
: extrusion_width(_extrusion_width)
|
|
||||||
{};
|
|
||||||
|
|
||||||
// the best direction is the one causing most lines to be bridged (thus most coverage)
|
|
||||||
bool operator() (double a, double b) {
|
|
||||||
// Initial sort by coverage only - comparator must obey strict weak ordering
|
|
||||||
return (this->dir_coverage[a] > this->dir_coverage[b]);
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
double extrusion_width;
|
|
||||||
};
|
|
||||||
|
|
||||||
BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices,
|
BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices,
|
||||||
coord_t _extrusion_width)
|
coord_t _extrusion_width)
|
||||||
: expolygon(_expolygon), lower_slices(_lower_slices), extrusion_width(_extrusion_width),
|
: expolygon(_expolygon), lower_slices(_lower_slices), extrusion_width(_extrusion_width),
|
||||||
@ -59,6 +41,8 @@ BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonColle
|
|||||||
bool
|
bool
|
||||||
BridgeDetector::detect_angle()
|
BridgeDetector::detect_angle()
|
||||||
{
|
{
|
||||||
|
// Do nothing if the bridging region is completely in the air
|
||||||
|
// and there are no anchors available at the layer below.
|
||||||
if (this->_edges.empty() || this->_anchors.empty()) return false;
|
if (this->_edges.empty() || this->_anchors.empty()) return false;
|
||||||
|
|
||||||
/* Outset the bridge expolygon by half the amount we used for detecting anchors;
|
/* Outset the bridge expolygon by half the amount we used for detecting anchors;
|
||||||
@ -70,60 +54,65 @@ BridgeDetector::detect_angle()
|
|||||||
bridge in several directions and then sum the length of lines having both
|
bridge in several directions and then sum the length of lines having both
|
||||||
endpoints within anchors */
|
endpoints within anchors */
|
||||||
|
|
||||||
// we test angles according to configured resolution
|
// generate the list of candidate angles
|
||||||
std::vector<double> angles;
|
std::vector<BridgeDirection> candidates;
|
||||||
for (int i = 0; i <= PI/this->resolution; ++i)
|
|
||||||
angles.push_back(i * this->resolution);
|
|
||||||
|
|
||||||
// we also test angles of each bridge contour
|
|
||||||
{
|
{
|
||||||
Polygons pp = this->expolygon;
|
// we test angles according to configured resolution
|
||||||
for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) {
|
std::vector<double> angles;
|
||||||
Lines lines = p->lines();
|
for (int i = 0; i <= PI/this->resolution; ++i)
|
||||||
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
|
angles.push_back(i * this->resolution);
|
||||||
angles.push_back(line->direction());
|
|
||||||
|
// we also test angles of each bridge contour
|
||||||
|
{
|
||||||
|
Polygons pp = this->expolygon;
|
||||||
|
for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) {
|
||||||
|
Lines lines = p->lines();
|
||||||
|
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
|
||||||
|
angles.push_back(line->direction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* we also test angles of each open supporting edge
|
/* we also test angles of each open supporting edge
|
||||||
(this finds the optimal angle for C-shaped supports) */
|
(this finds the optimal angle for C-shaped supports) */
|
||||||
for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge) {
|
for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge) {
|
||||||
if (edge->first_point().coincides_with(edge->last_point())) continue;
|
if (edge->first_point().coincides_with(edge->last_point())) continue;
|
||||||
angles.push_back(Line(edge->first_point(), edge->last_point()).direction());
|
angles.push_back(Line(edge->first_point(), edge->last_point()).direction());
|
||||||
}
|
|
||||||
|
|
||||||
// remove duplicates
|
|
||||||
double min_resolution = PI/180.0; // 1 degree
|
|
||||||
std::sort(angles.begin(), angles.end());
|
|
||||||
for (size_t i = 1; i < angles.size(); ++i) {
|
|
||||||
if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
|
|
||||||
angles.erase(angles.begin() + i);
|
|
||||||
--i;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* compare first value with last one and remove the greatest one (PI)
|
|
||||||
in case they are parallel (PI, 0) */
|
|
||||||
if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
|
|
||||||
angles.pop_back();
|
|
||||||
|
|
||||||
BridgeDirectionComparator bdcomp(this->extrusion_width);
|
// remove duplicates
|
||||||
std::map<double,double> dir_avg_length;
|
double min_resolution = PI/180.0; // 1 degree
|
||||||
|
std::sort(angles.begin(), angles.end());
|
||||||
|
for (size_t i = 1; i < angles.size(); ++i) {
|
||||||
|
if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
|
||||||
|
angles.erase(angles.begin() + i);
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* compare first value with last one and remove the greatest one (PI)
|
||||||
|
in case they are parallel (PI, 0) */
|
||||||
|
if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
|
||||||
|
angles.pop_back();
|
||||||
|
|
||||||
|
for (auto angle : angles)
|
||||||
|
candidates.push_back(BridgeDirection(angle));
|
||||||
|
}
|
||||||
|
|
||||||
double line_increment = this->extrusion_width;
|
double line_increment = this->extrusion_width;
|
||||||
bool have_coverage = false;
|
bool have_coverage = false;
|
||||||
for (std::vector<double>::const_iterator angle = angles.begin(); angle != angles.end(); ++angle) {
|
for (BridgeDirection &candidate : candidates) {
|
||||||
Polygons my_clip_area = clip_area;
|
Polygons my_clip_area = clip_area;
|
||||||
ExPolygons my_anchors = this->_anchors;
|
ExPolygons my_anchors = this->_anchors;
|
||||||
|
|
||||||
// rotate everything - the center point doesn't matter
|
// rotate everything - the center point doesn't matter
|
||||||
for (Polygons::iterator it = my_clip_area.begin(); it != my_clip_area.end(); ++it)
|
for (Polygon &p : my_clip_area)
|
||||||
it->rotate(-*angle, Point(0,0));
|
p.rotate(-candidate.angle, Point(0,0));
|
||||||
for (ExPolygons::iterator it = my_anchors.begin(); it != my_anchors.end(); ++it)
|
for (ExPolygon &e : my_anchors)
|
||||||
it->rotate(-*angle, Point(0,0));
|
e.rotate(-candidate.angle, Point(0,0));
|
||||||
|
|
||||||
// generate lines in this direction
|
// generate lines in this direction
|
||||||
BoundingBox bb;
|
BoundingBox bb;
|
||||||
for (ExPolygons::const_iterator it = my_anchors.begin(); it != my_anchors.end(); ++it)
|
for (const ExPolygon &e : my_anchors)
|
||||||
bb.merge((Points)*it);
|
bb.merge((Points)e);
|
||||||
|
|
||||||
Lines lines;
|
Lines lines;
|
||||||
for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
|
for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
|
||||||
@ -143,44 +132,39 @@ BridgeDetector::detect_angle()
|
|||||||
|
|
||||||
std::vector<double> lengths;
|
std::vector<double> lengths;
|
||||||
double total_length = 0;
|
double total_length = 0;
|
||||||
for (Lines::const_iterator line = clipped_lines.begin(); line != clipped_lines.end(); ++line) {
|
for (const Line &line : clipped_lines) {
|
||||||
double len = line->length();
|
const double len = line.length();
|
||||||
lengths.push_back(len);
|
lengths.push_back(len);
|
||||||
total_length += len;
|
total_length += len;
|
||||||
}
|
}
|
||||||
if (total_length) have_coverage = true;
|
if (total_length) have_coverage = true;
|
||||||
|
|
||||||
// sum length of bridged lines
|
// sum length of bridged lines
|
||||||
bdcomp.dir_coverage[*angle] = total_length;
|
candidate.coverage = total_length;
|
||||||
|
|
||||||
/* The following produces more correct results in some cases and more broken in others.
|
/* The following produces more correct results in some cases and more broken in others.
|
||||||
TODO: investigate, as it looks more reliable than line clipping. */
|
TODO: investigate, as it looks more reliable than line clipping. */
|
||||||
// $directions_coverage{$angle} = sum(map $_->area, @{$self->coverage($angle)}) // 0;
|
// $directions_coverage{$angle} = sum(map $_->area, @{$self->coverage($angle)}) // 0;
|
||||||
|
|
||||||
// max length of bridged lines
|
// max length of bridged lines
|
||||||
dir_avg_length[*angle] = !lengths.empty()
|
if (!lengths.empty())
|
||||||
? *std::max_element(lengths.begin(), lengths.end())
|
candidate.max_length = *std::max_element(lengths.begin(), lengths.end());
|
||||||
: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no direction produced coverage, then there's no bridge direction
|
// if no direction produced coverage, then there's no bridge direction
|
||||||
if (!have_coverage) return false;
|
if (!have_coverage) return false;
|
||||||
|
|
||||||
// sort directions by coverage - most coverage first
|
// sort directions by coverage - most coverage first
|
||||||
std::sort(angles.begin(), angles.end(), bdcomp);
|
std::sort(candidates.begin(), candidates.end());
|
||||||
this->angle = angles.front();
|
|
||||||
|
|
||||||
// if any other direction is within extrusion width of coverage, prefer it if shorter
|
// if any other direction is within extrusion width of coverage, prefer it if shorter
|
||||||
// TODO: There are two options here - within width of the angle with most coverage, or within width of the currently perferred?
|
// TODO: There are two options here - within width of the angle with most coverage, or within width of the currently perferred?
|
||||||
double most_coverage_angle = this->angle;
|
size_t i_best = 0;
|
||||||
for (std::vector<double>::const_iterator angle = angles.begin() + 1;
|
for (size_t i = 1; i < candidates.size() && candidates[i_best].coverage - candidates[i].coverage < this->extrusion_width; ++ i)
|
||||||
angle != angles.end() && bdcomp.dir_coverage[most_coverage_angle] - bdcomp.dir_coverage[*angle] < this->extrusion_width;
|
if (candidates[i].max_length < candidates[i_best].max_length)
|
||||||
++angle
|
i_best = i;
|
||||||
) {
|
|
||||||
if (dir_avg_length[*angle] < dir_avg_length[this->angle]) {
|
this->angle = candidates[i_best].angle;
|
||||||
this->angle = *angle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->angle >= PI) this->angle -= PI;
|
if (this->angle >= PI) this->angle -= PI;
|
||||||
|
|
||||||
|
@ -31,6 +31,19 @@ private:
|
|||||||
Polylines _edges;
|
Polylines _edges;
|
||||||
// Closed polygons representing the supporting areas.
|
// Closed polygons representing the supporting areas.
|
||||||
ExPolygons _anchors;
|
ExPolygons _anchors;
|
||||||
|
|
||||||
|
class BridgeDirection {
|
||||||
|
public:
|
||||||
|
BridgeDirection(double a = -1.) : angle(a), coverage(0.), max_length(0.) {}
|
||||||
|
// the best direction is the one causing most lines to be bridged (thus most coverage)
|
||||||
|
bool operator<(const BridgeDirection &other) const {
|
||||||
|
// Initial sort by coverage only - comparator must obey strict weak ordering
|
||||||
|
return this->coverage > other.coverage;
|
||||||
|
};
|
||||||
|
double angle;
|
||||||
|
double coverage;
|
||||||
|
double max_length;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#define DEBUG
|
||||||
|
#undef NDEBUG
|
||||||
|
#include <cassert>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -69,36 +72,6 @@ Fill::fill_surface(const Surface &surface)
|
|||||||
return polylines_out;
|
return polylines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate a new spacing to fill width with possibly integer number of lines,
|
|
||||||
// the first and last line being centered at the interval ends.
|
|
||||||
// This function possibly increases the spacing, never decreases,
|
|
||||||
// and for a narrow width the increase in spacing may become severe,
|
|
||||||
// therefore the adjustment is limited to 20% increase.
|
|
||||||
coord_t
|
|
||||||
Fill::adjust_solid_spacing(const coord_t width, const coord_t distance)
|
|
||||||
{
|
|
||||||
assert(width >= 0);
|
|
||||||
assert(distance > 0);
|
|
||||||
const int number_of_intervals = floor(width / distance);
|
|
||||||
if (number_of_intervals == 0) return distance;
|
|
||||||
|
|
||||||
coord_t distance_new = (width / number_of_intervals);
|
|
||||||
|
|
||||||
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
|
|
||||||
assert(factor > 1. - 1e-5);
|
|
||||||
|
|
||||||
// How much could the extrusion width be increased? By 20%.
|
|
||||||
// Because of this limit, this method is not idempotent: each run
|
|
||||||
// will increment distance by 20%.
|
|
||||||
const coordf_t factor_max = 1.2;
|
|
||||||
if (factor > factor_max)
|
|
||||||
distance_new = floor((double)distance * factor_max + 0.5);
|
|
||||||
|
|
||||||
assert((distance_new * number_of_intervals) <= width);
|
|
||||||
|
|
||||||
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.
|
||||||
Fill::direction_t
|
Fill::direction_t
|
||||||
|
@ -64,7 +64,6 @@ public:
|
|||||||
public:
|
public:
|
||||||
static Fill* new_from_type(const InfillPattern type);
|
static Fill* new_from_type(const InfillPattern type);
|
||||||
static Fill* new_from_type(const std::string &type);
|
static Fill* new_from_type(const std::string &type);
|
||||||
static coord_t adjust_solid_spacing(const coord_t width, const coord_t distance);
|
|
||||||
virtual Fill* clone() const = 0;
|
virtual Fill* clone() const = 0;
|
||||||
virtual ~Fill() {};
|
virtual ~Fill() {};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "../ClipperUtils.hpp"
|
#include "../ClipperUtils.hpp"
|
||||||
#include "../ExPolygon.hpp"
|
#include "../ExPolygon.hpp"
|
||||||
|
#include "../Flow.hpp"
|
||||||
#include "../Surface.hpp"
|
#include "../Surface.hpp"
|
||||||
|
|
||||||
#include "FillConcentric.hpp"
|
#include "FillConcentric.hpp"
|
||||||
@ -20,7 +21,7 @@ FillConcentric::_fill_surface_single(
|
|||||||
|
|
||||||
if (this->density > 0.9999f && !this->dont_adjust) {
|
if (this->density > 0.9999f && !this->dont_adjust) {
|
||||||
BoundingBox bounding_box = expolygon.contour.bounding_box();
|
BoundingBox bounding_box = expolygon.contour.bounding_box();
|
||||||
distance = this->adjust_solid_spacing(bounding_box.size().x, distance);
|
distance = Flow::solid_spacing(bounding_box.size().x, distance);
|
||||||
this->_spacing = unscale(distance);
|
this->_spacing = unscale(distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "../ClipperUtils.hpp"
|
#include "../ClipperUtils.hpp"
|
||||||
#include "../ExPolygon.hpp"
|
#include "../ExPolygon.hpp"
|
||||||
|
#include "../Flow.hpp"
|
||||||
#include "../PolylineCollection.hpp"
|
#include "../PolylineCollection.hpp"
|
||||||
#include "../Surface.hpp"
|
#include "../Surface.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -48,7 +49,7 @@ FillRectilinear::_fill_single_direction(ExPolygon expolygon,
|
|||||||
|
|
||||||
// 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) {
|
||||||
line_spacing = this->adjust_solid_spacing(bounding_box.size().x, line_spacing);
|
line_spacing = Flow::solid_spacing(bounding_box.size().x, line_spacing);
|
||||||
this->_spacing = unscale(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
|
||||||
|
@ -50,6 +50,11 @@ Flow::spacing() const {
|
|||||||
return this->width - OVERLAP_FACTOR * (this->width - min_flow_spacing);
|
return this->width - OVERLAP_FACTOR * (this->width - min_flow_spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Flow::set_spacing(float spacing) {
|
||||||
|
this->width = Flow::_width_from_spacing(spacing, this->nozzle_diameter, this->height, this->bridge);
|
||||||
|
}
|
||||||
|
|
||||||
/* This method returns the centerline spacing between an extrusion using this
|
/* This method returns the centerline spacing between an extrusion using this
|
||||||
flow and another one using another flow.
|
flow and another one using another flow.
|
||||||
this->spacing(other) shall return the same value as other.spacing(*this) */
|
this->spacing(other) shall return the same value as other.spacing(*this) */
|
||||||
@ -115,4 +120,37 @@ Flow::_width_from_spacing(float spacing, float nozzle_diameter, float height, bo
|
|||||||
return spacing + OVERLAP_FACTOR * height * (1 - PI/4.0);
|
return spacing + OVERLAP_FACTOR * height * (1 - PI/4.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate a new spacing to fill width with possibly integer number of lines,
|
||||||
|
// the first and last line being centered at the interval ends.
|
||||||
|
// This function possibly increases the spacing, never decreases,
|
||||||
|
// and for a narrow width the increase in spacing may become severe,
|
||||||
|
// therefore the adjustment is limited to 20% increase.
|
||||||
|
template <class T>
|
||||||
|
T
|
||||||
|
Flow::solid_spacing(const T total_width, const T spacing)
|
||||||
|
{
|
||||||
|
assert(total_width >= 0);
|
||||||
|
assert(spacing > 0);
|
||||||
|
const int number_of_intervals = floor(total_width / spacing);
|
||||||
|
if (number_of_intervals == 0) return spacing;
|
||||||
|
|
||||||
|
T spacing_new = (total_width / number_of_intervals);
|
||||||
|
|
||||||
|
const double factor = (double)spacing_new / (double)spacing;
|
||||||
|
assert(factor > 1. - 1e-5);
|
||||||
|
|
||||||
|
// How much could the extrusion width be increased? By 20%.
|
||||||
|
// Because of this limit, this method is not idempotent: each run
|
||||||
|
// will increment spacing by 20%.
|
||||||
|
const double factor_max = 1.2;
|
||||||
|
if (factor > factor_max)
|
||||||
|
spacing_new = floor((double)spacing * factor_max + 0.5);
|
||||||
|
|
||||||
|
assert((spacing_new * number_of_intervals) <= total_width);
|
||||||
|
|
||||||
|
return spacing_new;
|
||||||
|
}
|
||||||
|
template coord_t Flow::solid_spacing<coord_t>(const coord_t total_width, const coord_t spacing);
|
||||||
|
template coordf_t Flow::solid_spacing<coordf_t>(const coordf_t total_width, const coordf_t spacing);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,13 @@ class Flow
|
|||||||
: width(_w), height(_h), nozzle_diameter(_nd), bridge(_bridge) {};
|
: width(_w), height(_h), nozzle_diameter(_nd), bridge(_bridge) {};
|
||||||
float spacing() const;
|
float spacing() const;
|
||||||
float spacing(const Flow &other) const;
|
float spacing(const Flow &other) const;
|
||||||
|
void set_spacing(float spacing);
|
||||||
|
void set_solid_spacing(const coord_t total_width) {
|
||||||
|
this->set_spacing(Flow::solid_spacing(total_width, this->scaled_spacing()));
|
||||||
|
};
|
||||||
|
void set_solid_spacing(const coordf_t total_width) {
|
||||||
|
this->set_spacing(Flow::solid_spacing(total_width, (coordf_t)this->spacing()));
|
||||||
|
};
|
||||||
double mm3_per_mm() const;
|
double mm3_per_mm() const;
|
||||||
coord_t scaled_width() const {
|
coord_t scaled_width() const {
|
||||||
return scale_(this->width);
|
return scale_(this->width);
|
||||||
@ -43,12 +50,12 @@ class Flow
|
|||||||
|
|
||||||
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
||||||
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
||||||
|
template <class T> static T solid_spacing(const T total_width, const T spacing);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static float _bridge_width(float nozzle_diameter, float bridge_flow_ratio);
|
static float _bridge_width(float nozzle_diameter, float bridge_flow_ratio);
|
||||||
static float _auto_width(FlowRole role, float nozzle_diameter, float height);
|
static float _auto_width(FlowRole role, float nozzle_diameter, float height);
|
||||||
static float _width_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
static float _width_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
||||||
static float _spacing(float width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,10 @@ Print::invalidate_state_by_config(const PrintConfigBase &config)
|
|||||||
|| opt_key == "min_skirt_length"
|
|| opt_key == "min_skirt_length"
|
||||||
|| opt_key == "ooze_prevention") {
|
|| opt_key == "ooze_prevention") {
|
||||||
steps.insert(psSkirt);
|
steps.insert(psSkirt);
|
||||||
|
} else if (opt_key == "brim_width") {
|
||||||
|
steps.insert(psBrim);
|
||||||
|
steps.insert(psSkirt);
|
||||||
|
osteps.insert(posSupportMaterial);
|
||||||
} else if (opt_key == "brim_width"
|
} else if (opt_key == "brim_width"
|
||||||
|| opt_key == "interior_brim_width"
|
|| opt_key == "interior_brim_width"
|
||||||
|| opt_key == "brim_connections_width") {
|
|| opt_key == "brim_connections_width") {
|
||||||
@ -759,13 +763,18 @@ Print::brim_flow() const
|
|||||||
extruders and take the one with, say, the smallest index.
|
extruders and take the one with, say, the smallest index.
|
||||||
The same logic should be applied to the code that selects the extruder during G-code
|
The same logic should be applied to the code that selects the extruder during G-code
|
||||||
generation as well. */
|
generation as well. */
|
||||||
return Flow::new_from_config_width(
|
Flow flow = Flow::new_from_config_width(
|
||||||
frPerimeter,
|
frPerimeter,
|
||||||
width,
|
width,
|
||||||
this->config.nozzle_diameter.get_at(this->regions.front()->config.perimeter_extruder-1),
|
this->config.nozzle_diameter.get_at(this->regions.front()->config.perimeter_extruder-1),
|
||||||
this->skirt_first_layer_height(),
|
this->skirt_first_layer_height(),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Adjust extrusion width in order to fill the total brim width with an integer number of lines.
|
||||||
|
flow.set_solid_spacing(this->config.brim_width.value);
|
||||||
|
|
||||||
|
return flow;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flow
|
Flow
|
||||||
@ -844,8 +853,8 @@ Print::_make_brim()
|
|||||||
// perimeters because here we're offsetting outwards)
|
// perimeters because here we're offsetting outwards)
|
||||||
append_to(loops, offset2(
|
append_to(loops, offset2(
|
||||||
islands,
|
islands,
|
||||||
flow.scaled_width() + flow.scaled_spacing() * (i - 1.0 + 0.5),
|
flow.scaled_width() + flow.scaled_spacing() * (i - 1.5 + 0.5),
|
||||||
flow.scaled_spacing() * -1.0,
|
flow.scaled_spacing() * -0.5,
|
||||||
100000,
|
100000,
|
||||||
ClipperLib::jtSquare
|
ClipperLib::jtSquare
|
||||||
));
|
));
|
||||||
|
@ -78,8 +78,3 @@ new_from_type(CLASS, type)
|
|||||||
%}
|
%}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
%package{Slic3r::Filler};
|
|
||||||
|
|
||||||
coord_t adjust_solid_spacing(coord_t width, coord_t distance)
|
|
||||||
%code{% RETVAL = Fill::adjust_solid_spacing(width, distance); %};
|
|
||||||
|
@ -81,3 +81,6 @@ _constant()
|
|||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
coord_t solid_spacing(coord_t width, coord_t distance)
|
||||||
|
%code{% RETVAL = Flow::solid_spacing(width, distance); %};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user