Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
commit
3527cd48e8
@ -692,6 +692,40 @@ inline typename VectorType::Scalar squared_distance_to_indexed_triangle_set(
|
||||
detail::squared_distance_to_indexed_triangle_set_recursive(distancer, size_t(0), Scalar(0), std::numeric_limits<Scalar>::infinity(), hit_idx_out, hit_point_out);
|
||||
}
|
||||
|
||||
// Decides if exists some triangle in defined radius on a 3D indexed triangle set using a pre-built AABBTreeIndirect::Tree.
|
||||
// Closest point to triangle test will be performed with the accuracy of VectorType::Scalar
|
||||
// even if the triangle mesh and the AABB Tree are built with floats.
|
||||
// Returns true if exists some triangle in defined radius, false otherwise.
|
||||
template<typename VertexType, typename IndexedFaceType, typename TreeType, typename VectorType>
|
||||
inline bool is_any_triangle_in_radius(
|
||||
// Indexed triangle set - 3D vertices.
|
||||
const std::vector<VertexType> &vertices,
|
||||
// Indexed triangle set - triangular faces, references to vertices.
|
||||
const std::vector<IndexedFaceType> &faces,
|
||||
// AABBTreeIndirect::Tree over vertices & faces, bounding boxes built with the accuracy of vertices.
|
||||
const TreeType &tree,
|
||||
// Point to which the closest point on the indexed triangle set is searched for.
|
||||
const VectorType &point,
|
||||
// Maximum distance in which triangle is search for
|
||||
typename VectorType::Scalar &max_distance)
|
||||
{
|
||||
using Scalar = typename VectorType::Scalar;
|
||||
auto distancer = detail::IndexedTriangleSetDistancer<VertexType, IndexedFaceType, TreeType, VectorType>
|
||||
{ vertices, faces, tree, point };
|
||||
|
||||
size_t hit_idx;
|
||||
VectorType hit_point = VectorType::Ones() * (std::nan(""));
|
||||
|
||||
if(tree.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
detail::squared_distance_to_indexed_triangle_set_recursive(distancer, size_t(0), Scalar(0), max_distance, hit_idx, hit_point);
|
||||
|
||||
return hit_point.allFinite();
|
||||
}
|
||||
|
||||
} // namespace AABBTreeIndirect
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -46,6 +46,8 @@ add_library(libslic3r STATIC
|
||||
Fill/Fill.hpp
|
||||
Fill/Fill3DHoneycomb.cpp
|
||||
Fill/Fill3DHoneycomb.hpp
|
||||
Fill/FillAdaptive.cpp
|
||||
Fill/FillAdaptive.hpp
|
||||
Fill/FillBase.cpp
|
||||
Fill/FillBase.hpp
|
||||
Fill/FillConcentric.cpp
|
||||
|
@ -318,7 +318,7 @@ void export_group_fills_to_svg(const char *path, const std::vector<SurfaceFill>
|
||||
#endif
|
||||
|
||||
// friend to Layer
|
||||
void Layer::make_fills()
|
||||
void Layer::make_fills(FillAdaptive_Internal::Octree* adaptive_fill_octree)
|
||||
{
|
||||
for (LayerRegion *layerm : m_regions)
|
||||
layerm->fills.clear();
|
||||
@ -345,6 +345,7 @@ void Layer::make_fills()
|
||||
f->layer_id = this->id();
|
||||
f->z = this->print_z;
|
||||
f->angle = surface_fill.params.angle;
|
||||
f->adapt_fill_octree = adaptive_fill_octree;
|
||||
|
||||
// calculate flow spacing for infill pattern generation
|
||||
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.flow.bridge;
|
||||
|
270
src/libslic3r/Fill/FillAdaptive.cpp
Normal file
270
src/libslic3r/Fill/FillAdaptive.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../ExPolygon.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include "../AABBTreeIndirect.hpp"
|
||||
#include "../ShortestPath.hpp"
|
||||
|
||||
#include "FillAdaptive.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void FillAdaptive::_fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon &expolygon,
|
||||
Polylines &polylines_out)
|
||||
{
|
||||
// Store grouped lines by its direction (multiple of 120°)
|
||||
std::vector<Lines> infill_lines_dir(3);
|
||||
this->generate_infill_lines(this->adapt_fill_octree->root_cube.get(),
|
||||
this->z, this->adapt_fill_octree->origin,infill_lines_dir,
|
||||
this->adapt_fill_octree->cubes_properties,
|
||||
this->adapt_fill_octree->cubes_properties.size() - 1);
|
||||
|
||||
Polylines all_polylines;
|
||||
all_polylines.reserve(infill_lines_dir[0].size() * 3);
|
||||
for (Lines &infill_lines : infill_lines_dir)
|
||||
{
|
||||
for (const Line &line : infill_lines)
|
||||
{
|
||||
all_polylines.emplace_back(line.a, line.b);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.dont_connect)
|
||||
{
|
||||
// Crop all polylines
|
||||
polylines_out = intersection_pl(all_polylines, to_polygons(expolygon));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Crop all polylines
|
||||
all_polylines = intersection_pl(all_polylines, to_polygons(expolygon));
|
||||
|
||||
Polylines boundary_polylines;
|
||||
Polylines non_boundary_polylines;
|
||||
for (const Polyline &polyline : all_polylines)
|
||||
{
|
||||
// connect_infill required all polylines to touch the boundary.
|
||||
if(polyline.lines().size() == 1 && expolygon.has_boundary_point(polyline.lines().front().a) && expolygon.has_boundary_point(polyline.lines().front().b))
|
||||
{
|
||||
boundary_polylines.push_back(polyline);
|
||||
}
|
||||
else
|
||||
{
|
||||
non_boundary_polylines.push_back(polyline);
|
||||
}
|
||||
}
|
||||
|
||||
if(!boundary_polylines.empty())
|
||||
{
|
||||
boundary_polylines = chain_polylines(boundary_polylines);
|
||||
FillAdaptive::connect_infill(std::move(boundary_polylines), expolygon, polylines_out, this->spacing, params);
|
||||
}
|
||||
|
||||
polylines_out.insert(polylines_out.end(), non_boundary_polylines.begin(), non_boundary_polylines.end());
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
{
|
||||
static int iRuna = 0;
|
||||
BoundingBox bbox_svg = this->bounding_box;
|
||||
{
|
||||
::Slic3r::SVG svg(debug_out_path("FillAdaptive-%d.svg", iRuna), bbox_svg);
|
||||
for (const Polyline &polyline : polylines_out)
|
||||
{
|
||||
for (const Line &line : polyline.lines())
|
||||
{
|
||||
Point from = line.a;
|
||||
Point to = line.b;
|
||||
Point diff = to - from;
|
||||
|
||||
float shrink_length = scale_(0.4);
|
||||
float line_slope = (float)diff.y() / diff.x();
|
||||
float shrink_x = shrink_length / (float)std::sqrt(1.0 + (line_slope * line_slope));
|
||||
float shrink_y = line_slope * shrink_x;
|
||||
|
||||
to.x() -= shrink_x;
|
||||
to.y() -= shrink_y;
|
||||
from.x() += shrink_x;
|
||||
from.y() += shrink_y;
|
||||
|
||||
svg.draw(Line(from, to));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iRuna++;
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
}
|
||||
|
||||
void FillAdaptive::generate_infill_lines(
|
||||
FillAdaptive_Internal::Cube *cube,
|
||||
double z_position,
|
||||
const Vec3d &origin,
|
||||
std::vector<Lines> &dir_lines_out,
|
||||
const std::vector<FillAdaptive_Internal::CubeProperties> &cubes_properties,
|
||||
int depth)
|
||||
{
|
||||
using namespace FillAdaptive_Internal;
|
||||
|
||||
if(cube == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double z_diff = std::abs(z_position - cube->center.z());
|
||||
|
||||
if (z_diff > cubes_properties[depth].height / 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (z_diff < cubes_properties[depth].line_z_distance)
|
||||
{
|
||||
Point from(
|
||||
scale_((cubes_properties[depth].diagonal_length / 2) * (cubes_properties[depth].line_z_distance - z_diff) / cubes_properties[depth].line_z_distance),
|
||||
scale_(cubes_properties[depth].line_xy_distance - ((z_position - (cube->center.z() - cubes_properties[depth].line_z_distance)) / sqrt(2))));
|
||||
Point to(-from.x(), from.y());
|
||||
// Relative to cube center
|
||||
|
||||
float rotation_angle = (2.0 * M_PI) / 3.0;
|
||||
for (Lines &lines : dir_lines_out)
|
||||
{
|
||||
Vec3d offset = cube->center - origin;
|
||||
Point from_abs(from), to_abs(to);
|
||||
|
||||
from_abs.x() += scale_(offset.x());
|
||||
from_abs.y() += scale_(offset.y());
|
||||
to_abs.x() += scale_(offset.x());
|
||||
to_abs.y() += scale_(offset.y());
|
||||
|
||||
// lines.emplace_back(from_abs, to_abs);
|
||||
this->connect_lines(lines, Line(from_abs, to_abs));
|
||||
|
||||
from.rotate(rotation_angle);
|
||||
to.rotate(rotation_angle);
|
||||
}
|
||||
}
|
||||
|
||||
for(const std::unique_ptr<Cube> &child : cube->children)
|
||||
{
|
||||
if(child != nullptr)
|
||||
{
|
||||
generate_infill_lines(child.get(), z_position, origin, dir_lines_out, cubes_properties, depth - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FillAdaptive::connect_lines(Lines &lines, Line new_line)
|
||||
{
|
||||
int eps = scale_(0.10);
|
||||
for (size_t i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
if (std::abs(new_line.a.x() - lines[i].b.x()) < eps && std::abs(new_line.a.y() - lines[i].b.y()) < eps)
|
||||
{
|
||||
new_line.a = lines[i].a;
|
||||
lines.erase(lines.begin() + i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::abs(new_line.b.x() - lines[i].a.x()) < eps && std::abs(new_line.b.y() - lines[i].a.y()) < eps)
|
||||
{
|
||||
new_line.b = lines[i].b;
|
||||
lines.erase(lines.begin() + i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lines.emplace_back(new_line.a, new_line.b);
|
||||
}
|
||||
|
||||
std::unique_ptr<FillAdaptive_Internal::Octree> FillAdaptive::build_octree(
|
||||
TriangleMesh &triangle_mesh,
|
||||
coordf_t line_spacing,
|
||||
const Vec3d &cube_center)
|
||||
{
|
||||
using namespace FillAdaptive_Internal;
|
||||
|
||||
if(line_spacing <= 0 || std::isnan(line_spacing))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Vec3d bb_size = triangle_mesh.bounding_box().size();
|
||||
// The furthest point from the center of the bottom of the mesh bounding box.
|
||||
double furthest_point = std::sqrt(((bb_size.x() * bb_size.x()) / 4.0) +
|
||||
((bb_size.y() * bb_size.y()) / 4.0) +
|
||||
(bb_size.z() * bb_size.z()));
|
||||
double max_cube_edge_length = furthest_point * 2;
|
||||
|
||||
std::vector<CubeProperties> cubes_properties;
|
||||
for (double edge_length = (line_spacing * 2); edge_length < (max_cube_edge_length * 2); edge_length *= 2)
|
||||
{
|
||||
CubeProperties props{};
|
||||
props.edge_length = edge_length;
|
||||
props.height = edge_length * sqrt(3);
|
||||
props.diagonal_length = edge_length * sqrt(2);
|
||||
props.line_z_distance = edge_length / sqrt(3);
|
||||
props.line_xy_distance = edge_length / sqrt(6);
|
||||
cubes_properties.push_back(props);
|
||||
}
|
||||
|
||||
if (triangle_mesh.its.vertices.empty())
|
||||
{
|
||||
triangle_mesh.require_shared_vertices();
|
||||
}
|
||||
|
||||
Vec3d rotation = Vec3d((5.0 * M_PI) / 4.0, Geometry::deg2rad(215.264), M_PI / 6.0);
|
||||
Transform3d rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation, Vec3d::Ones(), Vec3d::Ones());
|
||||
|
||||
AABBTreeIndirect::Tree3f aabbTree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(
|
||||
triangle_mesh.its.vertices, triangle_mesh.its.indices);
|
||||
auto octree = std::make_unique<Octree>(std::make_unique<Cube>(cube_center), cube_center, cubes_properties);
|
||||
|
||||
FillAdaptive::expand_cube(octree->root_cube.get(), cubes_properties, rotation_matrix, aabbTree, triangle_mesh, cubes_properties.size() - 1);
|
||||
|
||||
return octree;
|
||||
}
|
||||
|
||||
void FillAdaptive::expand_cube(
|
||||
FillAdaptive_Internal::Cube *cube,
|
||||
const std::vector<FillAdaptive_Internal::CubeProperties> &cubes_properties,
|
||||
const Transform3d &rotation_matrix,
|
||||
const AABBTreeIndirect::Tree3f &distance_tree,
|
||||
const TriangleMesh &triangle_mesh, int depth)
|
||||
{
|
||||
using namespace FillAdaptive_Internal;
|
||||
|
||||
if (cube == nullptr || depth == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Vec3d> child_centers = {
|
||||
Vec3d(-1, -1, -1), Vec3d( 1, -1, -1), Vec3d(-1, 1, -1), Vec3d(-1, -1, 1),
|
||||
Vec3d( 1, 1, 1), Vec3d(-1, 1, 1), Vec3d( 1, -1, 1), Vec3d( 1, 1, -1)
|
||||
};
|
||||
|
||||
double cube_radius_squared = (cubes_properties[depth].height * cubes_properties[depth].height) / 16;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
const Vec3d &child_center = child_centers[i];
|
||||
Vec3d child_center_transformed = cube->center + rotation_matrix * (child_center * (cubes_properties[depth].edge_length / 4));
|
||||
|
||||
if(AABBTreeIndirect::is_any_triangle_in_radius(triangle_mesh.its.vertices, triangle_mesh.its.indices,
|
||||
distance_tree, child_center_transformed, cube_radius_squared))
|
||||
{
|
||||
cube->children[i] = std::make_unique<Cube>(child_center_transformed);
|
||||
FillAdaptive::expand_cube(cube->children[i].get(), cubes_properties, rotation_matrix, distance_tree, triangle_mesh, depth - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
87
src/libslic3r/Fill/FillAdaptive.hpp
Normal file
87
src/libslic3r/Fill/FillAdaptive.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
#ifndef slic3r_FillAdaptive_hpp_
|
||||
#define slic3r_FillAdaptive_hpp_
|
||||
|
||||
#include "../AABBTreeIndirect.hpp"
|
||||
|
||||
#include "FillBase.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace FillAdaptive_Internal
|
||||
{
|
||||
struct CubeProperties
|
||||
{
|
||||
double edge_length; // Lenght of edge of a cube
|
||||
double height; // Height of rotated cube (standing on the corner)
|
||||
double diagonal_length; // Length of diagonal of a cube a face
|
||||
double line_z_distance; // Defines maximal distance from a center of a cube on Z axis on which lines will be created
|
||||
double line_xy_distance;// Defines maximal distance from a center of a cube on X and Y axis on which lines will be created
|
||||
};
|
||||
|
||||
struct Cube
|
||||
{
|
||||
Vec3d center;
|
||||
std::unique_ptr<Cube> children[8] = {};
|
||||
Cube(const Vec3d ¢er) : center(center) {}
|
||||
};
|
||||
|
||||
struct Octree
|
||||
{
|
||||
std::unique_ptr<Cube> root_cube;
|
||||
Vec3d origin;
|
||||
std::vector<CubeProperties> cubes_properties;
|
||||
|
||||
Octree(std::unique_ptr<Cube> rootCube, const Vec3d &origin, const std::vector<CubeProperties> &cubes_properties)
|
||||
: root_cube(std::move(rootCube)), origin(origin), cubes_properties(cubes_properties) {}
|
||||
};
|
||||
}; // namespace FillAdaptive_Internal
|
||||
|
||||
//
|
||||
// Some of the algorithms used by class FillAdaptive were inspired by
|
||||
// Cura Engine's class SubDivCube
|
||||
// https://github.com/Ultimaker/CuraEngine/blob/master/src/infill/SubDivCube.h
|
||||
//
|
||||
class FillAdaptive : public Fill
|
||||
{
|
||||
public:
|
||||
virtual ~FillAdaptive() {}
|
||||
|
||||
protected:
|
||||
virtual Fill* clone() const { return new FillAdaptive(*this); };
|
||||
virtual void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon &expolygon,
|
||||
Polylines &polylines_out);
|
||||
|
||||
virtual bool no_sort() const { return true; }
|
||||
|
||||
void generate_infill_lines(
|
||||
FillAdaptive_Internal::Cube *cube,
|
||||
double z_position,
|
||||
const Vec3d & origin,
|
||||
std::vector<Lines> & dir_lines_out,
|
||||
const std::vector<FillAdaptive_Internal::CubeProperties> &cubes_properties,
|
||||
int depth);
|
||||
|
||||
static void connect_lines(Lines &lines, Line new_line);
|
||||
|
||||
public:
|
||||
static std::unique_ptr<FillAdaptive_Internal::Octree> build_octree(
|
||||
TriangleMesh &triangle_mesh,
|
||||
coordf_t line_spacing,
|
||||
const Vec3d & cube_center);
|
||||
|
||||
static void expand_cube(
|
||||
FillAdaptive_Internal::Cube *cube,
|
||||
const std::vector<FillAdaptive_Internal::CubeProperties> &cubes_properties,
|
||||
const Transform3d & rotation_matrix,
|
||||
const AABBTreeIndirect::Tree3f &distance_tree,
|
||||
const TriangleMesh & triangle_mesh,
|
||||
int depth);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_FillAdaptive_hpp_
|
@ -16,6 +16,7 @@
|
||||
#include "FillRectilinear.hpp"
|
||||
#include "FillRectilinear2.hpp"
|
||||
#include "FillRectilinear3.hpp"
|
||||
#include "FillAdaptive.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -37,6 +38,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||
case ipArchimedeanChords: return new FillArchimedeanChords();
|
||||
case ipHilbertCurve: return new FillHilbertCurve();
|
||||
case ipOctagramSpiral: return new FillOctagramSpiral();
|
||||
case ipAdaptiveCubic: return new FillAdaptive();
|
||||
default: throw std::invalid_argument("unknown type");
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,10 @@ class ExPolygon;
|
||||
class Surface;
|
||||
enum InfillPattern : int;
|
||||
|
||||
namespace FillAdaptive_Internal {
|
||||
struct Octree;
|
||||
};
|
||||
|
||||
class InfillFailedException : public std::runtime_error {
|
||||
public:
|
||||
InfillFailedException() : std::runtime_error("Infill failed") {}
|
||||
@ -69,6 +73,8 @@ public:
|
||||
// In scaled coordinates. Bounding box of the 2D projection of the object.
|
||||
BoundingBox bounding_box;
|
||||
|
||||
FillAdaptive_Internal::Octree* adapt_fill_octree = nullptr;
|
||||
|
||||
public:
|
||||
virtual ~Fill() {}
|
||||
|
||||
|
@ -13,6 +13,10 @@ class Layer;
|
||||
class PrintRegion;
|
||||
class PrintObject;
|
||||
|
||||
namespace FillAdaptive_Internal {
|
||||
struct Octree;
|
||||
};
|
||||
|
||||
class LayerRegion
|
||||
{
|
||||
public:
|
||||
@ -134,7 +138,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
void make_perimeters();
|
||||
void make_fills();
|
||||
void make_fills() { this->make_fills(nullptr); };
|
||||
void make_fills(FillAdaptive_Internal::Octree* adaptive_fill_octree);
|
||||
void make_ironing();
|
||||
|
||||
void export_region_slices_to_svg(const char *path) const;
|
||||
|
@ -30,6 +30,10 @@ enum class SlicingMode : uint32_t;
|
||||
class Layer;
|
||||
class SupportLayer;
|
||||
|
||||
namespace FillAdaptive_Internal {
|
||||
struct Octree;
|
||||
};
|
||||
|
||||
// Print step IDs for keeping track of the print state.
|
||||
enum PrintStep {
|
||||
psSkirt,
|
||||
@ -235,6 +239,7 @@ private:
|
||||
void discover_horizontal_shells();
|
||||
void combine_infill();
|
||||
void _generate_support_material();
|
||||
std::unique_ptr<FillAdaptive_Internal::Octree> prepare_adaptive_infill_data();
|
||||
|
||||
// XYZ in scaled coordinates
|
||||
Vec3crd m_size;
|
||||
|
@ -881,6 +881,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
def->enum_values.push_back("archimedeanchords");
|
||||
def->enum_values.push_back("octagramspiral");
|
||||
def->enum_values.push_back("adaptivecubic");
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Grid"));
|
||||
def->enum_labels.push_back(L("Triangles"));
|
||||
@ -894,6 +895,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||
def->enum_labels.push_back(L("Adaptive Cubic"));
|
||||
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipStars));
|
||||
|
||||
def = this->add("first_layer_acceleration", coFloat);
|
||||
|
@ -39,7 +39,7 @@ enum AuthorizationType {
|
||||
|
||||
enum InfillPattern : int {
|
||||
ipRectilinear, ipMonotonous, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipCount,
|
||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipCount,
|
||||
};
|
||||
|
||||
enum class IroningType {
|
||||
@ -139,6 +139,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
|
||||
keys_map["hilbertcurve"] = ipHilbertCurve;
|
||||
keys_map["archimedeanchords"] = ipArchimedeanChords;
|
||||
keys_map["octagramspiral"] = ipOctagramSpiral;
|
||||
keys_map["adaptivecubic"] = ipAdaptiveCubic;
|
||||
}
|
||||
return keys_map;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "Surface.hpp"
|
||||
#include "Slicing.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "AABBTreeIndirect.hpp"
|
||||
#include "Fill/FillAdaptive.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <boost/log/trivial.hpp>
|
||||
@ -369,13 +371,15 @@ void PrintObject::infill()
|
||||
this->prepare_infill();
|
||||
|
||||
if (this->set_started(posInfill)) {
|
||||
std::unique_ptr<FillAdaptive_Internal::Octree> octree = this->prepare_adaptive_infill_data();
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, m_layers.size()),
|
||||
[this](const tbb::blocked_range<size_t>& range) {
|
||||
[this, &octree](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
||||
m_print->throw_if_canceled();
|
||||
m_layers[layer_idx]->make_fills();
|
||||
m_layers[layer_idx]->make_fills(octree.get());
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -428,6 +432,48 @@ void PrintObject::generate_support_material()
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<FillAdaptive_Internal::Octree> PrintObject::prepare_adaptive_infill_data()
|
||||
{
|
||||
float fill_density = 0;
|
||||
float infill_extrusion_width = 0;
|
||||
|
||||
// Compute the average of above parameters over all layers
|
||||
for (size_t layer_idx = 0; layer_idx < this->m_layers.size(); ++layer_idx)
|
||||
{
|
||||
for (size_t region_id = 0; region_id < this->m_layers[layer_idx]->m_regions.size(); ++region_id)
|
||||
{
|
||||
LayerRegion *layerm = this->m_layers[layer_idx]->m_regions[region_id];
|
||||
|
||||
// Check if region_id is used for this layer
|
||||
if(!layerm->fill_surfaces.surfaces.empty()) {
|
||||
const PrintRegionConfig ®ion_config = layerm->region()->config();
|
||||
|
||||
fill_density += region_config.fill_density;
|
||||
infill_extrusion_width += region_config.infill_extrusion_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fill_density /= this->m_layers.size();
|
||||
infill_extrusion_width /= this->m_layers.size();
|
||||
|
||||
if(fill_density <= 0 || infill_extrusion_width <= 0)
|
||||
{
|
||||
return std::unique_ptr<FillAdaptive_Internal::Octree>{};
|
||||
}
|
||||
|
||||
coordf_t line_spacing = infill_extrusion_width / ((fill_density / 100.0f) * 0.333333333f);
|
||||
|
||||
TriangleMesh mesh = this->model_object()->raw_mesh();
|
||||
mesh.transform(m_trafo, true);
|
||||
// Apply XY shift
|
||||
mesh.translate(- unscale<float>(m_center_offset.x()), - unscale<float>(m_center_offset.y()), 0);
|
||||
|
||||
// Center of the first cube in octree
|
||||
Vec3d mesh_origin = mesh.bounding_box().center();
|
||||
return FillAdaptive::build_octree(mesh, line_spacing, mesh_origin);
|
||||
}
|
||||
|
||||
void PrintObject::clear_layers()
|
||||
{
|
||||
for (Layer *l : m_layers)
|
||||
|
Loading…
Reference in New Issue
Block a user