mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 19:15:56 +08:00
Recursive function with data stored on heap
This commit is contained in:
parent
5c2e368f7c
commit
179115eb75
@ -2431,6 +2431,57 @@ void append_neighbor_branch(VoronoiGraph::ExPath &dst,
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for process node during depth search of longest path in voronoi graph
|
||||
/// </summary>
|
||||
struct NodeData
|
||||
{
|
||||
// actual proccessed node
|
||||
const VoronoiGraph::Node *node;
|
||||
// distance to this node from input node
|
||||
double distance_to_node;
|
||||
|
||||
// path from start point to this node
|
||||
// last one is actual node
|
||||
VoronoiGraph::Path act_path;
|
||||
|
||||
// skip node when circle start - must end at this node
|
||||
// set --> multiple cirle could start at same node
|
||||
// previous node should be skiped to so it is initialized with it
|
||||
std::set<const VoronoiGraph::Node *> skip_nodes; // circle
|
||||
|
||||
// store all circle indexes this node is lay on
|
||||
// used to create connected circles structure
|
||||
std::vector<size_t> circle_indexes;
|
||||
// When circle_indexes is not empty node lays on circle
|
||||
// and in this node is not searching for longest path only store side
|
||||
// branches(not part of circle)
|
||||
|
||||
// indexes of circle ending in this node(could be more than one)
|
||||
std::vector<size_t> end_circle_indexes;
|
||||
// When end_circle_indexes == circle_indexes
|
||||
// than it is end of circle (multi circle structure) and it is processed
|
||||
|
||||
// contain possible continue path
|
||||
// possible empty
|
||||
VoronoiGraph::ExPath::SideBranches side_branches;
|
||||
public:
|
||||
// append node to act path
|
||||
NodeData(const VoronoiGraph::Node *node,
|
||||
double distance_to_node,
|
||||
const VoronoiGraph::Path &prev_path)
|
||||
: node(node), distance_to_node(distance_to_node)
|
||||
{
|
||||
const VoronoiGraph::Node *prev_node = (prev_path.path.size() >= 1) ?
|
||||
prev_path.path.back() :
|
||||
nullptr;
|
||||
skip_nodes = {prev_node};
|
||||
// append actual node
|
||||
act_path = prev_path; // copy
|
||||
act_path.append(node, distance_to_node); // increase path
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// PRIVATE:
|
||||
/// Depth search in Voronoi graph for longest path
|
||||
@ -2445,33 +2496,20 @@ VoronoiGraph::ExPath create_longest_branch_from_node(
|
||||
double distance_to_node = 0.,
|
||||
const VoronoiGraph::Path &prev_path = VoronoiGraph::Path({},0.))
|
||||
{
|
||||
const VoronoiGraph::Node *prev_node =
|
||||
(prev_path.path.size() >= 1) ? prev_path.path.back() : nullptr;
|
||||
// append actual node
|
||||
VoronoiGraph::Path act_path = prev_path; // make copy
|
||||
act_path.append(&node, distance_to_node);
|
||||
|
||||
VoronoiGraph::ExPath::SideBranches side_branches;
|
||||
|
||||
// skip node on circle when circle start at this node
|
||||
// vector --> multiple cirle could start at same node
|
||||
// prev node should be skiped to
|
||||
std::set<const VoronoiGraph::Node *> skip_nodes({prev_node}); // circle
|
||||
|
||||
// keep data out of stack
|
||||
std::unique_ptr<NodeData> data = std::make_unique<NodeData>(
|
||||
&node, distance_to_node, prev_path);
|
||||
VoronoiGraph::ExPath result;
|
||||
|
||||
// when search on cirle store only branches not search for longest Path
|
||||
std::vector<size_t> circle_indexes; // connected circles
|
||||
std::vector<size_t> end_circle_indexes;
|
||||
// Depth search for path of all neighbors --> fill paths
|
||||
for (const VoronoiGraph::Node::Neighbor &neighbor : node.neighbors) {
|
||||
if (skip_nodes.find(neighbor.node) != skip_nodes.end()) continue;
|
||||
if (data->skip_nodes.find(neighbor.node) != data->skip_nodes.end())
|
||||
continue;
|
||||
|
||||
// detection of circle
|
||||
auto circle_opt = create_circle(act_path, neighbor);
|
||||
auto circle_opt = create_circle(data->act_path, neighbor);
|
||||
if (circle_opt.has_value()) {
|
||||
size_t circle_index = result.circles.size();
|
||||
circle_indexes.push_back(circle_index);
|
||||
data->circle_indexes.push_back(circle_index);
|
||||
result.circles.emplace_back(std::move(circle_opt.value()));
|
||||
continue;
|
||||
}
|
||||
@ -2481,12 +2519,13 @@ VoronoiGraph::ExPath create_longest_branch_from_node(
|
||||
// is next node leaf ?
|
||||
if (next_node.neighbors.size() == 1) {
|
||||
VoronoiGraph::Path side_branch({&next_node}, neighbor.edge_length);
|
||||
side_branches.push(std::move(side_branch));
|
||||
data->side_branches.push(std::move(side_branch));
|
||||
continue;
|
||||
}
|
||||
|
||||
VoronoiGraph::ExPath next_path =
|
||||
create_longest_branch_from_node(next_node, neighbor.edge_length, act_path);
|
||||
create_longest_branch_from_node(next_node, neighbor.edge_length,
|
||||
data->act_path);
|
||||
|
||||
bool is_circle_neighbor = false;
|
||||
if (next_path.path.empty()) { // neighbor node is on circle
|
||||
@ -2497,18 +2536,18 @@ VoronoiGraph::ExPath create_longest_branch_from_node(
|
||||
|
||||
size_t next_circle_index = &circle - &next_path.circles.front();
|
||||
size_t circle_index = result.circles.size() + next_circle_index;
|
||||
circle_indexes.push_back(circle_index);
|
||||
data->circle_indexes.push_back(circle_index);
|
||||
|
||||
// check if this node is end of circle
|
||||
if (circle_item == circle.path.begin()) {
|
||||
end_circle_indexes.push_back(circle_index);
|
||||
data->end_circle_indexes.push_back(circle_index);
|
||||
|
||||
// !! this FIX circle lenght because at detection of
|
||||
// circle it will cost time to calculate it
|
||||
circle.length -= act_path.length;
|
||||
circle.length -= data->act_path.length;
|
||||
|
||||
// skip twice checking of circle
|
||||
skip_nodes.insert(circle.path.back());
|
||||
data->skip_nodes.insert(circle.path.back());
|
||||
}
|
||||
is_circle_neighbor = true;
|
||||
}
|
||||
@ -2516,13 +2555,14 @@ VoronoiGraph::ExPath create_longest_branch_from_node(
|
||||
|
||||
append_neighbor_branch(result, next_path);
|
||||
|
||||
if (!is_circle_neighbor) side_branches.push(std::move(next_path));
|
||||
if (!is_circle_neighbor)
|
||||
data->side_branches.push(std::move(next_path));
|
||||
}
|
||||
|
||||
// remember connected circle
|
||||
if (circle_indexes.size() > 1) {
|
||||
for (size_t circle_index : circle_indexes) {
|
||||
for (size_t circle_index2 : circle_indexes) {
|
||||
if (data->circle_indexes.size() > 1) {
|
||||
for (size_t circle_index : data->circle_indexes) {
|
||||
for (size_t circle_index2 : data->circle_indexes) {
|
||||
if (circle_index == circle_index2) continue;
|
||||
result.connected_circle[circle_index].insert(circle_index2);
|
||||
}
|
||||
@ -2530,32 +2570,33 @@ VoronoiGraph::ExPath create_longest_branch_from_node(
|
||||
}
|
||||
|
||||
// detect end of circles in this node
|
||||
if (!end_circle_indexes.empty() &&
|
||||
end_circle_indexes.size() == circle_indexes.size()) {
|
||||
size_t circle_index = circle_indexes.front(); // possible any of them
|
||||
side_branches.push(
|
||||
if (!data->end_circle_indexes.empty() &&
|
||||
data->end_circle_indexes.size() == data->circle_indexes.size()) {
|
||||
// possible any of circle indexes
|
||||
size_t circle_index = data->circle_indexes.front();
|
||||
data->side_branches.push(
|
||||
find_longest_path_on_circles(node, circle_index, result));
|
||||
|
||||
circle_indexes.clear(); // resolved circles
|
||||
data->circle_indexes.clear(); // resolved circles
|
||||
}
|
||||
|
||||
// simple node on circle --> only input and output neighbor
|
||||
if (side_branches.empty()) {
|
||||
if (data->side_branches.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// is node on unresolved circle?
|
||||
if (!circle_indexes.empty()) {
|
||||
if (!data->circle_indexes.empty()) {
|
||||
// not search for longest path, it will eval on end of circle
|
||||
result.side_branches[&node] = side_branches;
|
||||
result.side_branches[&node] = data->side_branches;
|
||||
return result;
|
||||
}
|
||||
|
||||
// create result longest path from longest side branch
|
||||
VoronoiGraph::Path longest_path(std::move(side_branches.top()));
|
||||
side_branches.pop();
|
||||
if (!side_branches.empty()) {
|
||||
result.side_branches[&node] = side_branches;
|
||||
VoronoiGraph::Path longest_path(std::move(data->side_branches.top()));
|
||||
data->side_branches.pop();
|
||||
if (!data->side_branches.empty()) {
|
||||
result.side_branches[&node] = data->side_branches;
|
||||
}
|
||||
longest_path.path.insert(longest_path.path.begin(), &node);
|
||||
result.path = std::move(longest_path.path);
|
||||
@ -2627,51 +2668,25 @@ void reshape_longest_path(VoronoiGraph::ExPath& path) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for process node to depth search to get longest path in voronoi graph
|
||||
/// DTO for non recursive call to search of longest path
|
||||
/// </summary>
|
||||
struct CallData
|
||||
struct NodeDataWithResult : public NodeData
|
||||
{
|
||||
// actual proccessed node
|
||||
const VoronoiGraph::Node *node;
|
||||
// distance to this node from input node
|
||||
double distance_to_node;
|
||||
|
||||
// path from start point to this node
|
||||
// last one is actual node
|
||||
VoronoiGraph::Path act_path;
|
||||
|
||||
// skip node when circle start - must end at this node
|
||||
// set --> multiple cirle could start at same node
|
||||
// previous node should be skiped to so it is initialized with it
|
||||
std::set<const VoronoiGraph::Node *> skip_nodes; // circle
|
||||
|
||||
// store all circle indexes this node is lay on
|
||||
// used to create connected circles structure
|
||||
std::vector<size_t> circle_indexes;
|
||||
// When circle_indexes is not empty node lays on circle
|
||||
// and in this node is not searching for longest path only store side
|
||||
// branches(not part of circle)
|
||||
|
||||
// indexes of circle ending in this node(could be more than one)
|
||||
std::vector<size_t> end_circle_indexes;
|
||||
// When end_circle_indexes == circle_indexes
|
||||
// than it is end of circle (multi circle structure) and it is processed
|
||||
|
||||
// contain possible continue path
|
||||
// possible empty
|
||||
VoronoiGraph::ExPath::SideBranches side_branches;
|
||||
|
||||
// result for this node
|
||||
VoronoiGraph::ExPath& result;
|
||||
VoronoiGraph::ExPath &result;
|
||||
|
||||
public:
|
||||
CallData(VoronoiGraph::ExPath & result,
|
||||
const VoronoiGraph::Node *node,
|
||||
double distance_to_node)
|
||||
: result(result), node(node), distance_to_node(distance_to_node)
|
||||
NodeDataWithResult(VoronoiGraph::ExPath & result,
|
||||
const VoronoiGraph::Node *node,
|
||||
double distance_to_node,
|
||||
const VoronoiGraph::Path &prev_path)
|
||||
: result(result), NodeData(node, distance_to_node, prev_path)
|
||||
{}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// interface for objects inside of CallStack
|
||||
/// </summary>
|
||||
class IStackFunction
|
||||
{
|
||||
public:
|
||||
@ -2702,23 +2717,16 @@ public:
|
||||
/// <summary>
|
||||
/// call after all neighbors are processed
|
||||
/// </summary>
|
||||
class PostProcessNeighbors : public CallData , public IStackFunction
|
||||
class PostProcessNeighbors : public NodeDataWithResult , public IStackFunction
|
||||
{
|
||||
public:
|
||||
PostProcessNeighbors(
|
||||
VoronoiGraph::ExPath & result,
|
||||
const VoronoiGraph::Node *node,
|
||||
double distance_to_node = 0.,
|
||||
VoronoiGraph::Path prev_path = VoronoiGraph::Path({}, 0.) // make copy
|
||||
): CallData(result, node, distance_to_node)
|
||||
{
|
||||
const VoronoiGraph::Node *prev_node =
|
||||
(prev_path.path.size() >= 1) ? prev_path.path.back() : nullptr;
|
||||
skip_nodes = {prev_node};
|
||||
// append actual node
|
||||
act_path = std::move(prev_path);
|
||||
act_path.append(node, distance_to_node);
|
||||
}
|
||||
const VoronoiGraph::Path& prev_path = VoronoiGraph::Path({}, 0.) // make copy
|
||||
): NodeDataWithResult(result, node, distance_to_node, prev_path)
|
||||
{}
|
||||
|
||||
virtual void process([[maybe_unused]] CallStack &call_stack)
|
||||
{
|
||||
@ -2780,10 +2788,10 @@ public:
|
||||
/// </summary>
|
||||
class PostProcessNeighbor : public IStackFunction
|
||||
{
|
||||
CallData &data;
|
||||
NodeDataWithResult &data;
|
||||
public:
|
||||
VoronoiGraph::ExPath neighbor_path; // data filled in EvaluateNeighbor
|
||||
PostProcessNeighbor(CallData &data): data(data) {}
|
||||
PostProcessNeighbor(NodeDataWithResult &data): data(data) {}
|
||||
|
||||
virtual void process([[maybe_unused]] CallStack &call_stack)
|
||||
{
|
||||
@ -2827,11 +2835,11 @@ public:
|
||||
|
||||
class ExpandNeighbor: public IStackFunction
|
||||
{
|
||||
CallData &data;
|
||||
NodeDataWithResult &data;
|
||||
const VoronoiGraph::Node::Neighbor &neighbor;
|
||||
|
||||
public:
|
||||
ExpandNeighbor(CallData & data,
|
||||
ExpandNeighbor(NodeDataWithResult & data,
|
||||
const VoronoiGraph::Node::Neighbor &neighbor)
|
||||
: data(data), neighbor(neighbor)
|
||||
{}
|
||||
@ -2888,7 +2896,7 @@ EvaluateNeighbor::EvaluateNeighbor(VoronoiGraph::ExPath & result,
|
||||
|
||||
void EvaluateNeighbor::process(IStackFunction::CallStack &call_stack)
|
||||
{
|
||||
CallData &data = *post_process_neighbor;
|
||||
NodeDataWithResult &data = *post_process_neighbor;
|
||||
call_stack.emplace(std::move(post_process_neighbor));
|
||||
for (const VoronoiGraph::Node::Neighbor &neighbor : data.node->neighbors)
|
||||
call_stack.emplace(std::make_unique<ExpandNeighbor>(data, neighbor));
|
||||
@ -3035,7 +3043,8 @@ std::vector<Point> sample_voronoi_graph(const VoronoiGraph &graph,
|
||||
// every island has to have a point on contour
|
||||
assert(start_node != nullptr);
|
||||
|
||||
longest_path = create_longest_path(start_node);
|
||||
//longest_path = create_longest_path(start_node);
|
||||
longest_path = create_longest_path_recursive(start_node);
|
||||
if (longest_path.length < config.max_length_for_one_support_point)
|
||||
{ // create only one point in center
|
||||
// sample in center of voronoi
|
||||
@ -3276,7 +3285,7 @@ TEST_CASE("Sample small islands", "[VoronoiSkeleton]")
|
||||
{4 * size5, size5},
|
||||
{3 * size5, size5}}};
|
||||
|
||||
size_t count_cirlce_lines = 100; // test stack overfrow
|
||||
size_t count_cirlce_lines = 1000; // test stack overfrow
|
||||
double r_CCW = size / 2;
|
||||
double r_CW = r_CCW - size / 6;
|
||||
// CCW: couter clock wise, CW: clock wise
|
||||
|
Loading…
x
Reference in New Issue
Block a user