Skip to content

Commit 3c04740

Browse files
committed
SpriteHandler.h:
* More robust polygon parts detection algo in VectorSprite::finalize_topology() by - Trying both vertex directions when traversing line segments - Deferring visited marking until a loop is confirmed - Allowing detection of mixed-direction closed loops This improves handling of arbitrarily ordered or flipped segments and ensures proper grouping of closed polylines.
1 parent e4feefd commit 3c04740

File tree

1 file changed

+59
-51
lines changed

1 file changed

+59
-51
lines changed

SpriteHandler.h

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <Core/Vec2.h>
1414
#include <Core/bool_vector.h>
1515
#include <map>
16-
#include <set>
16+
#include <unordered_set>
1717
#include <memory>
1818

1919

@@ -931,74 +931,82 @@ class VectorSprite : public Sprite
931931

932932
bool_vector visited(N, false); // Mark line segments.
933933
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;
935936

936937
for (int start_idx = 0; start_idx < N; ++start_idx)
937938
{
938939
if (visited[start_idx])
939940
continue;
940941

941942
path_indices.clear();
942-
visited_positions.clear();
943943

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)
948945
{
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];
960949

961-
visited_positions.insert(next_pos_idx);
950+
temp_path_indices.clear();
951+
visited_in_this_walk.clear();
962952

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 (;;)
966954
{
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);
975965

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+
}
977982

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; });
981987

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)
996990
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+
}
9971005
}
1006+
1007+
if (!found)
1008+
break;
9981009
}
999-
1000-
if (!found)
1001-
break;
10021010
}
10031011
}
10041012

0 commit comments

Comments
 (0)