# 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 . 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)