Ejemplo n.º 1
0
 def _vertices(self, N, length, pos):
     self.length = length
     alpha = pi / N
     theta = 2 * alpha
     b = length / (2 * sin(alpha))
     P0 = Vector(b, 0)
     pos = Vector(*pos)
     return [(P0.rotated(n * theta)) + pos for n in range(N)]
Ejemplo n.º 2
0
    def gravity(self, value):
        try:
            gravity = self._gravity = Vector(*value)
        except TypeError:
            gravity = self._gravity = Vector(0, -value)

        for obj in self._objects:
            if not obj.owns_gravity:
                obj._gravity = gravity
Ejemplo n.º 3
0
    def __call__(self, t):
        # Se o argumento for uma função, significa que estamos usando o
        # decorador para definir o valor da força
        if callable(t):
            func = t
            self.clear()
            self.add(func)
            return func

        # Caso contrário, assume que o argumento é numérico e executa
        t = float(t)
        if self._fast is not None:
            return Vector(*self._fast(t))
        else:
            return Vector(0, 0)
Ejemplo n.º 4
0
    def __init__(self, obj, k, r0=(0, 0)):
        kxy = 0
        x0, y0 = self._r0 = Vector(*r0)

        try:  # Caso isotrópico
            kx = ky = k = self._k = float(k)
        except TypeError:  # Caso anisotrópico
            k = self._k = tuple(map(float, k))
            if len(k) == 2:
                kx, ky = k
            else:
                kx, ky, kxy = k

        # Define forças e potenciais
        def F(R):
            Dx = x0 - R._x
            Dy = y0 - R._y
            return Vector(kx * Dx + kxy * Dy, ky * Dy + kxy * Dx)

        def U(R):
            Dx = x0 - R._x
            Dy = y0 - R._y
            return (kx * Dx**2 + ky * Dy**2 + 2 * kxy * Dx * Dy) / 2

        super(SpringSF, self).__init__(obj, F, U)
Ejemplo n.º 5
0
    def __init__(self, A, B, k, delta=(0, 0)):
        kxy = 0
        dx, dy = delta = self._delta = Vector(*delta)

        try:  # Caso isotrópico
            kx = ky = k = self._k = float(k)
        except TypeError:  # Caso anisotrópico
            k = self._k = tuple(map(float, k))
            if len(k) == 2:
                kx, ky = k
            else:
                kx, ky, kxy = k

        # Define forças e potenciais
        def F(rA, rB):
            Dx = rB._x - rA._x + dx
            Dy = rB._y - rA._y + dy
            return Vector(kx * Dx + kxy * Dy, +ky * Dy + kxy * Dx)

        def U(rA, rB):
            Dx = rB._x - rA._x + dx
            Dy = rB._y - rA._y + dy
            return (kx * Dx**2 + ky * Dy**2 + 2 * kxy * Dx * Dy) / 2

        super(SpringF, self).__init__(A, B, F, U)
Ejemplo n.º 6
0
 def __init__(self, shape=(800, 600), pos=(0, 0), zoom=1, background=None):
     self.width, self.height = shape
     self.pos = Vector(*pos)
     self.zoom = zoom
     self.background = background
     self._direct = True
     self.init()
Ejemplo n.º 7
0
    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 Vector((-A * T_.x + B * T.x) * C, (-A * T_.y + B * T.y) * C)
Ejemplo n.º 8
0
    def get_normal(self, i):
        '''Retorna a normal unitária associada ao i-ésimo segmento. Cada
        segmento é definido pela diferença entre o (i+1)-ésimo ponto e o
        i-ésimo ponto.'''

        points = self.vertices
        x, y = points[(i + 1) % self.num_sides] - points[i]
        return Vector(y, -x).normalized()
Ejemplo n.º 9
0
    def vpoint(self, pos, relative=False):
        '''Retorna a velocidade linear de um ponto em pos preso rigidamente ao
        objeto.

        Se o parâmetro `relative` for verdadeiro, o vetor `pos` é interpretado
        como a posição relativa ao centro de massa. O padrão é considerá-lo
        como a posição absoluta no centro de coordenadas do mundo.'''

        x, y = pos - self._pos
        return self._vel + self._omega * Vector(-y, x)
Ejemplo n.º 10
0
    def get_normals(self):
        '''Retorna uma lista com as normais linearmente independentes.'''

        if self._normals_idxs is None:
            N = self.num_sides
            points = self.vertices
            segmentos = (points[(i + 1) % N] - points[i] for i in range(N))
            return [Vector(y, -x).normalized() for (x, y) in segmentos]
        else:
            return [self.get_normal(i) for i in self._normals_idxs]
Ejemplo n.º 11
0
def test_vector_algeb():
    v1 = Vector(1, 2)
    v2 = Vector(2, 3)
    v3 = Vector(4, 5)
    assert 2 * v1 == Vector(2, 4)
    assert v1 * 2 == Vector(2, 4)
    assert v1 + 2 * v2 - 3 * v3 == Vector(-7, -7)
Ejemplo n.º 12
0
def get_collision_aabb(A, B):
    '''Retorna uma colisão com o objeto other considerando apenas a caixas
    de contorno alinhadas ao eixo.'''

    # Detecta colisão pelas sombras das caixas de contorno
    shadowx = shadow_x(A, B)
    shadowy = shadow_y(A, B)
    if shadowx <= 0 or shadowy <= 0:
        return None

    # Calcula ponto de colisão
    x_col = max(A.xmin, B.xmin) + shadowx / 2.
    y_col = max(A.ymin, B.ymin) + shadowy / 2.
    pos_col = Vector(x_col, y_col)

    # Define sinal dos vetores normais: colisões tipo PONG
    if shadowx > shadowy:
        n = Vector(0, (1 if A.ymin < B.ymin else -1))
    else:
        n = Vector((1 if A.xmin < B.xmin else -1), 0)

    return Collision(A, B, pos_col, n)
Ejemplo n.º 13
0
    def _init_has_local_forces(self,
                               gravity=None,
                               damping=None,
                               adamping=None,
                               owns_gravity=None,
                               owns_damping=None,
                               owns_adamping=None):

        self._damping = 0.0
        if damping is not None:
            self.flag_owns_damping = True
            self._damping = float(damping)

        self._adamping = 0.0
        if adamping is not None:
            self.flag_owns_adamping = True
            self._adamping = float(adamping)

        self._gravity = Vector(0, 0)
        if gravity is not None:
            self.flag_owns_gravity = True
            self._gravity = (Vector(0, -gravity) if isinstance(
                gravity, (float, int)) else Vector(*gravity))
Ejemplo n.º 14
0
def aabb_pshape(bbox=None,
                rect=None,
                shape=None,
                pos=None,
                xmin=None,
                xmax=None,
                ymin=None,
                ymax=None):
    '''
    Retorna uma tupla de (centro, shape) a partir dos parâmetros fornecidos.
    '''
    x, y, xmax, ymax = aabb_bbox(bbox, rect, shape, pos, xmin, xmax, ymin,
                                 ymax)
    center = Vector((x + xmax) / 2.0, (y + ymax) / 2.0)
    shape = (xmax - x, ymax - y)
    return center, shape
Ejemplo n.º 15
0
    def __init__(self, obj, G, M=None, epsilon=0, r0=(0, 0)):
        if M is None:
            M = obj.mass
        M = self._M = float(M)
        self._epsilon = float(epsilon)
        self._G = float(G)
        r0 = self._r0 = Vector(*r0)

        def F(R):
            R = r0 - R
            r = R.norm()
            r3 = (r + epsilon)**2 * r
            R *= G * obj._mass * M / r3
            return R

        def U(R):
            R = (R - r0).norm()
            return -self._G * obj._mass * M / (R + self._epsilon)

        super(GravitySF, self).__init__(obj, F, U)
Ejemplo n.º 16
0
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
    -------

    >>> convex_hull([(0, 0), (1, 1), (1, 0), (0, 1), (0.5, 0.5)])
    [Vector(0, 0), Vector(1, 0), Vector(1, 1), Vector(0, 1)]
    '''

    # Ordena os pontos pela coordenada x, depois pela coordenada y
    points = sorted(set(map(tuple, points)))
    points = [Vector(*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 cross(L[-1] - L[-2], 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 cross(U[-1] - U[-2], 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]
Ejemplo n.º 17
0
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)
    Vector(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 Vector(x_cm, y_cm)
Ejemplo n.º 18
0
 def F(rA, rB):
     Dx = rB._x - rA._x + dx
     Dy = rB._y - rA._y + dy
     return Vector(kx * Dx + kxy * Dy, +ky * Dy + kxy * Dx)
Ejemplo n.º 19
0
 def F(R):
     Dx = x0 - R._x
     Dy = y0 - R._y
     return Vector(kx * Dx + kxy * Dy, ky * Dy + kxy * Dx)
Ejemplo n.º 20
0
def test_vector_getitem():
    v = Vector(1, 2)
    assert v[0] == 1, v[1] == 2
Ejemplo n.º 21
0
from FGAme.mathutils import Vector, dot, area, center_of_mass, clip, pi

from FGAme.physics.collision import (Collision, get_collision,
                                     get_collision_aabb)
from FGAme.physics.elements import (Circle, AABB, Poly, Rectangle)

u_x = Vector(1, 0)
DEFAULT_DIRECTIONS = [
    u_x.rotated(n * pi / 12) for n in [0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11]
]

###############################################################################
# Colisões entre figuras primitivas simples
###############################################################################

get_collision[AABB, AABB] = get_collision_aabb


@get_collision.dispatch(Circle, Circle)
def circle_collision(A, B):
    '''Testa a colisão pela distância dos centros'''

    delta = B.pos - A.pos
    if delta.norm() < A.radius + B.radius:
        n = delta.normalized()
        D = A.radius + B.radius - delta.norm()
        pos = A.pos + (A.radius - D / 2) * n
        return Collision(A, B, pos=pos, n=n)
    else:
        return None
Ejemplo n.º 22
0
 def __init__(self, vertices):
     self._data = [Vector(*x) for x in vertices]
Ejemplo n.º 23
0
 def vel(self):
     return Vector(*self._vel)
Ejemplo n.º 24
0
 def accel(self):
     return Vector(*self._accel)
Ejemplo n.º 25
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
Ejemplo n.º 26
0
 def pos(self):
     return Vector(self.center_x, self.center_y)
Ejemplo n.º 27
0
def test_vector_add():
    v1 = Vector(1, 2)
    v2 = Vector(2, 3)
    assert v1 + v2 == Vector(3, 5)
    assert tuple(v1 + v2) == (3, 5)
    assert v2 - v1 == Vector(1, 1)
Ejemplo n.º 28
0
# -*- coding: utf8 -*-

import six
from FGAme.mathutils import Vector
from FGAme.physics import flags

__all__ = ['PhysElement']

###############################################################################
#                                 Funções úteis
###############################################################################

NOT_IMPLEMENTED = NotImplementedError('must be implemented at child classes')
INF = float('inf')
ORIGIN = Vector(0, 0)


def do_nothing(*args, **kwds):
    pass


def raises_method(ex=NOT_IMPLEMENTED):
    def method(self, *args, **kwds):
        raise ex

    return method


###############################################################################
#          Classes Base --- todos objetos físicos derivam delas
###############################################################################
Ejemplo n.º 29
0
 def pos(self):
     return Vector(*self._pos)
Ejemplo n.º 30
0
# -*- coding: utf8 -*-

from FGAme.mathutils import Vector, dot, area, center_of_mass, clip, pi
from FGAme.mathutils import shadow_x, shadow_y

from FGAme.physics.collision import Collision
from FGAme.physics import Circle, AABB, Poly, Rectangle
from FGAme.util import multifunction

u_x = Vector(1, 0)
DEFAULT_DIRECTIONS = [u_x.rotated(n * pi / 12) for n in
                      [0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11]]


class CollisionError(Exception):

    '''Declara que não existem colisões disponíveis para os dois tipos de
    objetos'''
    pass


def get_collision_generic(A, B):
    '''Retorna uma colisão genérica definido pela CBB dos objetos A e B'''

    rA = A.cbb_radius
    rB = B.cbb_radius
    delta = B._pos - A._pos
    if delta.norm() < rA + rB:
        n = delta.normalized()
        D = rA + rB - delta.norm()
        pos = A._pos + (rA - D / 2) * n
Ejemplo n.º 31
0
class PhysElement(object):
    '''Classe mãe para os objetos que possuem física definida.

    Não possui propriedades, mas apenas define flags e (possivelmente) um
    dicionário extra de parâmetros. Por razões de performance e eficiência na
    alocação de memória, todas as sub-classes devem definir seus __slots__.

    É possível armazenar variáveis adicionais no dicionário privado do objeto
    utilizando o atributo _dict_. Para isso, a classe deve definir um conjunto
    de strings de atributos opcionais na variável _properties_. A
    metaclasse se encarrega de simular o comportamento de __slots__ no
    sentido que as sub-classes não precisam definir as _optinal_vars_ da
    classe mãe.

    Todas as variáveis dentro deste objeto possuem valores padrão de None.

    É possível criar parâmetros localmente utilizando o método
    'set_property()'. Estas propriedades são acessadas como atributos e podem
    ser listadas pelo método get_properties()

    Example
    -------

    Esta classe define apenas funcionalidades básicas, como acesso às flags de
    física e propriedades.

    Acesso a flags

    >>> elem = PhysElement()
    >>> elem.flag_has_mass
    False
    >>> elem.flag_has_mass = True
    >>> elem.flag_has_mass
    True

    Acesso a propriedades

    >>> elem.set_property('foo', 'bar')
    >>> elem.foo
    'bar'


    '''

    __slots__ = ['_flags', '_dict_']
    _properties_ = set()

    def __init__(self, flags=0, dict_=None):
        self._flags = flags
        self._dict_ = dict_

    def __getattr__(self, attr):
        # Captura slots não inicializados
        if hasattr(type(self), attr):
            raise AttributeError(attr)

        D = self._dict_
        if D is not None:
            try:
                return self._dict_[attr]
            except KeyError:
                pass

        if attr in self._properties_:
            return None
        else:
            raise AttributeError(attr)


# Mantêm a simetria com __getattr__, mas possivelmente incorre numa perda de
# performance. Do jeito que está, as propriedades são definidas como somente
# para leitura. É necessário definir propridedades explicitamente na classe
# para obter acesso de escrita.
#
# É fácil fazer alguma mágica na metaclasse para definir acesso rw, caso
# pareça interessante.
#
#     def __setattr__(self, attr, value):
#         try:
#             descriptor = self.__class__.__dict__[attr]
#         except KeyError:
#             if (attr in self._properties_ or
#                     (self._dict_ is not None and attr in self._dict_)):
#                 self._dict_[attr] = value
#         else:
#             descriptor.__set__(self, value)

    @property
    def _dict(self):
        if self._dict_ is None:
            self._dict_ = {}
        return self._dict_

    def set_property(self, name, value):
        '''Define uma propriedade do objeto'''

        if name.startswith('_'):
            raise ValueError('cannot change private properties'
                             ' (names starting with _)')

        self._dict[name] = value

    def get_property(self, name):
        '''Retorna uma propriedade do objeto'''

        if name.startswith('_'):
            raise ValueError('cannot access private properties'
                             ' (names starting with _)')

        try:
            return self._dict_[name]
        except (KeyError, TypeError):
            if name in self._properties_:
                return None
            else:
                raise ValueError('property')

    def get_properties(self):
        '''Retorna um dicionário com todas as propriedades definidas para o
        objeto em questão'''

        items = (self._dict_ or {}).items()
        return {k: v for (k, v) in items if not k.startswith('_')}

    def _getp(self, name, default):
        '''Versão mais rápida e privada de get_property(). Pode acessar
        qualquer propriedade adicional'''

        try:
            return self._dict_.get(name, default)
        except (TypeError, KeyError):
            return default

    def _setp(self, name, value):
        '''Versão mais rápida e privada de set_property(). Pode acessar
        qualquer propriedade adicional'''

        try:
            self._dict_[name] = value
        except TypeError:

            self._dict_ = {name: value}

    def _delp(self, name):
        '''Apaga uma propriedade do dicionário'''

        del self._dict_[name]
        if not self._dict_:
            self._dict_ = None

    def _clearp(self, *names):
        '''Limpa propriedades do dicionário, caso estejam definidas'''

        D = self._dict_
        if D is not None:
            for name in names:
                if name in D:
                    del D[name]

        if not D:
            self._dict_ = None  # Interface Python

    # Define igualdade <==> identidade ########################################
    def __eq__(self, other):
        return self is other

    def __hash__(self):
        return id(self)

    # Valores padrão ##########################################################
    mass = float('inf')
    inertia = float('inf')
    pos = Vector(0, 0)
    vel = Vector(0, 0)
    theta = 0.0
    omega = 0.0

    area = 0
    ROG_sqr = 0
    ROG = 0

    # Métodos com implementações inócuas ######################################
    move = do_nothing()
    boost = do_nothing()
    rotate = do_nothing()
    aboost = do_nothing()

    ###########################################################################
    #                           Controle de flags
    ###########################################################################
    # Propriedades de controle de flags -- metacódigo
    #
    # Descomente e rode este código caso queira recalcular as propriedades
    # associadas à cada flag de física.
    #
    #     from FGAme.physics.flags import _FlagBits
    #     template = '''
    #     @property
    #     def flag_flagname(self):
    #         return bool(self._flags & flags.FLAGNAME)
    #
    #     @flag_flagname.setter
    #     def flag_flagname(self, value):
    #         if value:
    #             self._flags |= flags.FLAGNAME
    #         else:
    #             self._flags &= ~flags.FLAGNAME'''
    #
    #     attrs = [(n, k) for (k, n) in _FlagBits.__dict__.items()
    #              if isinstance(n, int)]
    #     for n, k in sorted(attrs):
    #         func_def = template.replace('flagname', k)
    #         func_def = func_def.replace('FLAGNAME', k.upper())
    #         print(func_def)

    # Definições geradas pelo código acima
    @property
    def flag_has_inertia(self):
        return bool(self._flags & flags.HAS_INERTIA)

    @flag_has_inertia.setter
    def flag_has_inertia(self, value):
        if value:
            self._flags |= flags.HAS_INERTIA
        else:
            self._flags &= ~flags.HAS_INERTIA

    @property
    def flag_has_linear(self):
        return bool(self._flags & flags.HAS_LINEAR)

    @flag_has_linear.setter
    def flag_has_linear(self, value):
        if value:
            self._flags |= flags.HAS_LINEAR
        else:
            self._flags &= ~flags.HAS_LINEAR

    @property
    def flag_has_angular(self):
        return bool(self._flags & flags.HAS_ANGULAR)

    @flag_has_angular.setter
    def flag_has_angular(self, value):
        if value:
            self._flags |= flags.HAS_ANGULAR
        else:
            self._flags &= ~flags.HAS_ANGULAR

    @property
    def flag_has_bbox(self):
        return bool(self._flags & flags.HAS_BBOX)

    @flag_has_bbox.setter
    def flag_has_bbox(self, value):
        if value:
            self._flags |= flags.HAS_BBOX
        else:
            self._flags &= ~flags.HAS_BBOX

    @property
    def flag_owns_gravity(self):
        return bool(self._flags & flags.OWNS_GRAVITY)

    @flag_owns_gravity.setter
    def flag_owns_gravity(self, value):
        if value:
            self._flags |= flags.OWNS_GRAVITY
        else:
            self._flags &= ~flags.OWNS_GRAVITY

    @property
    def flag_owns_damping(self):
        return bool(self._flags & flags.OWNS_DAMPING)

    @flag_owns_damping.setter
    def flag_owns_damping(self, value):
        if value:
            self._flags |= flags.OWNS_DAMPING
        else:
            self._flags &= ~flags.OWNS_DAMPING

    @property
    def flag_owns_adamping(self):
        return bool(self._flags & flags.OWNS_ADAMPING)

    @flag_owns_adamping.setter
    def flag_owns_adamping(self, value):
        if value:
            self._flags |= flags.OWNS_ADAMPING
        else:
            self._flags &= ~flags.OWNS_ADAMPING

    @property
    def flag_accel_static(self):
        return bool(self._flags & flags.ACCEL_STATIC)

    @flag_accel_static.setter
    def flag_accel_static(self, value):
        if value:
            self._flags |= flags.ACCEL_STATIC
        else:
            self._flags &= ~flags.ACCEL_STATIC

    @property
    def flag_has_world(self):
        return bool(self._flags & flags.HAS_WORLD)

    @flag_has_world.setter
    def flag_has_world(self, value):
        if value:
            self._flags |= flags.HAS_WORLD
        else:
            self._flags &= ~flags.HAS_WORLD

    @property
    def flag_has_visualization(self):
        return bool(self._flags & flags.HAS_VISUALIZATION)

    @flag_has_visualization.setter
    def flag_has_visualization(self, value):
        if value:
            self._flags |= flags.HAS_VISUALIZATION
        else:
            self._flags &= ~flags.HAS_VISUALIZATION

    ###########################################################################
    #               Manipulação/consulta do estado dinâmico
    ###########################################################################

    def is_dynamic(self, what=None):
        '''Retorna True se o objeto for dinâmico ou nas variáveis lineares ou
        nas angulares. Um objeto é considerado dinâmico nas variáveis lineares
        se possuir massa finita. De maneira análoga, o objeto torna-se dinâmico
        nas variáveis angulares se possuir momento de inércia finito.

        Opcionalmente pode especificar um parâmetro posicional 'linear',
        'angular', 'both' or 'any' (padrão) para determinar o tipo de consulta
        a ser realizada'''

        if what is None or what == 'any':
            return self.is_dynamic_linear() or self.is_dynamic_angular()
        elif what == 'both':
            return self.is_dynamic_linear() and self.is_dynamic_angular()
        elif what == 'linear':
            return self.is_dynamic_linear()
        elif what == 'angular':
            return self.is_dynamic_angular()
        else:
            raise ValueError('unknown mode: %r' % what)

    def is_dynamic_linear(self):
        '''Verifica se o objeto é dinâmico nas variáveis lineares'''

        return self.mass == INF

    def is_dynamic_angular(self):
        '''Verifica se o objeto é dinâmico nas variáveis angulares'''

        return self.inertia == INF

    def make_dynamic(self, what=None):
        '''Resgata a massa, inércia e velocidades anteriores de um objeto
        paralizado pelo método `obj.make_static()` ou `obj.make_kinematic()`.

        Aceita um argumento com a mesma semântica de is_dynamic()
        '''

        if what is None or what == 'both':
            self.make_dynamic_linear()
            self.make_dynamic_angular()
        elif what == 'linear':
            self.make_dynamic_linear()
        elif what == 'angular':
            self.make_dynamic_angular()
        else:
            raise ValueError('unknown mode: %r' % what)

    def make_dynamic_linear(self):
        '''Resgata os parâmetros dinâmicos lineares de um objeto estático ou
        cinemático paralizado pelos métodos `obj.make_static()` ou
        `obj.make_kinematic()`.'''

        if not self.is_dynamic_linear():
            # Regata a massa
            mass = self._getp('old_mass', None)
            if mass is None:
                raise RuntimeError('old mass is not available for recovery')
            else:
                self.mass = mass

            # Resgata a velocidade
            if self.vel == ORIGIN:
                self.vel = self._getp('old_vel', ORIGIN)

        self._clearp('old_mass', 'old_vel')

    def make_dynamic_angular(self):
        '''Resgata os parâmetros dinâmicos angulares de um objeto estático ou
        cinemático paralizado pelos métodos `obj.make_static()` ou
        `obj.make_kinematic()`.'''

        if not self.is_dynamic_angular():
            # Regata a massa
            inertia = self._getp('old_inertia', None)
            if inertia is None:
                raise RuntimeError('old inertia is not available for recovery')
            else:
                self.inertia = inertia

            # Resgata a velocidade
            if self.omega == 0:
                self.omega = self._getp('old_omega', 0)

        self._clearp('old_inertia', 'old_omega')

    # Kinematic ###############################################################
    def is_kinematic(self, what=None):
        '''Retorna True se o objeto for cinemático ou nas variáveis lineares ou
        nas angulares. Um objeto é considerado cinemático (em uma das
        variáveis) se não for dinâmico. Se, além de cinemático, o objeto
        possuir velocidade nula, ele é considerado estático.

        Opcionalmente pode especificar um parâmetro posicional 'linear',
        'angular', 'both' (padrão) or 'any' para determinar o tipo de consulta
        a ser realizada.
        '''

        if what is None or what == 'both':
            return not (self.is_dynamic_linear() or self.is_dynamic_angular())
        elif what == 'any':
            return (not self.is_dynamic_linear()) or (
                not self.is_dynamic_angular())
        elif what == 'linear':
            return not self.is_dynamic_linear()
        elif what == 'angular':
            return not self.is_dynamic_angular()
        else:
            raise ValueError('unknown mode: %r' % what)

    def is_kinematic_linear(self):
        '''Verifica se o objeto é dinâmico nas variáveis lineares'''

        return not self.is_dynamic_linear()

    def is_kinematic_angular(self):
        '''Verifica se o objeto é dinâmico nas variáveis angulares'''

        return not self.is_dynamic_angular()

    def make_kinematic(self, what=None):
        '''Define a massa e/ou inércia como infinito.

        Aceita um argumento com a mesma semântica de is_kinematic()
        '''

        if what is None or what == 'both':
            self.make_kinematic_linear()
            self.make_kinematic_angular()
        elif what == 'linear':
            self.make_kinematic_linear()
        elif what == 'angular':
            self.make_kinematic_angular()
        else:
            raise ValueError('unknown mode: %r' % what)

    def make_kinematic_linear(self):
        '''Resgata os parâmetros dinâmicos lineares de um objeto estático ou
        cinemático paralizado pelos métodos `obj.make_static()` ou
        `obj.make_kinematic()`.'''

        if not self.is_kinematic_linear():
            self._setp('old_mass', self.mass)
            self.mass = 'inf'

    def make_kinematic_angular(self):
        '''Resgata os parâmetros dinâmicos angulares de um objeto estático ou
        cinemático paralizado pelos métodos `obj.make_static()` ou
        `obj.make_kinematic()`.'''

        if not self.is_kinematic_angular():
            self._setp('old_inertia', self.inertia)
            self.inertia = 'inf'

    # Static ##################################################################
    def is_static(self, what=None):
        '''Retorna True se o objeto for estatático nas variáveis lineares e
        nas angulares. Um objeto é considerado estático (em uma das variáveis)
        se além de cinemático, a velocidade for nula.

        Opcionalmente pode especificar um parâmetro posicional 'linear',
        'angular', 'both' (padrão) or 'any' para determinar o tipo de consulta
        a ser realizada'''

        if what is None or what == 'both':
            return self.is_static_linear() and self.is_static_angular()
        elif what == 'any':
            return self.is_static_linear() or self.is_static_angular()
        elif what == 'linear':
            return self.is_static_linear()
        elif what == 'angular':
            return self.is_static_angular()
        else:
            raise ValueError('unknown mode: %r' % what)

    def is_static_linear(self):
        '''Verifica se o objeto é dinâmico nas variáveis lineares'''

        return self.is_kinematic_linear() and self.vel == ORIGIN

    def is_static_angular(self):
        '''Verifica se o objeto é dinâmico nas variáveis angulares'''

        return self.is_kinematic_angular() and self.omega == 0

    def make_static(self, what=None):
        '''Define a massa e/ou inércia como infinito.

        Aceita um argumento com a mesma semântica de is_static()
        '''

        if what is None or what == 'both':
            self.make_static_linear()
            self.make_static_angular()
        elif what == 'linear':
            self.make_static_linear()
        elif what == 'angular':
            self.make_static_angular()
        else:
            raise ValueError('unknown mode: %r' % what)

    def make_static_linear(self):
        '''Resgata os parâmetros dinâmicos lineares de um objeto estático ou
        cinemático paralizado pelos métodos `obj.make_static()` ou
        `obj.make_kinematic()`.'''

        self.make_kinematic_linear()
        if self.vel != ORIGIN:
            self._setp('old_vel', self.vel)
            self.vel = (0, 0)

    def make_static_angular(self):
        '''Resgata os parâmetros dinâmicos angulares de um objeto estático ou
        cinemático paralizado pelos métodos `obj.make_static()` ou
        `obj.make_kinematic()`.'''

        self.make_kinematic_angular()
        if self.omega != 0:
            self._setp('old_omega', self.omega)
            self.omega = 0.0