Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions libs/MeshKernel/src/MeshBoundaryExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,11 @@ void meshkernel::MeshBoundaryExtractor::FindAllBoundarEdges(const std::vector<Po
for (UInt count = 0; count < edges.size(); ++count)
{

if (edgesFaces[count][1] != constants::missing::uintValue || !IsValidEdge(edges[count]))
if (!IsValidEdge(edges[count]) ||

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the edgesFaces pair is a sorted pair? And thus these lines mean: if the first is uintValue (which is max-int, indicating no face) then the next must be too so no faces, if the last edge is not uintValue (valid face) then the first must also be, so this is an interior edge.

It would be helpful to have a little helper function IsBoundaryEdge that hides this logic, and maybe adds a comment that explains the logic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The edge-face pair contains the edge adjacent face id's.

AI overview:

edgesFaces[count][0] — the first face adjacent to the edge. For a boundary edge (an edge with only one neighbouring face), this is always populated with that one valid face id. It's populated for essentially every edge that touches at least one face.

edgesFaces[count][1] — the second face adjacent to the edge, only set if the edge is shared between two faces (i.e. an interior edge). If the edge has only one adjacent face (boundary edge) or no adjacent face (a dangling/hanging edge not part of any face), this slot is constants::missing::uintValue.

So the convention used throughout this file is:

[0] [1] meaning
valid valid interior edge, shared by two faces
valid missing boundary edge, touches exactly one face
missing missing edge belongs to no face at all ("hanging" edge)

edgesFaces[count][0] == constants::missing::uintValue ||
edgesFaces[count][1] != constants::missing::uintValue)
{
// Edge is either invalid or not on boundary
// Edge is invalid, has no adjacent face (hanging edge), or is interior (two faces)
continue;
}

Expand Down Expand Up @@ -366,12 +368,10 @@ void meshkernel::MeshBoundaryExtractor::FindBoundaryPolygons(const std::vector<P
for (UInt count = 0; count < edges.size(); ++count)
{

if (!IsValidEdge(edges[count]))
{
continue;
}

if (edgesFaces[count][1] != constants::missing::uintValue || edgeVisited[count])
if (edgeVisited[count] ||
!IsValidEdge(edges[count]) ||
edgesFaces[count][0] == constants::missing::uintValue ||
edgesFaces[count][1] != constants::missing::uintValue)
{
continue;
}
Expand Down
36 changes: 36 additions & 0 deletions libs/MeshKernel/tests/src/Mesh2DTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,42 @@ TEST(Mesh2D, HangingEdge)
ASSERT_EQ(1, mesh.GetNumFaces());
}

TEST(Mesh2D, MeshBoundaryToPolygonWithHangingEdge)
{
// 1 Setup
std::vector<meshkernel::Point> nodes;
nodes.push_back({0.0, 0.0});
nodes.push_back({5.0, 0.0});
nodes.push_back({3.0, 2.0});
nodes.push_back({3.0, 4.0});

std::vector<meshkernel::Edge> edges;
edges.push_back({0, 1});
edges.push_back({1, 3});
edges.push_back({3, 0});
edges.push_back({2, 1});

auto mesh = meshkernel::Mesh2D(meshkernel::Projection::cartesian);
mesh.SetNodes(nodes);
mesh.SetEdges(edges);
mesh.Administrate();

std::vector<meshkernel::Point> polygonNodes;

// 2 Execution
auto meshBoundaryPolygon = mesh.ComputeBoundaryPolygons(polygonNodes);

// 3 Validation
const double tolerance = 1e-5;
ASSERT_EQ(4, meshBoundaryPolygon.size());

for (const auto& point : meshBoundaryPolygon)
{
const double distanceToHangingNode = std::hypot(point.x - nodes[2].x, point.y - nodes[2].y);
EXPECT_GT(distanceToHangingNode, tolerance);
}
}

TEST(Mesh2D, NodeMerging)
{
// 1. Setup
Expand Down
Loading