WIP Lightning Infill, roughly integrated, untested, disabled with

HAS_LIGHTNING_INFILL
This commit is contained in:
Vojtech Bubnik 2021-12-01 18:11:41 +01:00
parent e8697d2fc2
commit 481def3205
14 changed files with 221 additions and 126 deletions

View File

@ -67,8 +67,8 @@ add_library(libslic3r STATIC
Fill/FillPlanePath.hpp Fill/FillPlanePath.hpp
Fill/FillLine.cpp Fill/FillLine.cpp
Fill/FillLine.hpp Fill/FillLine.hpp
Fill/FillRectilinear.cpp Fill/FillLightning.cpp
Fill/FillRectilinear.hpp Fill/FillLightning.hpp
Fill/Lightning/DistanceField.cpp Fill/Lightning/DistanceField.cpp
Fill/Lightning/DistanceField.hpp Fill/Lightning/DistanceField.hpp
Fill/Lightning/Generator.cpp Fill/Lightning/Generator.cpp
@ -77,6 +77,8 @@ add_library(libslic3r STATIC
Fill/Lightning/Layer.hpp Fill/Lightning/Layer.hpp
Fill/Lightning/TreeNode.cpp Fill/Lightning/TreeNode.cpp
Fill/Lightning/TreeNode.hpp Fill/Lightning/TreeNode.hpp
Fill/FillRectilinear.cpp
Fill/FillRectilinear.hpp
Flow.cpp Flow.cpp
Flow.hpp Flow.hpp
format.hpp format.hpp

View File

@ -19,6 +19,7 @@
#include "FillLine.hpp" #include "FillLine.hpp"
#include "FillRectilinear.hpp" #include "FillRectilinear.hpp"
#include "FillAdaptive.hpp" #include "FillAdaptive.hpp"
#include "FillLightning.hpp"
// #define INFILL_DEBUG_OUTPUT // #define INFILL_DEBUG_OUTPUT
@ -45,6 +46,9 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipAdaptiveCubic: return new FillAdaptive::Filler(); case ipAdaptiveCubic: return new FillAdaptive::Filler();
case ipSupportCubic: return new FillAdaptive::Filler(); case ipSupportCubic: return new FillAdaptive::Filler();
case ipSupportBase: return new FillSupportBase(); 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"); default: throw Slic3r::InvalidArgument("unknown type");
} }
} }

View File

@ -0,0 +1,28 @@
#include "../Print.hpp"
#include "FillLightning.hpp"
#include "Lightning/Generator.hpp"
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <numeric>
namespace Slic3r::FillLightning {
Polylines Filler::fill_surface(const Surface *surface, const FillParams &params)
{
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

View File

@ -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<Generator, GeneratorDeleter>;
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 &params) 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_

View File

@ -4,12 +4,12 @@
#include "DistanceField.hpp" //Class we're implementing. #include "DistanceField.hpp" //Class we're implementing.
#include "../FillRectilinear.hpp" #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. 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_cell_size(radius / radius_per_cell_size),
m_supporting_radius(radius) 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<double>(); Vec2d v = (added_leaf - to_node).cast<double>();
auto l2 = v.squaredNorm(); auto l2 = v.squaredNorm();
@ -95,4 +95,4 @@ void LightningDistanceField::update(const Point& to_node, const Point& added_lea
} }
} }
} // namespace Slic3r } // namespace Slic3r::FillLightning

View File

@ -4,7 +4,7 @@
#ifndef LIGHTNING_DISTANCE_FIELD_H #ifndef LIGHTNING_DISTANCE_FIELD_H
#define 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 * maintains how far it is removed from the edge, which is used to determine
* how it gets supported by Lightning Infill. * how it gets supported by Lightning Infill.
*/ */
class LightningDistanceField class DistanceField
{ {
public: public:
/*! /*!
@ -26,7 +26,7 @@ public:
* \param current_overhang The overhang that needs to be supported on this * \param current_overhang The overhang that needs to be supported on this
* layer. * 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. * Gets the next unsupported location to be supported by a new branch.
@ -92,6 +92,6 @@ protected:
std::unordered_map<Point, std::list<UnsupportedCell>::iterator, PointHash> m_unsupported_points_grid; std::unordered_map<Point, std::list<UnsupportedCell>::iterator, PointHash> m_unsupported_points_grid;
}; };
} // namespace Slic3r } // namespace Slic3r::FillLightning
#endif //LIGHTNING_DISTANCE_FIELD_H #endif //LIGHTNING_DISTANCE_FIELD_H

View File

@ -20,12 +20,12 @@
* - Make a pass with Arachne over the output. Somehow. * - 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.) * - 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? * - 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 PrintConfig &print_config = print_object.print()->config();
const PrintObjectConfig &object_config = print_object.config(); const PrintObjectConfig &object_config = print_object.config();
@ -51,7 +51,7 @@ LightningGenerator::LightningGenerator(const PrintObject &print_object)
generateTrees(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()); m_overhang_per_layer.resize(print_object.layers().size());
const float infill_wall_offset = - m_infill_extrusion_width; 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()); assert(layer_id < m_lightning_layers.size());
return m_lightning_layers[layer_id]; 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()); m_lightning_layers.resize(print_object.layers().size());
const coord_t infill_wall_offset = - m_infill_extrusion_width; 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-each layer from top to bottom:
for (int layer_id = top_layer_id; layer_id >= 0; layer_id--) 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]; Polygons& current_outlines = infill_outlines[layer_id];
// register all trees propagated from the previous layer as to-be-reconnected // register all trees propagated from the previous layer as to-be-reconnected
std::vector<LightningTreeNodeSPtr> to_be_reconnected_tree_roots = current_lightning_layer.tree_roots; std::vector<NodeSPtr> 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.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); 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.set_bbox(get_extents(below_outlines).inflated(SCALED_EPSILON));
outlines_locator.create(below_outlines, locator_cell_size); outlines_locator.create(below_outlines, locator_cell_size);
std::vector<LightningTreeNodeSPtr>& lower_trees = m_lightning_layers[layer_id - 1].tree_roots; std::vector<NodeSPtr>& lower_trees = m_lightning_layers[layer_id - 1].tree_roots;
for (auto& tree : current_lightning_layer.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); tree->propagateToNextLayer(lower_trees, below_outlines, outlines_locator, m_prune_length, m_straightening_max_distance, locator_cell_size / 2);
} }
} }
} // namespace Slic3r::FillLightning

View File

@ -14,6 +14,9 @@ namespace Slic3r
{ {
class PrintObject; class PrintObject;
namespace FillLightning
{
/*! /*!
* Generates the Lightning Infill pattern. * Generates the Lightning Infill pattern.
* *
@ -31,7 +34,7 @@ class PrintObject;
* Printing of Hollowed Objects" by Tricard, Claux and Lefebvre: * Printing of Hollowed Objects" by Tricard, Claux and Lefebvre:
* https://www.researchgate.net/publication/333808588_Ribbed_Support_Vaults_for_3D_Printing_of_Hollowed_Objects * 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: public:
/*! /*!
@ -42,7 +45,7 @@ public:
* already be calculated at this point. * already be calculated at this point.
* \param mesh The mesh to generate infill for. * \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. * 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 * \return A tree structure representing paths to print to create the
* Lightning Infill pattern. * 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: protected:
/*! /*!
@ -118,9 +123,10 @@ protected:
* *
* This is generated by \ref generateTrees. * This is generated by \ref generateTrees.
*/ */
std::vector<LightningLayer> m_lightning_layers; std::vector<Layer> m_lightning_layers;
}; };
} // namespace FillLightning
} // namespace Slic3r } // namespace Slic3r
#endif // LIGHTNING_GENERATOR_H #endif // LIGHTNING_GENERATOR_H

View File

@ -10,9 +10,9 @@
#include "../../Geometry.hpp" #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<double>().norm()); return coord_t((boundary_loc - unsupported_location).cast<double>().norm());
} }
@ -23,16 +23,16 @@ Point GroundingLocation::p() const
return tree_node ? tree_node->getLocation() : *boundary_location; return tree_node ? tree_node->getLocation() : *boundary_location;
} }
void LightningLayer::fillLocator(SparseLightningTreeNodeGrid &tree_node_locator) void Layer::fillLocator(SparseNodeGrid &tree_node_locator)
{ {
std::function<void(LightningTreeNodeSPtr)> add_node_to_locator_func = [&tree_node_locator](LightningTreeNodeSPtr node) { std::function<void(NodeSPtr)> 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)); 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) for (auto& tree : tree_roots)
tree->visitNodes(add_node_to_locator_func); tree->visitNodes(add_node_to_locator_func);
} }
void LightningLayer::generateNewTrees void Layer::generateNewTrees
( (
const Polygons& current_overhang, const Polygons& current_overhang,
const Polygons& current_outlines, const Polygons& current_outlines,
@ -41,9 +41,9 @@ void LightningLayer::generateNewTrees
const coord_t wall_supporting_radius 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); fillLocator(tree_node_locator);
// Until no more points need to be added to support all: // Until no more points need to be added to support all:
@ -53,8 +53,8 @@ void LightningLayer::generateNewTrees
GroundingLocation grounding_loc = getBestGroundingLocation( GroundingLocation grounding_loc = getBestGroundingLocation(
unsupported_location, current_outlines, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator); unsupported_location, current_outlines, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator);
LightningTreeNodeSPtr new_parent; NodeSPtr new_parent;
LightningTreeNodeSPtr new_child; NodeSPtr new_child;
this->attach(unsupported_location, grounding_loc, new_child, new_parent); 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)); 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) if (new_parent)
@ -93,15 +93,15 @@ static bool polygonCollidesWithLineSegment(const Point from, const Point to, con
return visitor.intersect; return visitor.intersect;
} }
GroundingLocation LightningLayer::getBestGroundingLocation GroundingLocation Layer::getBestGroundingLocation
( (
const Point& unsupported_location, const Point& unsupported_location,
const Polygons& current_outlines, const Polygons& current_outlines,
const EdgeGrid::Grid& outline_locator, const EdgeGrid::Grid& outline_locator,
const coord_t supporting_radius, const coord_t supporting_radius,
const coord_t wall_supporting_radius, const coord_t wall_supporting_radius,
const SparseLightningTreeNodeGrid& tree_node_locator, const SparseNodeGrid& tree_node_locator,
const LightningTreeNodeSPtr& exclude_tree const NodeSPtr& exclude_tree
) )
{ {
// Closest point on current_outlines to unsupported_location: // 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<double>().norm()); const auto within_dist = coord_t((node_location - unsupported_location).cast<double>().norm());
LightningTreeNodeSPtr sub_tree{ nullptr }; NodeSPtr sub_tree{ nullptr };
coord_t current_dist = getWeightedDistance(node_location, unsupported_location); 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. 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); const coord_t search_radius = std::min(current_dist, within_dist);
@ -154,15 +154,15 @@ GroundingLocation LightningLayer::getBestGroundingLocation
GroundingLocation{ sub_tree, std::optional<Point>() }; GroundingLocation{ sub_tree, std::optional<Point>() };
} }
bool LightningLayer::attach( bool Layer::attach(
const Point& unsupported_location, const Point& unsupported_location,
const GroundingLocation& grounding_loc, const GroundingLocation& grounding_loc,
LightningTreeNodeSPtr& new_child, NodeSPtr& new_child,
LightningTreeNodeSPtr& new_root) NodeSPtr& new_root)
{ {
// Update trees & distance fields. // Update trees & distance fields.
if (grounding_loc.boundary_location) { 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); new_child = new_root->addChild(unsupported_location);
tree_roots.push_back(new_root); tree_roots.push_back(new_root);
return true; return true;
@ -172,9 +172,9 @@ bool LightningLayer::attach(
} }
} }
void LightningLayer::reconnectRoots void Layer::reconnectRoots
( (
std::vector<LightningTreeNodeSPtr>& to_be_reconnected_tree_roots, std::vector<NodeSPtr>& to_be_reconnected_tree_roots,
const Polygons& current_outlines, const Polygons& current_outlines,
const EdgeGrid::Grid& outline_locator, const EdgeGrid::Grid& outline_locator,
const coord_t supporting_radius, const coord_t supporting_radius,
@ -183,7 +183,7 @@ void LightningLayer::reconnectRoots
{ {
constexpr coord_t tree_connecting_ignore_offset = 100; constexpr coord_t tree_connecting_ignore_offset = 100;
SparseLightningTreeNodeGrid tree_node_locator; SparseNodeGrid tree_node_locator;
fillLocator(tree_node_locator); fillLocator(tree_node_locator);
const coord_t within_max_dist = outline_locator.resolution() * 2; const coord_t within_max_dist = outline_locator.resolution() * 2;
@ -198,8 +198,8 @@ void LightningLayer::reconnectRoots
{ {
Point new_root_pt; 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. // 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)) { if (lineSegmentPolygonsIntersection(root_ptr->getLocation(), ground_loc, outline_locator, new_root_pt, within_max_dist)) {
auto new_root = LightningTreeNode::create(new_root_pt, new_root_pt); auto new_root = Node::create(new_root_pt, new_root_pt);
root_ptr->addChild(new_root); root_ptr->addChild(new_root);
new_root->reroot(); new_root->reroot();
@ -228,7 +228,7 @@ void LightningLayer::reconnectRoots
if (ground.boundary_location.value() == root_ptr->getLocation()) if (ground.boundary_location.value() == root_ptr->getLocation())
continue; // Already on the boundary. 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()); auto attach_ptr = root_ptr->closestNode(new_root->getLocation());
attach_ptr->reroot(); attach_ptr->reroot();
@ -375,14 +375,13 @@ static unsigned int moveInside(const Polygons& polygons, Point& from, int distan
} }
// Returns 'added someting'. // 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()) 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. // 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'.) // (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; constexpr coord_t epsilon = 5;
@ -393,13 +392,12 @@ Polygons LightningLayer::convertToLines(const Polygons& limit_to_outline, const
} }
// TODO: allow for polylines! // TODO: allow for polylines!
Polygons split_lines; Polylines split_lines;
for (Polygon &line : result_lines) for (Polygon &line : result_lines) {
{ if (line.size() <= 1)
if (line.size() <= 1) continue; continue;
Point last = line[0]; 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]; Point here = line[point_idx];
split_lines.push_back({ last, here }); split_lines.push_back({ last, here });
last = here; last = here;
@ -408,3 +406,5 @@ Polygons LightningLayer::convertToLines(const Polygons& limit_to_outline, const
return split_lines; return split_lines;
} }
} // namespace Slic3r::Lightning

View File

@ -12,16 +12,16 @@
#include <list> #include <list>
#include <unordered_map> #include <unordered_map>
namespace Slic3r namespace Slic3r::FillLightning
{ {
class LightningTreeNode;
using LightningTreeNodeSPtr = std::shared_ptr<LightningTreeNode>; class Node;
using SparseLightningTreeNodeGrid = std::unordered_multimap<Point, std::weak_ptr<LightningTreeNode>, PointHash>; using NodeSPtr = std::shared_ptr<Node>;
using SparseNodeGrid = std::unordered_multimap<Point, std::weak_ptr<Node>, PointHash>;
struct GroundingLocation 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<Point> boundary_location; //!< in case the gounding location is on the boundary std::optional<Point> boundary_location; //!< in case the gounding location is on the boundary
Point p() const; Point p() const;
}; };
@ -31,10 +31,10 @@ struct GroundingLocation
* *
* Contains the trees to be printed and propagated to the next layer below. * Contains the trees to be printed and propagated to the next layer below.
*/ */
class LightningLayer class Layer
{ {
public: public:
std::vector<LightningTreeNodeSPtr> tree_roots; std::vector<NodeSPtr> tree_roots;
void generateNewTrees void generateNewTrees
( (
@ -55,8 +55,8 @@ public:
const EdgeGrid::Grid& outline_locator, const EdgeGrid::Grid& outline_locator,
const coord_t supporting_radius, const coord_t supporting_radius,
const coord_t wall_supporting_radius, const coord_t wall_supporting_radius,
const SparseLightningTreeNodeGrid& tree_node_locator, const SparseNodeGrid& tree_node_locator,
const LightningTreeNodeSPtr& exclude_tree = nullptr const NodeSPtr& exclude_tree = nullptr
); );
/*! /*!
@ -64,24 +64,24 @@ public:
* \param[out] new_root The new root node if one had been made * \param[out] new_root The new root node if one had been made
* \return Whether a new root was added * \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 void reconnectRoots
( (
std::vector<LightningTreeNodeSPtr>& to_be_reconnected_tree_roots, std::vector<NodeSPtr>& to_be_reconnected_tree_roots,
const Polygons& current_outlines, const Polygons& current_outlines,
const EdgeGrid::Grid& outline_locator, const EdgeGrid::Grid& outline_locator,
const coord_t supporting_radius, const coord_t supporting_radius,
const coord_t wall_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); 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 #endif // LIGHTNING_LAYER_H

View File

@ -5,9 +5,9 @@
#include "../../Geometry.hpp" #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 min_valence_for_boost = 0;
constexpr coord_t max_valence_for_boost = 4; 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; 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()) if (to_be_checked == shared_from_this())
return true; return true;
@ -31,14 +31,14 @@ bool LightningTreeNode::hasOffspring(const LightningTreeNodeSPtr& to_be_checked)
return false; return false;
} }
LightningTreeNodeSPtr LightningTreeNode::addChild(const Point& child_loc) NodeSPtr Node::addChild(const Point& child_loc)
{ {
assert(m_p != child_loc); assert(m_p != child_loc);
LightningTreeNodeSPtr child = LightningTreeNode::create(child_loc); NodeSPtr child = Node::create(child_loc);
return addChild(child); return addChild(child);
} }
LightningTreeNodeSPtr LightningTreeNode::addChild(LightningTreeNodeSPtr& new_child) NodeSPtr Node::addChild(NodeSPtr& new_child)
{ {
assert(new_child != shared_from_this()); 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. //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; return new_child;
} }
void LightningTreeNode::propagateToNextLayer( void Node::propagateToNextLayer(
std::vector<LightningTreeNodeSPtr>& next_trees, std::vector<NodeSPtr>& next_trees,
const Polygons& next_outlines, const Polygons& next_outlines,
const EdgeGrid::Grid& outline_locator, const EdgeGrid::Grid& outline_locator,
const coord_t prune_distance, const coord_t prune_distance,
@ -65,7 +65,7 @@ void LightningTreeNode::propagateToNextLayer(
// NOTE: Depth-first, as currently implemented. // 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. // 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<void(const Point&, const Point&)>& visitor) const void Node::visitBranches(const std::function<void(const Point&, const Point&)>& visitor) const
{ {
for (const auto& node : m_children) { for (const auto& node : m_children) {
assert(node->m_parent.lock() == shared_from_this()); assert(node->m_parent.lock() == shared_from_this());
@ -75,7 +75,7 @@ void LightningTreeNode::visitBranches(const std::function<void(const Point&, con
} }
// NOTE: Depth-first, as currently implemented. // NOTE: Depth-first, as currently implemented.
void LightningTreeNode::visitNodes(const std::function<void(LightningTreeNodeSPtr)>& visitor) void Node::visitNodes(const std::function<void(NodeSPtr)>& visitor)
{ {
visitor(shared_from_this()); visitor(shared_from_this());
for (const auto& node : m_children) { for (const auto& node : m_children) {
@ -84,13 +84,13 @@ void LightningTreeNode::visitNodes(const std::function<void(LightningTreeNodeSPt
} }
} }
LightningTreeNode::LightningTreeNode(const Point& p, const std::optional<Point>& last_grounding_location /*= std::nullopt*/) : Node::Node(const Point& p, const std::optional<Point>& last_grounding_location /*= std::nullopt*/) :
m_is_root(true), m_p(p), m_last_grounding_location(last_grounding_location) 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; local_root->m_is_root = m_is_root;
if (m_is_root) if (m_is_root)
{ {
@ -99,14 +99,14 @@ LightningTreeNodeSPtr LightningTreeNode::deepCopy() const
local_root->m_children.reserve(m_children.size()); local_root->m_children.reserve(m_children.size());
for (const auto& node : m_children) for (const auto& node : m_children)
{ {
LightningTreeNodeSPtr child = node->deepCopy(); NodeSPtr child = node->deepCopy();
child->m_parent = local_root; child->m_parent = local_root;
local_root->m_children.push_back(child); local_root->m_children.push_back(child);
} }
return local_root; return local_root;
} }
void LightningTreeNode::reroot(LightningTreeNodeSPtr new_parent /*= nullptr*/) void Node::reroot(NodeSPtr new_parent /*= nullptr*/)
{ {
if (! m_is_root) { if (! m_is_root) {
auto old_parent = m_parent.lock(); 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<double>().norm()); auto closest_dist2 = coord_t((m_p - loc).cast<double>().norm());
for (const auto& child : m_children) { 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<double>().norm()); const auto child_dist2 = coord_t((candidate_node->m_p - loc).cast<double>().norm());
if (child_dist2 < closest_dist2) { if (child_dist2 < closest_dist2) {
closest_dist2 = child_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; return visitor.d2min < within_max_dist * within_max_dist;
} }
bool LightningTreeNode::realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locator, std::vector<LightningTreeNodeSPtr>& rerooted_parts) bool Node::realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locator, std::vector<NodeSPtr>& rerooted_parts)
{ {
if (outlines.empty()) if (outlines.empty())
return false; 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: // Only keep children that have an unbroken connection to here, realign will put the rest in rerooted parts due to recursion:
Point coll; Point coll;
bool reground_me = false; 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); 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. // 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_last_grounding_location.reset();
child->m_parent.reset(); child->m_parent.reset();
child->m_is_root = true; child->m_is_root = true;
@ -223,12 +223,12 @@ bool LightningTreeNode::realign(const Polygons& outlines, const EdgeGrid::Grid&
return false; 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); 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 coord_t magnitude,
const Point& junction_above, const Point& junction_above,
const coord_t accumulated_dist, const coord_t accumulated_dist,
@ -259,7 +259,7 @@ LightningTreeNode::RectilinearJunction LightningTreeNode::straighten(
constexpr coord_t close_enough = 10; constexpr coord_t close_enough = 10;
child_p = m_children.front(); //recursive call to straighten might have removed the child 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 && if (parent_node &&
(child_p->m_p - parent_node->m_p).cast<double>().squaredNorm() < max_remove_colinear_dist2 && (child_p->m_p - parent_node->m_p).cast<double>().squaredNorm() < max_remove_colinear_dist2 &&
Line::distance_to_squared(m_p, parent_node->m_p, child_p->m_p) < close_enough * close_enough) { 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. // 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) if (pruning_distance <= 0)
return 0; return 0;
@ -343,7 +343,7 @@ coord_t LightningTreeNode::prune(const coord_t& pruning_distance)
return max_distance_pruned; 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; Polygons result;
output.emplace_back(); output.emplace_back();
@ -352,7 +352,7 @@ void LightningTreeNode::convertToPolylines(Polygons& output, const coord_t line_
append(output, std::move(result)); 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()) { if (m_children.empty()) {
output[long_line_idx].points.push_back(m_p); 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++) { 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(); 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(); output.emplace_back();
size_t child_line_idx = output.size() - 1; size_t child_line_idx = output.size() - 1;
child.convertToPolylines(child_line_idx, output); 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? const coord_t reduction = line_width / 2; // TODO make configurable?
for (auto poly_it = result_lines.begin(); poly_it != result_lines.end(); ) { 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; ++ poly_it;
} }
} }
} // namespace Slic3r::FillLightning

View File

@ -12,14 +12,14 @@
#include "../../EdgeGrid.hpp" #include "../../EdgeGrid.hpp"
#include "../../Polygon.hpp" #include "../../Polygon.hpp"
namespace Slic3r namespace Slic3r::FillLightning
{ {
constexpr auto locator_cell_size = scaled<coord_t>(4.); constexpr auto locator_cell_size = scaled<coord_t>(4.);
class LightningTreeNode; class Node;
using LightningTreeNodeSPtr = std::shared_ptr<LightningTreeNode>; using NodeSPtr = std::shared_ptr<Node>;
// NOTE: As written, this struct will only be valid for a single layer, will have to be updated for the next. // 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: // NOTE: Reasons for implementing this with some separate closures:
@ -35,15 +35,15 @@ using LightningTreeNodeSPtr = std::shared_ptr<LightningTreeNode>;
* a tree. The class also has some helper functions specific to Lightning Infill * a tree. The class also has some helper functions specific to Lightning Infill
* e.g. to straighten the paths around this node. * e.g. to straighten the paths around this node.
*/ */
class LightningTreeNode : public std::enable_shared_from_this<LightningTreeNode> class Node : public std::enable_shared_from_this<Node>
{ {
public: public:
// Workaround for private/protected constructors and 'make_shared': https://stackoverflow.com/a/27832765 // Workaround for private/protected constructors and 'make_shared': https://stackoverflow.com/a/27832765
template<typename ...Arg> LightningTreeNodeSPtr static create(Arg&&...arg) template<typename ...Arg> NodeSPtr static create(Arg&&...arg)
{ {
struct EnableMakeShared : public LightningTreeNode struct EnableMakeShared : public Node
{ {
EnableMakeShared(Arg&&...arg) : LightningTreeNode(std::forward<Arg>(arg)...) {} EnableMakeShared(Arg&&...arg) : Node(std::forward<Arg>(arg)...) {}
}; };
return std::make_shared<EnableMakeShared>(std::forward<Arg>(arg)...); return std::make_shared<EnableMakeShared>(std::forward<Arg>(arg)...);
} }
@ -62,19 +62,19 @@ public:
void setLocation(const Point& p) { m_p = p; } 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. * this node.
* \param p The location of the new node. * \param p The location of the new node.
* \return A shared pointer to 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. * \param new_child The node that must be added as a child.
* \return Always returns \p new_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. * Propagate this node's sub-tree to the next layer.
@ -96,7 +96,7 @@ public:
*/ */
void propagateToNextLayer void propagateToNextLayer
( (
std::vector<LightningTreeNodeSPtr>& next_trees, std::vector<NodeSPtr>& next_trees,
const Polygons& next_outlines, const Polygons& next_outlines,
const EdgeGrid::Grid& outline_locator, const EdgeGrid::Grid& outline_locator,
const coord_t prune_distance, const coord_t prune_distance,
@ -127,7 +127,7 @@ public:
* \param visitor A function to execute for every node in this node's sub- * \param visitor A function to execute for every node in this node's sub-
* tree. * tree.
*/ */
void visitNodes(const std::function<void(LightningTreeNodeSPtr)>& visitor); void visitNodes(const std::function<void(NodeSPtr)>& visitor);
/*! /*!
* Get a weighted distance from an unsupported point to this node (given the current supporting radius). * 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. * 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. * \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. * Retrieves the closest node to the specified location.
* \param loc The specified location. * \param loc The specified location.
* \result The branch that starts at the position closest to the location within this tree. * \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. * 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, * \return ``true`` if the given node is a descendant or this node itself,
* or ``false`` if it is not in the sub-tree. * 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: 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. * 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 * Connecting other nodes to this node indicates that a line segment should
* be drawn between those two physical positions. * be drawn between those two physical positions.
*/ */
LightningTreeNode(const Point& p, const std::optional<Point>& last_grounding_location = std::nullopt); Node(const Point& p, const std::optional<Point>& last_grounding_location = std::nullopt);
/*! /*!
* Copy this node and its entire sub-tree. * Copy this node and its entire sub-tree.
* \return The equivalent of this node in the copy (the root of the new sub- * \return The equivalent of this node in the copy (the root of the new sub-
* tree). * tree).
*/ */
LightningTreeNodeSPtr deepCopy() const; NodeSPtr deepCopy() const;
/*! Reconnect trees from the layer above to the new outlines of the lower layer. /*! 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). * \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<LightningTreeNodeSPtr>& rerooted_parts); bool realign(const Polygons& outlines, const EdgeGrid::Grid& outline_locator, std::vector<NodeSPtr>& rerooted_parts);
struct RectilinearJunction struct RectilinearJunction
{ {
@ -261,15 +261,15 @@ protected:
bool m_is_root; bool m_is_root;
Point m_p; Point m_p;
std::weak_ptr<LightningTreeNode> m_parent; std::weak_ptr<Node> m_parent;
std::vector<LightningTreeNodeSPtr> m_children; std::vector<NodeSPtr> m_children;
std::optional<Point> m_last_grounding_location; //<! The last known grounding location, see 'getLastGroundingLocation()'. std::optional<Point> m_last_grounding_location; //<! The last known grounding location, see 'getLastGroundingLocation()'.
}; };
bool inside(const Polygons &polygons, const Point p); bool inside(const Polygons &polygons, const Point p);
bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const Polygons& current_outlines, const EdgeGrid::Grid& outline_locator, Point& result, const coord_t within_max_dist); bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const EdgeGrid::Grid& outline_locator, Point& result, const coord_t within_max_dist);
} // namespace Slic3r } // namespace Slic3r::FillLightning
#endif // LIGHTNING_TREE_NODE_H #endif // LIGHTNING_TREE_NODE_H

View File

@ -107,7 +107,10 @@ static t_config_enum_values s_keys_map_InfillPattern {
{ "archimedeanchords", ipArchimedeanChords }, { "archimedeanchords", ipArchimedeanChords },
{ "octagramspiral", ipOctagramSpiral }, { "octagramspiral", ipOctagramSpiral },
{ "adaptivecubic", ipAdaptiveCubic }, { "adaptivecubic", ipAdaptiveCubic },
{ "supportcubic", ipSupportCubic } { "supportcubic", ipSupportCubic },
#if HAS_LIGHTNING_INFILL
{ "lightning", ipLightning }
#endif // HAS_LIGHTNING_INFILL
}; };
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern) CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern)
@ -1135,6 +1138,9 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("octagramspiral"); def->enum_values.push_back("octagramspiral");
def->enum_values.push_back("adaptivecubic"); def->enum_values.push_back("adaptivecubic");
def->enum_values.push_back("supportcubic"); 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("Rectilinear"));
def->enum_labels.push_back(L("Aligned Rectilinear")); def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Grid")); 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("Octagram Spiral"));
def->enum_labels.push_back(L("Adaptive Cubic")); def->enum_labels.push_back(L("Adaptive Cubic"));
def->enum_labels.push_back(L("Support 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<InfillPattern>(ipStars)); def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipStars));
def = this->add("first_layer_acceleration", coFloat); def = this->add("first_layer_acceleration", coFloat);

View File

@ -57,9 +57,15 @@ enum class FuzzySkinType {
All, All,
}; };
#define HAS_LIGHTNING_INFILL 0
enum InfillPattern : int { enum InfillPattern : int {
ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, 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 { enum class IroningType {