mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-01-31 16:08:43 +03:00
add infill pattern "Cross Hatch"
This commit is contained in:
@@ -90,6 +90,8 @@ set(SLIC3R_SOURCES
|
||||
Fill/FillConcentric.hpp
|
||||
Fill/FillConcentricInternal.cpp
|
||||
Fill/FillConcentricInternal.hpp
|
||||
Fill/FillCrossHatch.cpp
|
||||
Fill/FillCrossHatch.hpp
|
||||
Fill/FillEnsuring.cpp
|
||||
Fill/FillEnsuring.hpp
|
||||
Fill/FillHoneycomb.cpp
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "FillEnsuring.hpp"
|
||||
//w29
|
||||
#include "FillConcentricInternal.hpp"
|
||||
//w32
|
||||
#include "FillCrossHatch.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
@@ -57,6 +59,8 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||
//w14
|
||||
//w29
|
||||
case ipConcentricInternal: return new FillConcentricInternal();
|
||||
//w32
|
||||
case ipCrossHatch: return new FillCrossHatch();
|
||||
default: throw Slic3r::InvalidArgument("unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
236
src/libslic3r/Fill/FillCrossHatch.cpp
Normal file
236
src/libslic3r/Fill/FillCrossHatch.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../ShortestPath.hpp"
|
||||
#include "../Surface.hpp"
|
||||
|
||||
#include "FillCrossHatch.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// CrossHatch Infill: Enhances 3D Printing Speed & Reduces Noise
|
||||
// CrossHatch, as its name hints, alternates line direction by 90 degrees every few layers to improve adhesion.
|
||||
// It introduces transform layers between direction shifts for better line cohesion, which fixes the weakness of line infill.
|
||||
// The transform technique is inspired by David Eccles, improved 3D honeycomb but also a more flexible implementation.
|
||||
// This method notably increases printing speed, meeting the demands of modern high-speed 3D printers, and reduces noise for most layers.
|
||||
// By Bambu Lab
|
||||
|
||||
// graph credits: David Eccles (gringer).
|
||||
// But we made a different definition for points.
|
||||
/* o---o
|
||||
* / \
|
||||
* / \
|
||||
* \ /
|
||||
* \ /
|
||||
* o---o
|
||||
* p1 p2 p3 p4
|
||||
*
|
||||
* // X1 = progress * (1/8) * period
|
||||
* // X2 = ( (1/2 - progress) * (1/8) ) * period
|
||||
* // X3 = X1 + (1/2) * period
|
||||
* // X4 = ( (1 - progress) * (1/8) ) * period
|
||||
* // Y1 = X1
|
||||
* // Y2 = X1
|
||||
* // Y3 = -X1
|
||||
* // Y4 = -X1
|
||||
*/
|
||||
|
||||
static Pointfs generate_one_cycle(double progress, coordf_t period)
|
||||
{
|
||||
Pointfs out;
|
||||
double offset = progress * 1. / 8. * period;
|
||||
out.reserve(4);
|
||||
out.push_back(Vec2d(0.25 * period - offset, offset));
|
||||
out.push_back(Vec2d(0.25 * period + offset, offset));
|
||||
out.push_back(Vec2d(0.75 * period - offset, -offset));
|
||||
out.push_back(Vec2d(0.75 * period + offset, -offset));
|
||||
return out;
|
||||
}
|
||||
|
||||
static Polylines generate_transform_pattern(double inprogress, int direction, coordf_t ingrid_size, coordf_t inwidth, coordf_t inheight)
|
||||
{
|
||||
coordf_t width = inwidth;
|
||||
coordf_t height = inheight;
|
||||
coordf_t grid_size = ingrid_size * 2; // we due with odd and even saparately.
|
||||
double progress = inprogress;
|
||||
Polylines out_polylines;
|
||||
|
||||
// generate template patterns;
|
||||
Pointfs one_cycle_points = generate_one_cycle(progress, grid_size);
|
||||
|
||||
Polyline one_cycle;
|
||||
one_cycle.points.reserve(one_cycle_points.size());
|
||||
for (size_t i = 0; i < one_cycle_points.size(); i++) one_cycle.points.push_back(Point(one_cycle_points[i]));
|
||||
|
||||
// swap if vertical
|
||||
if (direction < 0) {
|
||||
width = height;
|
||||
height = inwidth;
|
||||
}
|
||||
|
||||
// replicate polylines;
|
||||
Polylines odd_polylines;
|
||||
Polyline odd_poly;
|
||||
int num_of_cycle = width / grid_size + 2;
|
||||
odd_poly.points.reserve(num_of_cycle * one_cycle.size());
|
||||
|
||||
// replicate to odd line
|
||||
Point translate = Point(0, 0);
|
||||
for (size_t i = 0; i < num_of_cycle; i++) {
|
||||
Polyline odd_points;
|
||||
odd_points = Polyline(one_cycle);
|
||||
odd_points.translate(Point(i * grid_size, 0.0));
|
||||
odd_poly.points.insert(odd_poly.points.end(), odd_points.begin(), odd_points.end());
|
||||
}
|
||||
|
||||
// fill the height
|
||||
int num_of_lines = height / grid_size + 2;
|
||||
odd_polylines.reserve(num_of_lines * odd_poly.size());
|
||||
for (size_t i = 0; i < num_of_lines; i++) {
|
||||
Polyline poly = odd_poly;
|
||||
poly.translate(Point(0.0, grid_size * i));
|
||||
odd_polylines.push_back(poly);
|
||||
}
|
||||
// save to output
|
||||
out_polylines.insert(out_polylines.end(), odd_polylines.begin(), odd_polylines.end());
|
||||
|
||||
// replicate to even lines
|
||||
Polylines even_polylines;
|
||||
even_polylines.reserve(odd_polylines.size());
|
||||
for (size_t i = 0; i < odd_polylines.size(); i++) {
|
||||
Polyline even = odd_poly;
|
||||
even.translate(Point(-0.5 * grid_size, (i + 0.5) * grid_size));
|
||||
even_polylines.push_back(even);
|
||||
}
|
||||
|
||||
// save for output
|
||||
out_polylines.insert(out_polylines.end(), even_polylines.begin(), even_polylines.end());
|
||||
|
||||
// change to vertical if need
|
||||
if (direction < 0) {
|
||||
// swap xy, see if we need better performance method
|
||||
for (Polyline& poly : out_polylines) {
|
||||
for (Point& p : poly) { std::swap(p.x(), p.y()); }
|
||||
}
|
||||
}
|
||||
|
||||
return out_polylines;
|
||||
}
|
||||
|
||||
static Polylines generate_repeat_pattern(int direction, coordf_t grid_size, coordf_t inwidth, coordf_t inheight)
|
||||
{
|
||||
coordf_t width = inwidth;
|
||||
coordf_t height = inheight;
|
||||
Polylines out_polylines;
|
||||
|
||||
// swap if vertical
|
||||
if (direction < 0) {
|
||||
width = height;
|
||||
height = inwidth;
|
||||
}
|
||||
|
||||
int num_of_lines = height / grid_size + 1;
|
||||
out_polylines.reserve(num_of_lines);
|
||||
|
||||
for (int i = 0; i < num_of_lines; i++) {
|
||||
Polyline poly;
|
||||
poly.points.reserve(2);
|
||||
poly.append(Point(coordf_t(0), coordf_t(grid_size * i)));
|
||||
poly.append(Point(width, coordf_t(grid_size * i)));
|
||||
out_polylines.push_back(poly);
|
||||
}
|
||||
|
||||
// change to vertical if needed
|
||||
if (direction < 0) {
|
||||
// swap xy
|
||||
for (Polyline& poly : out_polylines) {
|
||||
for (Point& p : poly) { std::swap(p.x(), p.y()); }
|
||||
}
|
||||
}
|
||||
|
||||
return out_polylines;
|
||||
}
|
||||
|
||||
// it makes the real patterns that overlap the bounding box
|
||||
// repeat_ratio define the ratio between the height of repeat pattern and grid
|
||||
static Polylines generate_infill_layers(coordf_t z_height, double repeat_ratio, coordf_t grid_size, coordf_t width, coordf_t height)
|
||||
{
|
||||
Polylines result;
|
||||
coordf_t trans_layer_size = grid_size * 0.4; // upper.
|
||||
coordf_t repeat_layer_size = grid_size * repeat_ratio; // lower.
|
||||
z_height += repeat_layer_size / 2; // offset to improve first few layer strength
|
||||
coordf_t period = trans_layer_size + repeat_layer_size;
|
||||
coordf_t remains = z_height - std::floor(z_height / period) * period;
|
||||
coordf_t trans_z = remains - repeat_layer_size; // put repeat layer first.
|
||||
coordf_t repeat_z = remains;
|
||||
|
||||
int phase = fmod(z_height, period * 2) - (period - 1); // add epsilon
|
||||
int direction = phase <= 0 ? -1 : 1;
|
||||
|
||||
// this is a repeat layer
|
||||
if (trans_z < 0) {
|
||||
result = generate_repeat_pattern(direction, grid_size, width, height);
|
||||
}
|
||||
// this is a transform layer
|
||||
else {
|
||||
double progress = fmod(trans_z, trans_layer_size) / trans_layer_size;
|
||||
|
||||
// split the progress to forward and backward, with a opposite direction.
|
||||
if (progress < 0.5)
|
||||
result = generate_transform_pattern((progress + 0.1) * 2, direction, grid_size, width, height); // increase overlapping.
|
||||
else
|
||||
result = generate_transform_pattern((1.1 - progress) * 2, -1 * direction, grid_size, width, height);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FillCrossHatch::_fill_surface_single(
|
||||
const FillParams& params, unsigned int thickness_layers, const std::pair<float, Point>& direction, ExPolygon expolygon, Polylines& polylines_out)
|
||||
{
|
||||
// rotate angle
|
||||
auto infill_angle = float(this->angle);
|
||||
if (std::abs(infill_angle) >= EPSILON) expolygon.rotate(-infill_angle);
|
||||
|
||||
// get the rotated bounding box
|
||||
BoundingBox bb = expolygon.contour.bounding_box();
|
||||
|
||||
// linespace modifier
|
||||
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
|
||||
|
||||
// reduce density
|
||||
if (params.density < 0.999) line_spacing *= 1.5;
|
||||
|
||||
bb.merge(align_to_grid(bb.min, Point(line_spacing * 4, line_spacing * 4)));
|
||||
|
||||
// generate pattern
|
||||
Polylines polylines = generate_infill_layers(scale_(this->z), 1, line_spacing, bb.size()(0), bb.size()(1));
|
||||
|
||||
// shift the pattern to the actual space
|
||||
for (Polyline& pl : polylines) { pl.translate(bb.min); }
|
||||
|
||||
polylines = intersection_pl(polylines, to_polygons(expolygon));
|
||||
|
||||
// --- remove small remains from gyroid infill
|
||||
if (!polylines.empty()) {
|
||||
// Remove very small bits, but be careful to not remove infill lines connecting thin walls!
|
||||
// The infill perimeter lines should be separated by around a single infill line width.
|
||||
const double minlength = scale_(0.8 * this->spacing);
|
||||
polylines.erase(std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline& pl)
|
||||
{ return pl.length() < minlength; }), polylines.end());
|
||||
}
|
||||
|
||||
if (!polylines.empty()) {
|
||||
int infill_start_idx = polylines_out.size(); // only rotate what belongs to us.
|
||||
// connect lines
|
||||
if (params.dont_connect() || polylines.size() <= 1)
|
||||
append(polylines_out, chain_polylines(std::move(polylines)));
|
||||
else
|
||||
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
|
||||
|
||||
// rotate back
|
||||
if (std::abs(infill_angle) >= EPSILON) {
|
||||
for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) it->rotate(infill_angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
28
src/libslic3r/Fill/FillCrossHatch.hpp
Normal file
28
src/libslic3r/Fill/FillCrossHatch.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef slic3r_FillCrossHatch_hpp_
|
||||
#define slic3r_FillCrossHatch_hpp_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class FillCrossHatch : public Fill
|
||||
{
|
||||
public:
|
||||
Fill *clone() const override { return new FillCrossHatch(*this); };
|
||||
~FillCrossHatch() override {}
|
||||
|
||||
protected:
|
||||
void _fill_surface_single(const FillParams & params,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon expolygon,
|
||||
Polylines & polylines_out) override;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_FillCrossHatch_hpp_
|
||||
@@ -120,7 +120,9 @@ static const t_config_enum_values s_keys_map_InfillPattern {
|
||||
{ "supportcubic", ipSupportCubic },
|
||||
{ "lightning", ipLightning },
|
||||
//w14
|
||||
{ "concentricInternal", ipConcentricInternal }
|
||||
{ "concentricInternal", ipConcentricInternal },
|
||||
//w32
|
||||
{ "crosshatch", ipCrossHatch}
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern)
|
||||
|
||||
@@ -1438,7 +1440,9 @@ void PrintConfigDef::init_fff_params()
|
||||
{ "octagramspiral", L("Octagram Spiral")},
|
||||
{ "adaptivecubic", L("Adaptive Cubic")},
|
||||
{ "supportcubic", L("Support Cubic")},
|
||||
{ "lightning", L("Lightning")}
|
||||
{ "lightning", L("Lightning")},
|
||||
//w32
|
||||
{ "crosshatch", L("Cross Hatch")}
|
||||
});
|
||||
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipStars));
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ enum InfillPattern : int {
|
||||
ipCount,
|
||||
//w14
|
||||
ipConcentricInternal,
|
||||
//w32
|
||||
ipCrossHatch,
|
||||
};
|
||||
|
||||
enum class IroningType {
|
||||
|
||||
@@ -2115,6 +2115,8 @@ void PrintObject::bridge_over_infill()
|
||||
switch (dominant_pattern) {
|
||||
case ipHilbertCurve: bridging_angle += 0.25 * PI; break;
|
||||
case ipOctagramSpiral: bridging_angle += (1.0 / 16.0) * PI; break;
|
||||
//w32
|
||||
case ipCrossHatch: return (bridging_angle + 45.0) * 2.0 * M_PI / 360.;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user