TPMS-FK Infill ( Triply Periodic Minimal Surface Fischer Koch S) (#10360)

* seteo inicial

* version inicial

* Update FillTpmsFK.cpp

* marching squares

* Multiline support

* density adjusted

* tuning

cleaning

* symplify points

* optimization

* smoothing

* center offset contour

* icon

* bugfix 1

* reverse tbb scalar field bug fix

* safety

* Update Icon

Co-Authored-By: yw4z <28517890+yw4z@users.noreply.github.com>

* Update FillTpmsFK.cpp

* delete allptpos

---------

Co-authored-by: yw4z <28517890+yw4z@users.noreply.github.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
Rodrigo
2025-08-10 12:10:35 -03:00
committed by GitHub
parent 2e63ce2196
commit 202875a4bb
10 changed files with 596 additions and 2 deletions

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><circle id="b" cx="12" cy="12" r="2.5" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><circle id="c" cx="4" cy="20" r="2.5" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><path id="d" d="M10.71,22c-.13-.31-.21-.64-.21-1,0-1.38,1.12-2.5,2.5-2.5s2.5,1.12,2.5,2.5c0,.36-.08.71-.22,1.02" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><path id="e" d="M19.5,22c0-1.38,1.12-2.5,2.5-2.5" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><path id="f" d="M2,8.71c.31-.13.64-.21,1-.21,1.38,0,2.5,1.12,2.5,2.5s-1.12,2.5-2.5,2.5c-.35,0-.67-.07-.97-.2" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><path id="g" d="M4.5,2c0,1.38-1.12,2.5-2.5,2.5" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><path id="h" d="M22,15.29c-.31.13-.65.21-1,.21-1.38,0-2.5-1.12-2.5-2.5s1.12-2.5,2.5-2.5c.35,0,.67.07.97.2" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><circle id="i" cx="20" cy="4" r="2.5" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><path id="j" d="M13.28,1.96c.14.32.22.67.22,1.04,0,1.38-1.12,2.5-2.5,2.5s-2.5-1.12-2.5-2.5c0-.37.08-.72.22-1.04" style="fill:none; opacity:.75; stroke:#949494; stroke-linecap:round; stroke-linejoin:round;"/><path d="M15.5,1.5v3.5c0,1.38-1.12,2.5-2.5,2.5h-3c-1.38,0-2.5,1.12-2.5,2.5v3c0,1.38-1.12,2.5-2.5,2.5H1.5M17.5,22.5v-2.5c0-1.38,1.12-2.5,2.5-2.5h2.5M22.5,8.5h-3.5c-1.38,0-2.5,1.12-2.5,2.5v3c0,1.38-1.12,2.5-2.5,2.5h-3c-1.38,0-2.5,1.12-2.5,2.5v3.5M6.5,1.5v2.5c0,1.38-1.12,2.5-2.5,2.5H1.5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/><path id="k" d="M3.5,1.5h17c1.1,0,2,.9,2,2v17c0,1.1-.9,2-2,2H3.5c-1.1,0-2-.9-2-2V3.5c0-1.1.9-2,2-2Z" style="fill:none; stroke:#949494; stroke-linecap:round; stroke-linejoin:round; stroke-width:.89px;"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -104,6 +104,8 @@ set(lisbslic3r_sources
Fill/FillGyroid.hpp
Fill/FillTpmsD.cpp
Fill/FillTpmsD.hpp
Fill/FillTpmsFK.cpp
Fill/FillTpmsFK.hpp
Fill/FillPlanePath.cpp
Fill/FillPlanePath.hpp
Fill/FillLine.cpp

View File

@@ -15,6 +15,7 @@
#include "FillLightning.hpp"
#include "FillConcentricInternal.hpp"
#include "FillTpmsD.hpp"
#include "FillTpmsFK.hpp"
#include "FillConcentric.hpp"
#include "libslic3r.h"
@@ -1330,6 +1331,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
case ip3DHoneycomb:
case ipGyroid:
case ipTpmsD:
case ipTpmsFK:
case ipHilbertCurve:
case ipArchimedeanChords:
case ipOctagramSpiral:

View File

@@ -18,6 +18,7 @@
#include "Fill3DHoneycomb.hpp"
#include "FillGyroid.hpp"
#include "FillTpmsD.hpp"
#include "FillTpmsFK.hpp"
#include "FillPlanePath.hpp"
#include "FillLine.hpp"
#include "FillRectilinear.hpp"
@@ -44,6 +45,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ip3DHoneycomb: return new Fill3DHoneycomb();
case ipGyroid: return new FillGyroid();
case ipTpmsD: return new FillTpmsD();//from creality print
case ipTpmsFK: return new FillTpmsFK();
case ipRectilinear: return new FillRectilinear();
case ipAlignedRectilinear: return new FillAlignedRectilinear();
case ipCrossHatch: return new FillCrossHatch();

View File

@@ -0,0 +1,543 @@
#include "../ClipperUtils.hpp"
#include "FillTpmsFK.hpp"
#include <cmath>
#include <algorithm>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <tbb/parallel_for.h>
#include <mutex>
namespace Slic3r {
using namespace std;
struct myPoint
{
coord_t x, y;
};
class LineSegmentMerger
{
public:
void mergeSegments(const vector<pair<myPoint, myPoint>>& segments, vector<vector<myPoint>>& polylines2)
{
std::unordered_map<int, myPoint> point_id_xy;
std::set<std::pair<int, int>> segment_ids;
std::unordered_map<int64_t, int> map_keyxy_pointid;
auto get_itr = [&](coord_t x, coord_t y) {
for (auto i : {0}) //,-2,2
{
for (auto j : {0}) //,-2,2
{
int64_t combined_key1 = static_cast<int64_t>(x + i) << 32 | static_cast<uint32_t>(y + j);
auto itr1 = map_keyxy_pointid.find(combined_key1);
if (itr1 != map_keyxy_pointid.end()) {
return itr1;
}
}
}
return map_keyxy_pointid.end();
};
int pointid = 0;
for (const auto& segment : segments) {
coord_t x = segment.first.x;
coord_t y = segment.first.y;
auto itr = get_itr(x, y);
int segmentid0 = -1;
if (itr == map_keyxy_pointid.end()) {
int64_t combined_key = static_cast<int64_t>(x) << 32 | static_cast<uint32_t>(y);
segmentid0 = pointid;
point_id_xy[pointid] = segment.first;
map_keyxy_pointid[combined_key] = pointid++;
} else {
segmentid0 = itr->second;
}
int segmentid1 = -1;
x = segment.second.x;
y = segment.second.y;
itr = get_itr(x, y);
if (itr == map_keyxy_pointid.end()) {
int64_t combined_key = static_cast<int64_t>(x) << 32 | static_cast<uint32_t>(y);
segmentid1 = pointid;
point_id_xy[pointid] = segment.second;
map_keyxy_pointid[combined_key] = pointid++;
} else {
segmentid1 = itr->second;
}
if (segmentid0 != segmentid1) {
segment_ids.insert(segmentid0 < segmentid1 ? std::make_pair(segmentid0, segmentid1) :
std::make_pair(segmentid1, segmentid0));
}
}
unordered_map<int, vector<int>> graph;
unordered_set<int> visited;
vector<vector<int>> polylines;
// Build the graph
for (const auto& segment : segment_ids) {
graph[segment.first].push_back(segment.second);
graph[segment.second].push_back(segment.first);
}
vector<int> startnodes;
for (const auto& node : graph) {
if (node.second.size() == 1) {
startnodes.push_back(node.first);
}
}
// Find all connected components
for (const auto& point_first : startnodes) {
if (visited.find(point_first) == visited.end()) {
vector<int> polyline;
dfs(point_first, graph, visited, polyline);
polylines.push_back(std::move(polyline));
}
}
for (const auto& point : graph) {
if (visited.find(point.first) == visited.end()) {
vector<int> polyline;
dfs(point.first, graph, visited, polyline);
polylines.push_back(std::move(polyline));
}
}
for (auto& pl : polylines) {
vector<myPoint> tmpps;
for (auto& pid : pl) {
tmpps.push_back(point_id_xy[pid]);
}
polylines2.push_back(tmpps);
}
}
private:
void dfs(const int& start_node,
std::unordered_map<int, std::vector<int>>& graph,
std::unordered_set<int>& visited,
std::vector<int>& polyline)
{
std::vector<int> stack;
stack.reserve(graph.size());
stack.push_back(start_node);
while (!stack.empty()) {
int node = stack.back();
stack.pop_back();
if (!visited.insert(node).second) {
continue;
}
polyline.push_back(node);
auto& neighbors = graph[node];
for (const auto& neighbor : neighbors) {
if (visited.find(neighbor) == visited.end()) {
stack.push_back(neighbor);
}
}
}
}
};
namespace MarchingSquares {
struct Point
{
double x, y;
};
vector<double> getGridValues(int i, int j, vector<vector<double>>& data)
{
vector<double> values;
values.push_back(data[i][j + 1]);
values.push_back(data[i + 1][j + 1]);
values.push_back(data[i + 1][j]);
values.push_back(data[i][j]);
return values;
}
bool needContour(double value, double contourValue) { return value >= contourValue; }
Point interpolate(std::vector<std::vector<MarchingSquares::Point>>& posxy,
std::vector<int> p1ij,
std::vector<int> p2ij,
double v1,
double v2,
double contourValue)
{
Point p1;
p1.x = posxy[p1ij[0]][p1ij[1]].x;
p1.y = posxy[p1ij[0]][p1ij[1]].y;
Point p2;
p2.x = posxy[p2ij[0]][p2ij[1]].x;
p2.y = posxy[p2ij[0]][p2ij[1]].y;
double denom = v2 - v1;
double mu;
if (std::abs(denom) < 1e-12) {
// avoid division by zero
mu = 0.5;
} else {
mu = (contourValue - v1) / denom;
}
Point p;
p.x = p1.x + mu * (p2.x - p1.x);
p.y = p1.y + mu * (p2.y - p1.y);
return p;
}
void process_block(int i,
int j,
vector<vector<double>>& data,
double contourValue,
std::vector<std::vector<MarchingSquares::Point>>& posxy,
vector<Point>& contourPoints)
{
vector<double> values = getGridValues(i, j, data);
vector<bool> isNeedContour;
for (double value : values) {
isNeedContour.push_back(needContour(value, contourValue));
}
int index = 0;
if (isNeedContour[0])
index |= 1;
if (isNeedContour[1])
index |= 2;
if (isNeedContour[2])
index |= 4;
if (isNeedContour[3])
index |= 8;
vector<Point> points;
switch (index) {
case 0:
case 15: break;
case 1:
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
break;
case 14:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
break;
case 2:
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
break;
case 13:
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 3:
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
break;
case 12:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 4:
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 11:
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
break;
case 5:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i + 1, j}, values[3], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
case 6:
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
break;
case 9:
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
break;
case 7:
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
break;
case 8:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i + 1, j}, {i, j}, values[2], values[3], contourValue));
break;
case 10:
points.push_back(interpolate(posxy, {i, j}, {i, j + 1}, values[3], values[0], contourValue));
points.push_back(interpolate(posxy, {i, j}, {i + 1, j}, values[3], values[2], contourValue));
points.push_back(interpolate(posxy, {i, j + 1}, {i + 1, j + 1}, values[0], values[1], contourValue));
points.push_back(interpolate(posxy, {i + 1, j + 1}, {i + 1, j}, values[1], values[2], contourValue));
break;
}
for (Point& p : points) {
contourPoints.push_back(p);
}
}
// --- Chaikin Smooth ---
static Polyline chaikin_smooth(Polyline poly, int iterations , double weight )
{
if (poly.points.size() < 3) return poly;
const double w1 = 1.0 - weight;
decltype(poly.points) buffer;
buffer.reserve(poly.points.size() * 2);
for (int it = 0; it < iterations; ++it) {
buffer.clear();
buffer.push_back(poly.points.front());
for (size_t i = 0; i < poly.points.size() - 1; ++i) {
const auto &p0 = poly.points[i];
const auto &p1 = poly.points[i + 1];
buffer.emplace_back(
p0.x() * w1 + p1.x() * weight,
p0.y() * w1 + p1.y() * weight
);
buffer.emplace_back(
p0.x() * weight + p1.x() * w1,
p0.y() * weight + p1.y() * w1
);
}
buffer.push_back(poly.points.back());
poly.points.swap(buffer);
}
return poly;
}
void drawContour(double contourValue,
int gridSize_w,
int gridSize_h,
vector<vector<double>>& data,
std::vector<std::vector<MarchingSquares::Point>>& posxy,
Polylines& repls,
const FillParams& params)
{
if (data.empty() || data[0].empty()) {
return;
}
gridSize_h = static_cast<int>(data.size());
gridSize_w = static_cast<int>(data[0].size());
if (static_cast<int>(posxy.size()) != gridSize_h || static_cast<int>(posxy[0].size()) != gridSize_w) {
return;
}
int total_size = (gridSize_h - 1) * (gridSize_w - 1);
vector<vector<MarchingSquares::Point>> contourPointss(total_size);
tbb::parallel_for(tbb::blocked_range<size_t>(0, total_size),
[&contourValue, &posxy, &contourPointss, &data, gridSize_w](const tbb::blocked_range<size_t>& range) {
for (size_t k = range.begin(); k < range.end(); ++k) {
int i = static_cast<int>(k) / (gridSize_w - 1);
int j = static_cast<int>(k) % (gridSize_w - 1);
if (i + 1 < static_cast<int>(data.size()) && j + 1 < static_cast<int>(data[0].size())) {
process_block(i, j, data, contourValue, posxy, contourPointss[k]);
}
}
});
vector<pair<myPoint, myPoint>> segments2;
myPoint p1, p2;
for (int k = 0; k < total_size; k++) {
for (int i = 0; i < static_cast<int>(contourPointss[k].size()) / 2; i++) {
p1.x = scale_(contourPointss[k][i * 2].x);
p1.y = scale_(contourPointss[k][i * 2].y);
p2.x = scale_(contourPointss[k][i * 2 + 1].x);
p2.y = scale_(contourPointss[k][i * 2 + 1].y);
segments2.push_back({p1, p2});
}
}
LineSegmentMerger merger;
vector<vector<myPoint>> result;
merger.mergeSegments(segments2, result);
for (vector<myPoint>& p : result) {
Polyline repltmp;
for (myPoint& pt : p) {
repltmp.points.push_back(Slic3r::Point(pt.x, pt.y));
}
// symplify tolerance based on density
const float min_tolerance = 0.005f;
const float max_tolerance = 0.2f;
float simplify_tolerance = (0.005f / params.density);
simplify_tolerance = std::clamp(simplify_tolerance, min_tolerance, max_tolerance);
repltmp.simplify(scale_(simplify_tolerance));
repltmp = chaikin_smooth(repltmp, 2, 0.25);
repls.push_back(repltmp);
}
}
} // namespace MarchingSquares
static float sin_table[360];
static float cos_table[360];
static std::once_flag trig_tables_once_flag;
#define PIratio 57.29577951308232 // 180/PI
static void initialize_lookup_tables()
{
for (int i = 0; i < 360; ++i) {
float angle = i * (M_PI / 180.0);
sin_table[i] = std::sin(angle);
cos_table[i] = std::cos(angle);
}
}
inline static void ensure_trig_tables_initialized()
{
std::call_once(trig_tables_once_flag, initialize_lookup_tables);
}
inline static float get_sin(float angle)
{
angle = angle * PIratio;
int index = static_cast<int>(std::fmod(angle, 360) + 360) % 360;
return sin_table[index];
}
inline static float get_cos(float angle)
{
angle = angle * PIratio;
int index = static_cast<int>(std::fmod(angle, 360) + 360) % 360;
return cos_table[index];
}
void FillTpmsFK::_fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
Polylines& polylines_out)
{
ensure_trig_tables_initialized();
auto infill_angle = float(this->angle + (CorrectionAngle * 2 * M_PI) / 360.);
if(std::abs(infill_angle) >= EPSILON)
expolygon.rotate(-infill_angle);
float density_factor = std::min(0.9f, params.density);
// Density adjusted to have a good %of weight.
const float vari_T = 4.18f * spacing * params.multiline / density_factor;
BoundingBox bb = expolygon.contour.bounding_box();
auto cenpos = unscale(bb.center());
auto boxsize = unscale(bb.size());
float xlen = boxsize.x();
float ylen = boxsize.y();
const float delta = 0.5f; // mesh step (adjust for quality/performance)
float myperiod = 2 * PI / vari_T;
float c_z = myperiod * this->z; // z height
// scalar field Fischer-Koch
auto scalar_field = [&](float x, float y) {
float a_x = myperiod * x;
float b_y = myperiod * y;
// Fischer - Koch S equation:
// cos(2x)sin(y)cos(z) + cos(2y)sin(z)cos(x) + cos(2z)sin(x)cos(y) = 0
const float cos2ax = get_cos(2*a_x);
const float cos2by = get_cos(2*b_y);
const float cos2cz = get_cos(2*c_z);
const float sinby = get_sin(b_y);
const float cosax = get_cos(a_x);
const float sinax = get_sin(a_x);
const float cosby = get_cos(b_y);
const float sincz = get_sin(c_z);
const float coscz = get_cos(c_z);
return cos2ax * sinby * coscz
+ cos2by * sincz * cosax
+ cos2cz * sinax * cosby;
};
// Mesh generation
std::vector<std::vector<MarchingSquares::Point>> posxy;
int i = 0, j = 0;
for (float y = -(ylen) / 2.0f - 2; y < (ylen) / 2.0f + 2; y = y + delta, i++) {
j = 0;
std::vector<MarchingSquares::Point> colposxy;
for (float x = -(xlen) / 2.0f - 2; x < (xlen) / 2.0f + 2; x = x + delta, j++) {
MarchingSquares::Point pt;
pt.x = cenpos.x() + x;
pt.y = cenpos.y() + y;
colposxy.push_back(pt);
}
posxy.push_back(colposxy);
}
std::vector<std::vector<double>> data(posxy.size(), std::vector<double>(posxy[0].size()));
int width = posxy[0].size();
int height = posxy.size();
int total_size = (height) * (width);
tbb::parallel_for(tbb::blocked_range<size_t>(0, total_size),
[&width, &scalar_field, &data, &posxy](const tbb::blocked_range<size_t>& range) {
for (size_t k = range.begin(); k < range.end(); ++k) {
int i = k / (width);
int j = k % (width);
data[i][j] = scalar_field(posxy[i][j].x, posxy[i][j].y);
}
});
Polylines polylines;
const double contour_value = 0.075; // offset from zero to avoid numerical issues
MarchingSquares::drawContour(contour_value, width , height , data, posxy, polylines, params);
if (!polylines.empty()) {
// Apply multiline offset if needed
multiline_fill(polylines, params, spacing);
polylines = intersection_pl(polylines, expolygon);
// 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());
// 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

View File

@@ -0,0 +1,40 @@
#ifndef slic3r_FillTpmsFK_hpp_
#define slic3r_FillTpmsFK_hpp_
#include <utility>
#include "libslic3r/libslic3r.h"
#include "FillBase.hpp"
#include "libslic3r/ExPolygon.hpp"
#include "libslic3r/Polyline.hpp"
namespace Slic3r {
class Point;
class FillTpmsFK : public Fill
{
public:
FillTpmsFK() {}
Fill* clone() const override { return new FillTpmsFK(*this); }
// require bridge flow since most of this pattern hangs in air
bool use_bridge_flow() const override { return false; }
// Correction applied to regular infill angle to maximize printing
// speed in default configuration (degrees)
static constexpr float CorrectionAngle = -45.;
void _fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
Polylines& polylines_out) override;
bool is_self_crossing() override { return false; }
};
} // namespace Slic3r
#endif // slic3r_FillTpmsFK_hpp_

View File

@@ -392,6 +392,7 @@ coordf_t Layer::get_sparse_infill_max_void_area()
case ipLine:
case ipGyroid:
case ipTpmsD:
case ipTpmsFK:
case ipAlignedRectilinear:
case ipOctagramSpiral:
case ipHilbertCurve:

View File

@@ -165,6 +165,7 @@ static t_config_enum_values s_keys_map_InfillPattern {
{ "2dlattice", ip2DLattice },
{ "crosshatch", ipCrossHatch },
{ "tpmsd", ipTpmsD },
{ "tpmsfk", ipTpmsFK },
{ "gyroid", ipGyroid },
{ "concentric", ipConcentric },
{ "hilbertcurve", ipHilbertCurve },
@@ -2417,6 +2418,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("2dlattice");
def->enum_values.push_back("crosshatch");
def->enum_values.push_back("tpmsd");
def->enum_values.push_back("tpmsfk");
def->enum_values.push_back("gyroid");
def->enum_values.push_back("concentric");
def->enum_values.push_back("hilbertcurve");
@@ -2442,6 +2444,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("2D Lattice"));
def->enum_labels.push_back(L("Cross Hatch"));
def->enum_labels.push_back(L("TPMS-D"));
def->enum_labels.push_back(L("TPMS-FK"));
def->enum_labels.push_back(L("Gyroid"));
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Hilbert Curve"));

View File

@@ -71,7 +71,7 @@ enum InfillPattern : int {
ipTriangles, ipStars,
ipCubic, ipAdaptiveCubic, ipQuarterCubic, ipSupportCubic, ipLightning,
ipHoneycomb, ip3DHoneycomb, ip2DHoneycomb, ip2DLattice,
ipCrossHatch, ipTpmsD, ipGyroid,
ipCrossHatch, ipTpmsD, ipTpmsFK, ipGyroid,
ipConcentric, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
ipSupportBase, ipConcentricInternal,
ipCount,

View File

@@ -566,7 +566,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
// Infill patterns that support multiline infill.
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ip2DLattice || pattern == ip2DHoneycomb ||
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ip2DLattice || pattern == ip2DHoneycomb ||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic;
toggle_line("fill_multiline", have_multiline_infill_pattern);