diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 6d5f18fc6..6f5b26420 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -67,8 +67,8 @@ add_library(libslic3r STATIC Fill/FillPlanePath.hpp Fill/FillLine.cpp Fill/FillLine.hpp - Fill/FillRectilinear.cpp - Fill/FillRectilinear.hpp + Fill/FillLightning.cpp + Fill/FillLightning.hpp Fill/Lightning/DistanceField.cpp Fill/Lightning/DistanceField.hpp Fill/Lightning/Generator.cpp @@ -77,6 +77,8 @@ add_library(libslic3r STATIC Fill/Lightning/Layer.hpp Fill/Lightning/TreeNode.cpp Fill/Lightning/TreeNode.hpp + Fill/FillRectilinear.cpp + Fill/FillRectilinear.hpp Flow.cpp Flow.hpp format.hpp diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 52653f975..7ca0699c0 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -19,6 +19,7 @@ #include "FillLine.hpp" #include "FillRectilinear.hpp" #include "FillAdaptive.hpp" +#include "FillLightning.hpp" // #define INFILL_DEBUG_OUTPUT @@ -45,6 +46,9 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipAdaptiveCubic: return new FillAdaptive::Filler(); case ipSupportCubic: return new FillAdaptive::Filler(); case ipSupportBase: return new FillSupportBase(); +#if HAS_LIGHTNING_INFILL + case ipLightning: return new FillLightning::Filler(); +#endif // HAS_LIGHTNING_INFILL default: throw Slic3r::InvalidArgument("unknown type"); } } diff --git a/src/libslic3r/Fill/FillLightning.cpp b/src/libslic3r/Fill/FillLightning.cpp new file mode 100644 index 000000000..52c3ce4c5 --- /dev/null +++ b/src/libslic3r/Fill/FillLightning.cpp @@ -0,0 +1,28 @@ +#include "../Print.hpp" + +#include "FillLightning.hpp" +#include "Lightning/Generator.hpp" + +#include +#include +#include +#include + +namespace Slic3r::FillLightning { + +Polylines Filler::fill_surface(const Surface *surface, const FillParams ¶ms) +{ + const Layer &layer = generator->getTreesForLayer(this->layer_id); + return layer.convertToLines(to_polygons(surface->expolygon), generator->infilll_extrusion_width()); +} + +void GeneratorDeleter::operator()(Generator *p) { + delete p; +} + +GeneratorPtr build_generator(const PrintObject &print_object) +{ + return GeneratorPtr(new Generator(print_object)); +} + +} // namespace Slic3r::FillAdaptive diff --git a/src/libslic3r/Fill/FillLightning.hpp b/src/libslic3r/Fill/FillLightning.hpp new file mode 100644 index 000000000..b4e7e35f1 --- /dev/null +++ b/src/libslic3r/Fill/FillLightning.hpp @@ -0,0 +1,36 @@ +#ifndef slic3r_FillLightning_hpp_ +#define slic3r_FillLightning_hpp_ + +#include "FillBase.hpp" + +namespace Slic3r { + +class PrintObject; + +namespace FillLightning { + +class Generator; +// To keep the definition of Octree opaque, we have to define a custom deleter. +struct GeneratorDeleter { void operator()(Generator *p); }; +using GeneratorPtr = std::unique_ptr; + +GeneratorPtr build_generator(const PrintObject &print_object); + +class Filler : public Slic3r::Fill +{ +public: + ~Filler() override = default; + + Generator *generator { nullptr }; +protected: + Fill* clone() const override { return new Filler(*this); } + // Perform the fill. + Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; + // Let the G-code export reoder the infill lines. + bool no_sort() const override { return false; } +}; + +} // namespace FillAdaptive +} // namespace Slic3r + +#endif // slic3r_FillLightning_hpp_ diff --git a/src/libslic3r/Fill/Lightning/DistanceField.cpp b/src/libslic3r/Fill/Lightning/DistanceField.cpp index 0a731915d..125da9222 100644 --- a/src/libslic3r/Fill/Lightning/DistanceField.cpp +++ b/src/libslic3r/Fill/Lightning/DistanceField.cpp @@ -4,12 +4,12 @@ #include "DistanceField.hpp" //Class we're implementing. #include "../FillRectilinear.hpp" -namespace Slic3r +namespace Slic3r::FillLightning { constexpr coord_t radius_per_cell_size = 6; // The cell-size should be small compared to the radius, but not so small as to be inefficient. -LightningDistanceField::LightningDistanceField(const coord_t& radius, const Polygons& current_outline, const Polygons& current_overhang) : +DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outline, const Polygons& current_overhang) : m_cell_size(radius / radius_per_cell_size), m_supporting_radius(radius) { @@ -44,7 +44,7 @@ LightningDistanceField::LightningDistanceField(const coord_t& radius, const Poly } } -void LightningDistanceField::update(const Point& to_node, const Point& added_leaf) +void DistanceField::update(const Point& to_node, const Point& added_leaf) { Vec2d v = (added_leaf - to_node).cast(); auto l2 = v.squaredNorm(); @@ -95,4 +95,4 @@ void LightningDistanceField::update(const Point& to_node, const Point& added_lea } } -} // namespace Slic3r +} // namespace Slic3r::FillLightning diff --git a/src/libslic3r/Fill/Lightning/DistanceField.hpp b/src/libslic3r/Fill/Lightning/DistanceField.hpp index 9d761a03b..6e550a7e2 100644 --- a/src/libslic3r/Fill/Lightning/DistanceField.hpp +++ b/src/libslic3r/Fill/Lightning/DistanceField.hpp @@ -4,7 +4,7 @@ #ifndef LIGHTNING_DISTANCE_FIELD_H #define LIGHTNING_DISTANCE_FIELD_H -namespace Slic3r +namespace Slic3r::FillLightning { /*! @@ -15,7 +15,7 @@ namespace Slic3r * maintains how far it is removed from the edge, which is used to determine * how it gets supported by Lightning Infill. */ -class LightningDistanceField +class DistanceField { public: /*! @@ -26,7 +26,7 @@ public: * \param current_overhang The overhang that needs to be supported on this * layer. */ - LightningDistanceField(const coord_t& radius, const Polygons& current_outline, const Polygons& current_overhang); + DistanceField(const coord_t& radius, const Polygons& current_outline, const Polygons& current_overhang); /*! * Gets the next unsupported location to be supported by a new branch. @@ -92,6 +92,6 @@ protected: std::unordered_map::iterator, PointHash> m_unsupported_points_grid; }; -} // namespace Slic3r +} // namespace Slic3r::FillLightning #endif //LIGHTNING_DISTANCE_FIELD_H diff --git a/src/libslic3r/Fill/Lightning/Generator.cpp b/src/libslic3r/Fill/Lightning/Generator.cpp index dfe0d9e35..5d935b104 100644 --- a/src/libslic3r/Fill/Lightning/Generator.cpp +++ b/src/libslic3r/Fill/Lightning/Generator.cpp @@ -20,12 +20,12 @@ * - Make a pass with Arachne over the output. Somehow. * - Generate all to-be-supported points at once instead of sequentially: See branch interlocking_gen PolygonUtils::spreadDots (Or work with sparse grids.) * - Lots of magic values ... to many to parameterize. But are they the best? - * - Move more complex computations from LightningGenerator constructor to elsewhere. + * - Move more complex computations from Generator constructor to elsewhere. */ -using namespace Slic3r; +namespace Slic3r::FillLightning { -LightningGenerator::LightningGenerator(const PrintObject &print_object) +Generator::Generator(const PrintObject &print_object) { const PrintConfig &print_config = print_object.print()->config(); const PrintObjectConfig &object_config = print_object.config(); @@ -51,7 +51,7 @@ LightningGenerator::LightningGenerator(const PrintObject &print_object) generateTrees(print_object); } -void LightningGenerator::generateInitialInternalOverhangs(const PrintObject &print_object) +void Generator::generateInitialInternalOverhangs(const PrintObject &print_object) { m_overhang_per_layer.resize(print_object.layers().size()); const float infill_wall_offset = - m_infill_extrusion_width; @@ -73,13 +73,13 @@ void LightningGenerator::generateInitialInternalOverhangs(const PrintObject &pri } } -const LightningLayer& LightningGenerator::getTreesForLayer(const size_t& layer_id) const +const Layer& Generator::getTreesForLayer(const size_t& layer_id) const { assert(layer_id < m_lightning_layers.size()); return m_lightning_layers[layer_id]; } -void LightningGenerator::generateTrees(const PrintObject &print_object) +void Generator::generateTrees(const PrintObject &print_object) { m_lightning_layers.resize(print_object.layers().size()); const coord_t infill_wall_offset = - m_infill_extrusion_width; @@ -101,11 +101,11 @@ void LightningGenerator::generateTrees(const PrintObject &print_object) // For-each layer from top to bottom: for (int layer_id = top_layer_id; layer_id >= 0; layer_id--) { - LightningLayer& current_lightning_layer = m_lightning_layers[layer_id]; + Layer& current_lightning_layer = m_lightning_layers[layer_id]; Polygons& current_outlines = infill_outlines[layer_id]; // register all trees propagated from the previous layer as to-be-reconnected - std::vector to_be_reconnected_tree_roots = current_lightning_layer.tree_roots; + std::vector to_be_reconnected_tree_roots = current_lightning_layer.tree_roots; current_lightning_layer.generateNewTrees(m_overhang_per_layer[layer_id], current_outlines, outlines_locator, m_supporting_radius, m_wall_supporting_radius); current_lightning_layer.reconnectRoots(to_be_reconnected_tree_roots, current_outlines, outlines_locator, m_supporting_radius, m_wall_supporting_radius); @@ -118,8 +118,10 @@ void LightningGenerator::generateTrees(const PrintObject &print_object) outlines_locator.set_bbox(get_extents(below_outlines).inflated(SCALED_EPSILON)); outlines_locator.create(below_outlines, locator_cell_size); - std::vector& lower_trees = m_lightning_layers[layer_id - 1].tree_roots; + std::vector& lower_trees = m_lightning_layers[layer_id - 1].tree_roots; for (auto& tree : current_lightning_layer.tree_roots) tree->propagateToNextLayer(lower_trees, below_outlines, outlines_locator, m_prune_length, m_straightening_max_distance, locator_cell_size / 2); } } + +} // namespace Slic3r::FillLightning diff --git a/src/libslic3r/Fill/Lightning/Generator.hpp b/src/libslic3r/Fill/Lightning/Generator.hpp index 7de05d203..c44ecfe7a 100644 --- a/src/libslic3r/Fill/Lightning/Generator.hpp +++ b/src/libslic3r/Fill/Lightning/Generator.hpp @@ -14,6 +14,9 @@ namespace Slic3r { class PrintObject; +namespace FillLightning +{ + /*! * Generates the Lightning Infill pattern. * @@ -31,7 +34,7 @@ class PrintObject; * Printing of Hollowed Objects" by Tricard, Claux and Lefebvre: * https://www.researchgate.net/publication/333808588_Ribbed_Support_Vaults_for_3D_Printing_of_Hollowed_Objects */ -class LightningGenerator // "Just like Nicola used to make!" +class Generator // "Just like Nicola used to make!" { public: /*! @@ -42,7 +45,7 @@ public: * already be calculated at this point. * \param mesh The mesh to generate infill for. */ - LightningGenerator(const PrintObject &print_object); + Generator(const PrintObject &print_object); /*! * Get a tree of paths generated for a certain layer of the mesh. @@ -53,7 +56,9 @@ public: * \return A tree structure representing paths to print to create the * Lightning Infill pattern. */ - const LightningLayer& getTreesForLayer(const size_t& layer_id) const; + const Layer& getTreesForLayer(const size_t& layer_id) const; + + float infilll_extrusion_width() const { return m_infill_extrusion_width; } protected: /*! @@ -118,9 +123,10 @@ protected: * * This is generated by \ref generateTrees. */ - std::vector m_lightning_layers; + std::vector m_lightning_layers; }; +} // namespace FillLightning } // namespace Slic3r #endif // LIGHTNING_GENERATOR_H diff --git a/src/libslic3r/Fill/Lightning/Layer.cpp b/src/libslic3r/Fill/Lightning/Layer.cpp index 62f1617f9..19bf7ec48 100644 --- a/src/libslic3r/Fill/Lightning/Layer.cpp +++ b/src/libslic3r/Fill/Lightning/Layer.cpp @@ -10,9 +10,9 @@ #include "../../Geometry.hpp" -using namespace Slic3r; +namespace Slic3r::FillLightning { -coord_t LightningLayer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location) +coord_t Layer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location) { return coord_t((boundary_loc - unsupported_location).cast().norm()); } @@ -23,16 +23,16 @@ Point GroundingLocation::p() const return tree_node ? tree_node->getLocation() : *boundary_location; } -void LightningLayer::fillLocator(SparseLightningTreeNodeGrid &tree_node_locator) +void Layer::fillLocator(SparseNodeGrid &tree_node_locator) { - std::function add_node_to_locator_func = [&tree_node_locator](LightningTreeNodeSPtr node) { + std::function add_node_to_locator_func = [&tree_node_locator](NodeSPtr node) { tree_node_locator.insert(std::make_pair(Point(node->getLocation().x() / locator_cell_size, node->getLocation().y() / locator_cell_size), node)); }; for (auto& tree : tree_roots) tree->visitNodes(add_node_to_locator_func); } -void LightningLayer::generateNewTrees +void Layer::generateNewTrees ( const Polygons& current_overhang, const Polygons& current_outlines, @@ -41,9 +41,9 @@ void LightningLayer::generateNewTrees const coord_t wall_supporting_radius ) { - LightningDistanceField distance_field(supporting_radius, current_outlines, current_overhang); + DistanceField distance_field(supporting_radius, current_outlines, current_overhang); - SparseLightningTreeNodeGrid tree_node_locator; + SparseNodeGrid tree_node_locator; fillLocator(tree_node_locator); // Until no more points need to be added to support all: @@ -53,8 +53,8 @@ void LightningLayer::generateNewTrees GroundingLocation grounding_loc = getBestGroundingLocation( unsupported_location, current_outlines, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator); - LightningTreeNodeSPtr new_parent; - LightningTreeNodeSPtr new_child; + NodeSPtr new_parent; + NodeSPtr new_child; this->attach(unsupported_location, grounding_loc, new_child, new_parent); tree_node_locator.insert(std::make_pair(Point(new_child->getLocation().x() / locator_cell_size, new_child->getLocation().y() / locator_cell_size), new_child)); if (new_parent) @@ -93,15 +93,15 @@ static bool polygonCollidesWithLineSegment(const Point from, const Point to, con return visitor.intersect; } -GroundingLocation LightningLayer::getBestGroundingLocation +GroundingLocation Layer::getBestGroundingLocation ( const Point& unsupported_location, const Polygons& current_outlines, const EdgeGrid::Grid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius, - const SparseLightningTreeNodeGrid& tree_node_locator, - const LightningTreeNodeSPtr& exclude_tree + const SparseNodeGrid& tree_node_locator, + const NodeSPtr& exclude_tree ) { // Closest point on current_outlines to unsupported_location: @@ -123,7 +123,7 @@ GroundingLocation LightningLayer::getBestGroundingLocation const auto within_dist = coord_t((node_location - unsupported_location).cast().norm()); - LightningTreeNodeSPtr sub_tree{ nullptr }; + NodeSPtr sub_tree{ nullptr }; coord_t current_dist = getWeightedDistance(node_location, unsupported_location); if (current_dist >= wall_supporting_radius) { // Only reconnect tree roots to other trees if they are not already close to the outlines. const coord_t search_radius = std::min(current_dist, within_dist); @@ -154,15 +154,15 @@ GroundingLocation LightningLayer::getBestGroundingLocation GroundingLocation{ sub_tree, std::optional() }; } -bool LightningLayer::attach( +bool Layer::attach( const Point& unsupported_location, const GroundingLocation& grounding_loc, - LightningTreeNodeSPtr& new_child, - LightningTreeNodeSPtr& new_root) + NodeSPtr& new_child, + NodeSPtr& new_root) { // Update trees & distance fields. if (grounding_loc.boundary_location) { - new_root = LightningTreeNode::create(grounding_loc.p(), std::make_optional(grounding_loc.p())); + new_root = Node::create(grounding_loc.p(), std::make_optional(grounding_loc.p())); new_child = new_root->addChild(unsupported_location); tree_roots.push_back(new_root); return true; @@ -172,9 +172,9 @@ bool LightningLayer::attach( } } -void LightningLayer::reconnectRoots +void Layer::reconnectRoots ( - std::vector& to_be_reconnected_tree_roots, + std::vector& to_be_reconnected_tree_roots, const Polygons& current_outlines, const EdgeGrid::Grid& outline_locator, const coord_t supporting_radius, @@ -183,7 +183,7 @@ void LightningLayer::reconnectRoots { constexpr coord_t tree_connecting_ignore_offset = 100; - SparseLightningTreeNodeGrid tree_node_locator; + SparseNodeGrid tree_node_locator; fillLocator(tree_node_locator); const coord_t within_max_dist = outline_locator.resolution() * 2; @@ -198,8 +198,8 @@ void LightningLayer::reconnectRoots { Point new_root_pt; // Find an intersection of the line segment from root_ptr->getLocation() to ground_loc, at within_max_dist from ground_loc. - if (lineSegmentPolygonsIntersection(root_ptr->getLocation(), ground_loc, current_outlines, outline_locator, new_root_pt, within_max_dist)) { - auto new_root = LightningTreeNode::create(new_root_pt, new_root_pt); + if (lineSegmentPolygonsIntersection(root_ptr->getLocation(), ground_loc, outline_locator, new_root_pt, within_max_dist)) { + auto new_root = Node::create(new_root_pt, new_root_pt); root_ptr->addChild(new_root); new_root->reroot(); @@ -228,7 +228,7 @@ void LightningLayer::reconnectRoots if (ground.boundary_location.value() == root_ptr->getLocation()) continue; // Already on the boundary. - auto new_root = LightningTreeNode::create(ground.p(), ground.p()); + auto new_root = Node::create(ground.p(), ground.p()); auto attach_ptr = root_ptr->closestNode(new_root->getLocation()); attach_ptr->reroot(); @@ -375,14 +375,13 @@ static unsigned int moveInside(const Polygons& polygons, Point& from, int distan } // Returns 'added someting'. -Polygons LightningLayer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const +Polylines Layer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const { - Polygons result_lines; if (tree_roots.empty()) - return result_lines; + return {}; - for (const auto& tree : tree_roots) - { + Polygons result_lines; + for (const auto& tree : tree_roots) { // If even the furthest location in the tree is inside the polygon, the entire tree must be inside of the polygon. // (Don't take the root as that may be on the edge and cause rounding errors to register as 'outside'.) constexpr coord_t epsilon = 5; @@ -393,13 +392,12 @@ Polygons LightningLayer::convertToLines(const Polygons& limit_to_outline, const } // TODO: allow for polylines! - Polygons split_lines; - for (Polygon &line : result_lines) - { - if (line.size() <= 1) continue; + Polylines split_lines; + for (Polygon &line : result_lines) { + if (line.size() <= 1) + continue; Point last = line[0]; - for (size_t point_idx = 1; point_idx < line.size(); point_idx++) - { + for (size_t point_idx = 1; point_idx < line.size(); point_idx++) { Point here = line[point_idx]; split_lines.push_back({ last, here }); last = here; @@ -408,3 +406,5 @@ Polygons LightningLayer::convertToLines(const Polygons& limit_to_outline, const return split_lines; } + +} // namespace Slic3r::Lightning diff --git a/src/libslic3r/Fill/Lightning/Layer.hpp b/src/libslic3r/Fill/Lightning/Layer.hpp index 6f68d323f..7ef5eaec1 100644 --- a/src/libslic3r/Fill/Lightning/Layer.hpp +++ b/src/libslic3r/Fill/Lightning/Layer.hpp @@ -12,16 +12,16 @@ #include #include -namespace Slic3r +namespace Slic3r::FillLightning { -class LightningTreeNode; -using LightningTreeNodeSPtr = std::shared_ptr; -using SparseLightningTreeNodeGrid = std::unordered_multimap, PointHash>; +class Node; +using NodeSPtr = std::shared_ptr; +using SparseNodeGrid = std::unordered_multimap, PointHash>; struct GroundingLocation { - LightningTreeNodeSPtr tree_node; //!< not null if the gounding location is on a tree + NodeSPtr tree_node; //!< not null if the gounding location is on a tree std::optional boundary_location; //!< in case the gounding location is on the boundary Point p() const; }; @@ -31,10 +31,10 @@ struct GroundingLocation * * Contains the trees to be printed and propagated to the next layer below. */ -class LightningLayer +class Layer { public: - std::vector tree_roots; + std::vector tree_roots; void generateNewTrees ( @@ -55,8 +55,8 @@ public: const EdgeGrid::Grid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius, - const SparseLightningTreeNodeGrid& tree_node_locator, - const LightningTreeNodeSPtr& exclude_tree = nullptr + const SparseNodeGrid& tree_node_locator, + const NodeSPtr& exclude_tree = nullptr ); /*! @@ -64,24 +64,24 @@ public: * \param[out] new_root The new root node if one had been made * \return Whether a new root was added */ - bool attach(const Point& unsupported_location, const GroundingLocation& ground, LightningTreeNodeSPtr& new_child, LightningTreeNodeSPtr& new_root); + bool attach(const Point& unsupported_location, const GroundingLocation& ground, NodeSPtr& new_child, NodeSPtr& new_root); void reconnectRoots ( - std::vector& to_be_reconnected_tree_roots, + std::vector& to_be_reconnected_tree_roots, const Polygons& current_outlines, const EdgeGrid::Grid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius ); - Polygons convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const; + Polylines convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const; coord_t getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location); - void fillLocator(SparseLightningTreeNodeGrid& tree_node_locator); + void fillLocator(SparseNodeGrid& tree_node_locator); }; -} // namespace Slic3r +} // namespace Slic3r::FillLightning #endif // LIGHTNING_LAYER_H diff --git a/src/libslic3r/Fill/Lightning/TreeNode.cpp b/src/libslic3r/Fill/Lightning/TreeNode.cpp index 97bbbbc33..2cb2b5f6d 100644 --- a/src/libslic3r/Fill/Lightning/TreeNode.cpp +++ b/src/libslic3r/Fill/Lightning/TreeNode.cpp @@ -5,9 +5,9 @@ #include "../../Geometry.hpp" -using namespace Slic3r; +namespace Slic3r::FillLightning { -coord_t LightningTreeNode::getWeightedDistance(const Point& unsupported_location, const coord_t& supporting_radius) const +coord_t Node::getWeightedDistance(const Point& unsupported_location, const coord_t& supporting_radius) const { constexpr coord_t min_valence_for_boost = 0; constexpr coord_t max_valence_for_boost = 4; @@ -19,7 +19,7 @@ coord_t LightningTreeNode::getWeightedDistance(const Point& unsupported_location return dist_here - valence_boost; } -bool LightningTreeNode::hasOffspring(const LightningTreeNodeSPtr& to_be_checked) const +bool Node::hasOffspring(const NodeSPtr& to_be_checked) const { if (to_be_checked == shared_from_this()) return true; @@ -31,14 +31,14 @@ bool LightningTreeNode::hasOffspring(const LightningTreeNodeSPtr& to_be_checked) return false; } -LightningTreeNodeSPtr LightningTreeNode::addChild(const Point& child_loc) +NodeSPtr Node::addChild(const Point& child_loc) { assert(m_p != child_loc); - LightningTreeNodeSPtr child = LightningTreeNode::create(child_loc); + NodeSPtr child = Node::create(child_loc); return addChild(child); } -LightningTreeNodeSPtr LightningTreeNode::addChild(LightningTreeNodeSPtr& new_child) +NodeSPtr Node::addChild(NodeSPtr& new_child) { assert(new_child != shared_from_this()); //assert(p != new_child->p); // NOTE: No problem for now. Issue to solve later. Maybe even afetr final. Low prio. @@ -48,8 +48,8 @@ LightningTreeNodeSPtr LightningTreeNode::addChild(LightningTreeNodeSPtr& new_chi return new_child; } -void LightningTreeNode::propagateToNextLayer( - std::vector& next_trees, +void Node::propagateToNextLayer( + std::vector& next_trees, const Polygons& next_outlines, const EdgeGrid::Grid& outline_locator, const coord_t prune_distance, @@ -65,7 +65,7 @@ void LightningTreeNode::propagateToNextLayer( // NOTE: Depth-first, as currently implemented. // Skips the root (because that has no root itself), but all initial nodes will have the root point anyway. -void LightningTreeNode::visitBranches(const std::function& visitor) const +void Node::visitBranches(const std::function& visitor) const { for (const auto& node : m_children) { assert(node->m_parent.lock() == shared_from_this()); @@ -75,7 +75,7 @@ void LightningTreeNode::visitBranches(const std::function& visitor) +void Node::visitNodes(const std::function& visitor) { visitor(shared_from_this()); for (const auto& node : m_children) { @@ -84,13 +84,13 @@ void LightningTreeNode::visitNodes(const std::function& last_grounding_location /*= std::nullopt*/) : +Node::Node(const Point& p, const std::optional& last_grounding_location /*= std::nullopt*/) : m_is_root(true), m_p(p), m_last_grounding_location(last_grounding_location) {} -LightningTreeNodeSPtr LightningTreeNode::deepCopy() const +NodeSPtr Node::deepCopy() const { - LightningTreeNodeSPtr local_root = LightningTreeNode::create(m_p); + NodeSPtr local_root = Node::create(m_p); local_root->m_is_root = m_is_root; if (m_is_root) { @@ -99,14 +99,14 @@ LightningTreeNodeSPtr LightningTreeNode::deepCopy() const local_root->m_children.reserve(m_children.size()); for (const auto& node : m_children) { - LightningTreeNodeSPtr child = node->deepCopy(); + NodeSPtr child = node->deepCopy(); child->m_parent = local_root; local_root->m_children.push_back(child); } return local_root; } -void LightningTreeNode::reroot(LightningTreeNodeSPtr new_parent /*= nullptr*/) +void Node::reroot(NodeSPtr new_parent /*= nullptr*/) { if (! m_is_root) { auto old_parent = m_parent.lock(); @@ -124,13 +124,13 @@ void LightningTreeNode::reroot(LightningTreeNodeSPtr new_parent /*= nullptr*/) } } -LightningTreeNodeSPtr LightningTreeNode::closestNode(const Point& loc) +NodeSPtr Node::closestNode(const Point& loc) { - LightningTreeNodeSPtr result = shared_from_this(); + NodeSPtr result = shared_from_this(); auto closest_dist2 = coord_t((m_p - loc).cast().norm()); for (const auto& child : m_children) { - LightningTreeNodeSPtr candidate_node = child->closestNode(loc); + NodeSPtr candidate_node = child->closestNode(loc); const auto child_dist2 = coord_t((candidate_node->m_p - loc).cast().norm()); if (child_dist2 < closest_dist2) { closest_dist2 = child_dist2; @@ -183,7 +183,7 @@ bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const EdgeG return visitor.d2min < within_max_dist * within_max_dist; } -bool LightningTreeNode::realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locator, std::vector& rerooted_parts) +bool Node::realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locator, std::vector& rerooted_parts) { if (outlines.empty()) return false; @@ -192,10 +192,10 @@ bool LightningTreeNode::realign(const Polygons& outlines, const EdgeGrid::Grid& // Only keep children that have an unbroken connection to here, realign will put the rest in rerooted parts due to recursion: Point coll; bool reground_me = false; - m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&](const LightningTreeNodeSPtr &child) { + m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&](const NodeSPtr &child) { bool connect_branch = child->realign(outlines, outline_locator, rerooted_parts); // Find an intersection of the line segment from p to child->p, at maximum outline_locator.resolution() * 2 distance from p. - if (connect_branch && lineSegmentPolygonsIntersection(child->m_p, m_p, outlines, outline_locator, coll, outline_locator.resolution() * 2)) { + if (connect_branch && lineSegmentPolygonsIntersection(child->m_p, m_p, outline_locator, coll, outline_locator.resolution() * 2)) { child->m_last_grounding_location.reset(); child->m_parent.reset(); child->m_is_root = true; @@ -223,12 +223,12 @@ bool LightningTreeNode::realign(const Polygons& outlines, const EdgeGrid::Grid& return false; } -void LightningTreeNode::straighten(const coord_t magnitude, const coord_t max_remove_colinear_dist) +void Node::straighten(const coord_t magnitude, const coord_t max_remove_colinear_dist) { straighten(magnitude, m_p, 0, max_remove_colinear_dist * max_remove_colinear_dist); } -LightningTreeNode::RectilinearJunction LightningTreeNode::straighten( +Node::RectilinearJunction Node::straighten( const coord_t magnitude, const Point& junction_above, const coord_t accumulated_dist, @@ -259,7 +259,7 @@ LightningTreeNode::RectilinearJunction LightningTreeNode::straighten( constexpr coord_t close_enough = 10; child_p = m_children.front(); //recursive call to straighten might have removed the child - const LightningTreeNodeSPtr& parent_node = m_parent.lock(); + const NodeSPtr& parent_node = m_parent.lock(); if (parent_node && (child_p->m_p - parent_node->m_p).cast().squaredNorm() < max_remove_colinear_dist2 && Line::distance_to_squared(m_p, parent_node->m_p, child_p->m_p) < close_enough * close_enough) { @@ -306,7 +306,7 @@ LightningTreeNode::RectilinearJunction LightningTreeNode::straighten( } // Prune the tree from the extremeties (leaf-nodes) until the pruning distance is reached. -coord_t LightningTreeNode::prune(const coord_t& pruning_distance) +coord_t Node::prune(const coord_t& pruning_distance) { if (pruning_distance <= 0) return 0; @@ -343,7 +343,7 @@ coord_t LightningTreeNode::prune(const coord_t& pruning_distance) return max_distance_pruned; } -void LightningTreeNode::convertToPolylines(Polygons& output, const coord_t line_width) const +void Node::convertToPolylines(Polygons& output, const coord_t line_width) const { Polygons result; output.emplace_back(); @@ -352,7 +352,7 @@ void LightningTreeNode::convertToPolylines(Polygons& output, const coord_t line_ append(output, std::move(result)); } -void LightningTreeNode::convertToPolylines(size_t long_line_idx, Polygons& output) const +void Node::convertToPolylines(size_t long_line_idx, Polygons& output) const { if (m_children.empty()) { output[long_line_idx].points.push_back(m_p); @@ -364,7 +364,7 @@ void LightningTreeNode::convertToPolylines(size_t long_line_idx, Polygons& outpu for (size_t idx_offset = 1; idx_offset < m_children.size(); idx_offset++) { size_t child_idx = (first_child_idx + idx_offset) % m_children.size(); - const LightningTreeNode& child = *m_children[child_idx]; + const Node& child = *m_children[child_idx]; output.emplace_back(); size_t child_line_idx = output.size() - 1; child.convertToPolylines(child_line_idx, output); @@ -372,7 +372,7 @@ void LightningTreeNode::convertToPolylines(size_t long_line_idx, Polygons& outpu } } -void LightningTreeNode::removeJunctionOverlap(Polygons& result_lines, const coord_t line_width) const +void Node::removeJunctionOverlap(Polygons& result_lines, const coord_t line_width) const { const coord_t reduction = line_width / 2; // TODO make configurable? for (auto poly_it = result_lines.begin(); poly_it != result_lines.end(); ) { @@ -406,3 +406,5 @@ void LightningTreeNode::removeJunctionOverlap(Polygons& result_lines, const coor ++ poly_it; } } + +} // namespace Slic3r::FillLightning diff --git a/src/libslic3r/Fill/Lightning/TreeNode.hpp b/src/libslic3r/Fill/Lightning/TreeNode.hpp index 1ca4b01d6..bc2e76dc2 100644 --- a/src/libslic3r/Fill/Lightning/TreeNode.hpp +++ b/src/libslic3r/Fill/Lightning/TreeNode.hpp @@ -12,14 +12,14 @@ #include "../../EdgeGrid.hpp" #include "../../Polygon.hpp" -namespace Slic3r +namespace Slic3r::FillLightning { constexpr auto locator_cell_size = scaled(4.); -class LightningTreeNode; +class Node; -using LightningTreeNodeSPtr = std::shared_ptr; +using NodeSPtr = std::shared_ptr; // NOTE: As written, this struct will only be valid for a single layer, will have to be updated for the next. // NOTE: Reasons for implementing this with some separate closures: @@ -35,15 +35,15 @@ using LightningTreeNodeSPtr = std::shared_ptr; * a tree. The class also has some helper functions specific to Lightning Infill * e.g. to straighten the paths around this node. */ -class LightningTreeNode : public std::enable_shared_from_this +class Node : public std::enable_shared_from_this { public: // Workaround for private/protected constructors and 'make_shared': https://stackoverflow.com/a/27832765 - template LightningTreeNodeSPtr static create(Arg&&...arg) + template NodeSPtr static create(Arg&&...arg) { - struct EnableMakeShared : public LightningTreeNode + struct EnableMakeShared : public Node { - EnableMakeShared(Arg&&...arg) : LightningTreeNode(std::forward(arg)...) {} + EnableMakeShared(Arg&&...arg) : Node(std::forward(arg)...) {} }; return std::make_shared(std::forward(arg)...); } @@ -62,19 +62,19 @@ public: void setLocation(const Point& p) { m_p = p; } /*! - * Construct a new ``LightningTreeNode`` instance and add it as a child of + * Construct a new ``Node`` instance and add it as a child of * this node. * \param p The location of the new node. * \return A shared pointer to the new node. */ - LightningTreeNodeSPtr addChild(const Point& p); + NodeSPtr addChild(const Point& p); /*! - * Add an existing ``LightningTreeNode`` as a child of this node. + * Add an existing ``Node`` as a child of this node. * \param new_child The node that must be added as a child. * \return Always returns \p new_child. */ - LightningTreeNodeSPtr addChild(LightningTreeNodeSPtr& new_child); + NodeSPtr addChild(NodeSPtr& new_child); /*! * Propagate this node's sub-tree to the next layer. @@ -96,7 +96,7 @@ public: */ void propagateToNextLayer ( - std::vector& next_trees, + std::vector& next_trees, const Polygons& next_outlines, const EdgeGrid::Grid& outline_locator, const coord_t prune_distance, @@ -127,7 +127,7 @@ public: * \param visitor A function to execute for every node in this node's sub- * tree. */ - void visitNodes(const std::function& visitor); + void visitNodes(const std::function& visitor); /*! * Get a weighted distance from an unsupported point to this node (given the current supporting radius). @@ -156,14 +156,14 @@ public: * This is then recursively bubbled up until it reaches the (former) root, which then will become a leaf. * \param new_parent The (new) parent-node of the root, useful for recursing or immediately attaching the node to another tree. */ - void reroot(LightningTreeNodeSPtr new_parent = nullptr); + void reroot(NodeSPtr new_parent = nullptr); /*! * Retrieves the closest node to the specified location. * \param loc The specified location. * \result The branch that starts at the position closest to the location within this tree. */ - LightningTreeNodeSPtr closestNode(const Point& loc); + NodeSPtr closestNode(const Point& loc); /*! * Returns whether the given tree node is a descendant of this node. @@ -174,10 +174,10 @@ public: * \return ``true`` if the given node is a descendant or this node itself, * or ``false`` if it is not in the sub-tree. */ - bool hasOffspring(const LightningTreeNodeSPtr& to_be_checked) const; + bool hasOffspring(const NodeSPtr& to_be_checked) const; protected: - LightningTreeNode() = delete; // Don't allow empty contruction + Node() = delete; // Don't allow empty contruction /*! * Construct a new node, either for insertion in a tree or as root. @@ -185,19 +185,19 @@ protected: * Connecting other nodes to this node indicates that a line segment should * be drawn between those two physical positions. */ - LightningTreeNode(const Point& p, const std::optional& last_grounding_location = std::nullopt); + Node(const Point& p, const std::optional& last_grounding_location = std::nullopt); /*! * Copy this node and its entire sub-tree. * \return The equivalent of this node in the copy (the root of the new sub- * tree). */ - LightningTreeNodeSPtr deepCopy() const; + NodeSPtr deepCopy() const; /*! Reconnect trees from the layer above to the new outlines of the lower layer. * \return Wether or not the root is kept (false is no, true is yes). */ - bool realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locator, std::vector& rerooted_parts); + bool realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locator, std::vector& rerooted_parts); struct RectilinearJunction { @@ -261,15 +261,15 @@ protected: bool m_is_root; Point m_p; - std::weak_ptr m_parent; - std::vector m_children; + std::weak_ptr m_parent; + std::vector m_children; std::optional m_last_grounding_location; //enum_values.push_back("octagramspiral"); def->enum_values.push_back("adaptivecubic"); def->enum_values.push_back("supportcubic"); +#if HAS_LIGHTNING_INFILL + def->enum_values.push_back("lightning"); +#endif // HAS_LIGHTNING_INFILL def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Aligned Rectilinear")); def->enum_labels.push_back(L("Grid")); @@ -1151,6 +1157,9 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Octagram Spiral")); def->enum_labels.push_back(L("Adaptive Cubic")); def->enum_labels.push_back(L("Support Cubic")); +#if HAS_LIGHTNING_INFILL + def->enum_labels.push_back(L("Lightning")); +#endif // HAS_LIGHTNING_INFILL 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 8d3ab3720..6851ceb10 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -57,9 +57,15 @@ enum class FuzzySkinType { All, }; +#define HAS_LIGHTNING_INFILL 0 + enum InfillPattern : int { ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, - ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipSupportBase, ipCount, + ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipSupportBase, +#if HAS_LIGHTNING_INFILL + ipLightning, +#endif // HAS_LIGHTNING_INFILL +ipCount, }; enum class IroningType {