|
13 | 13 | #include <Core/Vec2.h> |
14 | 14 | #include <Core/bool_vector.h> |
15 | 15 | #include <map> |
16 | | -#include <set> |
| 16 | +#include <unordered_set> |
17 | 17 | #include <memory> |
18 | 18 |
|
19 | 19 |
|
@@ -931,74 +931,82 @@ class VectorSprite : public Sprite |
931 | 931 |
|
932 | 932 | bool_vector visited(N, false); // Mark line segments. |
933 | 933 | std::vector<int> path_indices; |
934 | | - std::set<int> visited_positions; |
| 934 | + std::vector<int> temp_path_indices; |
| 935 | + std::unordered_set<int> visited_in_this_walk; |
935 | 936 |
|
936 | 937 | for (int start_idx = 0; start_idx < N; ++start_idx) |
937 | 938 | { |
938 | 939 | if (visited[start_idx]) |
939 | 940 | continue; |
940 | 941 |
|
941 | 942 | path_indices.clear(); |
942 | | - visited_positions.clear(); |
943 | 943 |
|
944 | | - int curr_idx = start_idx; |
945 | | - int curr_vtx = 0; // Can also try both ends. |
946 | | - |
947 | | - for (;;) |
| 944 | + for (int initial_vtx = 0; initial_vtx < 2; ++initial_vtx) |
948 | 945 | { |
949 | | - const auto& seg = vector_frame->open_polylines[curr_idx]; |
950 | | - visited[curr_idx] = true; |
951 | | - path_indices.emplace_back(curr_idx); |
952 | | - |
953 | | - Vec2 next_pos = seg.pos[1 - curr_vtx]; |
954 | | - int next_pos_idx = stlutils::find_if_idx(positions, |
955 | | - [c_snap_dist_sq, &next_pos](const Vec2& pos) |
956 | | - { return math::distance_squared(pos, next_pos) < c_snap_dist_sq; }); |
957 | | - |
958 | | - if (next_pos_idx == -1 || visited_positions.count(next_pos_idx) > 0) |
959 | | - break; // Either disconnected or looping over visited node. |
| 946 | + int curr_idx = start_idx; |
| 947 | + int curr_vtx = initial_vtx; |
| 948 | + Vec2 start_pos = vector_frame->open_polylines[start_idx].pos[initial_vtx]; |
960 | 949 |
|
961 | | - visited_positions.insert(next_pos_idx); |
| 950 | + temp_path_indices.clear(); |
| 951 | + visited_in_this_walk.clear(); |
962 | 952 |
|
963 | | - // Closed loop check. |
964 | | - int start_pos_idx = stlutils::find_if_idx(positions, |
965 | | - [c_snap_dist_sq, &vector_frame, start_idx, curr_vtx](const Vec2& pos) |
| 953 | + for (;;) |
966 | 954 | { |
967 | | - return math::distance_squared(pos, vector_frame->open_polylines[start_idx].pos[curr_vtx]) < c_snap_dist_sq; |
968 | | - }); |
969 | | - if (next_pos_idx == start_pos_idx) |
970 | | - { |
971 | | - // Closed loop detected! |
972 | | - std::vector<LineSeg> closed; |
973 | | - for (int idx : path_indices) |
974 | | - closed.emplace_back(vector_frame->open_polylines[idx]); |
| 955 | + // Check early exit. |
| 956 | + if (visited[curr_idx] || visited_in_this_walk.count(curr_idx)) |
| 957 | + break; |
| 958 | + |
| 959 | + visited_in_this_walk.insert(curr_idx); |
| 960 | + temp_path_indices.push_back(curr_idx); |
| 961 | + |
| 962 | + const auto& seg = vector_frame->open_polylines[curr_idx]; |
| 963 | + //visited[curr_idx] = true; |
| 964 | + //path_indices.emplace_back(curr_idx); |
975 | 965 |
|
976 | | - vector_frame->closed_polylines.emplace_back(std::move(closed)); |
| 966 | + Vec2 next_pos = seg.pos[1 - curr_vtx]; |
| 967 | + |
| 968 | + // Closed loop check. |
| 969 | + if (math::distance_squared(next_pos, start_pos) < c_snap_dist_sq) |
| 970 | + { |
| 971 | + // Closed loop detected! |
| 972 | + std::vector<LineSeg> closed; |
| 973 | + for (int idx : temp_path_indices) |
| 974 | + { |
| 975 | + closed.emplace_back(vector_frame->open_polylines[idx]); |
| 976 | + visited[idx] = true; |
| 977 | + } |
| 978 | + |
| 979 | + vector_frame->closed_polylines.emplace_back(std::move(closed)); |
| 980 | + break; |
| 981 | + } |
977 | 982 |
|
978 | | - // Remove from open_polylines later |
979 | | - for (int idx : path_indices) |
980 | | - visited[idx] = true; |
| 983 | + // Find next segment |
| 984 | + int next_pos_idx = stlutils::find_if_idx(positions, |
| 985 | + [c_snap_dist_sq, &next_pos](const Vec2& pos) |
| 986 | + { return math::distance_squared(pos, next_pos) < c_snap_dist_sq; }); |
981 | 987 |
|
982 | | - break; |
983 | | - } |
984 | | - |
985 | | - const auto& candidates = pos_lineseg_map[next_pos_idx]; |
986 | | - |
987 | | - // Try to find unvisited segment. |
988 | | - bool found = false; |
989 | | - for (const auto& lsd : candidates) |
990 | | - { |
991 | | - if (!visited[lsd.idx]) |
992 | | - { |
993 | | - curr_idx = lsd.idx; |
994 | | - curr_vtx = lsd.v_idx; |
995 | | - found = true; |
| 988 | + // Disconnected. |
| 989 | + if (next_pos_idx == -1) |
996 | 990 | break; |
| 991 | + |
| 992 | + const auto& candidates = pos_lineseg_map[next_pos_idx]; |
| 993 | + |
| 994 | + // Try to find unvisited segment. |
| 995 | + bool found = false; |
| 996 | + for (const auto& lsd : candidates) |
| 997 | + { |
| 998 | + if (!visited[lsd.idx] && !visited_in_this_walk.count(lsd.idx)) |
| 999 | + { |
| 1000 | + curr_idx = lsd.idx; |
| 1001 | + curr_vtx = lsd.v_idx; |
| 1002 | + found = true; |
| 1003 | + break; |
| 1004 | + } |
997 | 1005 | } |
| 1006 | + |
| 1007 | + if (!found) |
| 1008 | + break; |
998 | 1009 | } |
999 | | - |
1000 | | - if (!found) |
1001 | | - break; |
1002 | 1010 | } |
1003 | 1011 | } |
1004 | 1012 |
|
|
0 commit comments