From aab6387f262f4d973608c8b4e45cdd488cebd570 Mon Sep 17 00:00:00 2001 From: Dark98 Date: Fri, 30 Jan 2026 06:50:58 +0000 Subject: [PATCH] Add CrossHatch Infill --- app/CMakeLists.txt | 2 + app/src/main/jni/libslic3r/Fill/Fill.cpp | 1 + app/src/main/jni/libslic3r/Fill/FillBase.cpp | 2 + .../jni/libslic3r/Fill/FillCrossHatch.cpp | 206 ++++++++++++++++++ .../jni/libslic3r/Fill/FillCrossHatch.hpp | 28 +++ app/src/main/jni/libslic3r/PrintConfig.cpp | 2 + app/src/main/jni/libslic3r/PrintConfig.hpp | 2 +- 7 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 app/src/main/jni/libslic3r/Fill/FillCrossHatch.cpp create mode 100644 app/src/main/jni/libslic3r/Fill/FillCrossHatch.hpp diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index fee77c8..38c5fff 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -782,6 +782,8 @@ add_library(slic3r src/main/jni/libslic3r/Fill/FillBase.hpp src/main/jni/libslic3r/Fill/FillConcentric.cpp src/main/jni/libslic3r/Fill/FillConcentric.hpp + src/main/jni/libslic3r/Fill/FillCrossHatch.cpp + src/main/jni/libslic3r/Fill/FillCrossHatch.hpp src/main/jni/libslic3r/Fill/FillEnsuring.cpp src/main/jni/libslic3r/Fill/FillEnsuring.hpp src/main/jni/libslic3r/Fill/FillHoneycomb.cpp diff --git a/app/src/main/jni/libslic3r/Fill/Fill.cpp b/app/src/main/jni/libslic3r/Fill/Fill.cpp index df493ab..5ee5488 100644 --- a/app/src/main/jni/libslic3r/Fill/Fill.cpp +++ b/app/src/main/jni/libslic3r/Fill/Fill.cpp @@ -657,6 +657,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc case ipHoneycomb: case ip3DHoneycomb: case ipGyroid: + case ipCrossHatch: case ipHilbertCurve: case ipArchimedeanChords: case ipOctagramSpiral: break; diff --git a/app/src/main/jni/libslic3r/Fill/FillBase.cpp b/app/src/main/jni/libslic3r/Fill/FillBase.cpp index a7f99af..dfe8ab9 100644 --- a/app/src/main/jni/libslic3r/Fill/FillBase.cpp +++ b/app/src/main/jni/libslic3r/Fill/FillBase.cpp @@ -30,6 +30,7 @@ #include "FillAdaptive.hpp" #include "FillLightning.hpp" #include "FillEnsuring.hpp" +#include "FillCrossHatch.hpp" #include @@ -60,6 +61,7 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipSupportCubic: return new FillAdaptive::Filler(); case ipSupportBase: return new FillSupportBase(); case ipLightning: return new FillLightning::Filler(); + case ipCrossHatch: return new FillCrossHatch(); case ipEnsuring: return new FillEnsuring(); default: throw Slic3r::InvalidArgument("unknown type"); } diff --git a/app/src/main/jni/libslic3r/Fill/FillCrossHatch.cpp b/app/src/main/jni/libslic3r/Fill/FillCrossHatch.cpp new file mode 100644 index 0000000..86a6afe --- /dev/null +++ b/app/src/main/jni/libslic3r/Fill/FillCrossHatch.cpp @@ -0,0 +1,206 @@ +#include "../ClipperUtils.hpp" +#include "../ShortestPath.hpp" +#include "../Surface.hpp" + +#include +#include + +#include "FillBase.hpp" +#include "FillCrossHatch.hpp" + +namespace Slic3r { + +// CrossHatch Infill: alternates line direction by 90 degrees every few layers +// with transform layers between direction shifts. + +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; // odd and even separately. + double progress = inprogress; + Polylines out_polylines; + + 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])); + + if (direction < 0) { + width = height; + height = inwidth; + } + + Polylines odd_polylines; + Polyline odd_poly; + int num_of_cycle = int(width / grid_size) + 2; + odd_poly.points.reserve(num_of_cycle * one_cycle.size()); + + for (int i = 0; i < num_of_cycle; i++) { + Polyline 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()); + } + + int num_of_lines = int(height / grid_size) + 2; + odd_polylines.reserve(num_of_lines * odd_poly.size()); + for (int i = 0; i < num_of_lines; i++) { + Polyline poly = odd_poly; + poly.translate(Point(0.0, grid_size * i)); + odd_polylines.push_back(poly); + } + out_polylines.insert(out_polylines.end(), odd_polylines.begin(), odd_polylines.end()); + + 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, (coordf_t(i) + 0.5) * grid_size)); + even_polylines.push_back(even); + } + + out_polylines.insert(out_polylines.end(), even_polylines.begin(), even_polylines.end()); + + if (direction < 0) { + 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; + + if (direction < 0) { + width = height; + height = inwidth; + } + + int num_of_lines = int(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); + } + + if (direction < 0) { + for (Polyline &poly : out_polylines) { + for (Point &p : poly) + std::swap(p.x(), p.y()); + } + } + + return out_polylines; +} + +// repeat_ratio defines 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; + coordf_t repeat_layer_size = grid_size * repeat_ratio; + z_height += repeat_layer_size / 2 + trans_layer_size; + 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; + + int phase = int(fmod(z_height, period * 2) - (period - 1)); // add epsilon + int direction = phase <= 0 ? -1 : 1; + + if (trans_z < 0) { + result = generate_repeat_pattern(direction, grid_size, width, height); + } else { + double progress = fmod(trans_z, trans_layer_size) / trans_layer_size; + if (progress < 0.5) + result = generate_transform_pattern((progress + 0.1) * 2, direction, grid_size, width, height); + else + result = generate_transform_pattern((1.1 - progress) * 2, -1 * direction, grid_size, width, height); + } + + return result; +} + +void FillCrossHatch::_fill_surface_single( + const FillParams ¶ms, + unsigned int thickness_layers, + const std::pair &direction, + ExPolygon expolygon, + Polylines &polylines_out) +{ + (void)thickness_layers; + (void)direction; + + if (params.density <= 0.f) + return; + + auto infill_angle = float(this->angle); + if (std::abs(infill_angle) >= EPSILON) + expolygon.rotate(-infill_angle); + + BoundingBox bb = expolygon.contour.bounding_box(); + + double density_adjusted = params.density; + coord_t line_spacing = coord_t(scale_(this->spacing) / density_adjusted); + + if (params.density < 0.999f) + line_spacing = coord_t(line_spacing * 1.08); + + bb.merge(align_to_grid(bb.min, Point(line_spacing * 4, line_spacing * 4))); + + double repeat_ratio = 1.0; + if (params.density < 0.3f) + repeat_ratio = std::clamp(1.0 - std::exp(-5 * params.density), 0.2, 1.0); + + Polylines polylines = generate_infill_layers(scale_(this->z), repeat_ratio, line_spacing, bb.size()(0), bb.size()(1)); + + for (Polyline &pl : polylines) + pl.translate(bb.min); + + polylines = intersection_pl(polylines, to_polygons(expolygon)); + + if (!polylines.empty()) { + 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()) { + const size_t infill_start_idx = polylines_out.size(); + if (params.dont_connect()) + append(polylines_out, chain_polylines(std::move(polylines))); + else + connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); + + 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 diff --git a/app/src/main/jni/libslic3r/Fill/FillCrossHatch.hpp b/app/src/main/jni/libslic3r/Fill/FillCrossHatch.hpp new file mode 100644 index 0000000..4731988 --- /dev/null +++ b/app/src/main/jni/libslic3r/Fill/FillCrossHatch.hpp @@ -0,0 +1,28 @@ +#ifndef slic3r_FillCrossHatch_hpp_ +#define slic3r_FillCrossHatch_hpp_ + +#include "../libslic3r.h" + +#include "FillBase.hpp" + +namespace Slic3r { + +class FillCrossHatch : public Fill +{ +public: + Fill *clone() const override { return new FillCrossHatch(*this); } + ~FillCrossHatch() override {} + bool is_self_crossing() override { return false; } + +protected: + void _fill_surface_single( + const FillParams ¶ms, + unsigned int thickness_layers, + const std::pair &direction, + ExPolygon expolygon, + Polylines &polylines_out) override; +}; + +} // namespace Slic3r + +#endif // slic3r_FillCrossHatch_hpp_ diff --git a/app/src/main/jni/libslic3r/PrintConfig.cpp b/app/src/main/jni/libslic3r/PrintConfig.cpp index 16e9fb0..4765907 100644 --- a/app/src/main/jni/libslic3r/PrintConfig.cpp +++ b/app/src/main/jni/libslic3r/PrintConfig.cpp @@ -136,6 +136,7 @@ static const t_config_enum_values s_keys_map_InfillPattern { { "honeycomb", ipHoneycomb }, { "3dhoneycomb", ip3DHoneycomb }, { "gyroid", ipGyroid }, + { "crosshatch", ipCrossHatch }, { "hilbertcurve", ipHilbertCurve }, { "archimedeanchords", ipArchimedeanChords }, { "octagramspiral", ipOctagramSpiral }, @@ -1486,6 +1487,7 @@ void PrintConfigDef::init_fff_params() { "honeycomb", L("Honeycomb")}, { "3dhoneycomb", L("3D Honeycomb")}, { "gyroid", L("Gyroid")}, + { "crosshatch", L("Cross Hatch")}, { "hilbertcurve", L("Hilbert Curve")}, { "archimedeanchords", L("Archimedean Chords")}, { "octagramspiral", L("Octagram Spiral")}, diff --git a/app/src/main/jni/libslic3r/PrintConfig.hpp b/app/src/main/jni/libslic3r/PrintConfig.hpp index c6cb9cc..0974d1d 100644 --- a/app/src/main/jni/libslic3r/PrintConfig.hpp +++ b/app/src/main/jni/libslic3r/PrintConfig.hpp @@ -86,7 +86,7 @@ enum class ElegooBedType { enum InfillPattern : int { ipRectilinear, ipMonotonic, ipMonotonicLines, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipSupportBase, - ipLightning, + ipLightning, ipCrossHatch, ipEnsuring, ipCount, };