def __init__(self, vertices, pos=None, vel=(0, 0), theta=0.0, omega=0.0, mass=None, density=None, inertia=None, **kwargs): if isinstance(vertices, int): raise ValueError('must pass a list of vertices. ' 'Use RegularPoly to define a polygon by the ' 'number of vertices') vertices = [Vec2(*pt) for pt in vertices] pos_cm = center_of_mass(vertices) vertices = [v - pos_cm for v in vertices] self._vertices = vertices # Cache vertices self._cache_theta = None self._cache_rvertices_last = None self._cache_rbbox_last = None super(Poly, self).__init__(pos_cm, vel, theta, omega, mass=mass, density=density, inertia=inertia, cbb_radius=max(v.norm() for v in vertices), **kwargs) self.num_sides = len(vertices) self._normals_idxs = self.get_li_indexes() self.num_normals = len(self._normals_idxs or self.vertices) # Slightly faster when all normals are linear dependent: if # self._normals_idx = None, all normals are recomputed at each frame. if self.num_normals == self.num_sides: self._normals_idxs = None # Move to specified position, if pos is given. if pos is not None: self._pos = Vec2(*pos)
def collision_poly(A, B, directions=None, collision_class=Collision): """ Collision detection using SAT. """ # List of directions from normals if directions is None: if A.num_normals + B.num_normals < 9: directions = A.get_normals() + B.get_normals() else: directions = DEFAULT_DIRECTIONS # Test overlap in all considered directions and picks the smaller # penetration min_overlap = float('inf') norm = None for u in directions: A_coords = [dot(pt, u) for pt in A.vertices] B_coords = [dot(pt, u) for pt in B.vertices] Amax, Amin = max(A_coords), min(A_coords) Bmax, Bmin = max(B_coords), min(B_coords) minmax, maxmin = min(Amax, Bmax), max(Amin, Bmin) overlap = minmax - maxmin if overlap < 0: return None elif overlap < min_overlap: min_overlap = overlap norm = u # Finds the correct direction for the normal if dot(A.pos, norm) > dot(B.pos, norm): norm = -norm # Computes the clipped polygon: collision happens at its center point. try: clipped = clip(A.vertices, B.vertices) col_pt = center_of_mass(clipped) except ValueError: return None if area(clipped) == 0: return None return collision_class(A, B, pos=col_pt, normal=norm, delta=min_overlap)
def pos(self): return center_of_mass(self)
def test_poly_center_of_mass(): tri = Poly((0, 0), (3, 0), (0, 3)) assert tri.pos == center_of_mass([(0, 0), (3, 0), (0, 3)]) assert tri.pos == (1, 1)