diff --git a/tests/libslic3r/test_voronoi.cpp b/tests/libslic3r/test_voronoi.cpp index 44bbd1016a..3e0759d0c9 100644 --- a/tests/libslic3r/test_voronoi.cpp +++ b/tests/libslic3r/test_voronoi.cpp @@ -2431,6 +2431,57 @@ void append_neighbor_branch(VoronoiGraph::ExPath &dst, } } +/// +/// DTO for process node during depth search of longest path in voronoi graph +/// +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 skip_nodes; // circle + + // store all circle indexes this node is lay on + // used to create connected circles structure + std::vector 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 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 + } +}; + /// /// 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 skip_nodes({prev_node}); // circle - + // keep data out of stack + std::unique_ptr data = std::make_unique( + &node, distance_to_node, prev_path); VoronoiGraph::ExPath result; - - // when search on cirle store only branches not search for longest Path - std::vector circle_indexes; // connected circles - std::vector 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) { } /// -/// DTO for process node to depth search to get longest path in voronoi graph +/// DTO for non recursive call to search of longest path /// -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 skip_nodes; // circle - - // store all circle indexes this node is lay on - // used to create connected circles structure - std::vector 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 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) {} }; +/// +/// interface for objects inside of CallStack +/// class IStackFunction { public: @@ -2702,23 +2717,16 @@ public: /// /// call after all neighbors are processed /// -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: /// 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(data, neighbor)); @@ -3035,7 +3043,8 @@ std::vector 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