From 0d26df3cf6a2a75973a0c6df235089e12f1195ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 26 Aug 2020 16:51:34 +0200 Subject: [PATCH 01/19] Preparation for new infill --- src/libslic3r/CMakeLists.txt | 2 ++ src/libslic3r/Fill/Fill.cpp | 1 + src/libslic3r/Fill/FillAdaptive.cpp | 19 +++++++++++ src/libslic3r/Fill/FillAdaptive.hpp | 53 +++++++++++++++++++++++++++++ src/libslic3r/Fill/FillBase.cpp | 2 ++ src/libslic3r/Fill/FillBase.hpp | 6 ++++ src/libslic3r/Print.hpp | 8 +++++ src/libslic3r/PrintConfig.cpp | 2 ++ src/libslic3r/PrintConfig.hpp | 3 +- 9 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/libslic3r/Fill/FillAdaptive.cpp create mode 100644 src/libslic3r/Fill/FillAdaptive.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 3d241dd37..09f75c747 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -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 diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 3c16527f0..c948df400 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -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 = this->object()->adaptiveInfillOctree(); // calculate flow spacing for infill pattern generation bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.flow.bridge; diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp new file mode 100644 index 000000000..cb1138598 --- /dev/null +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -0,0 +1,19 @@ +#include "../ClipperUtils.hpp" +#include "../ExPolygon.hpp" +#include "../Surface.hpp" + +#include "FillAdaptive.hpp" + +namespace Slic3r { + +void FillAdaptive::_fill_surface_single( + const FillParams ¶ms, + unsigned int thickness_layers, + const std::pair &direction, + ExPolygon &expolygon, + Polylines &polylines_out) +{ + +} + +} // namespace Slic3r diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp new file mode 100644 index 000000000..e0a97a1b9 --- /dev/null +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -0,0 +1,53 @@ +#ifndef slic3r_FillAdaptive_hpp_ +#define slic3r_FillAdaptive_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; + size_t depth; + CubeProperties properties; + std::vector children; + }; + + struct Octree + { + Cube *root_cube; + Vec3d origin; + }; +}; // namespace FillAdaptive_Internal + +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 &direction, + ExPolygon &expolygon, + Polylines &polylines_out); + + virtual bool no_sort() const { return true; } +}; + +} // namespace Slic3r + +#endif // slic3r_FillAdaptive_hpp_ diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index c760218c0..c1f38dad5 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -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"); } } diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 2e9b64735..9f70b69e0 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -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() {} diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index d436f90bf..02dd6df35 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -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, @@ -194,6 +198,7 @@ public: // Helpers to project custom facets on slices void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector& expolys) const; + FillAdaptive_Internal::Octree* adaptiveInfillOctree() { return m_adapt_fill_octree; } private: // to be called from Print only. friend class Print; @@ -235,6 +240,7 @@ private: void discover_horizontal_shells(); void combine_infill(); void _generate_support_material(); + void prepare_adaptive_infill_data(); // XYZ in scaled coordinates Vec3crd m_size; @@ -255,6 +261,8 @@ private: // so that next call to make_perimeters() performs a union() before computing loops bool m_typed_slices = false; + FillAdaptive_Internal::Octree* m_adapt_fill_octree = nullptr; + std::vector slice_region(size_t region_id, const std::vector &z, SlicingMode mode) const; std::vector slice_modifiers(size_t region_id, const std::vector &z) const; std::vector slice_volumes(const std::vector &z, SlicingMode mode, const std::vector &volumes) const; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 239969a1d..718fae365 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -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(ipStars)); def = this->add("first_layer_acceleration", coFloat); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index b133a2e4e..3726444fa 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -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::g keys_map["hilbertcurve"] = ipHilbertCurve; keys_map["archimedeanchords"] = ipArchimedeanChords; keys_map["octagramspiral"] = ipOctagramSpiral; + keys_map["adaptivecubic"] = ipAdaptiveCubic; } return keys_map; } From 34f38c4a79e426d4a479bdf33644b2cb77ed0eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 26 Aug 2020 18:15:59 +0200 Subject: [PATCH 02/19] Building octree based on distance from mesh --- src/libslic3r/Fill/FillAdaptive.cpp | 86 +++++++++++++++++++++++++++++ src/libslic3r/Fill/FillAdaptive.hpp | 16 ++++++ src/libslic3r/PrintObject.cpp | 23 ++++++++ 3 files changed, 125 insertions(+) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index cb1138598..ce779ad00 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -1,6 +1,8 @@ #include "../ClipperUtils.hpp" #include "../ExPolygon.hpp" #include "../Surface.hpp" +#include "../Geometry.hpp" +#include "../AABBTreeIndirect.hpp" #include "FillAdaptive.hpp" @@ -16,4 +18,88 @@ void FillAdaptive::_fill_surface_single( } +FillAdaptive_Internal::Octree* FillAdaptive::build_octree( + TriangleMesh &triangleMesh, + coordf_t line_spacing, + const BoundingBoxf3 &printer_volume, + const Vec3d &cube_center) +{ + using namespace FillAdaptive_Internal; + + if(line_spacing <= 0) + { + return nullptr; + } + + // The furthest point from center of bed. + double furthest_point = std::sqrt(((printer_volume.size()[0] * printer_volume.size()[0]) / 4.0) + + ((printer_volume.size()[1] * printer_volume.size()[1]) / 4.0) + + (printer_volume.size()[2] * printer_volume.size()[2])); + double max_cube_edge_length = furthest_point * 2; + + std::vector 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 (triangleMesh.its.vertices.empty()) + { + triangleMesh.require_shared_vertices(); + } + + Vec3d rotation = Vec3d(Geometry::deg2rad(225.0), Geometry::deg2rad(215.0), Geometry::deg2rad(30.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(triangleMesh.its.vertices, triangleMesh.its.indices); + Octree *octree = new Octree{new Cube{cube_center, cubes_properties.size() - 1, cubes_properties.back()}, cube_center}; + + FillAdaptive::expand_cube(octree->root_cube, cubes_properties, rotation_matrix, aabbTree, triangleMesh); + + return octree; +} + +void FillAdaptive::expand_cube( + FillAdaptive_Internal::Cube *cube, + const std::vector &cubes_properties, + const Transform3d &rotation_matrix, + const AABBTreeIndirect::Tree3f &distanceTree, + const TriangleMesh &triangleMesh) +{ + using namespace FillAdaptive_Internal; + + if (cube == nullptr || cube->depth == 0) + { + return; + } + + std::vector 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 = (cube->properties.height * cube->properties.height) / 16; + + for (const Vec3d &child_center : child_centers) { + Vec3d child_center_transformed = cube->center + rotation_matrix * (child_center * (cube->properties.edge_length / 4)); + Vec3d closest_point = Vec3d::Zero(); + size_t closest_triangle_idx = 0; + + double distance_squared = AABBTreeIndirect::squared_distance_to_indexed_triangle_set( + triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, + closest_triangle_idx,closest_point); + + if(distance_squared <= cube_radius_squared) { + cube->children.push_back(new Cube{child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1]}); + FillAdaptive::expand_cube(cube->children.back(), cubes_properties, rotation_matrix, distanceTree, triangleMesh); + } + } +} + } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index e0a97a1b9..49c5276a9 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -1,6 +1,8 @@ #ifndef slic3r_FillAdaptive_hpp_ #define slic3r_FillAdaptive_hpp_ +#include "../AABBTreeIndirect.hpp" + #include "FillBase.hpp" namespace Slic3r { @@ -46,6 +48,20 @@ protected: Polylines &polylines_out); virtual bool no_sort() const { return true; } + +public: + static FillAdaptive_Internal::Octree* build_octree( + TriangleMesh &triangleMesh, + coordf_t line_spacing, + const BoundingBoxf3 &printer_volume, + const Vec3d &cube_center); + + static void expand_cube( + FillAdaptive_Internal::Cube *cube, + const std::vector &cubes_properties, + const Transform3d &rotation_matrix, + const AABBTreeIndirect::Tree3f &distanceTree, + const TriangleMesh &triangleMesh); }; } // namespace Slic3r diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index aecf90771..272ee6e81 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -9,6 +9,8 @@ #include "Surface.hpp" #include "Slicing.hpp" #include "Utils.hpp" +#include "AABBTreeIndirect.hpp" +#include "Fill/FillAdaptive.hpp" #include #include @@ -360,6 +362,8 @@ void PrintObject::prepare_infill() } // for each layer #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ + this->prepare_adaptive_infill_data(); + this->set_done(posPrepareInfill); } @@ -428,6 +432,25 @@ void PrintObject::generate_support_material() } } +void PrintObject::prepare_adaptive_infill_data() +{ + float fill_density = this->print()->full_print_config().opt_float("fill_density"); + float infill_extrusion_width = this->print()->full_print_config().opt_float("infill_extrusion_width"); + + coordf_t line_spacing = infill_extrusion_width / ((fill_density / 100.0f) * 0.333333333f); + + BoundingBoxf bed_shape(this->print()->config().bed_shape.values); + BoundingBoxf3 printer_volume(Vec3d(bed_shape.min(0), bed_shape.min(1), 0), + Vec3d(bed_shape.max(0), bed_shape.max(1), this->print()->config().max_print_height)); + + Vec3d model_center = this->model_object()->bounding_box().center(); + model_center(2) = 0.0f; // Set position in Z axis to 0 + // Center of the first cube in octree + + TriangleMesh mesh = this->model_object()->mesh(); + this->m_adapt_fill_octree = FillAdaptive::build_octree(mesh, line_spacing, printer_volume, model_center); +} + void PrintObject::clear_layers() { for (Layer *l : m_layers) From 9f049b26198f49f34539b4ed694bdb417eec5e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 26 Aug 2020 22:18:51 +0200 Subject: [PATCH 03/19] Generating polylines from octree --- src/libslic3r/Fill/FillAdaptive.cpp | 57 +++++++++++++++++++++++++++++ src/libslic3r/Fill/FillAdaptive.hpp | 7 ++++ 2 files changed, 64 insertions(+) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index ce779ad00..cac9c1c3b 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -15,7 +15,64 @@ void FillAdaptive::_fill_surface_single( ExPolygon &expolygon, Polylines &polylines_out) { + Polylines infill_polylines; + this->generate_polylines(this->adapt_fill_octree->root_cube, this->z, this->adapt_fill_octree->origin, infill_polylines); + // Crop all polylines + polylines_out = intersection_pl(infill_polylines, to_polygons(expolygon)); +} + +void FillAdaptive::generate_polylines( + FillAdaptive_Internal::Cube *cube, + double z_position, + const Vec3d &origin, + Polylines &polylines_out) +{ + using namespace FillAdaptive_Internal; + + if(cube == nullptr) + { + return; + } + + double z_diff = std::abs(z_position - cube->center.z()); + + if (z_diff > cube->properties.height / 2) + { + return; + } + + if (z_diff < cube->properties.line_z_distance) + { + Point from( + scale_((cube->properties.diagonal_length / 2) * (cube->properties.line_z_distance - z_diff) / cube->properties.line_z_distance), + scale_(cube->properties.line_xy_distance - ((z_position - (cube->center.z() - cube->properties.line_z_distance)) / sqrt(2)))); + Point to(-from.x(), from.y()); + // Relative to cube center + + float rotation_angle = Geometry::deg2rad(120.0); + + for (int dir_idx = 0; dir_idx < 3; dir_idx++) + { + 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()); + + polylines_out.push_back(Polyline(from_abs, to_abs)); + + from.rotate(rotation_angle); + to.rotate(rotation_angle); + } + } + + for(Cube *child : cube->children) + { + generate_polylines(child, z_position, origin, polylines_out); + } } FillAdaptive_Internal::Octree* FillAdaptive::build_octree( diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index 49c5276a9..9e1a196af 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -33,6 +33,11 @@ namespace FillAdaptive_Internal }; }; // 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: @@ -49,6 +54,8 @@ protected: virtual bool no_sort() const { return true; } + void generate_polylines(FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, Polylines &polylines_out); + public: static FillAdaptive_Internal::Octree* build_octree( TriangleMesh &triangleMesh, From c311b84b212329f04d6ed48305b935db4cc6d498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 26 Aug 2020 23:28:52 +0200 Subject: [PATCH 04/19] Add function for check existence of triangle in define radius --- src/libslic3r/AABBTreeIndirect.hpp | 34 +++++++++++++++++++++++++++++ src/libslic3r/Fill/FillAdaptive.cpp | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/AABBTreeIndirect.hpp b/src/libslic3r/AABBTreeIndirect.hpp index ec9b14a7a..17d918aeb 100644 --- a/src/libslic3r/AABBTreeIndirect.hpp +++ b/src/libslic3r/AABBTreeIndirect.hpp @@ -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::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 +inline bool is_any_triangle_in_radius( + // Indexed triangle set - 3D vertices. + const std::vector &vertices, + // Indexed triangle set - triangular faces, references to vertices. + const std::vector &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 + { 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 diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index cac9c1c3b..ae067e659 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -152,7 +152,7 @@ void FillAdaptive::expand_cube( triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, closest_triangle_idx,closest_point); - if(distance_squared <= cube_radius_squared) { + if(AABBTreeIndirect::is_any_triangle_in_radius(triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, cube_radius_squared)) { cube->children.push_back(new Cube{child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1]}); FillAdaptive::expand_cube(cube->children.back(), cubes_properties, rotation_matrix, distanceTree, triangleMesh); } From c0d21bd2b496bf8b6393cb395cfce169bd857c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 27 Aug 2020 01:59:35 +0200 Subject: [PATCH 05/19] Polylines merging --- src/libslic3r/Fill/FillAdaptive.cpp | 84 ++++++++++++++++++++++++----- src/libslic3r/Fill/FillAdaptive.hpp | 4 +- 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index ae067e659..adc6c0c6f 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -15,18 +15,54 @@ void FillAdaptive::_fill_surface_single( ExPolygon &expolygon, Polylines &polylines_out) { - Polylines infill_polylines; + std::vector infill_polylines(3); this->generate_polylines(this->adapt_fill_octree->root_cube, this->z, this->adapt_fill_octree->origin, infill_polylines); - // Crop all polylines - polylines_out = intersection_pl(infill_polylines, to_polygons(expolygon)); + for (Polylines &infill_polyline : infill_polylines) { + // Crop all polylines + infill_polyline = intersection_pl(infill_polyline, to_polygons(expolygon)); + polylines_out.insert(polylines_out.end(), infill_polyline.begin(), infill_polyline.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_polylines( FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, - Polylines &polylines_out) + std::vector &polylines_out) { using namespace FillAdaptive_Internal; @@ -52,7 +88,7 @@ void FillAdaptive::generate_polylines( float rotation_angle = Geometry::deg2rad(120.0); - for (int dir_idx = 0; dir_idx < 3; dir_idx++) + for (int i = 0; i < 3; i++) { Vec3d offset = cube->center - origin; Point from_abs(from), to_abs(to); @@ -62,7 +98,8 @@ void FillAdaptive::generate_polylines( to_abs.x() += scale_(offset.x()); to_abs.y() += scale_(offset.y()); - polylines_out.push_back(Polyline(from_abs, to_abs)); +// polylines_out[i].push_back(Polyline(from_abs, to_abs)); + this->merge_polylines(polylines_out[i], Line(from_abs, to_abs)); from.rotate(rotation_angle); to.rotate(rotation_angle); @@ -75,6 +112,35 @@ void FillAdaptive::generate_polylines( } } +void FillAdaptive::merge_polylines(Polylines &polylines, const Line &new_line) +{ + int eps = scale_(0.10); + bool modified = false; + + for (Polyline &polyline : polylines) + { + if (std::abs(new_line.a.x() - polyline.points[1].x()) < eps && std::abs(new_line.a.y() - polyline.points[1].y()) < eps) + { + polyline.points[1].x() = new_line.b.x(); + polyline.points[1].y() = new_line.b.y(); + modified = true; + } + + if (std::abs(new_line.b.x() - polyline.points[0].x()) < eps && std::abs(new_line.b.y() - polyline.points[0].y()) < eps) + { + polyline.points[0].x() = new_line.a.x(); + polyline.points[0].y() = new_line.a.y(); + modified = true; + } + } + + if(!modified) + { + polylines.emplace_back(Polyline(new_line.a, new_line.b)); + } +} + + FillAdaptive_Internal::Octree* FillAdaptive::build_octree( TriangleMesh &triangleMesh, coordf_t line_spacing, @@ -145,12 +211,6 @@ void FillAdaptive::expand_cube( for (const Vec3d &child_center : child_centers) { Vec3d child_center_transformed = cube->center + rotation_matrix * (child_center * (cube->properties.edge_length / 4)); - Vec3d closest_point = Vec3d::Zero(); - size_t closest_triangle_idx = 0; - - double distance_squared = AABBTreeIndirect::squared_distance_to_indexed_triangle_set( - triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, - closest_triangle_idx,closest_point); if(AABBTreeIndirect::is_any_triangle_in_radius(triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, cube_radius_squared)) { cube->children.push_back(new Cube{child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1]}); diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index 9e1a196af..b2f4e37b1 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -54,7 +54,9 @@ protected: virtual bool no_sort() const { return true; } - void generate_polylines(FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, Polylines &polylines_out); + void generate_polylines(FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, std::vector &polylines_out); + + void merge_polylines(Polylines &polylines, const Line &new_line); public: static FillAdaptive_Internal::Octree* build_octree( From 14a7fbc9f70755f058d15be76318425537d3ca9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 27 Aug 2020 07:28:43 +0200 Subject: [PATCH 06/19] Switch to smart pointers --- src/libslic3r/Fill/FillAdaptive.cpp | 17 +++++++++-------- src/libslic3r/Fill/FillAdaptive.hpp | 6 +++--- src/libslic3r/Print.hpp | 8 +++----- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index adc6c0c6f..96509923c 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -16,7 +16,7 @@ void FillAdaptive::_fill_surface_single( Polylines &polylines_out) { std::vector infill_polylines(3); - this->generate_polylines(this->adapt_fill_octree->root_cube, this->z, this->adapt_fill_octree->origin, infill_polylines); + this->generate_polylines(this->adapt_fill_octree->root_cube.get(), this->z, this->adapt_fill_octree->origin, infill_polylines); for (Polylines &infill_polyline : infill_polylines) { // Crop all polylines @@ -106,9 +106,9 @@ void FillAdaptive::generate_polylines( } } - for(Cube *child : cube->children) + for(const std::unique_ptr &child : cube->children) { - generate_polylines(child, z_position, origin, polylines_out); + generate_polylines(child.get(), z_position, origin, polylines_out); } } @@ -141,7 +141,7 @@ void FillAdaptive::merge_polylines(Polylines &polylines, const Line &new_line) } -FillAdaptive_Internal::Octree* FillAdaptive::build_octree( +std::unique_ptr FillAdaptive::build_octree( TriangleMesh &triangleMesh, coordf_t line_spacing, const BoundingBoxf3 &printer_volume, @@ -181,9 +181,10 @@ FillAdaptive_Internal::Octree* FillAdaptive::build_octree( Transform3d rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation, Vec3d::Ones(), Vec3d::Ones()); AABBTreeIndirect::Tree3f aabbTree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(triangleMesh.its.vertices, triangleMesh.its.indices); - Octree *octree = new Octree{new Cube{cube_center, cubes_properties.size() - 1, cubes_properties.back()}, cube_center}; + std::unique_ptr octree = std::unique_ptr( + new Octree{std::unique_ptr(new Cube{cube_center, cubes_properties.size() - 1, cubes_properties.back()}), cube_center}); - FillAdaptive::expand_cube(octree->root_cube, cubes_properties, rotation_matrix, aabbTree, triangleMesh); + FillAdaptive::expand_cube(octree->root_cube.get(), cubes_properties, rotation_matrix, aabbTree, triangleMesh); return octree; } @@ -213,8 +214,8 @@ void FillAdaptive::expand_cube( Vec3d child_center_transformed = cube->center + rotation_matrix * (child_center * (cube->properties.edge_length / 4)); if(AABBTreeIndirect::is_any_triangle_in_radius(triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, cube_radius_squared)) { - cube->children.push_back(new Cube{child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1]}); - FillAdaptive::expand_cube(cube->children.back(), cubes_properties, rotation_matrix, distanceTree, triangleMesh); + cube->children.push_back(std::unique_ptr(new Cube{child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1]})); + FillAdaptive::expand_cube(cube->children.back().get(), cubes_properties, rotation_matrix, distanceTree, triangleMesh); } } } diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index b2f4e37b1..fb1f2da8e 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -23,12 +23,12 @@ namespace FillAdaptive_Internal Vec3d center; size_t depth; CubeProperties properties; - std::vector children; + std::vector> children; }; struct Octree { - Cube *root_cube; + std::unique_ptr root_cube; Vec3d origin; }; }; // namespace FillAdaptive_Internal @@ -59,7 +59,7 @@ protected: void merge_polylines(Polylines &polylines, const Line &new_line); public: - static FillAdaptive_Internal::Octree* build_octree( + static std::unique_ptr build_octree( TriangleMesh &triangleMesh, coordf_t line_spacing, const BoundingBoxf3 &printer_volume, diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 02dd6df35..1cc83dbe4 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -11,6 +11,7 @@ #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" #include "GCode/ThumbnailData.hpp" +#include "Fill/FillAdaptive.hpp" #if ENABLE_GCODE_VIEWER #include "GCode/GCodeProcessor.hpp" #endif // ENABLE_GCODE_VIEWER @@ -30,9 +31,6 @@ 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 { @@ -198,7 +196,7 @@ public: // Helpers to project custom facets on slices void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector& expolys) const; - FillAdaptive_Internal::Octree* adaptiveInfillOctree() { return m_adapt_fill_octree; } + FillAdaptive_Internal::Octree* adaptiveInfillOctree() { return m_adapt_fill_octree.get(); } private: // to be called from Print only. friend class Print; @@ -261,7 +259,7 @@ private: // so that next call to make_perimeters() performs a union() before computing loops bool m_typed_slices = false; - FillAdaptive_Internal::Octree* m_adapt_fill_octree = nullptr; + std::unique_ptr m_adapt_fill_octree = nullptr; std::vector slice_region(size_t region_id, const std::vector &z, SlicingMode mode) const; std::vector slice_modifiers(size_t region_id, const std::vector &z) const; From 867681ae56f85e828fb4fc9370d43605c05f1906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 27 Aug 2020 13:04:53 +0200 Subject: [PATCH 07/19] Fix discontinuous extrusion lines for adaptive infill --- src/libslic3r/Fill/FillAdaptive.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 96509923c..a3068989e 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -88,7 +88,7 @@ void FillAdaptive::generate_polylines( float rotation_angle = Geometry::deg2rad(120.0); - for (int i = 0; i < 3; i++) + for (int i = 0; i < polylines_out.size(); i++) { Vec3d offset = cube->center - origin; Point from_abs(from), to_abs(to); @@ -177,7 +177,7 @@ std::unique_ptr FillAdaptive::build_octree( triangleMesh.require_shared_vertices(); } - Vec3d rotation = Vec3d(Geometry::deg2rad(225.0), Geometry::deg2rad(215.0), Geometry::deg2rad(30.0)); + Vec3d rotation = Vec3d(Geometry::deg2rad(225.0), Geometry::deg2rad(215.264), Geometry::deg2rad(30.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(triangleMesh.its.vertices, triangleMesh.its.indices); From 65ba40f0445b938045f9f5e5cfdcf9acba9e4cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Sun, 30 Aug 2020 20:38:07 +0200 Subject: [PATCH 08/19] Fix crash on inconsistent input --- src/libslic3r/Fill/FillAdaptive.cpp | 2 +- src/libslic3r/PrintObject.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index a3068989e..0563b612a 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -149,7 +149,7 @@ std::unique_ptr FillAdaptive::build_octree( { using namespace FillAdaptive_Internal; - if(line_spacing <= 0) + if(line_spacing <= 0 || std::isnan(line_spacing)) { return nullptr; } diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 272ee6e81..43ebf58db 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -434,8 +434,16 @@ void PrintObject::generate_support_material() void PrintObject::prepare_adaptive_infill_data() { - float fill_density = this->print()->full_print_config().opt_float("fill_density"); - float infill_extrusion_width = this->print()->full_print_config().opt_float("infill_extrusion_width"); + const ConfigOptionFloatOrPercent* opt_fill_density = this->print()->full_print_config().option("fill_density"); + const ConfigOptionFloatOrPercent* opt_infill_extrusion_width = this->print()->full_print_config().option("infill_extrusion_width"); + + if(opt_fill_density == nullptr || opt_infill_extrusion_width == nullptr || opt_fill_density->value <= 0 || opt_infill_extrusion_width->value <= 0) + { + return; + } + + float fill_density = opt_fill_density->value; + float infill_extrusion_width = opt_infill_extrusion_width->value; coordf_t line_spacing = infill_extrusion_width / ((fill_density / 100.0f) * 0.333333333f); From 9eeb5e4364f641c30eeb8bf78594455fbf1f50dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 31 Aug 2020 08:49:17 +0200 Subject: [PATCH 09/19] Fix wrong data type --- src/libslic3r/PrintObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 43ebf58db..9d023a095 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -434,7 +434,7 @@ void PrintObject::generate_support_material() void PrintObject::prepare_adaptive_infill_data() { - const ConfigOptionFloatOrPercent* opt_fill_density = this->print()->full_print_config().option("fill_density"); + const ConfigOptionPercent* opt_fill_density = this->print()->full_print_config().option("fill_density"); const ConfigOptionFloatOrPercent* opt_infill_extrusion_width = this->print()->full_print_config().option("infill_extrusion_width"); if(opt_fill_density == nullptr || opt_infill_extrusion_width == nullptr || opt_fill_density->value <= 0 || opt_infill_extrusion_width->value <= 0) From 33121b705a58d00ca80398d99ad5e60e8387a342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 2 Sep 2020 22:53:10 +0200 Subject: [PATCH 10/19] Change in passing octree struct --- src/libslic3r/Fill/Fill.cpp | 4 ++-- src/libslic3r/Layer.hpp | 6 +++++- src/libslic3r/Print.hpp | 9 ++++----- src/libslic3r/PrintObject.cpp | 20 ++++++++++---------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index c948df400..9d468a6aa 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -318,7 +318,7 @@ void export_group_fills_to_svg(const char *path, const std::vector #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,7 +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 = this->object()->adaptiveInfillOctree(); + 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; diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index c104d46da..4c824a109 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -13,6 +13,10 @@ class Layer; class PrintRegion; class PrintObject; +namespace FillAdaptive_Internal { + struct Octree; +}; + class LayerRegion { public: @@ -134,7 +138,7 @@ public: return false; } void make_perimeters(); - void make_fills(); + void make_fills(FillAdaptive_Internal::Octree* adaptive_fill_octree); void make_ironing(); void export_region_slices_to_svg(const char *path) const; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 1cc83dbe4..effb6bde9 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -11,7 +11,6 @@ #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" #include "GCode/ThumbnailData.hpp" -#include "Fill/FillAdaptive.hpp" #if ENABLE_GCODE_VIEWER #include "GCode/GCodeProcessor.hpp" #endif // ENABLE_GCODE_VIEWER @@ -31,6 +30,9 @@ 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 { @@ -196,7 +198,6 @@ public: // Helpers to project custom facets on slices void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector& expolys) const; - FillAdaptive_Internal::Octree* adaptiveInfillOctree() { return m_adapt_fill_octree.get(); } private: // to be called from Print only. friend class Print; @@ -238,7 +239,7 @@ private: void discover_horizontal_shells(); void combine_infill(); void _generate_support_material(); - void prepare_adaptive_infill_data(); + std::unique_ptr prepare_adaptive_infill_data(); // XYZ in scaled coordinates Vec3crd m_size; @@ -259,8 +260,6 @@ private: // so that next call to make_perimeters() performs a union() before computing loops bool m_typed_slices = false; - std::unique_ptr m_adapt_fill_octree = nullptr; - std::vector slice_region(size_t region_id, const std::vector &z, SlicingMode mode) const; std::vector slice_modifiers(size_t region_id, const std::vector &z) const; std::vector slice_volumes(const std::vector &z, SlicingMode mode, const std::vector &volumes) const; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 9d023a095..1699cd5ad 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -362,8 +362,6 @@ void PrintObject::prepare_infill() } // for each layer #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ - this->prepare_adaptive_infill_data(); - this->set_done(posPrepareInfill); } @@ -373,13 +371,15 @@ void PrintObject::infill() this->prepare_infill(); if (this->set_started(posInfill)) { + std::unique_ptr octree = this->prepare_adaptive_infill_data(); + BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start"; tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), - [this](const tbb::blocked_range& range) { + [this, &octree](const tbb::blocked_range& 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()); } } ); @@ -432,14 +432,14 @@ void PrintObject::generate_support_material() } } -void PrintObject::prepare_adaptive_infill_data() +std::unique_ptr PrintObject::prepare_adaptive_infill_data() { const ConfigOptionPercent* opt_fill_density = this->print()->full_print_config().option("fill_density"); const ConfigOptionFloatOrPercent* opt_infill_extrusion_width = this->print()->full_print_config().option("infill_extrusion_width"); if(opt_fill_density == nullptr || opt_infill_extrusion_width == nullptr || opt_fill_density->value <= 0 || opt_infill_extrusion_width->value <= 0) { - return; + return std::unique_ptr{}; } float fill_density = opt_fill_density->value; @@ -448,15 +448,15 @@ void PrintObject::prepare_adaptive_infill_data() coordf_t line_spacing = infill_extrusion_width / ((fill_density / 100.0f) * 0.333333333f); BoundingBoxf bed_shape(this->print()->config().bed_shape.values); - BoundingBoxf3 printer_volume(Vec3d(bed_shape.min(0), bed_shape.min(1), 0), - Vec3d(bed_shape.max(0), bed_shape.max(1), this->print()->config().max_print_height)); + BoundingBoxf3 printer_volume(Vec3d(bed_shape.min.x(), bed_shape.min.y(), 0), + Vec3d(bed_shape.max.x(), bed_shape.max.y(), this->print()->config().max_print_height)); Vec3d model_center = this->model_object()->bounding_box().center(); - model_center(2) = 0.0f; // Set position in Z axis to 0 + model_center.z() = 0.0f; // Set position in Z axis to 0 // Center of the first cube in octree TriangleMesh mesh = this->model_object()->mesh(); - this->m_adapt_fill_octree = FillAdaptive::build_octree(mesh, line_spacing, printer_volume, model_center); + return FillAdaptive::build_octree(mesh, line_spacing, printer_volume, model_center); } void PrintObject::clear_layers() From 2debffc49629b57f8e5751bab4b363d11f7e7e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 07:52:53 +0200 Subject: [PATCH 11/19] Fix tests which expect make_fills without arguments --- src/libslic3r/Layer.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 4c824a109..014d2623a 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -138,6 +138,7 @@ public: return false; } void make_perimeters(); + void make_fills() { this->make_fills(nullptr); }; void make_fills(FillAdaptive_Internal::Octree* adaptive_fill_octree); void make_ironing(); From d09ac41d2c602f58a5bc6b549b53d67c3f1308bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 08:04:05 +0200 Subject: [PATCH 12/19] Octree's first cube depends on model size. --- src/libslic3r/Fill/FillAdaptive.cpp | 21 +++++++++++---------- src/libslic3r/Fill/FillAdaptive.hpp | 3 +-- src/libslic3r/PrintObject.cpp | 9 ++------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 0563b612a..62c4a3af7 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -142,9 +142,8 @@ void FillAdaptive::merge_polylines(Polylines &polylines, const Line &new_line) std::unique_ptr FillAdaptive::build_octree( - TriangleMesh &triangleMesh, + TriangleMesh &triangle_mesh, coordf_t line_spacing, - const BoundingBoxf3 &printer_volume, const Vec3d &cube_center) { using namespace FillAdaptive_Internal; @@ -154,10 +153,11 @@ std::unique_ptr FillAdaptive::build_octree( return nullptr; } - // The furthest point from center of bed. - double furthest_point = std::sqrt(((printer_volume.size()[0] * printer_volume.size()[0]) / 4.0) + - ((printer_volume.size()[1] * printer_volume.size()[1]) / 4.0) + - (printer_volume.size()[2] * printer_volume.size()[2])); + 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 cubes_properties; @@ -172,19 +172,20 @@ std::unique_ptr FillAdaptive::build_octree( cubes_properties.push_back(props); } - if (triangleMesh.its.vertices.empty()) + if (triangle_mesh.its.vertices.empty()) { - triangleMesh.require_shared_vertices(); + triangle_mesh.require_shared_vertices(); } Vec3d rotation = Vec3d(Geometry::deg2rad(225.0), Geometry::deg2rad(215.264), Geometry::deg2rad(30.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(triangleMesh.its.vertices, triangleMesh.its.indices); + AABBTreeIndirect::Tree3f aabbTree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set( + triangle_mesh.its.vertices, triangle_mesh.its.indices); std::unique_ptr octree = std::unique_ptr( new Octree{std::unique_ptr(new Cube{cube_center, cubes_properties.size() - 1, cubes_properties.back()}), cube_center}); - FillAdaptive::expand_cube(octree->root_cube.get(), cubes_properties, rotation_matrix, aabbTree, triangleMesh); + FillAdaptive::expand_cube(octree->root_cube.get(), cubes_properties, rotation_matrix, aabbTree, triangle_mesh); return octree; } diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index fb1f2da8e..c7539df5a 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -60,9 +60,8 @@ protected: public: static std::unique_ptr build_octree( - TriangleMesh &triangleMesh, + TriangleMesh &triangle_mesh, coordf_t line_spacing, - const BoundingBoxf3 &printer_volume, const Vec3d &cube_center); static void expand_cube( diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 1699cd5ad..1236a297f 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -447,16 +447,11 @@ std::unique_ptr PrintObject::prepare_adaptive_inf coordf_t line_spacing = infill_extrusion_width / ((fill_density / 100.0f) * 0.333333333f); - BoundingBoxf bed_shape(this->print()->config().bed_shape.values); - BoundingBoxf3 printer_volume(Vec3d(bed_shape.min.x(), bed_shape.min.y(), 0), - Vec3d(bed_shape.max.x(), bed_shape.max.y(), this->print()->config().max_print_height)); - - Vec3d model_center = this->model_object()->bounding_box().center(); - model_center.z() = 0.0f; // Set position in Z axis to 0 // Center of the first cube in octree + Vec3d model_center = this->model_object()->bounding_box().center(); TriangleMesh mesh = this->model_object()->mesh(); - return FillAdaptive::build_octree(mesh, line_spacing, printer_volume, model_center); + return FillAdaptive::build_octree(mesh, line_spacing, model_center); } void PrintObject::clear_layers() From 398d429ce1913bc7916b0a422b8f1d33f2a20971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 11:56:41 +0200 Subject: [PATCH 13/19] Code cleanup --- src/libslic3r/Fill/FillAdaptive.cpp | 56 +++++++++++++++-------------- src/libslic3r/Fill/FillAdaptive.hpp | 10 ++++-- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 62c4a3af7..91da86b69 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -15,15 +15,20 @@ void FillAdaptive::_fill_surface_single( ExPolygon &expolygon, Polylines &polylines_out) { - std::vector infill_polylines(3); - this->generate_polylines(this->adapt_fill_octree->root_cube.get(), this->z, this->adapt_fill_octree->origin, infill_polylines); + std::vector 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); - for (Polylines &infill_polyline : infill_polylines) { - // Crop all polylines - infill_polyline = intersection_pl(infill_polyline, to_polygons(expolygon)); - polylines_out.insert(polylines_out.end(), infill_polyline.begin(), infill_polyline.end()); + for (Lines &infill_lines : infill_lines_dir) + { + for (const Line &line : infill_lines) + { + polylines_out.emplace_back(line.a, line.b); + } } + // Crop all polylines + polylines_out = intersection_pl(polylines_out, to_polygons(expolygon)); + #ifdef SLIC3R_DEBUG_SLICE_PROCESSING { static int iRuna = 0; @@ -58,11 +63,11 @@ void FillAdaptive::_fill_surface_single( #endif /* SLIC3R_DEBUG */ } -void FillAdaptive::generate_polylines( +void FillAdaptive::generate_infill_lines( FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, - std::vector &polylines_out) + std::vector &dir_lines_out) { using namespace FillAdaptive_Internal; @@ -86,9 +91,8 @@ void FillAdaptive::generate_polylines( Point to(-from.x(), from.y()); // Relative to cube center - float rotation_angle = Geometry::deg2rad(120.0); - - for (int i = 0; i < polylines_out.size(); i++) + 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); @@ -98,8 +102,8 @@ void FillAdaptive::generate_polylines( to_abs.x() += scale_(offset.x()); to_abs.y() += scale_(offset.y()); -// polylines_out[i].push_back(Polyline(from_abs, to_abs)); - this->merge_polylines(polylines_out[i], Line(from_abs, to_abs)); +// lines.emplace_back(from_abs, to_abs); + this->connect_lines(lines, Line(from_abs, to_abs)); from.rotate(rotation_angle); to.rotate(rotation_angle); @@ -108,35 +112,35 @@ void FillAdaptive::generate_polylines( for(const std::unique_ptr &child : cube->children) { - generate_polylines(child.get(), z_position, origin, polylines_out); + generate_infill_lines(child.get(), z_position, origin, dir_lines_out); } } -void FillAdaptive::merge_polylines(Polylines &polylines, const Line &new_line) +void FillAdaptive::connect_lines(Lines &lines, const Line &new_line) { int eps = scale_(0.10); bool modified = false; - for (Polyline &polyline : polylines) + for (Line &line : lines) { - if (std::abs(new_line.a.x() - polyline.points[1].x()) < eps && std::abs(new_line.a.y() - polyline.points[1].y()) < eps) + if (std::abs(new_line.a.x() - line.b.x()) < eps && std::abs(new_line.a.y() - line.b.y()) < eps) { - polyline.points[1].x() = new_line.b.x(); - polyline.points[1].y() = new_line.b.y(); + line.b.x() = new_line.b.x(); + line.b.y() = new_line.b.y(); modified = true; } - if (std::abs(new_line.b.x() - polyline.points[0].x()) < eps && std::abs(new_line.b.y() - polyline.points[0].y()) < eps) + if (std::abs(new_line.b.x() - line.a.x()) < eps && std::abs(new_line.b.y() - line.a.y()) < eps) { - polyline.points[0].x() = new_line.a.x(); - polyline.points[0].y() = new_line.a.y(); + line.a.x() = new_line.a.x(); + line.a.y() = new_line.a.y(); modified = true; } } if(!modified) { - polylines.emplace_back(Polyline(new_line.a, new_line.b)); + lines.push_back(new_line); } } @@ -182,8 +186,8 @@ std::unique_ptr FillAdaptive::build_octree( AABBTreeIndirect::Tree3f aabbTree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set( triangle_mesh.its.vertices, triangle_mesh.its.indices); - std::unique_ptr octree = std::unique_ptr( - new Octree{std::unique_ptr(new Cube{cube_center, cubes_properties.size() - 1, cubes_properties.back()}), cube_center}); + auto octree = std::make_unique( + std::make_unique(cube_center, cubes_properties.size() - 1, cubes_properties.back()), cube_center); FillAdaptive::expand_cube(octree->root_cube.get(), cubes_properties, rotation_matrix, aabbTree, triangle_mesh); @@ -215,7 +219,7 @@ void FillAdaptive::expand_cube( Vec3d child_center_transformed = cube->center + rotation_matrix * (child_center * (cube->properties.edge_length / 4)); if(AABBTreeIndirect::is_any_triangle_in_radius(triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, cube_radius_squared)) { - cube->children.push_back(std::unique_ptr(new Cube{child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1]})); + cube->children.emplace_back(std::make_unique(child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1])); FillAdaptive::expand_cube(cube->children.back().get(), cubes_properties, rotation_matrix, distanceTree, triangleMesh); } } diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index c7539df5a..570318aa4 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -24,12 +24,18 @@ namespace FillAdaptive_Internal size_t depth; CubeProperties properties; std::vector> children; + + Cube(const Vec3d ¢er, size_t depth, const CubeProperties &properties) + : center(center), depth(depth), properties(properties) {} }; struct Octree { std::unique_ptr root_cube; Vec3d origin; + + Octree(std::unique_ptr rootCube, const Vec3d &origin) + : root_cube(std::move(rootCube)), origin(origin) {} }; }; // namespace FillAdaptive_Internal @@ -54,9 +60,9 @@ protected: virtual bool no_sort() const { return true; } - void generate_polylines(FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, std::vector &polylines_out); + void generate_infill_lines(FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, std::vector &dir_lines_out); - void merge_polylines(Polylines &polylines, const Line &new_line); + void connect_lines(Lines &lines, const Line &new_line); public: static std::unique_ptr build_octree( From 03e103fcc89383866d7275fb583579fefee7dc8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 13:05:28 +0200 Subject: [PATCH 14/19] Connect infill to perimeters --- src/libslic3r/Fill/FillAdaptive.cpp | 35 ++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 91da86b69..d3246dc18 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -3,6 +3,7 @@ #include "../Surface.hpp" #include "../Geometry.hpp" #include "../AABBTreeIndirect.hpp" +#include "../ShortestPath.hpp" #include "FillAdaptive.hpp" @@ -15,19 +16,47 @@ void FillAdaptive::_fill_surface_single( ExPolygon &expolygon, Polylines &polylines_out) { + // Store grouped lines by its direction (multiple of 120°) std::vector 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); + 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) { - polylines_out.emplace_back(line.a, line.b); + all_polylines.emplace_back(line.a, line.b); } } - // Crop all polylines - polylines_out = intersection_pl(polylines_out, to_polygons(expolygon)); + 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); + } + } + + 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 { From 000987451a6a537d752e5c683dd7f69018273dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 14:28:25 +0200 Subject: [PATCH 15/19] Fix bug in lines merging --- src/libslic3r/Fill/FillAdaptive.cpp | 30 +++++++++++++---------------- src/libslic3r/Fill/FillAdaptive.hpp | 2 +- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index d3246dc18..030debad6 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -145,35 +145,31 @@ void FillAdaptive::generate_infill_lines( } } -void FillAdaptive::connect_lines(Lines &lines, const Line &new_line) +void FillAdaptive::connect_lines(Lines &lines, Line new_line) { int eps = scale_(0.10); - bool modified = false; - - for (Line &line : lines) + for (size_t i = 0; i < lines.size(); ++i) { - if (std::abs(new_line.a.x() - line.b.x()) < eps && std::abs(new_line.a.y() - line.b.y()) < eps) + if (std::abs(new_line.a.x() - lines[i].b.x()) < eps && std::abs(new_line.a.y() - lines[i].b.y()) < eps) { - line.b.x() = new_line.b.x(); - line.b.y() = new_line.b.y(); - modified = true; + new_line.a = lines[i].a; + lines.erase(lines.begin() + i); + --i; + continue; } - if (std::abs(new_line.b.x() - line.a.x()) < eps && std::abs(new_line.b.y() - line.a.y()) < eps) + if (std::abs(new_line.b.x() - lines[i].a.x()) < eps && std::abs(new_line.b.y() - lines[i].a.y()) < eps) { - line.a.x() = new_line.a.x(); - line.a.y() = new_line.a.y(); - modified = true; + new_line.b = lines[i].b; + lines.erase(lines.begin() + i); + --i; + continue; } } - if(!modified) - { - lines.push_back(new_line); - } + lines.emplace_back(new_line.a, new_line.b); } - std::unique_ptr FillAdaptive::build_octree( TriangleMesh &triangle_mesh, coordf_t line_spacing, diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index 570318aa4..44a2536f0 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -62,7 +62,7 @@ protected: void generate_infill_lines(FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, std::vector &dir_lines_out); - void connect_lines(Lines &lines, const Line &new_line); + static void connect_lines(Lines &lines, Line new_line); public: static std::unique_ptr build_octree( From acedb66cdc5abb6d5f9c2d575eefb9a4f834a00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 16:08:40 +0200 Subject: [PATCH 16/19] Change to using raw_mesh instead of mesh --- src/libslic3r/PrintObject.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 1236a297f..d9c533939 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -447,11 +447,14 @@ std::unique_ptr PrintObject::prepare_adaptive_inf coordf_t line_spacing = infill_extrusion_width / ((fill_density / 100.0f) * 0.333333333f); - // Center of the first cube in octree - Vec3d model_center = this->model_object()->bounding_box().center(); + TriangleMesh mesh = this->model_object()->raw_mesh(); + mesh.transform(m_trafo, true); + // Apply XY shift + mesh.translate(- unscale(m_center_offset.x()), - unscale(m_center_offset.y()), 0); - TriangleMesh mesh = this->model_object()->mesh(); - return FillAdaptive::build_octree(mesh, line_spacing, model_center); + // 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() From aca212c5bca2bd8373c212c23e038c618a02a47e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 19:21:55 +0200 Subject: [PATCH 17/19] Octree representation rework --- src/libslic3r/Fill/FillAdaptive.cpp | 51 ++++++++++++++++++----------- src/libslic3r/Fill/FillAdaptive.hpp | 44 ++++++++++++++----------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 030debad6..577ba7e61 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -18,7 +18,10 @@ void FillAdaptive::_fill_surface_single( { // Store grouped lines by its direction (multiple of 120°) std::vector 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->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); @@ -96,7 +99,9 @@ void FillAdaptive::generate_infill_lines( FillAdaptive_Internal::Cube *cube, double z_position, const Vec3d &origin, - std::vector &dir_lines_out) + std::vector &dir_lines_out, + const std::vector &cubes_properties, + int depth) { using namespace FillAdaptive_Internal; @@ -107,16 +112,16 @@ void FillAdaptive::generate_infill_lines( double z_diff = std::abs(z_position - cube->center.z()); - if (z_diff > cube->properties.height / 2) + if (z_diff > cubes_properties[depth].height / 2) { return; } - if (z_diff < cube->properties.line_z_distance) + if (z_diff < cubes_properties[depth].line_z_distance) { Point from( - scale_((cube->properties.diagonal_length / 2) * (cube->properties.line_z_distance - z_diff) / cube->properties.line_z_distance), - scale_(cube->properties.line_xy_distance - ((z_position - (cube->center.z() - cube->properties.line_z_distance)) / sqrt(2)))); + 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 @@ -141,7 +146,10 @@ void FillAdaptive::generate_infill_lines( for(const std::unique_ptr &child : cube->children) { - generate_infill_lines(child.get(), z_position, origin, dir_lines_out); + if(child != nullptr) + { + generate_infill_lines(child.get(), z_position, origin, dir_lines_out, cubes_properties, depth - 1); + } } } @@ -206,15 +214,14 @@ std::unique_ptr FillAdaptive::build_octree( triangle_mesh.require_shared_vertices(); } - Vec3d rotation = Vec3d(Geometry::deg2rad(225.0), Geometry::deg2rad(215.264), Geometry::deg2rad(30.0)); + 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( - std::make_unique(cube_center, cubes_properties.size() - 1, cubes_properties.back()), cube_center); + auto octree = std::make_unique(std::make_unique(cube_center), cube_center, cubes_properties); - FillAdaptive::expand_cube(octree->root_cube.get(), cubes_properties, rotation_matrix, aabbTree, triangle_mesh); + FillAdaptive::expand_cube(octree->root_cube.get(), cubes_properties, rotation_matrix, aabbTree, triangle_mesh, cubes_properties.size() - 1); return octree; } @@ -223,12 +230,12 @@ void FillAdaptive::expand_cube( FillAdaptive_Internal::Cube *cube, const std::vector &cubes_properties, const Transform3d &rotation_matrix, - const AABBTreeIndirect::Tree3f &distanceTree, - const TriangleMesh &triangleMesh) + const AABBTreeIndirect::Tree3f &distance_tree, + const TriangleMesh &triangle_mesh, int depth) { using namespace FillAdaptive_Internal; - if (cube == nullptr || cube->depth == 0) + if (cube == nullptr || depth == 0) { return; } @@ -238,14 +245,18 @@ void FillAdaptive::expand_cube( Vec3d( 1, 1, 1), Vec3d(-1, 1, 1), Vec3d( 1, -1, 1), Vec3d( 1, 1, -1) }; - double cube_radius_squared = (cube->properties.height * cube->properties.height) / 16; + double cube_radius_squared = (cubes_properties[depth].height * cubes_properties[depth].height) / 16; - for (const Vec3d &child_center : child_centers) { - Vec3d child_center_transformed = cube->center + rotation_matrix * (child_center * (cube->properties.edge_length / 4)); + 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(triangleMesh.its.vertices, triangleMesh.its.indices, distanceTree, child_center_transformed, cube_radius_squared)) { - cube->children.emplace_back(std::make_unique(child_center_transformed, cube->depth - 1, cubes_properties[cube->depth - 1])); - FillAdaptive::expand_cube(cube->children.back().get(), cubes_properties, rotation_matrix, distanceTree, triangleMesh); + 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(child_center_transformed); + FillAdaptive::expand_cube(cube->children[i].get(), cubes_properties, rotation_matrix, distance_tree, triangle_mesh, depth - 1); } } } diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index 44a2536f0..14694b766 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -21,21 +21,18 @@ namespace FillAdaptive_Internal struct Cube { Vec3d center; - size_t depth; - CubeProperties properties; - std::vector> children; - - Cube(const Vec3d ¢er, size_t depth, const CubeProperties &properties) - : center(center), depth(depth), properties(properties) {} + std::unique_ptr children[8] = {}; + Cube(const Vec3d ¢er) : center(center) {} }; struct Octree { std::unique_ptr root_cube; Vec3d origin; + std::vector cubes_properties; - Octree(std::unique_ptr rootCube, const Vec3d &origin) - : root_cube(std::move(rootCube)), origin(origin) {} + Octree(std::unique_ptr rootCube, const Vec3d &origin, const std::vector &cubes_properties) + : root_cube(std::move(rootCube)), origin(origin), cubes_properties(cubes_properties) {} }; }; // namespace FillAdaptive_Internal @@ -52,30 +49,37 @@ public: protected: virtual Fill* clone() const { return new FillAdaptive(*this); }; virtual void _fill_surface_single( - const FillParams ¶ms, + const FillParams ¶ms, unsigned int thickness_layers, - const std::pair &direction, - ExPolygon &expolygon, + const std::pair &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 &dir_lines_out); + void generate_infill_lines( + FillAdaptive_Internal::Cube *cube, + double z_position, + const Vec3d & origin, + std::vector & dir_lines_out, + const std::vector &cubes_properties, + int depth); static void connect_lines(Lines &lines, Line new_line); public: static std::unique_ptr build_octree( - TriangleMesh &triangle_mesh, - coordf_t line_spacing, - const Vec3d &cube_center); + TriangleMesh &triangle_mesh, + coordf_t line_spacing, + const Vec3d & cube_center); static void expand_cube( - FillAdaptive_Internal::Cube *cube, - const std::vector &cubes_properties, - const Transform3d &rotation_matrix, - const AABBTreeIndirect::Tree3f &distanceTree, - const TriangleMesh &triangleMesh); + FillAdaptive_Internal::Cube *cube, + const std::vector &cubes_properties, + const Transform3d & rotation_matrix, + const AABBTreeIndirect::Tree3f &distance_tree, + const TriangleMesh & triangle_mesh, + int depth); }; } // namespace Slic3r From 5633526ecfa9215180a6009c4c300cbedf24fa83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 3 Sep 2020 23:15:46 +0200 Subject: [PATCH 18/19] Enable changing adaptive infill density for different objects --- src/libslic3r/PrintObject.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index d9c533939..167be8a36 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -434,17 +434,34 @@ void PrintObject::generate_support_material() std::unique_ptr PrintObject::prepare_adaptive_infill_data() { - const ConfigOptionPercent* opt_fill_density = this->print()->full_print_config().option("fill_density"); - const ConfigOptionFloatOrPercent* opt_infill_extrusion_width = this->print()->full_print_config().option("infill_extrusion_width"); + float fill_density = 0; + float infill_extrusion_width = 0; - if(opt_fill_density == nullptr || opt_infill_extrusion_width == nullptr || opt_fill_density->value <= 0 || opt_infill_extrusion_width->value <= 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{}; } - float fill_density = opt_fill_density->value; - float infill_extrusion_width = opt_infill_extrusion_width->value; - coordf_t line_spacing = infill_extrusion_width / ((fill_density / 100.0f) * 0.333333333f); TriangleMesh mesh = this->model_object()->raw_mesh(); From 5e9399247c414dc8b41db9b8ab8622754a0209eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 7 Sep 2020 09:14:06 +0200 Subject: [PATCH 19/19] Check if exist any boundary polyline --- src/libslic3r/Fill/FillAdaptive.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 577ba7e61..bf9cd7f9d 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -51,13 +51,19 @@ void FillAdaptive::_fill_surface_single( 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 { + } + else + { non_boundary_polylines.push_back(polyline); } } - boundary_polylines = chain_polylines(boundary_polylines); - FillAdaptive::connect_infill(std::move(boundary_polylines), expolygon, polylines_out, this->spacing, params); + 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()); }