|
| 1 | +from collections import defaultdict |
| 2 | +from dataclasses import dataclass |
| 3 | +import logging |
| 4 | +from typing import Tuple |
| 5 | + |
| 6 | +import numpy |
| 7 | + |
| 8 | +from vtkmodules.vtkCommonCore import ( |
| 9 | + reference, |
| 10 | + vtkPoints, |
| 11 | +) |
| 12 | +from vtkmodules.vtkCommonDataModel import ( |
| 13 | + vtkIncrementalOctreePointLocator, |
| 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 | + nodes_buckets: Tuple[Tuple[int]] |
| 27 | + |
| 28 | + |
| 29 | +def __check(mesh, options: Options) -> Result: |
| 30 | + points = mesh.GetPoints() |
| 31 | + |
| 32 | + locator = vtkIncrementalOctreePointLocator() |
| 33 | + locator.SetTolerance(options.tolerance) |
| 34 | + output = vtkPoints() |
| 35 | + locator.InitPointInsertion(output, points.GetBounds()) |
| 36 | + |
| 37 | + # original ids to/from filtered ids. |
| 38 | + # original_to_filtered = numpy.ones(points.GetNumberOfPoints(), dtype=int) * -1 |
| 39 | + filtered_to_original = numpy.ones(points.GetNumberOfPoints(), dtype=int) * -1 |
| 40 | + |
| 41 | + rejected_points = defaultdict(list) |
| 42 | + point_id = reference(0) |
| 43 | + for i in range(points.GetNumberOfPoints()): |
| 44 | + is_inserted = locator.InsertUniquePoint(points.GetPoint(i), point_id) |
| 45 | + if not is_inserted: |
| 46 | + # If it's not inserted, `point_id` contains the node that was already at that location. |
| 47 | + # But in that case, `point_id` is the new numbering in the destination points array. |
| 48 | + # It's more useful for the user to get the old index in the original mesh, so he can look for it in his data. |
| 49 | + logging.debug(f"Point {i} at {points.GetPoint(i)} has been rejected, point {filtered_to_original[point_id.get()]} is already inserted.") |
| 50 | + rejected_points[point_id.get()].append(i) |
| 51 | + else: |
| 52 | + # If it's inserted, `point_id` contains the new index in the destination array. |
| 53 | + # We store this information to be able to connect the source and destination arrays. |
| 54 | + # original_to_filtered[i] = point_id.get() |
| 55 | + filtered_to_original[point_id.get()] = i |
| 56 | + |
| 57 | + tmp = [] |
| 58 | + for n, ns in rejected_points.items(): |
| 59 | + tmp.append((n, *ns)) |
| 60 | + |
| 61 | + return Result(nodes_buckets=tmp) |
| 62 | + |
| 63 | + |
| 64 | +def check(vtk_input_file: str, options: Options) -> Result: |
| 65 | + mesh = vtk_utils.read_mesh(vtk_input_file) |
| 66 | + return __check(mesh, options) |
0 commit comments