def center_of_mass(L): """ Return the center of mass vector for a solid polygon defined by the given list of points. Example: >>> pts = [(0, 0), (1, 0), (1, 1), (0, 1)] >>> center_of_mass(pts) Vec(0.5, 0.5) """ W = _w_list(L) A = sum(W) N = len(L) x_cm = 0 y_cm = 0 if A == 0: return Vec(*L[0]) for i in range(N): x1, y1 = L[(i + 1) % N] x0, y0 = L[i] wi = W[i] x_cm += (x1 + x0) * wi / 3.0 y_cm += (y1 + y0) * wi / 3.0 x_cm /= A y_cm /= A return Vec(x_cm, y_cm)
def eigenpairs(self): a, b, c, d = self.flat l1 = (d + a + self._sqrt(d * d - 2 * a * d + a * a + 4 * c * b)) / 2 l2 = (d + a - self._sqrt(d * d - 2 * a * d + a * a + 4 * c * b)) / 2 try: v1 = Vec(b / (l1 - a), 1) except ZeroDivisionError: v1 = Vec(1, 0) try: v2 = Vec(b / (l2 - a), 1) except ZeroDivisionError: v2 = Vec(1, 0) return [(l1, v1.normalize()), (l2, v2.normalize())]
def intercept_point(): '''Retorna o ponto de intercepção entre os segmentos formados por ``r1 - r0`` e ``v1 - v0``''' A = r0.x * r1.y - r0.y * r1.x B = v0.x * v1.y - v0.y * v1.x C = 1.0 / (T.x * T_.y - T.y * T_.x) return Vec((-A * T_.x + B * T.x) * C, (-A * T_.y + B * T.y) * C)
def __getitem__(self, idx): N = len(self._data) // 2 if idx < -N or idx >= N: raise IndexError(idx) elif idx < 0: idx = N + idx i = 2 * idx return Vec(*self._data[i:i + 2])
def intercept_point(): """ Return intercept between segments formed by ``r1 - r0`` and ``v1 - v0``. """ A = r0.x * r1.y - r0.y * r1.x B = v0.x * v1.y - v0.y * v1.x C = 1.0 / (T.x * T_.y - T.y * T_.x) return Vec((-A * T_.x + B * T.x) * C, (-A * T_.y + B * T.y) * C)
def pos(self): pt0 = self[-1] M, S = 0, Vec(0, 0) for pt in self: L = (pt - pt0).norm() M += L S += (pt + pt0) * (L / 2) pt0 = pt return S / M
def directions(self, n): '''Retorna a lista de direções exaustivas para o teste do SAT associadas ao objeto.''' out = [] p0 = self._data[-1] for p in self._data: x, y = p - p0 p0 = p out.append(Vec(-y, x)) return out
def aabb_pshape(xmin=None, xmax=None, ymin=None, ymax=None, bbox=None, rect=None, shape=None, pos=None): ''' Retorna uma tupla de (centro, shape) a partir dos parâmetros fornecidos. ''' x, xmax, y, ymax = aabb_bbox(xmin, xmax, ymin, ymax, bbox, rect, shape, pos) center = Vec((x + xmax) / 2.0, (y + ymax) / 2.0) shape = (xmax - x, ymax - y) return center, shape
def pos(self): length = 0 vector_part = Vec(0.0, 0.0) pt0 = self[-1] for pt in self: delta = asvector(pt - pt0).norm() #FIXME: Point subtraction --> Vec middle = asvector(pt.middle(pt0)) vector_part += delta * middle length += delta pt0 = pt return vector_part / length
def normals_aabb_circle(A, B): # Encontra o vértice mais próximo do centro D = float('inf') pt = Vec(0, 0) for v in A.vertices: delta = B.pos - v dnew = delta.norm() if dnew < D: D = dnew pt = delta return [pt.normalized(), e1, e2]
def aabb_center(xmin=None, xmax=None, ymin=None, ymax=None, rect=None, shape=None, pos=None): """ Return AABB's center position vector from given parameters. """ xmin, xmax, ymin, ymax = aabb_coords(xmin, ymin, xmax, ymax, rect, shape, pos) return Vec((xmin + xmax) / 2, (ymin + ymax) / 2)
def __init__(self, N, length, theta=None, pos=None): alpha = pi / N R = Rotation2d(2 * alpha) p = Vec(length / (2 * sin(alpha)), 0) vertices = [] for _ in range(N): vertices.append(p) p = R * p super(RegularPolyAny, self).__init__(vertices) # Altera posição e ângulo if pos is not None: self += pos if theta is not None: self.rotate(theta)
def aabb_pshape(xmin=None, xmax=None, ymin=None, ymax=None, rect=None, shape=None, pos=None): """ Return AABB's (pos, shape) from given parameters. """ x, xmax, y, ymax = aabb_coords(xmin, xmax, ymin, ymax, rect, shape, pos) center = Vec((x + xmax) / 2.0, (y + ymax) / 2.0) shape = (xmax - x, ymax - y) return center, shape
def convex_hull(points): '''Retorna a envoltória convexa do conjunto de pontos fornecidos. Implementa o algorítimo da cadeia monótona de Andrew, O(n log n) Exemplo ------- >>> hull = convex_hull([(0, 0), (1, 1), (1, 0), (0, 1), (0.5, 0.5)]) >>> hull == [(0, 0), (1, 0), (1, 1), (0, 1)] True ''' # Ordena os pontos pela coordenada x, depois pela coordenada y points = sorted(set(map(tuple, points))) points = [Vec(*pt) for pt in points] if len(points) <= 1: return points # Cria a lista L: lista com os vértices da parte inferior da envoltória # # Algoritimo: acrescenta os pontos de points em L e a cada novo ponto # remove o último caso não faça uma volta na direção anti-horária L = [] for p in points: while len(L) >= 2 and (L[-1] - L[-2]).cross(p - L[-2]) <= 0: L.pop() L.append(p) # Cria a lista U: vértices da parte superior # Semelhante à anterior, mas itera sobre os pontos na ordem inversa U = [] for p in reversed(points): while len(U) >= 2 and (U[-1] - U[-2]).cross(p - U[-2]) <= 0: U.pop() U.append(p) # Remove o último ponto de cada lista, pois ele se repete na outra return L[:-1] + U[:-1]
def center_of_mass(L): '''Calcula o vetor centro de massa de um polígono definido por uma lista de pontos. >>> pontos = [(0, 0), (1, 0), (1, 1), (0, 1)] >>> center_of_mass(pontos) Vec(0.5, 0.5) ''' W = _w_list(L) A = sum(W) N = len(L) x_cm = 0 y_cm = 0 for i in range(N): x1, y1 = L[(i + 1) % N] x0, y0 = L[i] wi = W[i] x_cm += (x1 + x0) * wi / 3.0 y_cm += (y1 + y0) * wi / 3.0 x_cm /= A y_cm /= A return Vec(x_cm, y_cm)
def convex_hull(points): """ Convex hull for the list of points. Uses Andrew's monotonic chain algorithm in O(n log n). Example: >>> hull = convex_hull([(0, 0), (1, 1), (1, 0), (0, 1), (0.5, 0.5)]) >>> hull == [(0, 0), (1, 0), (1, 1), (0, 1)] True """ # Lexicographical sort points = sorted(set(map(tuple, points))) points = [Vec(*pt) for pt in points] if len(points) <= 1: return points # L: lower vertices # Adds points to L if the result preserves an counter-clockwise direction. L = [] for p in points: while len(L) >= 2 and (L[-1] - L[-2]).cross(p - L[-2]) <= 0: L.pop() L.append(p) # U: upper vertices # Similar as before, but iterates in the opposite order. U = [] for p in reversed(points): while len(U) >= 2 and (U[-1] - U[-2]).cross(p - U[-2]) <= 0: U.pop() U.append(p) # Remove last point since it is duplicated return L[:-1] + U[:-1]
def test_rows(): M1 = Mat([1, 2], [3, 4], [5, 6]) assert list(M1.rows()) == [Vec(1, 2), Vec(3, 4), Vec(5, 6)]
def test_cols(): M1 = Mat([1, 2], [3, 4], [5, 6]) assert list(M1.cols()) == [Vec(1, 3, 5), Vec(2, 4, 6)]
def test_identity_solve(self, I, N): b = Vec(*range(1, N + 1)) assert I.solve(b) == b assert I.solve_jacobi(b) == b assert I.solve_gauss(b) == b assert I.solve_triangular(b) == b
def vertices(self): return (Vec(self.xmin, self.ymin), Vec(self.xmax, self.ymin), Vec(self.xmax, self.ymax), Vec(self.xmin, self.ymax))
def pos(self): x = (self.xmin + self.xmax) / 2 y = (self.ymin + self.ymax) / 2 return Vec(x, y)
def __init__(self, points): self._points = list(Vec(*pt) for pt in points)
def pos(self): return Vec(self._x, self._y)
def move(self, x_or_delta, y=None): if y is not None: x_or_delta = Vec(x_or_delta, y) self._data[:] = [u + x_or_delta for u in self._data]
def test_droppingrow(): M1 = Mat([1, 2], [3, 4], [5, 6]) M2 = Mat([1, 2], [5, 6]) assert M1.drop_row(1) == (M2, Vec(3, 4))
from smallshapes import Convex from smallvectors import dot, Vec from smallvectors.core.mutability import Mutable, Immutable direction_x = Vec(1, 0) direction_y = Vec(0, 1) class AABBAny(Convex): """ Base class for AABB and mAABB. """ __slots__ = ('xmin', 'xmax', 'ymin', 'ymax') _vec = Vec[2, float] @property def pos(self): x = (self.xmin + self.xmax) / 2 y = (self.ymin + self.ymax) / 2 return self._vec(x, y) @property def vertices(self): vec = self._vec return (vec(self.xmin, self.ymin), vec(self.xmax, self.ymin), vec(self.xmax, self.ymax), vec(self.xmin, self.ymax)) @property def cbb_radius(self):
def test_droppingcol(): M1 = Mat([1, 2], [3, 4], [5, 6]) M2 = Mat([1], [3], [5]) assert M1.drop_col(1) == (M2, Vec(2, 4, 6))
def test_vec_displacement_creates_a_new_object(self, obj): new = obj.move_vec(Vec(1, 1)) assert new is not obj
def insert(self, idx, value): self._data.insert(idx, Vec(value))
def standing_object_has_heading(self, obj): obj.vel *= 0 assert obj.heading == Vec(1, 0)