* Infill Line Multiplier * Modular Offset Function * Lightning multiline * Crosshatch Multiline ipCrosshatch * cleaning Cleaning clean2 * 3d Honeycomb cut poliline ends * Fill Tpmsd Multiline Fill Tpmsd Multiline * Update Multiline function multiline funcion simplify * Update FillTpmsD * FillHoneycomb * Update src/libslic3r/PrintConfig.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix Honeycomb Multiline Simplify polylines in honeycomb infill generation * Improve multiline infill support and pattern simplification Moved multiline infill application after pattern translation and simplification in Fill3DHoneycomb, and added multiline support to FillAdaptive. Updated honeycomb and 3D honeycomb infill to simplify polylines to 5x line width. Extended GUI and config to support multiline for Adaptive Cubic infill pattern and clarified max value comment. minimum changes Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com> * Increase multiline fill spacing in honeycomb infill Adjusts the spacing parameter in the multiline_fill function to 1.1 times the original spacing, potentially improving infill distribution or print quality. * Refine fill_multiline tooltip and pattern support logic Updated the tooltip for the 'fill_multiline' parameter to improve clarity and punctuation. Refactored the logic in ConfigManipulation.cpp to clarify which infill patterns support multiline infill. * better management of non supported infill patterns --------- Co-authored-by: SoftFever <softfeverever@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ian Bassi <ian.bassi@outlook.com> Co-authored-by: Ian Bassi <12130714+ianalexis@users.noreply.github.com>
215 lines
7.8 KiB
C++
215 lines
7.8 KiB
C++
#include "../ClipperUtils.hpp"
|
|
#include "../ShortestPath.hpp"
|
|
#include "../Surface.hpp"
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include "FillBase.hpp"
|
|
#include "FillGyroid.hpp"
|
|
|
|
namespace Slic3r {
|
|
|
|
static inline double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
|
|
{
|
|
if (vertical) {
|
|
double phase_offset = (z_cos < 0 ? M_PI : 0) + M_PI;
|
|
double a = sin(x + phase_offset);
|
|
double b = - z_cos;
|
|
double res = z_sin * cos(x + phase_offset + (flip ? M_PI : 0.));
|
|
double r = sqrt(sqr(a) + sqr(b));
|
|
return asin(a/r) + asin(res/r) + M_PI;
|
|
}
|
|
else {
|
|
double phase_offset = z_sin < 0 ? M_PI : 0.;
|
|
double a = cos(x + phase_offset);
|
|
double b = - z_sin;
|
|
double res = z_cos * sin(x + phase_offset + (flip ? 0 : M_PI));
|
|
double r = sqrt(sqr(a) + sqr(b));
|
|
return (asin(a/r) + asin(res/r) + 0.5 * M_PI);
|
|
}
|
|
}
|
|
|
|
static inline Polyline make_wave(
|
|
const std::vector<Vec2d>& one_period, double width, double height, double offset, double scaleFactor,
|
|
double z_cos, double z_sin, bool vertical, bool flip)
|
|
{
|
|
std::vector<Vec2d> points = one_period;
|
|
double period = points.back()(0);
|
|
if (width != period) // do not extend if already truncated
|
|
{
|
|
points.reserve(one_period.size() * size_t(floor(width / period)));
|
|
points.pop_back();
|
|
|
|
size_t n = points.size();
|
|
do {
|
|
points.emplace_back(points[points.size()-n].x() + period, points[points.size()-n].y());
|
|
} while (points.back()(0) < width - EPSILON);
|
|
|
|
points.emplace_back(Vec2d(width, f(width, z_sin, z_cos, vertical, flip)));
|
|
}
|
|
|
|
// and construct the final polyline to return:
|
|
Polyline polyline;
|
|
polyline.points.reserve(points.size());
|
|
for (auto& point : points) {
|
|
point(1) += offset;
|
|
point(1) = std::clamp(double(point.y()), 0., height);
|
|
if (vertical)
|
|
std::swap(point(0), point(1));
|
|
polyline.points.emplace_back((point * scaleFactor).cast<coord_t>());
|
|
}
|
|
|
|
return polyline;
|
|
}
|
|
|
|
static std::vector<Vec2d> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip, double tolerance)
|
|
{
|
|
std::vector<Vec2d> points;
|
|
double dx = M_PI_2; // exact coordinates on main inflexion lobes
|
|
double limit = std::min(2*M_PI, width);
|
|
points.reserve(coord_t(ceil(limit / tolerance / 3)));
|
|
|
|
for (double x = 0.; x < limit - EPSILON; x += dx) {
|
|
points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip)));
|
|
}
|
|
points.emplace_back(Vec2d(limit, f(limit, z_sin, z_cos, vertical, flip)));
|
|
|
|
// piecewise increase in resolution up to requested tolerance
|
|
for(;;)
|
|
{
|
|
size_t size = points.size();
|
|
for (unsigned int i = 1;i < size; ++i) {
|
|
auto& lp = points[i-1]; // left point
|
|
auto& rp = points[i]; // right point
|
|
double x = lp(0) + (rp(0) - lp(0)) / 2;
|
|
double y = f(x, z_sin, z_cos, vertical, flip);
|
|
Vec2d ip = {x, y};
|
|
if (std::abs(cross2(Vec2d(ip - lp), Vec2d(ip - rp))) > sqr(tolerance)) {
|
|
points.emplace_back(std::move(ip));
|
|
}
|
|
}
|
|
|
|
if (size == points.size())
|
|
break;
|
|
else
|
|
{
|
|
// insert new points in order
|
|
std::sort(points.begin(), points.end(),
|
|
[](const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0); });
|
|
}
|
|
}
|
|
|
|
return points;
|
|
}
|
|
|
|
static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height)
|
|
{
|
|
const double scaleFactor = scale_(line_spacing) / density_adjusted;
|
|
|
|
// tolerance in scaled units. clamp the maximum tolerance as there's
|
|
// no processing-speed benefit to do so beyond a certain point
|
|
const double tolerance = std::min(line_spacing / 2, FillGyroid::PatternTolerance) / unscale<double>(scaleFactor);
|
|
|
|
//scale factor for 5% : 8 712 388
|
|
// 1z = 10^-6 mm ?
|
|
const double z = gridZ / scaleFactor;
|
|
const double z_sin = sin(z);
|
|
const double z_cos = cos(z);
|
|
|
|
bool vertical = (std::abs(z_sin) <= std::abs(z_cos));
|
|
double lower_bound = 0.;
|
|
double upper_bound = height;
|
|
bool flip = true;
|
|
if (vertical) {
|
|
flip = false;
|
|
lower_bound = -M_PI;
|
|
upper_bound = width - M_PI_2;
|
|
std::swap(width,height);
|
|
}
|
|
|
|
std::vector<Vec2d> one_period_odd = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip, tolerance); // creates one period of the waves, so it doesn't have to be recalculated all the time
|
|
flip = !flip; // even polylines are a bit shifted
|
|
std::vector<Vec2d> one_period_even = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip, tolerance);
|
|
Polylines result;
|
|
|
|
for (double y0 = lower_bound; y0 < upper_bound + EPSILON; y0 += M_PI) {
|
|
// creates odd polylines
|
|
result.emplace_back(make_wave(one_period_odd, width, height, y0, scaleFactor, z_cos, z_sin, vertical, flip));
|
|
// creates even polylines
|
|
y0 += M_PI;
|
|
if (y0 < upper_bound + EPSILON) {
|
|
result.emplace_back(make_wave(one_period_even, width, height, y0, scaleFactor, z_cos, z_sin, vertical, flip));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// FIXME: needed to fix build on Mac on buildserver
|
|
constexpr double FillGyroid::PatternTolerance;
|
|
|
|
void FillGyroid::_fill_surface_single(
|
|
const FillParams ¶ms,
|
|
unsigned int thickness_layers,
|
|
const std::pair<float, Point> &direction,
|
|
ExPolygon expolygon,
|
|
Polylines &polylines_out)
|
|
{
|
|
auto infill_angle = float(this->angle + (CorrectionAngle * 2*M_PI) / 360.);
|
|
if(std::abs(infill_angle) >= EPSILON)
|
|
expolygon.rotate(-infill_angle);
|
|
|
|
BoundingBox bb = expolygon.contour.bounding_box();
|
|
// Density adjusted to have a good %of weight.
|
|
double density_adjusted = std::max(0., params.density * DensityAdjust / params.multiline);
|
|
// Distance between the gyroid waves in scaled coordinates.
|
|
coord_t distance = coord_t(scale_(this->spacing) / density_adjusted);
|
|
|
|
// align bounding box to a multiple of our grid module
|
|
bb.merge(align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
|
|
|
|
// Expand the bounding box to avoid artifacts at the edges
|
|
coord_t expand = 10 * (scale_(this->spacing));
|
|
bb.offset(expand);
|
|
|
|
// generate pattern
|
|
Polylines polylines = make_gyroid_waves(
|
|
scale_(this->z),
|
|
density_adjusted,
|
|
this->spacing,
|
|
ceil(bb.size()(0) / distance) + 1.,
|
|
ceil(bb.size()(1) / distance) + 1.);
|
|
|
|
// shift the polyline to the grid origin
|
|
for (Polyline &pl : polylines)
|
|
pl.translate(bb.min);
|
|
|
|
// Apply multiline offset if needed
|
|
multiline_fill(polylines, params, spacing);
|
|
|
|
polylines = intersection_pl(polylines, expolygon);
|
|
|
|
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()) {
|
|
// connect lines
|
|
size_t polylines_out_first_idx = polylines_out.size();
|
|
chain_or_connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
|
|
|
|
// new paths must be rotated back
|
|
if (std::abs(infill_angle) >= EPSILON) {
|
|
for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it)
|
|
it->rotate(infill_angle);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Slic3r
|