Cherry picked FillBoundedRectilinear
Co-authored-by: Lukáš Hejl <hejl.lukas@gmail.com>
This commit is contained in:
parent
b255278339
commit
398222a49f
9 changed files with 131 additions and 13 deletions
|
@ -49,6 +49,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||||
case ipSupportCubic: return new FillAdaptive::Filler();
|
case ipSupportCubic: return new FillAdaptive::Filler();
|
||||||
case ipSupportBase: return new FillSupportBase();
|
case ipSupportBase: return new FillSupportBase();
|
||||||
case ipLightning: return new FillLightning::Filler();
|
case ipLightning: return new FillLightning::Filler();
|
||||||
|
case ipBoundedRectilinear: return new FillBoundedRectilinear();
|
||||||
default: throw Slic3r::InvalidArgument("unknown type");
|
default: throw Slic3r::InvalidArgument("unknown type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,10 @@ public:
|
||||||
// Octree builds on mesh for usage in the adaptive cubic infill
|
// Octree builds on mesh for usage in the adaptive cubic infill
|
||||||
FillAdaptive::Octree* adapt_fill_octree = nullptr;
|
FillAdaptive::Octree* adapt_fill_octree = nullptr;
|
||||||
|
|
||||||
|
// PrintConfig and PrintObjectConfig are used by infills that use Arachne (Concentric and FillBoundedRectilinear).
|
||||||
|
const PrintConfig *print_config = nullptr;
|
||||||
|
const PrintObjectConfig *print_object_config = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Fill() {}
|
virtual ~Fill() {}
|
||||||
virtual Fill* clone() const = 0;
|
virtual Fill* clone() const = 0;
|
||||||
|
|
|
@ -97,14 +97,8 @@ void FillConcentric::_fill_surface_single(const FillParams ¶ms,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion);
|
ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion);
|
||||||
if (extrusion->is_closed && thick_polyline.points.front() == thick_polyline.points.back() && thick_polyline.width.front() == thick_polyline.width.back()) {
|
if (extrusion->is_closed)
|
||||||
thick_polyline.points.pop_back();
|
thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, last_pos));
|
||||||
assert(thick_polyline.points.size() * 2 == thick_polyline.width.size());
|
|
||||||
int nearest_idx = nearest_point_index(thick_polyline.points, last_pos);
|
|
||||||
std::rotate(thick_polyline.points.begin(), thick_polyline.points.begin() + nearest_idx, thick_polyline.points.end());
|
|
||||||
std::rotate(thick_polyline.width.begin(), thick_polyline.width.begin() + 2 * nearest_idx, thick_polyline.width.end());
|
|
||||||
thick_polyline.points.emplace_back(thick_polyline.points.front());
|
|
||||||
}
|
|
||||||
thick_polylines_out.emplace_back(std::move(thick_polyline));
|
thick_polylines_out.emplace_back(std::move(thick_polyline));
|
||||||
last_pos = thick_polylines_out.back().last_point();
|
last_pos = thick_polylines_out.back().last_point();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,6 @@ protected:
|
||||||
ThickPolylines &thick_polylines_out) override;
|
ThickPolylines &thick_polylines_out) override;
|
||||||
|
|
||||||
bool no_sort() const override { return true; }
|
bool no_sort() const override { return true; }
|
||||||
|
|
||||||
const PrintConfig *print_config = nullptr;
|
|
||||||
const PrintObjectConfig *print_object_config = nullptr;
|
|
||||||
|
|
||||||
friend class Layer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "../Geometry.hpp"
|
#include "../Geometry.hpp"
|
||||||
#include "../Surface.hpp"
|
#include "../Surface.hpp"
|
||||||
#include "../ShortestPath.hpp"
|
#include "../ShortestPath.hpp"
|
||||||
|
#include "../Arachne/WallToolPaths.hpp"
|
||||||
|
|
||||||
#include "FillRectilinear.hpp"
|
#include "FillRectilinear.hpp"
|
||||||
|
|
||||||
|
@ -3043,6 +3044,90 @@ Polylines FillSupportBase::fill_surface(const Surface *surface, const FillParams
|
||||||
return polylines_out;
|
return polylines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThickPolylines FillBoundedRectilinear::fill_surface_arachne(const Surface *surface, const FillParams ¶ms)
|
||||||
|
{
|
||||||
|
// Perform offset.
|
||||||
|
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
|
||||||
|
// Create the infills for each of the regions.
|
||||||
|
ThickPolylines thick_polylines_out;
|
||||||
|
for (ExPolygon &ex_poly : expp)
|
||||||
|
_fill_surface_single(Surface(*surface, std::move(ex_poly)), params, thick_polylines_out);
|
||||||
|
|
||||||
|
return thick_polylines_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FillBoundedRectilinear::_fill_surface_single(const Surface &surface, const FillParams ¶ms, ThickPolylines &thick_polylines_out)
|
||||||
|
{
|
||||||
|
assert(params.use_arachne);
|
||||||
|
assert(this->print_config != nullptr && this->print_object_config != nullptr && this->print_region_config != nullptr);
|
||||||
|
|
||||||
|
coord_t scaled_spacing = scaled<coord_t>(this->spacing);
|
||||||
|
Polygons polygons = offset(surface.expolygon, float(scaled_spacing) / 2.f);
|
||||||
|
Arachne::WallToolPaths wall_tool_paths(polygons, scaled_spacing, scaled_spacing, 1, 0, params.layer_height, *this->print_object_config, *this->print_config);
|
||||||
|
if (std::vector<Arachne::VariableWidthLines> loop = wall_tool_paths.getToolPaths(); !loop.empty()) {
|
||||||
|
assert(loop.size() == 1);
|
||||||
|
|
||||||
|
size_t firts_poly_idx = thick_polylines_out.size();
|
||||||
|
Point last_pos(0, 0);
|
||||||
|
for (const Arachne::ExtrusionLine &extrusion : loop.front()) {
|
||||||
|
if (extrusion.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion);
|
||||||
|
if (thick_polyline.length() == 0.)
|
||||||
|
//FIXME this should not happen.
|
||||||
|
continue;
|
||||||
|
assert(thick_polyline.size() > 1);
|
||||||
|
assert(thick_polyline.length() > 0.);
|
||||||
|
//assert(thick_polyline.points.size() == thick_polyline.width.size());
|
||||||
|
if (extrusion.is_closed)
|
||||||
|
thick_polyline.start_at_index(nearest_point_index(thick_polyline.points, last_pos));
|
||||||
|
|
||||||
|
assert(thick_polyline.size() > 1);
|
||||||
|
//assert(thick_polyline.points.size() == thick_polyline.width.size());
|
||||||
|
thick_polylines_out.emplace_back(std::move(thick_polyline));
|
||||||
|
last_pos = thick_polylines_out.back().last_point();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clip the paths to prevent the extruder from getting exactly on the first point of the loop
|
||||||
|
// Keep valid paths only.
|
||||||
|
size_t j = firts_poly_idx;
|
||||||
|
for (size_t i = firts_poly_idx; i < thick_polylines_out.size(); ++i) {
|
||||||
|
assert(thick_polylines_out[i].size() > 1);
|
||||||
|
assert(thick_polylines_out[i].length() > 0.);
|
||||||
|
//assert(thick_polylines_out[i].points.size() == thick_polylines_out[i].width.size());
|
||||||
|
thick_polylines_out[i].clip_end(this->loop_clipping);
|
||||||
|
assert(thick_polylines_out[i].size() > 1);
|
||||||
|
if (thick_polylines_out[i].is_valid()) {
|
||||||
|
if (j < i)
|
||||||
|
thick_polylines_out[j] = std::move(thick_polylines_out[i]);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j < thick_polylines_out.size())
|
||||||
|
thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remaining infill area will be filled with classic Rectilinear infill.
|
||||||
|
ExPolygons infill_contour = union_ex(wall_tool_paths.getInnerContour());
|
||||||
|
if (offset_ex(infill_contour, -float(scaled_spacing / 2.)).empty())
|
||||||
|
infill_contour.clear(); // Infill region is too small, so let's filter it out.
|
||||||
|
|
||||||
|
Polygons pp;
|
||||||
|
for (ExPolygon &ex : infill_contour)
|
||||||
|
ex.simplify_p(scaled<double>(params.resolution), &pp);
|
||||||
|
|
||||||
|
// Collapse too narrow infill areas and append them to thick_polylines_out.
|
||||||
|
const auto min_perimeter_infill_spacing = coord_t(scaled_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||||
|
const auto infill_overlap = coord_t(scale_(this->print_region_config->get_abs_value("infill_overlap", this->spacing)));
|
||||||
|
for (ExPolygon &ex_poly : offset2_ex(union_ex(pp), float(-min_perimeter_infill_spacing / 2.), float(infill_overlap + min_perimeter_infill_spacing / 2.))) {
|
||||||
|
Polylines polylines;
|
||||||
|
if (Surface new_surface(surface, std::move(ex_poly)); !fill_surface_by_lines(&new_surface, params, 0.f, 0.f, polylines))
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "FillBoundedRectilinear::fill_surface() failed to fill a region.";
|
||||||
|
append(thick_polylines_out, to_thick_polylines(std::move(polylines), scaled<coord_t>(this->spacing)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Lightning infill assumes that the distance between any two sampled points is always
|
// Lightning infill assumes that the distance between any two sampled points is always
|
||||||
// at least equal to the value of spacing. To meet this assumption, we need to use
|
// at least equal to the value of spacing. To meet this assumption, we need to use
|
||||||
// BoundingBox for whole layers instead of bounding box just around processing ExPolygon.
|
// BoundingBox for whole layers instead of bounding box just around processing ExPolygon.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class PrintRegionConfig;
|
||||||
class Surface;
|
class Surface;
|
||||||
|
|
||||||
class FillRectilinear : public Fill
|
class FillRectilinear : public Fill
|
||||||
|
@ -109,6 +110,25 @@ protected:
|
||||||
float _layer_angle(size_t idx) const override { return 0.f; }
|
float _layer_angle(size_t idx) const override { return 0.f; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FillBoundedRectilinear : public FillRectilinear
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Fill *clone() const override { return new FillBoundedRectilinear(*this); }
|
||||||
|
~FillBoundedRectilinear() override = default;
|
||||||
|
Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override { return {}; };
|
||||||
|
ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams ¶ms) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _fill_surface_single(const Surface &surface, const FillParams ¶ms, ThickPolylines &thick_polylines_out);
|
||||||
|
|
||||||
|
bool no_sort() const override { return true; }
|
||||||
|
|
||||||
|
// PrintRegionConfig is used for computing overlap between boundary contour and inner Rectilinear infill.
|
||||||
|
const PrintRegionConfig *print_region_config = nullptr;
|
||||||
|
|
||||||
|
friend class Layer;
|
||||||
|
};
|
||||||
|
|
||||||
Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing, const BoundingBox &global_bounding_box);
|
Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing, const BoundingBox &global_bounding_box);
|
||||||
Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing, const BoundingBox &global_bounding_box);
|
Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing, const BoundingBox &global_bounding_box);
|
||||||
Points sample_grid_pattern(const Polygons &polygons, coord_t spacing, const BoundingBox &global_bounding_box);
|
Points sample_grid_pattern(const Polygons &polygons, coord_t spacing, const BoundingBox &global_bounding_box);
|
||||||
|
|
|
@ -292,6 +292,19 @@ void ThickPolyline::clip_end(double distance)
|
||||||
assert(this->width.size() == (this->points.size() - 1) * 2);
|
assert(this->width.size() == (this->points.size() - 1) * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThickPolyline::start_at_index(int index)
|
||||||
|
{
|
||||||
|
assert(index >= 0 && index < this->points.size());
|
||||||
|
assert(this->points.front() == this->points.back() && this->width.front() == this->width.back());
|
||||||
|
if (index != 0 && index != (this->points.size() - 1) && this->points.front() == this->points.back() && this->width.front() == this->width.back()) {
|
||||||
|
this->points.pop_back();
|
||||||
|
assert(this->points.size() * 2 == this->width.size());
|
||||||
|
std::rotate(this->points.begin(), this->points.begin() + index, this->points.end());
|
||||||
|
std::rotate(this->width.begin(), this->width.begin() + 2 * index, this->width.end());
|
||||||
|
this->points.emplace_back(this->points.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double Polyline3::length() const
|
double Polyline3::length() const
|
||||||
{
|
{
|
||||||
double l = 0;
|
double l = 0;
|
||||||
|
|
|
@ -191,6 +191,11 @@ public:
|
||||||
|
|
||||||
void clip_end(double distance);
|
void clip_end(double distance);
|
||||||
|
|
||||||
|
// Make this closed ThickPolyline starting in the specified index.
|
||||||
|
// Be aware that this method can be applicable just for closed ThickPolyline.
|
||||||
|
// On open ThickPolyline make no effect.
|
||||||
|
void start_at_index(int index);
|
||||||
|
|
||||||
std::vector<coordf_t> width;
|
std::vector<coordf_t> width;
|
||||||
std::pair<bool,bool> endpoints;
|
std::pair<bool,bool> endpoints;
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,6 +60,7 @@ enum InfillPattern : int {
|
||||||
ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipSupportBase,
|
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipSupportBase,
|
||||||
ipLightning,
|
ipLightning,
|
||||||
|
ipBoundedRectilinear,
|
||||||
ipCount,
|
ipCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue