icosahedron.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. # Copyright (C) 2016 Intel Corporation. All rights reserved.
  2. #
  3. # This file is free software: you can redistribute it and/or modify it
  4. # under the terms of the GNU General Public License as published by the
  5. # Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This file is distributed in the hope that it will be useful, but
  9. # WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. # See the GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License along
  14. # with this program. If not, see <http://www.gnu.org/licenses/>.
  15. import math
  16. from scipy.constants import golden as g
  17. class Vertex(tuple):
  18. def __new__(cls, x, y, z):
  19. instance = tuple.__new__(cls, (x, y, z))
  20. instance.x = x
  21. instance.y = y
  22. instance.z = z
  23. return instance
  24. def __repr__(self):
  25. return "(" + ",".join(Vertex._print_map.get(x, str(x)) for x in self) + ")"
  26. def __str__(self):
  27. return self.__repr__()
  28. def __neg__(self):
  29. return Vertex(-self.x, -self.y, -self.z)
  30. def __add__(self, other):
  31. return Vertex(self.x + other.x, self.y + other.y, self.z + other.z)
  32. def __sub__(self, other):
  33. return Vertex(self.x - other.x, self.y - other.y, self.z - other.z)
  34. def __mul__(self, s):
  35. return Vertex(s * self.x, s * self.y, s * self.z)
  36. __rmul__ = __mul__
  37. def length(self):
  38. return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
  39. def normalized(self):
  40. return (1.0 / self.length()) * self
  41. class Triangle(tuple):
  42. def __new__(cls, a, b, c):
  43. instance = tuple.__new__(cls, (a, b, c))
  44. instance.a = a
  45. instance.b = b
  46. instance.c = c
  47. return instance
  48. def __neg__(self):
  49. return Triangle(-self.a, -self.b, -self.c)
  50. def __str__(self):
  51. if self in triangles:
  52. i = triangles.index(self)
  53. return "Triangle %2d: %s" % (i, self.__repr__())
  54. else:
  55. return self.__repr__()
  56. Vertex._print_map = {
  57. g: ' g', -g: '-g', 1: ' 1', -1: '-1', 0: ' 0',
  58. }
  59. vertices = tuple(
  60. Vertex(x, y, z) for x, y, z in (
  61. ( g, 1, 0),
  62. ( g,-1, 0),
  63. (-g, 1, 0),
  64. (-g,-1, 0),
  65. ( 1, 0, g),
  66. (-1, 0, g),
  67. ( 1, 0,-g),
  68. (-1, 0,-g),
  69. ( 0, g, 1),
  70. ( 0, g,-1),
  71. ( 0,-g, 1),
  72. ( 0,-g,-1),
  73. )
  74. )
  75. _first_half = (
  76. Triangle(Vertex(-g, 1, 0), Vertex(-1, 0,-g), Vertex(-g,-1, 0)),
  77. Triangle(Vertex(-1, 0,-g), Vertex(-g,-1, 0), Vertex( 0,-g,-1)),
  78. Triangle(Vertex(-g,-1, 0), Vertex( 0,-g,-1), Vertex( 0,-g, 1)),
  79. Triangle(Vertex(-1, 0,-g), Vertex( 0,-g,-1), Vertex( 1, 0,-g)),
  80. Triangle(Vertex( 0,-g,-1), Vertex( 0,-g, 1), Vertex( g,-1, 0)),
  81. Triangle(Vertex( 0,-g,-1), Vertex( 1, 0,-g), Vertex( g,-1, 0)),
  82. Triangle(Vertex( g,-1, 0), Vertex( 1, 0,-g), Vertex( g, 1, 0)),
  83. Triangle(Vertex( 1, 0,-g), Vertex( g, 1, 0), Vertex( 0, g,-1)),
  84. Triangle(Vertex( 1, 0,-g), Vertex( 0, g,-1), Vertex(-1, 0,-g)),
  85. Triangle(Vertex( 0, g,-1), Vertex(-g, 1, 0), Vertex(-1, 0,-g)),
  86. )
  87. _second_half = tuple(-t for t in _first_half)
  88. triangles = _first_half + _second_half
  89. _neighbor_triangle_data = {}
  90. def neighbor_triangle(t, edge):
  91. """ Return the neighbor triangle of t with respect to edge = (a, b) """
  92. e = frozenset(edge)
  93. if (t, e) in _neighbor_triangle_data:
  94. return _neighbor_triangle_data[(t, e)]
  95. a, b = edge
  96. if a not in t or b not in t:
  97. return None
  98. for w in triangles:
  99. if a in w and b in w and w != t:
  100. _neighbor_triangle_data[(t, e)] = w
  101. return w
  102. return None
  103. class _Umbrella:
  104. def __init__(self, pivot):
  105. self.pivot = pivot
  106. self.components = frozenset(t for t in triangles if pivot in t)
  107. all_vertices = set()
  108. for t in self.components:
  109. for v in t:
  110. if v != pivot:
  111. all_vertices.add(v)
  112. self.all_vertices = frozenset(all_vertices)
  113. self._vertex_data = {}
  114. self._component_data = {}
  115. def vertex(self, i, ordered_edge):
  116. """ Return the i-th vertex with respect to ordered_edge = (a, b) """
  117. a, b = ordered_edge
  118. if a not in self.all_vertices:
  119. return None
  120. if b not in self.all_vertices:
  121. return None
  122. if i == 0:
  123. return a
  124. if i == 1:
  125. return b
  126. if (i, a, b) in self._vertex_data:
  127. return self._vertex_data[(i, a, b)]
  128. previous = self.vertex(i - 1, ordered_edge)
  129. comp = self.component(i - 2, ordered_edge)
  130. neighbor = neighbor_triangle(comp, (self.pivot, previous))
  131. for v in neighbor:
  132. if v not in (self.pivot, previous):
  133. self._vertex_data[(i, a, b)] = v
  134. return v
  135. return None
  136. def component(self, i, ordered_edge):
  137. """ Return the i-th component with respect to ordered_edge = (a, b) """
  138. a, b = ordered_edge
  139. if (i, a, b) in self._component_data:
  140. return self._component_data[(i, a, b)]
  141. vi = self.vertex(i, ordered_edge)
  142. vj = self.vertex(i + 1, ordered_edge)
  143. for t in self.components:
  144. if vi in t and vj in t:
  145. self._component_data[(i, a, b)] = t
  146. return t
  147. return None
  148. _umbrelas = {}
  149. def umbrella(pivot):
  150. if pivot not in vertices:
  151. return None
  152. if pivot not in _umbrelas:
  153. _umbrelas[pivot] = _Umbrella(pivot)
  154. return _umbrelas[pivot]
  155. def neighbor_umbrella(t, edge):
  156. neighbor = neighbor_triangle(t, edge)
  157. if not neighbor:
  158. return None
  159. for pivot in neighbor:
  160. if pivot in edge:
  161. continue
  162. return umbrella(pivot)