|
| 1 | +from dataclasses import dataclass |
| 2 | +import logging |
| 3 | +from typing import List |
| 4 | + |
| 5 | +from vtkmodules.vtkFiltersGeneral import ( |
| 6 | + vtkCellValidator |
| 7 | +) |
| 8 | +from vtkmodules.vtkCommonCore import ( |
| 9 | + vtkOutputWindow, |
| 10 | + vtkFileOutputWindow |
| 11 | +) |
| 12 | +from vtk.util.numpy_support import ( |
| 13 | + vtk_to_numpy, |
| 14 | +) |
| 15 | + |
| 16 | +from . import vtk_utils |
| 17 | + |
| 18 | + |
| 19 | +@dataclass(frozen=True) |
| 20 | +class Options: |
| 21 | + tolerance: float |
| 22 | + |
| 23 | + |
| 24 | +@dataclass(frozen=True) |
| 25 | +class Result: |
| 26 | + wrong_number_of_points_elements: List[int] |
| 27 | + intersecting_edges_elements: List[int] |
| 28 | + intersecting_faces_elements: List[int] |
| 29 | + non_contiguous_edges_elements: List[int] |
| 30 | + non_convex_elements: List[int] |
| 31 | + faces_are_oriented_incorrectly_elements: List[int] |
| 32 | + |
| 33 | + |
| 34 | +def __check(mesh, options: Options) -> Result: |
| 35 | + err_out = vtkFileOutputWindow() |
| 36 | + err_out.SetFileName("/dev/null") # vtkCellValidator outputs loads for each cell... |
| 37 | + vtk_std_err_out = vtkOutputWindow() |
| 38 | + vtk_std_err_out.SetInstance(err_out) |
| 39 | + |
| 40 | + valid = 0x0 |
| 41 | + wrong_number_of_points = 0x01 |
| 42 | + intersecting_edges = 0x02 |
| 43 | + intersecting_faces = 0x04 |
| 44 | + non_contiguous_edges = 0x08 |
| 45 | + non_convex = 0x10 |
| 46 | + faces_are_oriented_incorrectly = 0x20 |
| 47 | + |
| 48 | + wrong_number_of_points_elements: List[int] = [] |
| 49 | + intersecting_edges_elements: List[int] = [] |
| 50 | + intersecting_faces_elements: List[int] = [] |
| 51 | + non_contiguous_edges_elements: List[int] = [] |
| 52 | + non_convex_elements: List[int] = [] |
| 53 | + faces_are_oriented_incorrectly_elements: List[int] = [] |
| 54 | + |
| 55 | + f = vtkCellValidator() |
| 56 | + f.SetTolerance(options.tolerance) |
| 57 | + |
| 58 | + f.SetInputData(mesh) |
| 59 | + f.Update() |
| 60 | + output = f.GetOutput() |
| 61 | + |
| 62 | + cd = output.GetCellData() |
| 63 | + for i in range(cd.GetNumberOfArrays()): |
| 64 | + if cd.GetArrayName(i) == "ValidityState": # Could not change name using the vtk interface. |
| 65 | + validity = vtk_to_numpy(cd.GetArray(i)) |
| 66 | + assert validity is not None |
| 67 | + for i, v in enumerate(validity): |
| 68 | + if not v & valid: |
| 69 | + if v & wrong_number_of_points: |
| 70 | + wrong_number_of_points_elements.append(i) |
| 71 | + if v & intersecting_edges: |
| 72 | + intersecting_edges_elements.append(i) |
| 73 | + if v & intersecting_faces: |
| 74 | + intersecting_faces_elements.append(i) |
| 75 | + if v & non_contiguous_edges: |
| 76 | + non_contiguous_edges_elements.append(i) |
| 77 | + if v & non_convex: |
| 78 | + non_convex_elements.append(i) |
| 79 | + if v & faces_are_oriented_incorrectly: |
| 80 | + faces_are_oriented_incorrectly_elements.append(i) |
| 81 | + return Result(wrong_number_of_points_elements=wrong_number_of_points_elements, |
| 82 | + intersecting_edges_elements=intersecting_edges_elements, |
| 83 | + intersecting_faces_elements=intersecting_faces_elements, |
| 84 | + non_contiguous_edges_elements=non_contiguous_edges_elements, |
| 85 | + non_convex_elements=non_convex_elements, |
| 86 | + faces_are_oriented_incorrectly_elements=faces_are_oriented_incorrectly_elements) |
| 87 | + |
| 88 | + |
| 89 | +def check(vtk_input_file: str, options: Options) -> Result: |
| 90 | + mesh = vtk_utils.read_mesh(vtk_input_file) |
| 91 | + return __check(mesh, options) |
0 commit comments