diff --git a/magpylib/_src/fields/field_BH_triangularmesh.py b/magpylib/_src/fields/field_BH_triangularmesh.py index 070a81505..852a0405d 100644 --- a/magpylib/_src/fields/field_BH_triangularmesh.py +++ b/magpylib/_src/fields/field_BH_triangularmesh.py @@ -129,7 +129,9 @@ def get_open_edges(faces: np.ndarray) -> bool: return edges_uniq[edge_counts != 2] -def fix_trimesh_orientation(vertices: np.ndarray, faces: np.ndarray) -> np.ndarray: +def fix_trimesh_orientation( + vertices: np.ndarray, faces: np.ndarray, show_progress=False +) -> np.ndarray: """Check if all faces are oriented outwards. Fix the ones that are not, and return an array of properly oriented faces. @@ -148,7 +150,7 @@ def fix_trimesh_orientation(vertices: np.ndarray, faces: np.ndarray) -> np.ndarr """ # use first triangle as a seed, this one needs to be oriented via inside check # compute facet orientation (normalized) - inwards_mask = get_inwards_mask(vertices, faces) + inwards_mask = get_inwards_mask(vertices, faces, show_progress=show_progress) new_faces = faces.copy() new_faces[inwards_mask] = new_faces[inwards_mask][:, [0, 2, 1]] return new_faces @@ -169,9 +171,13 @@ def is_facet_inwards(face, faces): return mask_inside_trimesh(np.array([check_point]), faces)[0] +from tqdm import tqdm + +from tqdm import tqdm + + def get_inwards_mask( - vertices: np.ndarray, - triangles: np.ndarray, + vertices: np.ndarray, triangles: np.ndarray, show_progress: bool = False ) -> np.ndarray: """Return a boolean mask of normals from triangles. True -> Inwards, False -> Outwards. @@ -186,6 +192,9 @@ def get_inwards_mask( triangles: np.ndarray, shape (n,3), dtype int Triples of indices + show_progress: bool, optional + If True, displays a progress bar + Returns ------- boolean mask : ndarray, shape (n,), dtype bool @@ -196,6 +205,15 @@ def get_inwards_mask( mask = np.full(len(triangles), False) indices = list(range(len(triangles))) + # Prepare progress bar + pbar = tqdm( + total=len(triangles), disable=not show_progress, desc="Reorienting faces" + ) + + # Set up variables for controlling update frequency + update_step = len(triangles) // 100 # update every 1% step + update_counter = 0 + # incrementally add triangles sharing at least a common edge by looping among left over # triangles. If next triangle with common edge is reversed, flip it. any_connected = False @@ -229,6 +247,17 @@ def get_inwards_mask( # having some indices to go trough -> mesh is is disconnected. A new seed is # needed and needs to be checked via ray tracing before continuing. any_connected = False + + # Update progress bar every update_step iterations + update_counter += 1 + if update_counter >= update_step: + pbar.update(update_step) + update_counter = 0 + + # Update for remaining progress not covered by update_step and close progress bar + pbar.update(update_counter) + pbar.close() + return mask diff --git a/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py b/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py index c6b9883ba..72ca68b56 100644 --- a/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py +++ b/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py @@ -123,6 +123,7 @@ def __init__( check_disconnected="warn", check_selfintersecting="warn", reorient_faces="warn", + show_progress=False, style=None, **kwargs, ): @@ -137,7 +138,7 @@ def __init__( self.check_open(mode=check_open) self.check_disconnected(mode=check_disconnected) - self.reorient_faces(mode=reorient_faces) + self.reorient_faces(mode=reorient_faces, show_progress=show_progress) self.check_selfintersecting(mode=check_selfintersecting) # inherit @@ -334,7 +335,7 @@ def check_selfintersecting(self, mode="warn"): raise ValueError(msg) return self._status_selfintersecting - def reorient_faces(self, mode="warn"): + def reorient_faces(self, mode="warn", show_progress=False): """Correctly reorients the mesh's faces. In a properly oriented mesh, all faces must be oriented outwards. This function @@ -383,7 +384,9 @@ def reorient_faces(self, mode="warn"): elif mode == "raise": raise ValueError(msg) - self._faces = fix_trimesh_orientation(self._vertices, self._faces) + self._faces = fix_trimesh_orientation( + self._vertices, self._faces, show_progress=show_progress + ) self._status_reoriented = True def get_faces_subsets(self):