[utils] remove_duplicate_vertices now takes a tolerance (default exact)

This commit is contained in:
Jan Petykiewicz 2026-06-16 00:12:16 -07:00
commit f4df8e0553
2 changed files with 40 additions and 3 deletions

View file

@ -5,7 +5,15 @@ from numpy.testing import assert_equal, assert_allclose
from numpy import pi
import pytest
from ..utils import remove_duplicate_vertices, remove_colinear_vertices, poly_contains_points, rotation_matrix_2d, apply_transforms, normalize_mirror, DeferredDict
from ..utils import (
DeferredDict,
apply_transforms,
normalize_mirror,
poly_contains_points,
remove_colinear_vertices,
remove_duplicate_vertices,
rotation_matrix_2d,
)
from ..file.utils import tmpfile
from ..utils.curves import bezier
from ..error import PatternError
@ -23,6 +31,23 @@ def test_remove_duplicate_vertices() -> None:
assert_equal(v_clean_open, [[0, 0], [1, 1], [2, 2], [0, 0]])
def test_remove_duplicate_vertices_tolerance_defaults_to_exact_match() -> None:
v = [[0, 0], [1, 1], [1 + 1e-13, 1], [2, 2], [1e-13, 0]]
assert_allclose(remove_duplicate_vertices(v, closed_path=True), v, atol=0, rtol=0)
assert_allclose(
remove_duplicate_vertices(v, closed_path=True, tolerance=1e-12),
[[0, 0], [1 + 1e-13, 1], [2, 2]],
atol=0,
rtol=0,
)
def test_remove_duplicate_vertices_rejects_negative_tolerance() -> None:
with pytest.raises(ValueError, match='non-negative'):
remove_duplicate_vertices([[0, 0]], tolerance=-1)
def test_remove_colinear_vertices() -> None:
v = [[0, 0], [1, 0], [2, 0], [2, 1], [2, 2], [1, 1], [0, 0]]
v_clean = remove_colinear_vertices(v, closed_path=True)

View file

@ -5,7 +5,11 @@ import numpy
from numpy.typing import NDArray, ArrayLike
def remove_duplicate_vertices(vertices: ArrayLike, closed_path: bool = True) -> NDArray[numpy.float64]:
def remove_duplicate_vertices(
vertices: ArrayLike,
closed_path: bool = True,
tolerance: float = 0.0,
) -> NDArray[numpy.float64]:
"""
Given a list of vertices, remove any consecutive duplicates.
@ -13,14 +17,22 @@ def remove_duplicate_vertices(vertices: ArrayLike, closed_path: bool = True) ->
vertices: `[[x0, y0], [x1, y1], ...]`
closed_path: If True, `vertices` is interpreted as an implicity-closed path
(i.e. the last vertex will be removed if it is the same as the first)
tolerance: Maximum coordinate-wise absolute difference for two vertices to
be considered duplicates. Default `0` requires exact equality.
Returns:
`vertices` with no consecutive duplicates. This may be a view into the original array.
"""
if tolerance < 0:
raise ValueError(f'tolerance must be non-negative, got {tolerance}')
vertices = numpy.asarray(vertices)
if vertices.shape[0] <= 1:
return vertices
duplicates = (vertices == numpy.roll(vertices, -1, axis=0)).all(axis=1)
if tolerance == 0:
duplicates = (vertices == numpy.roll(vertices, -1, axis=0)).all(axis=1)
else:
duplicates = (numpy.abs(vertices - numpy.roll(vertices, -1, axis=0)) <= tolerance).all(axis=1)
if not closed_path:
duplicates[-1] = False