test_spherical_voronoi.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. from __future__ import print_function
  2. import numpy as np
  3. import itertools
  4. from numpy.testing import (assert_equal,
  5. assert_almost_equal,
  6. assert_array_equal,
  7. assert_array_almost_equal)
  8. from pytest import raises as assert_raises
  9. from scipy.spatial import SphericalVoronoi, distance
  10. from scipy.spatial import _spherical_voronoi as spherical_voronoi
  11. class TestCircumcenters(object):
  12. def test_circumcenters(self):
  13. tetrahedrons = np.array([
  14. [[1, 2, 3],
  15. [-1.1, -2.1, -3.1],
  16. [-1.2, 2.2, 3.2],
  17. [-1.3, -2.3, 3.3]],
  18. [[10, 20, 30],
  19. [-10.1, -20.1, -30.1],
  20. [-10.2, 20.2, 30.2],
  21. [-10.3, -20.3, 30.3]]
  22. ])
  23. result = spherical_voronoi.calc_circumcenters(tetrahedrons)
  24. expected = [
  25. [-0.5680861153262529, -0.133279590288315, 0.1843323216995444],
  26. [-0.5965330784014926, -0.1480377040397778, 0.1981967854886021]
  27. ]
  28. assert_array_almost_equal(result, expected)
  29. class TestProjectToSphere(object):
  30. def test_unit_sphere(self):
  31. points = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
  32. center = np.array([0, 0, 0])
  33. radius = 1
  34. projected = spherical_voronoi.project_to_sphere(points, center, radius)
  35. assert_array_almost_equal(points, projected)
  36. def test_scaled_points(self):
  37. points = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
  38. center = np.array([0, 0, 0])
  39. radius = 1
  40. scaled = points * 2
  41. projected = spherical_voronoi.project_to_sphere(scaled, center, radius)
  42. assert_array_almost_equal(points, projected)
  43. def test_translated_sphere(self):
  44. points = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
  45. center = np.array([1, 2, 3])
  46. translated = points + center
  47. radius = 1
  48. projected = spherical_voronoi.project_to_sphere(translated, center,
  49. radius)
  50. assert_array_almost_equal(translated, projected)
  51. class TestSphericalVoronoi(object):
  52. def setup_method(self):
  53. self.points = np.array([
  54. [-0.78928481, -0.16341094, 0.59188373],
  55. [-0.66839141, 0.73309634, 0.12578818],
  56. [0.32535778, -0.92476944, -0.19734181],
  57. [-0.90177102, -0.03785291, -0.43055335],
  58. [0.71781344, 0.68428936, 0.12842096],
  59. [-0.96064876, 0.23492353, -0.14820556],
  60. [0.73181537, -0.22025898, -0.6449281],
  61. [0.79979205, 0.54555747, 0.25039913]]
  62. )
  63. def test_constructor(self):
  64. center = np.array([1, 2, 3])
  65. radius = 2
  66. s1 = SphericalVoronoi(self.points)
  67. # user input checks in SphericalVoronoi now require
  68. # the radius / center to match the generators so adjust
  69. # accordingly here
  70. s2 = SphericalVoronoi(self.points * radius, radius)
  71. s3 = SphericalVoronoi(self.points + center, None, center)
  72. s4 = SphericalVoronoi(self.points * radius + center, radius, center)
  73. assert_array_equal(s1.center, np.array([0, 0, 0]))
  74. assert_equal(s1.radius, 1)
  75. assert_array_equal(s2.center, np.array([0, 0, 0]))
  76. assert_equal(s2.radius, 2)
  77. assert_array_equal(s3.center, center)
  78. assert_equal(s3.radius, 1)
  79. assert_array_equal(s4.center, center)
  80. assert_equal(s4.radius, radius)
  81. def test_vertices_regions_translation_invariance(self):
  82. sv_origin = SphericalVoronoi(self.points)
  83. center = np.array([1, 1, 1])
  84. sv_translated = SphericalVoronoi(self.points + center, None, center)
  85. assert_array_equal(sv_origin.regions, sv_translated.regions)
  86. assert_array_almost_equal(sv_origin.vertices + center,
  87. sv_translated.vertices)
  88. def test_vertices_regions_scaling_invariance(self):
  89. sv_unit = SphericalVoronoi(self.points)
  90. sv_scaled = SphericalVoronoi(self.points * 2, 2)
  91. assert_array_equal(sv_unit.regions, sv_scaled.regions)
  92. assert_array_almost_equal(sv_unit.vertices * 2,
  93. sv_scaled.vertices)
  94. def test_sort_vertices_of_regions(self):
  95. sv = SphericalVoronoi(self.points)
  96. unsorted_regions = sv.regions
  97. sv.sort_vertices_of_regions()
  98. assert_array_equal(sorted(sv.regions), sorted(unsorted_regions))
  99. def test_sort_vertices_of_regions_flattened(self):
  100. expected = sorted([[0, 6, 5, 2, 3], [2, 3, 10, 11, 8, 7], [0, 6, 4, 1], [4, 8,
  101. 7, 5, 6], [9, 11, 10], [2, 7, 5], [1, 4, 8, 11, 9], [0, 3, 10, 9,
  102. 1]])
  103. expected = list(itertools.chain(*sorted(expected)))
  104. sv = SphericalVoronoi(self.points)
  105. sv.sort_vertices_of_regions()
  106. actual = list(itertools.chain(*sorted(sv.regions)))
  107. assert_array_equal(actual, expected)
  108. def test_num_vertices(self):
  109. # for any n >= 3, a spherical Voronoi diagram has 2n - 4
  110. # vertices; this is a direct consequence of Euler's formula
  111. # as explained by Dinis and Mamede (2010) Proceedings of the
  112. # 2010 International Symposium on Voronoi Diagrams in Science
  113. # and Engineering
  114. sv = SphericalVoronoi(self.points)
  115. expected = self.points.shape[0] * 2 - 4
  116. actual = sv.vertices.shape[0]
  117. assert_equal(actual, expected)
  118. def test_voronoi_circles(self):
  119. sv = spherical_voronoi.SphericalVoronoi(self.points)
  120. for vertex in sv.vertices:
  121. distances = distance.cdist(sv.points,np.array([vertex]))
  122. closest = np.array(sorted(distances)[0:3])
  123. assert_almost_equal(closest[0], closest[1], 7, str(vertex))
  124. assert_almost_equal(closest[0], closest[2], 7, str(vertex))
  125. def test_duplicate_point_handling(self):
  126. # an exception should be raised for degenerate generators
  127. # related to Issue# 7046
  128. self.degenerate = np.concatenate((self.points, self.points))
  129. with assert_raises(ValueError):
  130. sv = spherical_voronoi.SphericalVoronoi(self.degenerate)
  131. def test_incorrect_radius_handling(self):
  132. # an exception should be raised if the radius provided
  133. # cannot possibly match the input generators
  134. with assert_raises(ValueError):
  135. sv = spherical_voronoi.SphericalVoronoi(self.points,
  136. radius=0.98)
  137. def test_incorrect_center_handling(self):
  138. # an exception should be raised if the center provided
  139. # cannot possibly match the input generators
  140. with assert_raises(ValueError):
  141. sv = spherical_voronoi.SphericalVoronoi(self.points,
  142. center=[0.1,0,0])