mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-18 04:35:53 +08:00
Add scattered rectilinear infill method for optical diffusers
This commit is contained in:
parent
162132eb35
commit
bc5e299511
@ -28,6 +28,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
|||||||
case ipGyroid: return new FillGyroid();
|
case ipGyroid: return new FillGyroid();
|
||||||
case ipRectilinear: return new FillRectilinear2();
|
case ipRectilinear: return new FillRectilinear2();
|
||||||
// case ipRectilinear: return new FillRectilinear();
|
// case ipRectilinear: return new FillRectilinear();
|
||||||
|
case ipScatteredRectilinear:return new FillScatteredRectilinear();
|
||||||
case ipLine: return new FillLine();
|
case ipLine: return new FillLine();
|
||||||
case ipGrid: return new FillGrid2();
|
case ipGrid: return new FillGrid2();
|
||||||
case ipTriangles: return new FillTriangles();
|
case ipTriangles: return new FillTriangles();
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
|
#include <boost/random/mersenne_twister.hpp>
|
||||||
|
#include <boost/random/uniform_int_distribution.hpp>
|
||||||
|
#include <boost/random/uniform_real_distribution.hpp>
|
||||||
|
|
||||||
#include "../ExtrusionEntityCollection.hpp"
|
#include "../ExtrusionEntityCollection.hpp"
|
||||||
#include "../ClipperUtils.hpp"
|
#include "../ClipperUtils.hpp"
|
||||||
@ -759,55 +762,9 @@ enum DirectionMask
|
|||||||
DIR_BACKWARD = 2
|
DIR_BACKWARD = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out)
|
// Intersect a set of equally spaced vertical lines with expolygon.
|
||||||
|
std::vector<SegmentedIntersectionLine> FillRectilinear2::_vert_lines_for_polygon(const ExPolygonWithOffset &poly_with_offset, const BoundingBox &bounding_box, const FillParams ¶ms, coord_t line_spacing) const
|
||||||
{
|
{
|
||||||
// At the end, only the new polylines will be rotated back.
|
|
||||||
size_t n_polylines_out_initial = polylines_out.size();
|
|
||||||
|
|
||||||
// Shrink the input polygon a bit first to not push the infill lines out of the perimeters.
|
|
||||||
// const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
|
|
||||||
const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
|
|
||||||
assert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
|
|
||||||
|
|
||||||
// Rotate polygons so that we can work with vertical lines here
|
|
||||||
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
|
|
||||||
rotate_vector.first += angleBase;
|
|
||||||
|
|
||||||
assert(params.density > 0.0001f);
|
|
||||||
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
|
|
||||||
|
|
||||||
// On the polygons of poly_with_offset, the infill lines will be connected.
|
|
||||||
ExPolygonWithOffset poly_with_offset(
|
|
||||||
surface->expolygon,
|
|
||||||
- rotate_vector.first,
|
|
||||||
scale_(0 - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->spacing),
|
|
||||||
scale_(0 - 0.5 * this->spacing));
|
|
||||||
if (poly_with_offset.n_contours_inner == 0) {
|
|
||||||
// Not a single infill line fits.
|
|
||||||
//FIXME maybe one shall trigger the gap fill here?
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BoundingBox bounding_box = poly_with_offset.bounding_box_src();
|
|
||||||
|
|
||||||
// define flow spacing according to requested density
|
|
||||||
if (params.full_infill() && !params.dont_adjust) {
|
|
||||||
line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
|
|
||||||
this->spacing = unscale<double>(line_spacing);
|
|
||||||
} else {
|
|
||||||
// extend bounding box so that our pattern will be aligned with other layers
|
|
||||||
// Transform the reference point to the rotated coordinate system.
|
|
||||||
Point refpt = rotate_vector.second.rotated(- rotate_vector.first);
|
|
||||||
// _align_to_grid will not work correctly with positive pattern_shift.
|
|
||||||
coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing;
|
|
||||||
refpt(0) -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
|
|
||||||
bounding_box.merge(_align_to_grid(
|
|
||||||
bounding_box.min,
|
|
||||||
Point(line_spacing, line_spacing),
|
|
||||||
refpt));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intersect a set of euqally spaced vertical lines wiht expolygon.
|
|
||||||
// n_vlines = ceil(bbox_width / line_spacing)
|
// n_vlines = ceil(bbox_width / line_spacing)
|
||||||
size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing;
|
size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing;
|
||||||
coord_t x0 = bounding_box.min(0);
|
coord_t x0 = bounding_box.min(0);
|
||||||
@ -902,6 +859,65 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return segs;
|
||||||
|
}
|
||||||
|
|
||||||
|
coord_t FillRectilinear2::_line_spacing_for_density(float density) const
|
||||||
|
{
|
||||||
|
return coord_t(scale_(this->spacing) / density);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out)
|
||||||
|
{
|
||||||
|
// At the end, only the new polylines will be rotated back.
|
||||||
|
size_t n_polylines_out_initial = polylines_out.size();
|
||||||
|
|
||||||
|
// Shrink the input polygon a bit first to not push the infill lines out of the perimeters.
|
||||||
|
// const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
|
||||||
|
const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
|
||||||
|
assert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
|
||||||
|
|
||||||
|
// Rotate polygons so that we can work with vertical lines here
|
||||||
|
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
|
||||||
|
rotate_vector.first += angleBase;
|
||||||
|
|
||||||
|
assert(params.density > 0.0001f && params.density <= 1.f);
|
||||||
|
coord_t line_spacing = _line_spacing_for_density(params.density);
|
||||||
|
|
||||||
|
// On the polygons of poly_with_offset, the infill lines will be connected.
|
||||||
|
ExPolygonWithOffset poly_with_offset(
|
||||||
|
surface->expolygon,
|
||||||
|
- rotate_vector.first,
|
||||||
|
scale_(this->overlap - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->spacing),
|
||||||
|
scale_(this->overlap - 0.5 * this->spacing));
|
||||||
|
if (poly_with_offset.n_contours_inner == 0) {
|
||||||
|
// Not a single infill line fits.
|
||||||
|
//FIXME maybe one shall trigger the gap fill here?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox bounding_box = poly_with_offset.bounding_box_src();
|
||||||
|
|
||||||
|
// define flow spacing according to requested density
|
||||||
|
if (params.full_infill() && !params.dont_adjust) {
|
||||||
|
line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
|
||||||
|
this->spacing = unscale<double>(line_spacing);
|
||||||
|
} else {
|
||||||
|
// extend bounding box so that our pattern will be aligned with other layers
|
||||||
|
// Transform the reference point to the rotated coordinate system.
|
||||||
|
Point refpt = rotate_vector.second.rotated(- rotate_vector.first);
|
||||||
|
// _align_to_grid will not work correctly with positive pattern_shift.
|
||||||
|
coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing;
|
||||||
|
refpt(0) -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
|
||||||
|
bounding_box.merge(_align_to_grid(
|
||||||
|
bounding_box.min,
|
||||||
|
Point(line_spacing, line_spacing),
|
||||||
|
refpt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intersect a set of equally spaced vertical lines with expolygon.
|
||||||
|
std::vector<SegmentedIntersectionLine> segs = _vert_lines_for_polygon(poly_with_offset, bounding_box, params, line_spacing);
|
||||||
|
|
||||||
// Sort the intersections along their segments, specify the intersection types.
|
// Sort the intersections along their segments, specify the intersection types.
|
||||||
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
|
||||||
SegmentedIntersectionLine &sil = segs[i_seg];
|
SegmentedIntersectionLine &sil = segs[i_seg];
|
||||||
@ -1569,4 +1585,68 @@ FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillP
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns a float uniformly distributed in the range [0..1.0) using the given integer as the seed
|
||||||
|
*
|
||||||
|
* N.B. calling this is super slow as it must rebuild the initial state for a Mersenne Twister with each call, so
|
||||||
|
* don't call this in a loop if you can avoid it.
|
||||||
|
*/
|
||||||
|
static float randomFloatFromSeed(uint32_t x)
|
||||||
|
{
|
||||||
|
boost::random::mt19937 rng(x);
|
||||||
|
boost::random::uniform_real_distribution<> dist;
|
||||||
|
|
||||||
|
return (float) dist(rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
float FillScatteredRectilinear::_layer_angle(size_t idx) const
|
||||||
|
{
|
||||||
|
// Angle chosen at random using the layer index as a key
|
||||||
|
return randomFloatFromSeed((uint32_t) idx) * (float) M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
coord_t FillScatteredRectilinear::_line_spacing_for_density(float density) const
|
||||||
|
{
|
||||||
|
/* The density argument is ignored, we first generate lines at 100% density, then prune some generated lines
|
||||||
|
* later to achieve the target density
|
||||||
|
*/
|
||||||
|
(void) density;
|
||||||
|
|
||||||
|
return coord_t(scale_(this->spacing) / 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Polylines FillScatteredRectilinear::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||||
|
{
|
||||||
|
Polylines polylines_out;
|
||||||
|
|
||||||
|
// Offset the pattern randomly using the current layer index as the generator
|
||||||
|
float offset = randomFloatFromSeed((uint32_t) layer_id) * 0.5f * (float) this->spacing;
|
||||||
|
|
||||||
|
if (!fill_surface_by_lines(surface, params, 0.f, offset, polylines_out)) {
|
||||||
|
printf("FillScatteredRectilinear::fill_surface() failed to fill a region.\n");
|
||||||
|
}
|
||||||
|
return polylines_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SegmentedIntersectionLine> FillScatteredRectilinear::_vert_lines_for_polygon(const ExPolygonWithOffset &poly_with_offset, const BoundingBox &bounding_box, const FillParams ¶ms, coord_t line_spacing) const
|
||||||
|
{
|
||||||
|
std::vector<SegmentedIntersectionLine> segs = FillRectilinear2::_vert_lines_for_polygon(poly_with_offset, bounding_box, params, line_spacing);
|
||||||
|
|
||||||
|
if (!params.full_infill()) {
|
||||||
|
boost::random::mt19937 rng((uint32_t) layer_id);
|
||||||
|
boost::random::uniform_real_distribution<> dist;
|
||||||
|
|
||||||
|
// Remove generated lines with a probability that'll achieve the required density on average
|
||||||
|
for (auto iter = segs.begin(); iter != segs.end(); ) {
|
||||||
|
if (dist(rng) >= params.density) {
|
||||||
|
iter = segs.erase(iter);
|
||||||
|
} else {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return segs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class Surface;
|
class Surface;
|
||||||
|
class SegmentedIntersectionLine;
|
||||||
|
struct ExPolygonWithOffset;
|
||||||
|
|
||||||
class FillRectilinear2 : public Fill
|
class FillRectilinear2 : public Fill
|
||||||
{
|
{
|
||||||
@ -17,6 +19,9 @@ public:
|
|||||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual std::vector<SegmentedIntersectionLine> _vert_lines_for_polygon(const ExPolygonWithOffset &poly_with_offset, const BoundingBox &bounding_box, const FillParams ¶ms, coord_t line_spacing) const;
|
||||||
|
virtual coord_t _line_spacing_for_density(float density) const;
|
||||||
|
|
||||||
bool fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out);
|
bool fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,6 +86,22 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FillScatteredRectilinear : public FillRectilinear2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Fill* clone() const { return new FillScatteredRectilinear(*this); };
|
||||||
|
virtual ~FillScatteredRectilinear() {}
|
||||||
|
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual float _layer_angle(size_t idx) const;
|
||||||
|
virtual std::vector<SegmentedIntersectionLine> _vert_lines_for_polygon(const ExPolygonWithOffset &poly_with_offset, const BoundingBox &bounding_box, const FillParams ¶ms, coord_t line_spacing) const;
|
||||||
|
virtual coord_t _line_spacing_for_density(float density) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
||||||
#endif // slic3r_FillRectilinear2_hpp_
|
#endif // slic3r_FillRectilinear2_hpp_
|
||||||
|
@ -955,6 +955,7 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->enum_values.push_back("hilbertcurve");
|
def->enum_values.push_back("hilbertcurve");
|
||||||
def->enum_values.push_back("archimedeanchords");
|
def->enum_values.push_back("archimedeanchords");
|
||||||
def->enum_values.push_back("octagramspiral");
|
def->enum_values.push_back("octagramspiral");
|
||||||
|
def->enum_values.push_back("scatteredrectilinear");
|
||||||
def->enum_labels.push_back(L("Rectilinear"));
|
def->enum_labels.push_back(L("Rectilinear"));
|
||||||
def->enum_labels.push_back(L("Grid"));
|
def->enum_labels.push_back(L("Grid"));
|
||||||
def->enum_labels.push_back(L("Triangles"));
|
def->enum_labels.push_back(L("Triangles"));
|
||||||
@ -968,6 +969,7 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||||
|
def->enum_labels.push_back(L("Scattered Rectilinear"));
|
||||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipStars);
|
def->default_value = new ConfigOptionEnum<InfillPattern>(ipStars);
|
||||||
|
|
||||||
def = this->add("first_layer_acceleration", coFloat);
|
def = this->add("first_layer_acceleration", coFloat);
|
||||||
|
@ -42,7 +42,7 @@ enum PrintHostType {
|
|||||||
enum InfillPattern {
|
enum InfillPattern {
|
||||||
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSmooth, ipSmoothHilbert, ipSmoothTriple,
|
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSmooth, ipSmoothHilbert, ipSmoothTriple,
|
||||||
ipRectiWithPerimeter, ipConcentricGapFill
|
ipRectiWithPerimeter, ipConcentricGapFill, ipScatteredRectilinear
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SupportMaterialPattern {
|
enum SupportMaterialPattern {
|
||||||
@ -122,6 +122,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
|
|||||||
keys_map["smoothtriple"] = ipSmoothTriple;
|
keys_map["smoothtriple"] = ipSmoothTriple;
|
||||||
keys_map["smoothhilbert"] = ipSmoothHilbert;
|
keys_map["smoothhilbert"] = ipSmoothHilbert;
|
||||||
keys_map["rectiwithperimeter"] = ipRectiWithPerimeter;
|
keys_map["rectiwithperimeter"] = ipRectiWithPerimeter;
|
||||||
|
keys_map["scatteredrectilinear"]= ipScatteredRectilinear;
|
||||||
}
|
}
|
||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user