From b4f36c16aafc24cc7a15e98068fa0630c937931a Mon Sep 17 00:00:00 2001 From: TechyDaniel <117300186+TechyDaniel@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:33:26 +0100 Subject: [PATCH 1/7] feat: identify overlapping vertices at UV seams - Introduce `get_overlapping_vertices` for vertex grouping. - Account for floating-point imprecision in vertex positions. - Ensure accurate identification without false positives. - Function returns a list of arrays with vertex indices. test: ensure accurate overlapping vertex identification - Verify accurate detection of overlapping vertices. - Confirm no false positives are returned. - Test with varying mesh complexities. - Check for match detection within a few milliseconds. --- src/readyplayerme/meshops/mesh.py | 25 ++++++++++++++++++- tests/readyplayerme/meshops/unit/test_mesh.py | 11 ++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/readyplayerme/meshops/mesh.py b/src/readyplayerme/meshops/mesh.py index 787ca28..93ffc89 100644 --- a/src/readyplayerme/meshops/mesh.py +++ b/src/readyplayerme/meshops/mesh.py @@ -5,7 +5,7 @@ import numpy as np import trimesh -from readyplayerme.meshops.types import Edges, Indices, Mesh +from readyplayerme.meshops.types import Edges, Indices, Mesh, Vertices def read_mesh(filename: str | Path) -> Mesh: @@ -47,3 +47,26 @@ def get_boundary_vertices(edges: Edges) -> Indices: unique_edges, edge_triangle_count = np.unique(sorted_edges, return_counts=True, axis=0) border_edge_indices = np.where(edge_triangle_count == 1)[0] return np.unique(unique_edges[border_edge_indices]) + + +def get_overlapping_vertices(vertices: Vertices, vertex_indices_pool: Indices) -> list[np.int64]: + """Return the indices of the vertices grouped by the same position. + + Vertices that have the same position belong to a seam. + + + :param vertices: All the vertices of the mesh. + :param vertex_indices_pool: A specific pool of Vertex indices. + :return: A list of grouped border vertices that share position. + """ + vertex_positions_pool_ = vertices[vertex_indices_pool] + rounded_positions = np.round(vertex_positions_pool_, decimals=5) + structured_positions = np.core.records.fromarrays( + rounded_positions.transpose(), names="x, y, z", formats="f8, f8, f8" + ) + unique_positions, indices = np.unique(structured_positions, return_inverse=True) + grouped_indices = [ + vertex_indices_pool[indices == i] for i in range(len(unique_positions)) if (indices == i).sum() > 1 + ] + + return grouped_indices diff --git a/tests/readyplayerme/meshops/unit/test_mesh.py b/tests/readyplayerme/meshops/unit/test_mesh.py index eaaa655..cba7ad6 100644 --- a/tests/readyplayerme/meshops/unit/test_mesh.py +++ b/tests/readyplayerme/meshops/unit/test_mesh.py @@ -57,3 +57,14 @@ def test_get_boundary_vertices(mock_mesh: Mesh): assert np.array_equiv( np.sort(boundary_vertices), [0, 2, 4, 6, 7, 9, 10] ), "The vertices returned by get_border_vertices do not match the expected vertices." + + +def test_group_shared_border_vertices(mock_mesh: Mesh): + """Test the get_overlapping_vertices functions returns the expected indices groups.""" + border_vertices = np.array([0, 2, 4, 6, 7, 9, 10]) + vertices = mock_mesh.vertices + grouped_border_vertex_indices = mesh.get_overlapping_vertices(vertices, border_vertices) + + assert np.array_equiv( + (grouped_border_vertex_indices), [[9, 10]] + ), "The vertices returned by get_group_shared_border_vertices do not match the expected vertices." From 6145c91c92b681967dca84e67c19462b92bba80a Mon Sep 17 00:00:00 2001 From: TechyDaniel <117300186+TechyDaniel@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:59:54 +0100 Subject: [PATCH 2/7] feat: enhance get_overlapping_vertices for optional indices - Update function to process all vertices if indices are not provided. - Handle cases with 'None' or empty list for indices. - Improve function's flexibility and robustness for various cases. test: add new cases for get_overlapping_vertices function - Include unit tests for scenarios with 'None' or empty indices. - Ensure function behaves as expected in these special cases. - Enhance reliability and test coverage. --- src/readyplayerme/meshops/mesh.py | 17 ++++++++------- src/readyplayerme/meshops/types.py | 1 + tests/readyplayerme/meshops/unit/test_mesh.py | 21 ++++++++++++------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/readyplayerme/meshops/mesh.py b/src/readyplayerme/meshops/mesh.py index 93ffc89..315b630 100644 --- a/src/readyplayerme/meshops/mesh.py +++ b/src/readyplayerme/meshops/mesh.py @@ -5,7 +5,7 @@ import numpy as np import trimesh -from readyplayerme.meshops.types import Edges, Indices, Mesh, Vertices +from readyplayerme.meshops.types import Edges, Indices, Mesh, VariableLengthArrays, Vertices def read_mesh(filename: str | Path) -> Mesh: @@ -49,24 +49,27 @@ def get_boundary_vertices(edges: Edges) -> Indices: return np.unique(unique_edges[border_edge_indices]) -def get_overlapping_vertices(vertices: Vertices, vertex_indices_pool: Indices) -> list[np.int64]: +def get_overlapping_vertices(vertices_pos: Vertices, indices: Indices | None = None) -> VariableLengthArrays: """Return the indices of the vertices grouped by the same position. Vertices that have the same position belong to a seam. :param vertices: All the vertices of the mesh. - :param vertex_indices_pool: A specific pool of Vertex indices. + :param indices: Vertex indices. :return: A list of grouped border vertices that share position. """ - vertex_positions_pool_ = vertices[vertex_indices_pool] - rounded_positions = np.round(vertex_positions_pool_, decimals=5) + if indices is None: + indices = np.arange(len(vertices_pos)) + + vertex_positions = vertices_pos[indices] + rounded_positions = np.round(vertex_positions, decimals=5) structured_positions = np.core.records.fromarrays( rounded_positions.transpose(), names="x, y, z", formats="f8, f8, f8" ) - unique_positions, indices = np.unique(structured_positions, return_inverse=True) + unique_positions, local_indices = np.unique(structured_positions, return_inverse=True) grouped_indices = [ - vertex_indices_pool[indices == i] for i in range(len(unique_positions)) if (indices == i).sum() > 1 + indices[local_indices == i] for i in range(len(unique_positions)) if (local_indices == i).sum() > 1 ] return grouped_indices diff --git a/src/readyplayerme/meshops/types.py b/src/readyplayerme/meshops/types.py index aee2060..dc8535e 100644 --- a/src/readyplayerme/meshops/types.py +++ b/src/readyplayerme/meshops/types.py @@ -9,6 +9,7 @@ Vertices: TypeAlias = npt.NDArray[np.float32] | npt.NDArray[np.float64] # Shape (v, 3) Edges: TypeAlias = npt.NDArray[np.int32] | npt.NDArray[np.int64] # Shape (e, 2) Faces: TypeAlias = npt.NDArray[np.int32] | npt.NDArray[np.int64] # Shape (f, 3) +VariableLengthArrays: TypeAlias = list[npt.NDArray[np.int64]] class Mesh(Protocol): diff --git a/tests/readyplayerme/meshops/unit/test_mesh.py b/tests/readyplayerme/meshops/unit/test_mesh.py index cba7ad6..fd538d5 100644 --- a/tests/readyplayerme/meshops/unit/test_mesh.py +++ b/tests/readyplayerme/meshops/unit/test_mesh.py @@ -8,7 +8,7 @@ import pytest from readyplayerme.meshops import mesh -from readyplayerme.meshops.types import Mesh +from readyplayerme.meshops.types import Indices, Mesh class TestReadMesh: @@ -59,12 +59,19 @@ def test_get_boundary_vertices(mock_mesh: Mesh): ), "The vertices returned by get_border_vertices do not match the expected vertices." -def test_group_shared_border_vertices(mock_mesh: Mesh): +@pytest.mark.parametrize( + "mock_indices, expected", + [ + (np.array([0, 2, 4, 6, 7, 9, 10]), np.array([[9, 10]])), + (None, np.array([[9, 10]])), + ([], np.array([])), + ], +) +def test_overlapping_vertices(mock_mesh: Mesh, mock_indices: Indices, expected: Indices): """Test the get_overlapping_vertices functions returns the expected indices groups.""" - border_vertices = np.array([0, 2, 4, 6, 7, 9, 10]) vertices = mock_mesh.vertices - grouped_border_vertex_indices = mesh.get_overlapping_vertices(vertices, border_vertices) - + grouped_vertices = mesh.get_overlapping_vertices(vertices, mock_indices) + assert len(grouped_vertices) == len(expected), "Number of groups doesn't match expected" assert np.array_equiv( - (grouped_border_vertex_indices), [[9, 10]] - ), "The vertices returned by get_group_shared_border_vertices do not match the expected vertices." + grouped_vertices, expected + ), "The vertices returned by get_overlapping_vertices do not match the expected vertices." From 40ce8840ffc7a0a486b9921fd7c600bf039cc5a5 Mon Sep 17 00:00:00 2001 From: Olaf Haag Date: Thu, 16 Nov 2023 19:21:13 +0100 Subject: [PATCH 3/7] test: add overlap imprecision test, take vertices as argument imprecision test is failing with current implementation --- tests/readyplayerme/meshops/unit/test_mesh.py | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/tests/readyplayerme/meshops/unit/test_mesh.py b/tests/readyplayerme/meshops/unit/test_mesh.py index fd538d5..0a5b39c 100644 --- a/tests/readyplayerme/meshops/unit/test_mesh.py +++ b/tests/readyplayerme/meshops/unit/test_mesh.py @@ -8,7 +8,7 @@ import pytest from readyplayerme.meshops import mesh -from readyplayerme.meshops.types import Indices, Mesh +from readyplayerme.meshops.types import Indices, Mesh, Vertices class TestReadMesh: @@ -60,17 +60,42 @@ def test_get_boundary_vertices(mock_mesh: Mesh): @pytest.mark.parametrize( - "mock_indices, expected", + "vertices, indices, expected", [ - (np.array([0, 2, 4, 6, 7, 9, 10]), np.array([[9, 10]])), - (None, np.array([[9, 10]])), - ([], np.array([])), + # Vertices from our mock mesh. + ("mock_mesh", np.array([0, 2, 4, 6, 7, 9, 10]), [(np.array([9, 10]))]), + # Close positions, but with imprecision. + ( + np.array( + [ + [1.0, 1.0, 1.0], + [0.99998, 0.99998, 0.99998], + [0.49998, 0.5, 0.5], + [0.5, 0.5, 0.5], + [0.50001, 0.50001, 0.50001], + ] + ), + np.array([0, 1, 2, 3, 4]), + [np.array([0, 1]), np.array([2, 3, 4])], + ), + # Overlapping vertices, None indices given. + ( + np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]), + None, + [np.array([0, 1])], + ), + # Overlapping vertices, but empty indices given. + (np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]), np.array([], dtype=np.int32), []), ], ) -def test_overlapping_vertices(mock_mesh: Mesh, mock_indices: Indices, expected: Indices): +def test_overlapping_vertices(vertices: Vertices, indices: Indices, expected: Indices, request: pytest.FixtureRequest): """Test the get_overlapping_vertices functions returns the expected indices groups.""" - vertices = mock_mesh.vertices - grouped_vertices = mesh.get_overlapping_vertices(vertices, mock_indices) + # Get vertices from the fixture if one is given. + if isinstance(vertices, str) and vertices == "mock_mesh": + vertices = request.getfixturevalue("mock_mesh").vertices + + grouped_vertices = mesh.get_overlapping_vertices(vertices, indices) + assert len(grouped_vertices) == len(expected), "Number of groups doesn't match expected" assert np.array_equiv( grouped_vertices, expected From 2d917035329b776401ea41016372f1764a688880 Mon Sep 17 00:00:00 2001 From: TechyDaniel <117300186+TechyDaniel@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:47:25 +0100 Subject: [PATCH 4/7] feat: Enhance get_overlapping_vertices with tolerance parameter - Implement a tolerance parameter in get_overlapping_vertices for better vertex grouping. - Add tests to verify the new functionality. --- src/readyplayerme/meshops/mesh.py | 45 ++++++++++--------- src/readyplayerme/meshops/types.py | 4 +- tests/readyplayerme/meshops/unit/test_mesh.py | 19 ++++---- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/readyplayerme/meshops/mesh.py b/src/readyplayerme/meshops/mesh.py index 315b630..6c3caf7 100644 --- a/src/readyplayerme/meshops/mesh.py +++ b/src/readyplayerme/meshops/mesh.py @@ -4,8 +4,9 @@ import numpy as np import trimesh +from scipy.spatial import cKDTree -from readyplayerme.meshops.types import Edges, Indices, Mesh, VariableLengthArrays, Vertices +from readyplayerme.meshops.types import Edges, IndexGroups, Indices, Mesh, Vertices def read_mesh(filename: str | Path) -> Mesh: @@ -49,27 +50,31 @@ def get_boundary_vertices(edges: Edges) -> Indices: return np.unique(unique_edges[border_edge_indices]) -def get_overlapping_vertices(vertices_pos: Vertices, indices: Indices | None = None) -> VariableLengthArrays: +def get_overlapping_vertices( + vertices_pos: Vertices, indices: Indices | None = None, tolerance: float = 0.00001 +) -> IndexGroups: """Return the indices of the vertices grouped by the same position. - Vertices that have the same position belong to a seam. - - - :param vertices: All the vertices of the mesh. - :param indices: Vertex indices. - :return: A list of grouped border vertices that share position. + :param vertices_pos: All the vertices of the mesh. + :param indices: Vertex indices. + :param precision: Tolerance for considering positions as overlapping. + :return: A list of grouped vertices that share position. """ - if indices is None: - indices = np.arange(len(vertices_pos)) - - vertex_positions = vertices_pos[indices] - rounded_positions = np.round(vertex_positions, decimals=5) - structured_positions = np.core.records.fromarrays( - rounded_positions.transpose(), names="x, y, z", formats="f8, f8, f8" - ) - unique_positions, local_indices = np.unique(structured_positions, return_inverse=True) - grouped_indices = [ - indices[local_indices == i] for i in range(len(unique_positions)) if (local_indices == i).sum() > 1 - ] + selected_vertices = vertices_pos if indices is None else vertices_pos[indices] + + tree = cKDTree(selected_vertices) + + grouped_indices = [] + processed = set() + for idx, vertex in enumerate(selected_vertices): + if idx not in processed: + # Find all points within the tolerance distance + neighbors = tree.query_ball_point(vertex, tolerance) + if len(neighbors) > 1: # Include only groups with multiple vertices + # Translate to original indices if needed + group = np.array(neighbors, dtype=np.uint32) if indices is None else indices[neighbors] + grouped_indices.append(group) + # Mark these points as processed + processed.update(neighbors) return grouped_indices diff --git a/src/readyplayerme/meshops/types.py b/src/readyplayerme/meshops/types.py index dc8535e..d4189f7 100644 --- a/src/readyplayerme/meshops/types.py +++ b/src/readyplayerme/meshops/types.py @@ -5,11 +5,11 @@ import numpy.typing as npt # trimesh uses int64 and float64 for its arrays. -Indices: TypeAlias = npt.NDArray[np.int32] | npt.NDArray[np.int64] # Shape (i,) +Indices: TypeAlias = npt.NDArray[np.uint32] | npt.NDArray[np.uint64] # Shape (i,) Vertices: TypeAlias = npt.NDArray[np.float32] | npt.NDArray[np.float64] # Shape (v, 3) Edges: TypeAlias = npt.NDArray[np.int32] | npt.NDArray[np.int64] # Shape (e, 2) Faces: TypeAlias = npt.NDArray[np.int32] | npt.NDArray[np.int64] # Shape (f, 3) -VariableLengthArrays: TypeAlias = list[npt.NDArray[np.int64]] +IndexGroups: TypeAlias = list[npt.NDArray[np.uint32]] class Mesh(Protocol): diff --git a/tests/readyplayerme/meshops/unit/test_mesh.py b/tests/readyplayerme/meshops/unit/test_mesh.py index 0a5b39c..7ea892e 100644 --- a/tests/readyplayerme/meshops/unit/test_mesh.py +++ b/tests/readyplayerme/meshops/unit/test_mesh.py @@ -60,10 +60,10 @@ def test_get_boundary_vertices(mock_mesh: Mesh): @pytest.mark.parametrize( - "vertices, indices, expected", + "vertices, indices, precision, expected", [ # Vertices from our mock mesh. - ("mock_mesh", np.array([0, 2, 4, 6, 7, 9, 10]), [(np.array([9, 10]))]), + ("mock_mesh", np.array([0, 2, 4, 6, 7, 9, 10]), 0.1, [np.array([9, 10])]), # Close positions, but with imprecision. ( np.array( @@ -76,27 +76,30 @@ def test_get_boundary_vertices(mock_mesh: Mesh): ] ), np.array([0, 1, 2, 3, 4]), + 0.0001, [np.array([0, 1]), np.array([2, 3, 4])], ), # Overlapping vertices, None indices given. ( np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]), None, + 0.1, [np.array([0, 1])], ), # Overlapping vertices, but empty indices given. - (np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]), np.array([], dtype=np.int32), []), + (np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]), np.array([], dtype=np.int32), 0.1, []), ], ) -def test_overlapping_vertices(vertices: Vertices, indices: Indices, expected: Indices, request: pytest.FixtureRequest): +def test_get_overlapping_vertices( + vertices: Vertices, indices: Indices, precision: float, expected: Indices, request: pytest.FixtureRequest +): """Test the get_overlapping_vertices functions returns the expected indices groups.""" # Get vertices from the fixture if one is given. if isinstance(vertices, str) and vertices == "mock_mesh": vertices = request.getfixturevalue("mock_mesh").vertices - grouped_vertices = mesh.get_overlapping_vertices(vertices, indices) + grouped_vertices = mesh.get_overlapping_vertices(vertices, indices, precision) assert len(grouped_vertices) == len(expected), "Number of groups doesn't match expected" - assert np.array_equiv( - grouped_vertices, expected - ), "The vertices returned by get_overlapping_vertices do not match the expected vertices." + for group, exp_group in zip(grouped_vertices, expected, strict=False): + assert np.array_equal(group, exp_group), f"Grouped vertices {group} do not match expected {exp_group}" From 8965bd8e531c4b14ec304265bd610d01de4946ab Mon Sep 17 00:00:00 2001 From: Olaf Haag Date: Fri, 17 Nov 2023 18:04:46 +0100 Subject: [PATCH 5/7] test: catch IndexError Add test for IndexError in get_overlapping_vertices --- src/readyplayerme/meshops/mesh.py | 6 +++++- tests/readyplayerme/meshops/unit/test_mesh.py | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/readyplayerme/meshops/mesh.py b/src/readyplayerme/meshops/mesh.py index 6c3caf7..e528867 100644 --- a/src/readyplayerme/meshops/mesh.py +++ b/src/readyplayerme/meshops/mesh.py @@ -60,7 +60,11 @@ def get_overlapping_vertices( :param precision: Tolerance for considering positions as overlapping. :return: A list of grouped vertices that share position. """ - selected_vertices = vertices_pos if indices is None else vertices_pos[indices] + try: + selected_vertices = vertices_pos if indices is None else vertices_pos[indices] + except IndexError as error: + msg = "Indices must be within bounds of vertices array." + raise IndexError(msg) from error tree = cKDTree(selected_vertices) diff --git a/tests/readyplayerme/meshops/unit/test_mesh.py b/tests/readyplayerme/meshops/unit/test_mesh.py index 7ea892e..25098d3 100644 --- a/tests/readyplayerme/meshops/unit/test_mesh.py +++ b/tests/readyplayerme/meshops/unit/test_mesh.py @@ -103,3 +103,12 @@ def test_get_overlapping_vertices( assert len(grouped_vertices) == len(expected), "Number of groups doesn't match expected" for group, exp_group in zip(grouped_vertices, expected, strict=False): assert np.array_equal(group, exp_group), f"Grouped vertices {group} do not match expected {exp_group}" + + +def test_get_overlapping_vertices_index_error(): + """Test the get_overlapping_vertices function with indices that are out of bounds for the vertices.""" + vertices = np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]) + indices = np.array([2, 3, -4]) + + with pytest.raises(IndexError): + mesh.get_overlapping_vertices(vertices, indices) From ab93f12dba00e3d67f5fc0204e0b74683886f698 Mon Sep 17 00:00:00 2001 From: Olaf Haag Date: Fri, 17 Nov 2023 18:10:40 +0100 Subject: [PATCH 6/7] test: fix type of expected fix type of expected in test_get_overlapping_vertices to IndexGroups --- tests/readyplayerme/meshops/unit/test_mesh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/readyplayerme/meshops/unit/test_mesh.py b/tests/readyplayerme/meshops/unit/test_mesh.py index 25098d3..a9c32ba 100644 --- a/tests/readyplayerme/meshops/unit/test_mesh.py +++ b/tests/readyplayerme/meshops/unit/test_mesh.py @@ -8,7 +8,7 @@ import pytest from readyplayerme.meshops import mesh -from readyplayerme.meshops.types import Indices, Mesh, Vertices +from readyplayerme.meshops.types import IndexGroups, Indices, Mesh, Vertices class TestReadMesh: @@ -91,7 +91,7 @@ def test_get_boundary_vertices(mock_mesh: Mesh): ], ) def test_get_overlapping_vertices( - vertices: Vertices, indices: Indices, precision: float, expected: Indices, request: pytest.FixtureRequest + vertices: Vertices, indices: Indices, precision: float, expected: IndexGroups, request: pytest.FixtureRequest ): """Test the get_overlapping_vertices functions returns the expected indices groups.""" # Get vertices from the fixture if one is given. From e36832579f5ea637f26589827499aa8ef96a670e Mon Sep 17 00:00:00 2001 From: TechyDaniel <117300186+TechyDaniel@users.noreply.github.com> Date: Fri, 17 Nov 2023 20:54:21 +0100 Subject: [PATCH 7/7] refactor(mesh): update get_overlapping_vertices for edge case handling - Handle empty and negative indices in get_overlapping_vertices. - Include additional tests to cover new checks. --- src/readyplayerme/meshops/mesh.py | 20 ++++++++++++++----- tests/readyplayerme/meshops/unit/test_mesh.py | 15 ++++++++++---- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/readyplayerme/meshops/mesh.py b/src/readyplayerme/meshops/mesh.py index e528867..2ef70cc 100644 --- a/src/readyplayerme/meshops/mesh.py +++ b/src/readyplayerme/meshops/mesh.py @@ -60,11 +60,21 @@ def get_overlapping_vertices( :param precision: Tolerance for considering positions as overlapping. :return: A list of grouped vertices that share position. """ - try: - selected_vertices = vertices_pos if indices is None else vertices_pos[indices] - except IndexError as error: - msg = "Indices must be within bounds of vertices array." - raise IndexError(msg) from error + # Not using try / except because when using an index of -1 gets the last element and creates a false positive + if indices is None: + selected_vertices = vertices_pos + else: + if len(indices) == 0: + return [] + if np.any(indices < 0): + msg = "Negative index value is not allowed." + raise IndexError(msg) + + if np.max(indices) >= len(vertices_pos): + msg = "Index is out of bounds." + raise IndexError(msg) + + selected_vertices = vertices_pos[indices] tree = cKDTree(selected_vertices) diff --git a/tests/readyplayerme/meshops/unit/test_mesh.py b/tests/readyplayerme/meshops/unit/test_mesh.py index a9c32ba..1d09b17 100644 --- a/tests/readyplayerme/meshops/unit/test_mesh.py +++ b/tests/readyplayerme/meshops/unit/test_mesh.py @@ -105,10 +105,17 @@ def test_get_overlapping_vertices( assert np.array_equal(group, exp_group), f"Grouped vertices {group} do not match expected {exp_group}" -def test_get_overlapping_vertices_index_error(): - """Test the get_overlapping_vertices function with indices that are out of bounds for the vertices.""" +@pytest.mark.parametrize( + "indices", + [ + # Case with index out of bounds (higher than max) + np.array([0, 3], dtype=np.uint16), + # Case with index out of bounds (negative index) + np.array([0, -1], dtype=np.int32), # Using int32 to allow negative values + ], +) +def test_get_overlapping_vertices_error_handling(indices): + """Test that get_overlapping_vertices function raises an exception for out of bounds indices.""" vertices = np.array([[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]) - indices = np.array([2, 3, -4]) - with pytest.raises(IndexError): mesh.get_overlapping_vertices(vertices, indices)