示例#1
0
    def J_normal(self):
        '''Valor absoluto do impulso normal antes de considerar o efeito do
        atrito no cálculo da componente tangencial'''

        A, B = self.objects
        pos = self.pos
        n = self.normal
        J_denom = A._invmass + B._invmass

        if A._invinertia or A.omega:
            R = pos - A._pos
            J_denom += cross(R, n) ** 2 * A._invinertia

        if B._invinertia or B.omega:
            R = pos - B._pos
            J_denom += cross(R, n) ** 2 * B._invinertia

        # Determina o impulso total
        if J_denom == 0.0:
            return 0.0

        vrel_n = dot(self.vrel_contact, n)
        if vrel_n > 0:
            return 0.0

        return -(1 + self.e) * vrel_n / J_denom
示例#2
0
    def tangent(self):
        '''Vetor unitário tangente à colisão'''

        n = self.normal
        tangent = Vector(-n.y, n.x)
        if dot(tangent, self.vrel_contact) > 0:
            tangent *= -1
        return tangent
示例#3
0
def collision_poly(A, B, directions=None):
    '''Implementa a colisão entre dois polígonos arbitrários'''

    # Cria a lista de direções a partir das normais do polígono
    if directions is None:
        if A.num_normals + B.num_normals < 9:
            directions = A.get_normals() + B.get_normals()
        else:
            directions = DEFAULT_DIRECTIONS

    # Testa se há superposição de sombras em todas as direções consideradas
    # e calcula o menor valor para sombra e a direção normal
    min_shadow = float('inf')
    norm = None
    for u in directions:
        A_coords = [round(dot(pt, u), 6) for pt in A.vertices]
        B_coords = [round(dot(pt, u), 6) 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)
        shadow = minmax - maxmin
        if shadow < 0:
            return None
        elif shadow < min_shadow:
            min_shadow = shadow
            norm = u

    # Determina o sentido da normal
    if dot(A._pos, norm) > dot(B._pos, norm):
        norm = -norm

    # Computa o polígono de intersecção e usa o seu centro de massa como ponto
    # de colisão
    try:
        clipped = clip(A.vertices, B.vertices)
    # não houve superposição (talvez por usar normais aproximadas)
    except ValueError:
        return None

    if area(clipped) == 0:
        return None
    col_pt = center_of_mass(clipped)
    return Collision(A, B, pos=col_pt, normal=norm, delta=min_shadow)
示例#4
0
def get_collision_poly(A, B, directions=None):
    '''Implementa a colisão entre dois polígonos arbitrários'''

    # Cria a lista de direções a partir das normais do polígono
    if directions is None:
        if A.num_normals + B.num_normals < 9:
            directions = A.get_normals() + B.get_normals()
        else:
            directions = DEFAULT_DIRECTIONS

    # Testa se há superposição de sombras em todas as direções consideradas
    # e calcula o menor valor para sombra e a direção normal
    min_shadow = float('inf')
    norm = None
    for u in directions:
        A_coords = [round(dot(pt, u), 6) for pt in A.vertices]
        B_coords = [round(dot(pt, u), 6) 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)
        shadow = minmax - maxmin
        if shadow < 0:
            return None
        elif shadow < min_shadow:
            min_shadow = shadow
            norm = u

    # Determina o sentido da normal
    if dot(A.pos, norm) > dot(B.pos, norm):
        norm = -norm

    # Computa o polígono de intersecção e usa o seu centro de massa como ponto
    # de colisão
    try:
        clipped = clip(A.vertices, B.vertices)
    # não houve superposição (talvez por usar normais aproximadas)
    except ValueError:
        return None

    if area(clipped) == 0:
        return None
    col_pt = center_of_mass(clipped)
    return Collision(A, B, col_pt, norm, min_shadow)
示例#5
0
    def J_tangent(self):
        '''Retorna o módulo da componente tangencial do atrito'''

        A, B = self.objects
        vrel = self.vrel_contact

        # Calcula o impulso tangente máximo
        vrel_tan = -dot(vrel, self.tangent)
        Jtan_max = abs(self.mu * self.J_normal)

        # Limita a ação do impulso tangente
        A_can_move = A._invmass or A._invinertia
        B_can_move = B._invmass or B._invinertia

        # Calcula o tangente dependendo do estado dinâmico de cada objeto
        if A_can_move and B_can_move:
            return min([Jtan_max, vrel_tan * A.mass, vrel_tan * B.mass])
        elif A_can_move:
            return min([Jtan_max, vrel_tan * A.mass])
        elif B_can_move:
            return min([Jtan_max, vrel_tan * B.mass])
        else:
            return 0.0
示例#6
0
    def get_impulse(self, dt=0):
        '''Calcula o impulso devido à colisão. Retorna o impulso gerado pelo
        objeto A em cima do objeto B. (Ou seja: A recebe o negativo do impulso,
        enquanto B recebe o valor positivo).'''

        A, B = self.objects
        pos = self.pos
        n = self.normal
        e = self.rest_coeff()
        mu = self.friction_coeff()

        # Calcula a resposta impulsiva
        vrel = B.vel - A.vel
        J_denom = A._invmass + B._invmass

        if A._invinertia or A._omega:
            x, y = R = pos - A.pos
            vrel -= A._omega * Vector(-y, x)
            J_denom += cross(R, n)**2 * A._invinertia

        if B._invinertia or B._omega:
            x, y = R = pos - B.pos
            vrel += B.omega * Vector(-y, x)
            J_denom += cross(R, n)**2 * B._invinertia

        # Determina o impulso total
        if not J_denom:
            return 0

        # Não resolve colisão se o impulso estiver orientado a favor da normal
        # Isto acontece se a superposição não cessa no frame seguinte ao da
        # colisão.
        vrel_n = dot(vrel, n)
        if vrel_n > 0:
            return None

        J = -(1 + e) * vrel_n / J_denom

        # Determina influência do atrito
        if mu:
            # Encontra o vetor tangente adequado
            t = Vector(-n.y, n.x)
            if dot(t, vrel) > 0:
                t *= -1

            # Calcula o impulso tangente máximo
            vrel_tan = -dot(vrel, t)
            Jtan = abs(mu * J)

            # Limita a ação do impulso tangente
            A_can_move = A._invmass or A._invinertia
            B_can_move = B._invmass or B._invinertia
            if A_can_move and B_can_move:
                Jtan = min([Jtan, vrel_tan * A.mass, vrel_tan * B.mass])
            elif A_can_move:
                Jtan = min([Jtan, vrel_tan * A.mass])
            elif B_can_move:
                Jtan = min([Jtan, vrel_tan * B.mass])

            return J * n + Jtan * t
        else:
            return J * n
示例#7
0
    def linearE(self):
        '''Energia cinética das variáveis lineares'''

        return dot(self._vel, self._vel) / (2 * self._invmass)
示例#8
0
 def linearE(self):
     return self._mass * dot(self.vel, self.vel) / 2
示例#9
0
文件: obj_poly.py 项目: guiduck/FGAme
    def is_internal_point(self, pt):
        '''Retorna True se um ponto for interno ao polígono.'''

        n = self.get_normal
        P = self.vertices
        return all(dot(pt - P[i], n(i)) <= 0 for i in range(self.num_sides))