WIP Lightning Infill, roughly integrated, untested, disabled with
HAS_LIGHTNING_INFILL
This commit is contained in:
parent
e8697d2fc2
commit
481def3205
@ -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
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
src/libslic3r/Fill/FillLightning.cpp
Normal file
28
src/libslic3r/Fill/FillLightning.cpp
Normal 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 ¶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
|
36
src/libslic3r/Fill/FillLightning.hpp
Normal file
36
src/libslic3r/Fill/FillLightning.hpp
Normal 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 ¶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_
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user