Source code for entente.restore_correspondence
def _maybe_tqdm(iterable, progress):
if progress:
from tqdm import tqdm
return tqdm(iterable)
else:
return iterable
[docs]def find_correspondence(
a, b, atol=1e-4, all_must_match=True, ret_unmatched_b=False, progress=True
):
"""
Given `a[0], a[1], ..., a[k]` and `b[0], b[1], ..., b[j]`, match each element
of `a` to the corresponding element of `b`.
When `all_must_match` is `True` `a` and `b` must contain the same set of
elements. `b[find_correspondence(a, b)]` equals `a`. Otherwise, return
`-1` for elements with no match in `b`.
Args:
a (np.arraylike): `kxn` array.
b (np.arraylike): `jxn` array.
atol (float): Match tolerance.
all_must_match (bool): When `True`, `a` and `b` must contain the
same elements.
ret_unmatched_b (bool): When `True`, return a tuple which also contains
the indices of `b` which were not matched.
progress (bool): When `True`, show a progress bar.
Return:
np.ndarray: Indices of `b` as `kx1`
Note:
This relies on a brute-force algorithm.
For the interpretation of `atol`, see documentation for `np.isclose`.
"""
import numpy as np
if all_must_match and len(a) != len(b):
raise ValueError("a and b do not contain the same number of elements")
a_to_b = np.repeat(-1, len(a))
b_matched = np.zeros(len(b), dtype=np.bool_)
for a_index, item in _maybe_tqdm(enumerate(a), progress):
(indices,) = np.nonzero(np.all(np.isclose(b, item, atol=atol), axis=1))
if len(indices) >= 1:
b_index = indices[0]
b_matched[b_index] = True
a_to_b[a_index] = b_index
elif all_must_match:
raise ValueError(
"Couldn't find corresponding element in b for item {} in a".format(
a_index
)
)
if ret_unmatched_b:
(unmatched_b,) = np.where(b_matched == 0)
return a_to_b, unmatched_b
else:
return a_to_b
[docs]def restore_correspondence(shuffled_mesh, reference_mesh, atol=1e-4, progress=True):
"""
Given a reference mesh, reorder the vertices of a shuffled copy to restore
correspondence with the reference mesh. The vertex set of the shuffled
mesh and reference mesh must be equal within `atol`. Mutate
`reference_mesh`. Ignore faces but preserves their integrity.
Args:
reference_mesh (lace.mesh.Mesh): A mesh with the vertices in the
desired order.
shuffled_mesh (lace.mesh.Mesh): A mesh with the same vertex set as
`reference_mesh`.
progress (bool): When `True`, show a progress bar.
Returns:
np.ndarray: `vx1` which maps old vertices in `shuffled_mesh` to new.
Note:
This was designed to assist in extracting face ordering and groups from a
`shuffled_mesh` that "work" with `reference_mesh`, so the face ordering
and groups can be used with different vertices.
It relies on a brute-force algorithm.
"""
v_old_to_new = find_correspondence(
shuffled_mesh.v, reference_mesh.v, atol=atol, progress=progress
)
shuffled_mesh.reorder_vertices(v_old_to_new)
return v_old_to_new