123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- # Copyright (C) 2016 Intel Corporation. All rights reserved.
- #
- # This file is free software: you can redistribute it and/or modify it
- # under the terms of the GNU General Public License as published by the
- # Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This file is distributed in the hope that it will be useful, but
- # WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- # See the GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along
- # with this program. If not, see <http://www.gnu.org/licenses/>.
- import math
- from scipy.constants import golden as g
- class Vertex(tuple):
- def __new__(cls, x, y, z):
- instance = tuple.__new__(cls, (x, y, z))
- instance.x = x
- instance.y = y
- instance.z = z
- return instance
- def __repr__(self):
- return "(" + ",".join(Vertex._print_map.get(x, str(x)) for x in self) + ")"
- def __str__(self):
- return self.__repr__()
- def __neg__(self):
- return Vertex(-self.x, -self.y, -self.z)
- def __add__(self, other):
- return Vertex(self.x + other.x, self.y + other.y, self.z + other.z)
- def __sub__(self, other):
- return Vertex(self.x - other.x, self.y - other.y, self.z - other.z)
- def __mul__(self, s):
- return Vertex(s * self.x, s * self.y, s * self.z)
- __rmul__ = __mul__
- def length(self):
- return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
- def normalized(self):
- return (1.0 / self.length()) * self
- class Triangle(tuple):
- def __new__(cls, a, b, c):
- instance = tuple.__new__(cls, (a, b, c))
- instance.a = a
- instance.b = b
- instance.c = c
- return instance
- def __neg__(self):
- return Triangle(-self.a, -self.b, -self.c)
- def __str__(self):
- if self in triangles:
- i = triangles.index(self)
- return "Triangle %2d: %s" % (i, self.__repr__())
- else:
- return self.__repr__()
- Vertex._print_map = {
- g: ' g', -g: '-g', 1: ' 1', -1: '-1', 0: ' 0',
- }
- vertices = tuple(
- Vertex(x, y, z) for x, y, z in (
- ( g, 1, 0),
- ( g,-1, 0),
- (-g, 1, 0),
- (-g,-1, 0),
- ( 1, 0, g),
- (-1, 0, g),
- ( 1, 0,-g),
- (-1, 0,-g),
- ( 0, g, 1),
- ( 0, g,-1),
- ( 0,-g, 1),
- ( 0,-g,-1),
- )
- )
- _first_half = (
- Triangle(Vertex(-g, 1, 0), Vertex(-1, 0,-g), Vertex(-g,-1, 0)),
- Triangle(Vertex(-1, 0,-g), Vertex(-g,-1, 0), Vertex( 0,-g,-1)),
- Triangle(Vertex(-g,-1, 0), Vertex( 0,-g,-1), Vertex( 0,-g, 1)),
- Triangle(Vertex(-1, 0,-g), Vertex( 0,-g,-1), Vertex( 1, 0,-g)),
- Triangle(Vertex( 0,-g,-1), Vertex( 0,-g, 1), Vertex( g,-1, 0)),
- Triangle(Vertex( 0,-g,-1), Vertex( 1, 0,-g), Vertex( g,-1, 0)),
- Triangle(Vertex( g,-1, 0), Vertex( 1, 0,-g), Vertex( g, 1, 0)),
- Triangle(Vertex( 1, 0,-g), Vertex( g, 1, 0), Vertex( 0, g,-1)),
- Triangle(Vertex( 1, 0,-g), Vertex( 0, g,-1), Vertex(-1, 0,-g)),
- Triangle(Vertex( 0, g,-1), Vertex(-g, 1, 0), Vertex(-1, 0,-g)),
- )
- _second_half = tuple(-t for t in _first_half)
- triangles = _first_half + _second_half
- _neighbor_triangle_data = {}
- def neighbor_triangle(t, edge):
- """ Return the neighbor triangle of t with respect to edge = (a, b) """
- e = frozenset(edge)
- if (t, e) in _neighbor_triangle_data:
- return _neighbor_triangle_data[(t, e)]
- a, b = edge
- if a not in t or b not in t:
- return None
- for w in triangles:
- if a in w and b in w and w != t:
- _neighbor_triangle_data[(t, e)] = w
- return w
- return None
- class _Umbrella:
- def __init__(self, pivot):
- self.pivot = pivot
- self.components = frozenset(t for t in triangles if pivot in t)
- all_vertices = set()
- for t in self.components:
- for v in t:
- if v != pivot:
- all_vertices.add(v)
- self.all_vertices = frozenset(all_vertices)
- self._vertex_data = {}
- self._component_data = {}
- def vertex(self, i, ordered_edge):
- """ Return the i-th vertex with respect to ordered_edge = (a, b) """
- a, b = ordered_edge
- if a not in self.all_vertices:
- return None
- if b not in self.all_vertices:
- return None
- if i == 0:
- return a
- if i == 1:
- return b
- if (i, a, b) in self._vertex_data:
- return self._vertex_data[(i, a, b)]
- previous = self.vertex(i - 1, ordered_edge)
- comp = self.component(i - 2, ordered_edge)
- neighbor = neighbor_triangle(comp, (self.pivot, previous))
- for v in neighbor:
- if v not in (self.pivot, previous):
- self._vertex_data[(i, a, b)] = v
- return v
- return None
- def component(self, i, ordered_edge):
- """ Return the i-th component with respect to ordered_edge = (a, b) """
- a, b = ordered_edge
- if (i, a, b) in self._component_data:
- return self._component_data[(i, a, b)]
- vi = self.vertex(i, ordered_edge)
- vj = self.vertex(i + 1, ordered_edge)
- for t in self.components:
- if vi in t and vj in t:
- self._component_data[(i, a, b)] = t
- return t
- return None
- _umbrelas = {}
- def umbrella(pivot):
- if pivot not in vertices:
- return None
- if pivot not in _umbrelas:
- _umbrelas[pivot] = _Umbrella(pivot)
- return _umbrelas[pivot]
- def neighbor_umbrella(t, edge):
- neighbor = neighbor_triangle(t, edge)
- if not neighbor:
- return None
- for pivot in neighbor:
- if pivot in edge:
- continue
- return umbrella(pivot)
|