trifinder.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import numpy as np
  2. from matplotlib import cbook
  3. from matplotlib.tri import Triangulation
  4. class TriFinder:
  5. """
  6. Abstract base class for classes used to find the triangles of a
  7. Triangulation in which (x, y) points lie.
  8. Rather than instantiate an object of a class derived from TriFinder, it is
  9. usually better to use the function
  10. :func:`matplotlib.tri.Triangulation.get_trifinder`.
  11. Derived classes implement __call__(x, y) where x and y are array-like point
  12. coordinates of the same shape.
  13. """
  14. def __init__(self, triangulation):
  15. cbook._check_isinstance(Triangulation, triangulation=triangulation)
  16. self._triangulation = triangulation
  17. class TrapezoidMapTriFinder(TriFinder):
  18. """
  19. :class:`~matplotlib.tri.TriFinder` class implemented using the trapezoid
  20. map algorithm from the book "Computational Geometry, Algorithms and
  21. Applications", second edition, by M. de Berg, M. van Kreveld, M. Overmars
  22. and O. Schwarzkopf.
  23. The triangulation must be valid, i.e. it must not have duplicate points,
  24. triangles formed from colinear points, or overlapping triangles. The
  25. algorithm has some tolerance to triangles formed from colinear points, but
  26. this should not be relied upon.
  27. """
  28. def __init__(self, triangulation):
  29. from matplotlib import _tri
  30. TriFinder.__init__(self, triangulation)
  31. self._cpp_trifinder = _tri.TrapezoidMapTriFinder(
  32. triangulation.get_cpp_triangulation())
  33. self._initialize()
  34. def __call__(self, x, y):
  35. """
  36. Return an array containing the indices of the triangles in which the
  37. specified *x*, *y* points lie, or -1 for points that do not lie within
  38. a triangle.
  39. *x*, *y* are array-like x and y coordinates of the same shape and any
  40. number of dimensions.
  41. Returns integer array with the same shape and *x* and *y*.
  42. """
  43. x = np.asarray(x, dtype=np.float64)
  44. y = np.asarray(y, dtype=np.float64)
  45. if x.shape != y.shape:
  46. raise ValueError("x and y must be array-like with the same shape")
  47. # C++ does the heavy lifting, and expects 1D arrays.
  48. indices = (self._cpp_trifinder.find_many(x.ravel(), y.ravel())
  49. .reshape(x.shape))
  50. return indices
  51. def _get_tree_stats(self):
  52. """
  53. Return a python list containing the statistics about the node tree:
  54. 0: number of nodes (tree size)
  55. 1: number of unique nodes
  56. 2: number of trapezoids (tree leaf nodes)
  57. 3: number of unique trapezoids
  58. 4: maximum parent count (max number of times a node is repeated in
  59. tree)
  60. 5: maximum depth of tree (one more than the maximum number of
  61. comparisons needed to search through the tree)
  62. 6: mean of all trapezoid depths (one more than the average number
  63. of comparisons needed to search through the tree)
  64. """
  65. return self._cpp_trifinder.get_tree_stats()
  66. def _initialize(self):
  67. """
  68. Initialize the underlying C++ object. Can be called multiple times if,
  69. for example, the triangulation is modified.
  70. """
  71. self._cpp_trifinder.initialize()
  72. def _print_tree(self):
  73. """
  74. Print a text representation of the node tree, which is useful for
  75. debugging purposes.
  76. """
  77. self._cpp_trifinder.print_tree()