From 202875a4bbef6f6b2cb4f0341a5497c3f29ad275 Mon Sep 17 00:00:00 2001 From: Rodrigo <162915171+RF47@users.noreply.github.com> Date: Sun, 10 Aug 2025 12:10:35 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8TPMS-FK=20Infill=20(=20Triply=20Period?= =?UTF-8?q?ic=20Minimal=20Surface=20Fischer=20Koch=20S)=20=20(#10360)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- resources/images/param_tpmsfk.svg | 1 + src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Fill/Fill.cpp | 2 + src/libslic3r/Fill/FillBase.cpp | 2 + src/libslic3r/Fill/FillTpmsFK.cpp | 543 ++++++++++++++++++++++++++ src/libslic3r/Fill/FillTpmsFK.hpp | 40 ++ src/libslic3r/Layer.cpp | 1 + src/libslic3r/PrintConfig.cpp | 3 + src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/GUI/ConfigManipulation.cpp | 2 +- 10 files changed, 596 insertions(+), 2 deletions(-) create mode 100644 resources/images/param_tpmsfk.svg create mode 100644 src/libslic3r/Fill/FillTpmsFK.cpp create mode 100644 src/libslic3r/Fill/FillTpmsFK.hpp diff --git a/resources/images/param_tpmsfk.svg b/resources/images/param_tpmsfk.svg new file mode 100644 index 0000000000..5bc8d2d793 --- /dev/null +++ b/resources/images/param_tpmsfk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 2e56523334..925728e5a1 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -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 diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 2e83d0829f..87370b8075 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -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: diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 8936f5f55f..7f6d2e7229 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -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(); diff --git a/src/libslic3r/Fill/FillTpmsFK.cpp b/src/libslic3r/Fill/FillTpmsFK.cpp new file mode 100644 index 0000000000..aa4a9442f6 --- /dev/null +++ b/src/libslic3r/Fill/FillTpmsFK.cpp @@ -0,0 +1,543 @@ +#include "../ClipperUtils.hpp" +#include "FillTpmsFK.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Slic3r { + +using namespace std; +struct myPoint +{ + coord_t x, y; +}; +class LineSegmentMerger +{ +public: + void mergeSegments(const vector>& segments, vector>& polylines2) + { + std::unordered_map point_id_xy; + std::set> segment_ids; + std::unordered_map 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(x + i) << 32 | static_cast(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(x) << 32 | static_cast(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(x) << 32 | static_cast(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> graph; + unordered_set visited; + vector> 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 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 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 polyline; + dfs(point.first, graph, visited, polyline); + polylines.push_back(std::move(polyline)); + } + } + + for (auto& pl : polylines) { + vector 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>& graph, + std::unordered_set& visited, + std::vector& polyline) + { + std::vector 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 getGridValues(int i, int j, vector>& data) +{ + vector 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>& posxy, + std::vector p1ij, + std::vector 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>& data, + double contourValue, + std::vector>& posxy, + vector& contourPoints) +{ + vector values = getGridValues(i, j, data); + vector 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 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>& data, + std::vector>& posxy, + Polylines& repls, + const FillParams& params) +{ + + if (data.empty() || data[0].empty()) { + + return; + } + gridSize_h = static_cast(data.size()); + gridSize_w = static_cast(data[0].size()); + + + if (static_cast(posxy.size()) != gridSize_h || static_cast(posxy[0].size()) != gridSize_w) { + + return; + } + + int total_size = (gridSize_h - 1) * (gridSize_w - 1); + vector> contourPointss(total_size); + + tbb::parallel_for(tbb::blocked_range(0, total_size), + [&contourValue, &posxy, &contourPointss, &data, gridSize_w](const tbb::blocked_range& range) { + for (size_t k = range.begin(); k < range.end(); ++k) { + int i = static_cast(k) / (gridSize_w - 1); + int j = static_cast(k) % (gridSize_w - 1); + + if (i + 1 < static_cast(data.size()) && j + 1 < static_cast(data[0].size())) { + process_block(i, j, data, contourValue, posxy, contourPointss[k]); + } + } + }); + + vector> segments2; + myPoint p1, p2; + for (int k = 0; k < total_size; k++) { + for (int i = 0; i < static_cast(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> result; + merger.mergeSegments(segments2, result); + + for (vector& 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(std::fmod(angle, 360) + 360) % 360; + return sin_table[index]; +} + +inline static float get_cos(float angle) +{ + angle = angle * PIratio; + int index = static_cast(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& 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> 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 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> data(posxy.size(), std::vector(posxy[0].size())); + + int width = posxy[0].size(); + int height = posxy.size(); + int total_size = (height) * (width); + tbb::parallel_for(tbb::blocked_range(0, total_size), + [&width, &scalar_field, &data, &posxy](const tbb::blocked_range& 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 diff --git a/src/libslic3r/Fill/FillTpmsFK.hpp b/src/libslic3r/Fill/FillTpmsFK.hpp new file mode 100644 index 0000000000..b9cd7d208b --- /dev/null +++ b/src/libslic3r/Fill/FillTpmsFK.hpp @@ -0,0 +1,40 @@ +#ifndef slic3r_FillTpmsFK_hpp_ +#define slic3r_FillTpmsFK_hpp_ + +#include + +#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& direction, + ExPolygon expolygon, + Polylines& polylines_out) override; + + bool is_self_crossing() override { return false; } + +}; + +} // namespace Slic3r + +#endif // slic3r_FillTpmsFK_hpp_ \ No newline at end of file diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 326d1fffbe..60cc113906 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -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: diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 3ae3509b24..3db9b6cfbd 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -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")); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index bcd71cefea..c2ec764ec3 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -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, diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 01417fcbca..78d5027744 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -566,7 +566,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co // Infill patterns that support multiline infill. InfillPattern pattern = config->opt_enum("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);