T = TypeVar("T", bound="PickleMixin")
class PickleMixin:
    def __getstate__(self) -> _State:
    def __setstate__(self, state: _State) -> None:
    def copy(self: T) -> T: class TypingAttrMixing:
    """Type helper mixin to make mypy accept dynamic attribtutes.
    
    """

    def __setattr__(self, name: str, value: Any) -> None:
        """Override default setattr to make sure type checking works."""
        super().__setattr__(name, value)

    def __getattr__(self, name: str) -> Any:
        """Override default getattr to make sure type checking works."""
        return self.__getattribute__(name) class BB(NamedTuple):
    """Simple axis-aligned 2D bounding box.

    Stored as left, bottom, right, top values.

    An instance can be created in this way:
        >>> BB(left=1, bottom=5, right=20, top=10)
        BB(left=1, bottom=5, right=20, top=10)

    Or partially, for example like this:
        >>> BB(right=5, top=10)
        BB(left=0, bottom=0, right=5, top=10)
    """

    left: float = 0
    bottom: float = 0
    right: float = 0
    top: float = 0

    @staticmethod
    def newForCircle(p: Tuple[float, float], r: float) -> "BB":
        """Convenience constructor for making a BB fitting a circle at
        position p with radius r.
        """

        bb_ = lib.cpBBNewForCircle(p, r)
        return BB(bb_.l, bb_.b, bb_.r, bb_.t)

    def intersects(self, other: "BB") -> bool:
        """Returns true if the bounding boxes intersect"""
        return bool(lib.cpBBIntersects(self, other))

    def intersects_segment(
        self, a: Tuple[float, float], b: Tuple[float, float]
    ) -> bool:
        """Returns true if the segment defined by endpoints a and b
        intersect this bb."""
        assert len(a) == 2
        assert len(b) == 2
        return bool(lib.cpBBIntersectsSegment(self, a, b))

    def contains(self, other: "BB") -> bool:
        """Returns true if bb completley contains the other bb"""
        return bool(lib.cpBBContainsBB(self, other))

    def contains_vect(self, v: Tuple[float, float]) -> bool:
        """Returns true if this bb contains the vector v"""
        assert len(v) == 2
        return bool(lib.cpBBContainsVect(self, v))

    def merge(self, other: "BB") -> "BB":
        """Return the minimal bounding box that contains both this bb and the
        other bb
        """
        cp_bb = lib.cpBBMerge(self, other)
        return BB(cp_bb.l, cp_bb.b, cp_bb.r, cp_bb.t)

    def expand(self, v: Tuple[float, float]) -> "BB":
        """Return the minimal bounding box that contans both this bounding box
        and the vector v
        """
        cp_bb = lib.cpBBExpand(self, tuple(v))
        return BB(cp_bb.l, cp_bb.b, cp_bb.r, cp_bb.t)

    def center(self) -> Vec2d:
        """Return the center"""
        v = lib.cpBBCenter(self)
        return Vec2d(v.x, v.y)

    def area(self) -> float:
        """Return the area"""
        return lib.cpBBArea(self)

    def merged_area(self, other: "BB") -> float:
        """Merges this and other then returns the area of the merged bounding
        box.
        """
        return lib.cpBBMergedArea(self, other)

    def segment_query(self, a: Tuple[float, float], b: Tuple[float, float]) -> float:
        """Returns the fraction along the segment query the BB is hit.

        Returns infinity if it doesnt hit
        """
        assert len(a) == 2
        assert len(b) == 2
        return lib.cpBBSegmentQuery(self, a, b)

    def clamp_vect(self, v: Tuple[float, float]) -> Vec2d:
        """Returns a copy of the vector v clamped to the bounding box"""
        assert len(v) == 2
        v2 = lib.cpBBClampVect(self, v)
        return Vec2d(v2.x, v2.y)

    '''
    def wrap_vect(self, v):
        """Returns a copy of v wrapped to the bounding box.

        That is, BB(0,0,10,10).wrap_vect((5,5)) == Vec2d._fromcffi(10,10)
        """
        return lib._cpBBWrapVect(self.cp_bb[0], v)
    ''' class ContactPointSet(object):
    """Contact point sets make getting contact information simpler.

    normal is the normal of the collision

    points is the array of contact points. Can be at most 2 points.
    """

    normal: Vec2d
    points: List[ContactPoint]

    __slots__ = ("normal", "points")

    def __init__(self, normal: Vec2d, points: List[ContactPoint]) -> None:
        assert len(normal) == 2
        self.normal = normal
        self.points = points

    def __repr__(self) -> str:
        return "ContactPointSet(normal={}, points={})".format(self.normal, self.points)

    @classmethod
    def _from_cp(cls, _points: "ffi.CData") -> "ContactPointSet":
        normal = Vec2d(_points.normal.x, _points.normal.y)

        points = []
        for i in range(_points.count):
            _p = _points.points[i]
            p = ContactPoint(
                Vec2d(_p.pointA.x, _p.pointA.y),
                Vec2d(_p.pointB.x, _p.pointB.y),
                _p.distance,
            )
            points.append(p)

        return cls(normal, points) class PointQueryInfo(NamedTuple):
    """PointQueryInfo holds the result of a point query made on a Shape or
    Space.
    """

    shape: Optional["Shape"]
    """The nearest shape, None if no shape was within range."""

    point: "Vec2d"
    """The closest point on the shape's surface. (in world space
    coordinates)
    """

    distance: float
    """The distance to the point. The distance is negative if the
    point is inside the shape.
    """

    gradient: "Vec2d"
    """The gradient of the signed distance function.

    The value should be similar to
    PointQueryInfo.point/PointQueryInfo.distance, but accurate even for
    very small values of info.distance.
    """ class SegmentQueryInfo(NamedTuple):
    """Segment queries return more information than just a simple yes or no,
    they also return where a shape was hit and it's surface normal at the hit
    point. This object hold that information.

    To test if the query hit something, check if
    SegmentQueryInfo.shape == None or not.

    Segment queries are like ray casting, but because not all spatial indexes
    allow processing infinitely long ray queries it is limited to segments.
    In practice this is still very fast and you don't need to worry too much
    about the performance as long as you aren't using extremely long segments
    for your queries.

    """

    shape: Optional["Shape"]
    """Shape that was hit, or None if no collision occured"""

    point: "Vec2d"
    """The point of impact."""

    normal: "Vec2d"
    """The normal of the surface hit."""

    alpha: float
    """The normalized distance along the query segment in the range [0, 1]""" class ShapeFilter(NamedTuple):
    """
    Pymunk has two primary means of ignoring collisions: groups and
    category masks.

    Groups are used to ignore collisions between parts on a complex object. A
    ragdoll is a good example. When jointing an arm onto the torso, you'll
    want them to allow them to overlap. Groups allow you to do exactly that.
    Shapes that have the same group don't generate collisions. So by placing
    all of the shapes in a ragdoll in the same group, you'll prevent it from
    colliding against other parts of itself. Category masks allow you to mark
    which categories an object belongs to and which categories it collides
    with.

    For example, a game has four collision categories: player (0), enemy (1),
    player bullet (2), and enemy bullet (3). Neither players nor enemies
    should not collide with their own bullets, and bullets should not collide
    with other bullets. However, players collide with enemy bullets, and
    enemies collide with player bullets.

    ============= =============== ====================
    Object        Object Category Category Mask
    ============= =============== ====================
    Player        0b00001 (1)     0b11000 (4, 5)
    Enemy         0b00010 (2)     0b01110 (2, 3, 4)
    Player Bullet 0b00100 (3)     0b10001 (1, 5)
    Enemy Bullet  0b01000 (4)     0b10010 (2, 5)
    Walls         0b10000 (5)     0b01111 (1, 2, 3, 4)
    ============= =============== ====================

    Note that in the table the categories and masks are written as binary
    values to clearly show the logic. To save space only 5 digits are used. The
    default type of categories and mask in ShapeFilter is an unsigned int,
    with a resolution of 32 bits. That means that the you have 32 bits to use,
    in binary notation that is `0b00000000000000000000000000000000` to
    `0b11111111111111111111111111111111` which can be written in hex as
    `0x00000000` to `0xFFFFFFFF`.

    Everything in this example collides with walls. Additionally,
    the enemies collide with each other.

    By default, objects exist in every category and collide with every category.

    Objects can fall into multiple categories. For instance, you might have a
    category for a red team, and have a red player bullet. In the above
    example, each object only has one category.

    The default type of categories and mask in ShapeFilter is unsigned int
    which has a resolution of 32 bits on most systems.

    There is one last way of filtering collisions using collision handlers.
    See the section on callbacks for more information. Collision handlers can
    be more flexible, but can be slower. Fast collision filtering rejects
    collisions before running the expensive collision detection code, so
    using groups or category masks is preferred.

    Example of how category and mask can be used to filter out player from
    enemy object:

    >>> import pymunk
    >>> s = pymunk.Space()
    >>> player_b = pymunk.Body(1,1)
    >>> player_c = pymunk.Circle(player_b, 10)
    >>> s.add(player_b, player_c)
    >>> player_c.filter = pymunk.ShapeFilter(categories=0b1)
    >>> hit = s.point_query_nearest((0,0), 0, pymunk.ShapeFilter())
    >>> hit != None
    True
    >>> filter = pymunk.ShapeFilter(mask=pymunk.ShapeFilter.ALL_MASKS() ^ 0b1)
    >>> hit = s.point_query_nearest((0,0), 0, filter)
    >>> hit == None
    True
    >>> enemy_b = pymunk.Body(1,1)
    >>> enemy_c = pymunk.Circle(enemy_b, 10)
    >>> s.add(enemy_b, enemy_c)
    >>> hit = s.point_query_nearest((0,0), 0, filter)
    >>> hit != None
    True

    """

    group: int = 0
    """Two objects with the same non-zero group value do not collide.
	
    This is generally used to group objects in a composite object together to disable self collisions.
    """

    categories: int = 0xFFFFFFFF
    """A bitmask of user definable categories that this object belongs to.
	
    The category/mask combinations of both objects in a collision must agree for a collision to occur.
    """

    mask: int = 0xFFFFFFFF
    """A bitmask of user definable category types that this object object collides with.
	
    The category/mask combinations of both objects in a collision must agree for a collision to occur.
	"""

    @staticmethod
    def ALL_MASKS() -> int:
        return 0xFFFFFFFF

    @staticmethod
    def ALL_CATEGORIES() -> int:
        return 0xFFFFFFFF class Transform(NamedTuple):
    """Type used for 2x3 affine transforms.

    See wikipedia for details:
    http://en.wikipedia.org/wiki/Affine_transformation

    The properties map to the matrix in this way:

    = = ==
    a c tx
    b d ty
    0 0  1
    = = ==

    An instance can be created in this way:

        >>> Transform(1,2,3,4,5,6)
        Transform(a=1, b=2, c=3, d=4, tx=5, ty=6)

    Or overriding only some of the values (on a identity matrix):

        >>> Transform(b=3,ty=5)
        Transform(a=1, b=3, c=0, d=1, tx=0, ty=5)

    Or using one of the static methods like identity or translation (see each
    method for details).

    The Transform supports the matrix multiplicaiton operator (@) with a
    Transform, Vec2d or tuple as second operand, which produces a transformed
    Transform or Vec2d as result:

        >>> Transform.scaling(2) @ Transform.scaling(3)
        Transform(a=6, b=0, c=0, d=6, tx=0, ty=0)
        >>> Transform.scaling(2) @ Vec2d(1, 2)
        Vec2d(2, 4)

    """

    a: float = 1
    b: float = 0
    c: float = 0
    d: float = 1
    tx: float = 0
    ty: float = 0

    @overload
    def __matmul__(self, other: Tuple[float, float]) -> Vec2d:
        ...

    @overload
    def __matmul__(
        self, other: Tuple[float, float, float, float, float, float]
    ) -> "Transform":
        ...

    def __matmul__(
        self,
        other: Union[
            Tuple[float, float], Tuple[float, float, float, float, float, float]
        ],
    ) -> Union[Vec2d, "Transform"]:

        """Multiply this transform with a Transform, Vec2d or Tuple of size 2
        or 6.


        Examples (Transform @ Transform):

        >>> Transform() @ Transform() == Transform.identity()
        True
        >>> Transform.translation(2,3) @ Transform.translation(4,5)
        Transform(a=1, b=0, c=0, d=1, tx=6, ty=8)
        >>> Transform.scaling(2) @ Transform.scaling(3)
        Transform(a=6, b=0, c=0, d=6, tx=0, ty=0)
        >>> Transform.scaling(2) @ Transform.translation(3,4)
        Transform(a=2, b=0, c=0, d=2, tx=6, ty=8)
        >>> Transform.translation(3,4) @ Transform.scaling(2)
        Transform(a=2, b=0, c=0, d=2, tx=3, ty=4)


        Examples (Transform @ Vec2d):

        >>> Transform.identity() @ Vec2d(1, 2)
        Vec2d(1, 2)
        >>> Transform.scaling(2) @ Vec2d(1, 2)
        Vec2d(2, 4)
        >>> Transform.translation(3,5) @ Vec2d(1, 2)
        Vec2d(4, 7)
        >>> Transform.rotation(1) @ Vec2d(1, 2) == Vec2d(1, 2).rotated(1)
        True

        """
        assert (
            len(other) == 2 or len(other) == 6
        ), f"{other} not supported. Only Vec2d, Transform and Sequence of length 2 or 6 are supported."

        if len(other) == 2:
            assert len(other) == 2
            x, y = cast(Tuple[float, float], other)
            return Vec2d(
                self.a * x + self.c * y + self.tx, self.b * x + self.d * y + self.ty
            )
        else:
            a, b, c, d, tx, ty = cast(Tuple[float, float, float, float, float, float], other)
            return Transform(
                a=self.a * a + self.c * b + self.tx * 0,
                b=self.b * a + self.d * b + self.ty * 0,
                c=self.a * c + self.c * d + self.tx * 0,
                d=self.b * c + self.d * d + self.ty * 0,
                tx=self.a * tx + self.c * ty + self.tx * 1,
                ty=self.b * tx + self.d * ty + self.ty * 1,
            )

    @staticmethod
    def identity() -> "Transform":
        """The identity transform

        Example:

        >>> Transform.identity()
        Transform(a=1, b=0, c=0, d=1, tx=0, ty=0)

        Returns a Transform with this matrix:

        = = =
        1 0 0
        0 1 0
        0 0 1
        = = =

        """
        return Transform(1, 0, 0, 1, 0, 0)

    def translated(self, x: float, y: float) -> "Transform":
        """Translate this Transform and return the result.

        Example:
        >>> Transform.scaling(2).translated(3,4)
        Transform(a=2, b=0, c=0, d=2, tx=6, ty=8)

        """
        return self @ Transform.translation(x, y)

    def scaled(self, s: float) -> "Transform":
        """Scale this Transform and return the result.

        Example:

        >>> Transform.translation(3,4).scaled(2)
        Transform(a=2, b=0, c=0, d=2, tx=3, ty=4)
        """
        return self @ Transform.scaling(s)

    def rotated(self, t: float) -> "Transform":
        """Rotate this Transform and return the result.

        >>> '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f' % Transform.rotation(1).rotated(0.5)
        '0.07, 1.00, -1.00, 0.07, 0.00, 0.00'
        >>> '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f' % Transform.rotation(1.5)
        '0.07, 1.00, -1.00, 0.07, 0.00, 0.00'
        """
        return self @ Transform.rotation(t)

    @staticmethod
    def translation(x: float, y: float) -> "Transform":
        """A translation transform

        Example to translate (move) by 3 on x and 5 in y axis:

        >>> Transform.translation(3, 5)
        Transform(a=1, b=0, c=0, d=1, tx=3, ty=5)

        Returns a Transform with this matrix:

        = = =
        1 0 x
        0 1 y
        0 0 1
        = = =

        """
        return Transform(tx=x, ty=y)

    # split into scale and scale_non-uniform
    @staticmethod
    def scaling(s: float) -> "Transform":
        """A scaling transform

        Example to scale 4x:

        >>> Transform.scaling(4)
        Transform(a=4, b=0, c=0, d=4, tx=0, ty=0)

        Returns a Transform with this matrix:

        = = =
        s 0 0
        0 s 0
        0 0 1
        = = =

        """
        return Transform(a=s, d=s)

    @staticmethod
    def rotation(t: float) -> "Transform":
        """A rotation transform

        Example to rotate by 1 rad:

        >>> '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f' % Transform.rotation(1)
        '0.54, 0.84, -0.84, 0.54, 0.00, 0.00'

        Returns a Transform with this matrix:

        ====== ======= =
        cos(t) -sin(t) 0
        sin(t) cos(t)  0
        0      0       1
        ====== ======= =

        """
        c = math.cos(t)
        s = math.sin(t)
        return Transform(a=c, b=s, c=-s, d=c) class Vec2d(NamedTuple):
    """2d vector class, supports vector and scalar operators, and also
    provides some high level functions.
    """

    x: float
    y: float

    # String representaion (for debugging)
    def __repr__(self) -> str:
        return "Vec2d(%s, %s)" % (self.x, self.y)

    # Addition
    def __add__(self, other: Tuple[float, float]) -> "Vec2d":  # type: ignore
        """Add a Vec2d with another Vec2d or Tuple of size 2

        >>> Vec2d(3,4) + Vec2d(1,2)
        Vec2d(4, 6)
        >>> Vec2d(3,4) + (1,2)
        Vec2d(4, 6)
        """
        assert (
            len(other) == 2
        ), f"{other} not supported. Only Vec2d and Sequence of length 2 is supported."

        return Vec2d(self.x + other[0], self.y + other[1])

    def __radd__(self, other: Tuple[float, float]) -> "Vec2d":
        """Add a Tuple of size 2 with a Vec2d

        >>> (1,2) + Vec2d(3,4)
        Vec2d(4, 6)
        """
        return self.__add__(other)

    # Subtraction
    def __sub__(self, other: Tuple[float, float]) -> "Vec2d":
        """Subtract a Vec2d with another Vec2d or Tuple of size 2

        >>> Vec2d(3,4) - Vec2d(1,2)
        Vec2d(2, 2)
        >>> Vec2d(3,4) - (1,2)
        Vec2d(2, 2)
        """
        return Vec2d(self.x - other[0], self.y - other[1])

    def __rsub__(self, other: Tuple[float, float]) -> "Vec2d":
        """Subtract a Tuple of size 2 with a Vec2d

        >>> (1,2) - Vec2d(3,4)
        Vec2d(-2, -2)
        """
        assert (
            len(other) == 2
        ), f"{other} not supported. Only Vec2d and Sequence of length 2 is supported."
        return Vec2d(other[0] - self.x, other[1] - self.y)

    # Multiplication
    def __mul__(self, other: float) -> "Vec2d":
        """Multiply with a float

        >>> Vec2d(3,6) * 2.5
        Vec2d(7.5, 15.0)
        """
        assert isinstance(other, numbers.Real)
        return Vec2d(self.x * other, self.y * other)

    def __rmul__(self, other: float) -> "Vec2d":
        """Multiply a float with a Vec2d

        >>> 2.5 * Vec2d(3,6)
        Vec2d(7.5, 15.0)
        """
        return self.__mul__(other)

    # Division
    def __floordiv__(self, other: float) -> "Vec2d":
        """Floor division by a float (also known as integer division)

        >>> Vec2d(3,6) // 2.0
        Vec2d(1.0, 3.0)
        """
        assert isinstance(other, numbers.Real)
        return Vec2d(self.x // other, self.y // other)

    def __truediv__(self, other: float) -> "Vec2d":
        """Division by a float

        >>> Vec2d(3,6) / 2.0
        Vec2d(1.5, 3.0)
        """
        assert isinstance(other, numbers.Real)
        return Vec2d(self.x / other, self.y / other)

    # Unary operations
    def __neg__(self) -> "Vec2d":
        """Return the negated version of the Vec2d

        >>> -Vec2d(1,-2)
        Vec2d(-1, 2)
        """
        return Vec2d(operator.neg(self.x), operator.neg(self.y))

    def __pos__(self) -> "Vec2d":
        """Return the unary pos of the Vec2d.

        >>> +Vec2d(1,-2)
        Vec2d(1, -2)
        """
        return Vec2d(operator.pos(self.x), operator.pos(self.y))

    def __abs__(self) -> float:
        """Return the length of the Vec2d

        >>> abs(Vec2d(3,4))
        5.0
        """
        return self.length

    # vectory functions
    def get_length_sqrd(self) -> float:
        """Get the squared length of the vector.
        If the squared length is enough it is more efficient to use this method
        instead of first calling get_length() or access .length and then do a
        x**2.

        >>> v = Vec2d(3,4)
        >>> v.get_length_sqrd() == v.length**2
        True

        :return: The squared length
        """
        return self.x ** 2 + self.y ** 2

    @property
    def length(self) -> float:
        """Get the length of the vector.

        >>> Vec2d(10, 0).length
        10.0
        >>> '%.2f' % Vec2d(10, 20).length
        '22.36'

        :return: The length
        """
        return math.sqrt(self.x ** 2 + self.y ** 2)

    def scale_to_length(self, length: float) -> "Vec2d":
        """Return a copy of this vector scaled to the given length.

        >>> '%.2f, %.2f' % Vec2d(10, 20).scale_to_length(20)
        '8.94, 17.89'
        """
        old_length = self.length
        return Vec2d(self.x * length / old_length, self.y * length / old_length)

    def rotated(self, angle_radians: float) -> "Vec2d":
        """Create and return a new vector by rotating this vector by
        angle_radians radians.

        :return: Rotated vector
        """
        cos = math.cos(angle_radians)
        sin = math.sin(angle_radians)
        x = self.x * cos - self.y * sin
        y = self.x * sin + self.y * cos
        return Vec2d(x, y)

    def rotated_degrees(self, angle_degrees: float) -> "Vec2d":
        """Create and return a new vector by rotating this vector by
        angle_degrees degrees.

        :return: Rotade vector
        """
        return self.rotated(math.radians(angle_degrees))

    @property
    def angle(self) -> float:
        """The angle (in radians) of the vector"""
        if self.get_length_sqrd() == 0:
            return 0
        return math.atan2(self.y, self.x)

    @property
    def angle_degrees(self) -> float:
        """Gets the angle (in degrees) of a vector"""
        return math.degrees(self.angle)

    def get_angle_between(self, other: Tuple[float, float]) -> float:
        """Get the angle between the vector and the other in radians

        :return: The angle
        """
        assert len(other) == 2
        cross = self.x * other[1] - self.y * other[0]
        dot = self.x * other[0] + self.y * other[1]
        return math.atan2(cross, dot)

    def get_angle_degrees_between(self, other: "Vec2d") -> float:
        """Get the angle between the vector and the other in degrees

        :return: The angle (in degrees)
        """
        return math.degrees(self.get_angle_between(other))

    def normalized(self) -> "Vec2d":
        """Get a normalized copy of the vector
        Note: This function will return 0 if the length of the vector is 0.

        :return: A normalized vector
        """
        length = self.length
        if length != 0:
            return self / length
        return Vec2d(0, 0)

    def normalized_and_length(self) -> Tuple["Vec2d", float]:
        """Normalize the vector and return its length before the normalization

        :return: The length before the normalization
        """
        length = self.length
        if length != 0:
            return self / length, length
        return Vec2d(0, 0), 0

    def perpendicular(self) -> "Vec2d":
        return Vec2d(-self.y, self.x)

    def perpendicular_normal(self) -> "Vec2d":
        length = self.length
        if length != 0:
            return Vec2d(-self.y / length, self.x / length)
        return Vec2d(self.x, self.y)

    def dot(self, other: Tuple[float, float]) -> float:
        """The dot product between the vector and other vector
            v1.dot(v2) -> v1.x*v2.x + v1.y*v2.y

        :return: The dot product
        """
        assert len(other) == 2
        return float(self.x * other[0] + self.y * other[1])

    def get_distance(self, other: Tuple[float, float]) -> float:
        """The distance between the vector and other vector

        :return: The distance
        """
        assert len(other) == 2
        return math.sqrt((self.x - other[0]) ** 2 + (self.y - other[1]) ** 2)

    def get_dist_sqrd(self, other: Tuple[float, float]) -> float:
        """The squared distance between the vector and other vector
        It is more efficent to use this method than to call get_distance()
        first and then do a sqrt() on the result.

        :return: The squared distance
        """
        assert len(other) == 2
        return (self.x - other[0]) ** 2 + (self.y - other[1]) ** 2

    def projection(self, other: Tuple[float, float]) -> "Vec2d":
        """Project this vector on top of other vector"""
        assert len(other) == 2
        other_length_sqrd = other[0] * other[0] + other[1] * other[1]
        if other_length_sqrd == 0.0:
            return Vec2d(0, 0)
        projected_length_times_other_length = self.dot(other)
        new_length = projected_length_times_other_length / other_length_sqrd
        return Vec2d(other[0] * new_length, other[1] * new_length)

    def cross(self, other: Tuple[float, float]) -> float:
        """The cross product between the vector and other vector
            v1.cross(v2) -> v1.x*v2.y - v1.y*v2.x

        :return: The cross product
        """
        assert len(other) == 2
        return self.x * other[1] - self.y * other[0]

    def interpolate_to(self, other: Tuple[float, float], range: float) -> "Vec2d":
        assert len(other) == 2
        return Vec2d(
            self.x + (other[0] - self.x) * range, self.y + (other[1] - self.y) * range
        )

    def convert_to_basis(
        self, x_vector: Tuple[float, float], y_vector: Tuple[float, float]
    ) -> "Vec2d":
        assert len(x_vector) == 2
        assert len(y_vector) == 2
        x = self.dot(x_vector) / Vec2d(*x_vector).get_length_sqrd()
        y = self.dot(y_vector) / Vec2d(*y_vector).get_length_sqrd()
        return Vec2d(x, y)

    @property
    def int_tuple(self) -> Tuple[int, int]:
        """The x and y values of this vector as a tuple of ints.
        Uses round() to round to closest int.

        >>> Vec2d(0.9, 2.4).int_tuple
        (1, 2)
        """
        return round(self.x), round(self.y)

    @staticmethod
    def zero() -> "Vec2d":
        """A vector of zero length.

        >>> Vec2d.zero()
        Vec2d(0, 0)
        """
        return Vec2d(0, 0)

    @staticmethod
    def unit() -> "Vec2d":
        """A unit vector pointing up

        >>> Vec2d.unit()
        Vec2d(0, 1)
        """
        return Vec2d(0, 1)

    @staticmethod
    def ones() -> "Vec2d":
        """A vector where both x and y is 1

        >>> Vec2d.ones()
        Vec2d(1, 1)
        """
        return Vec2d(1, 1)

    # Extra functions, mainly for chipmunk
    def cpvrotate(self, other: Tuple[float, float]) -> "Vec2d":
        """Uses complex multiplication to rotate this vector by the other. """
        assert len(other) == 2
        return Vec2d(
            self.x * other[0] - self.y * other[1], self.x * other[1] + self.y * other[0]
        )

    def cpvunrotate(self, other: Tuple[float, float]) -> "Vec2d":
        """The inverse of cpvrotate"""
        assert len(other) == 2
        return Vec2d(
            self.x * other[0] + self.y * other[1], self.y * other[0] - self.x * other[1]
        )

import logging
from typing import TYPE_CHECKING, Any, List, Optional, Sequence, Tuple
    from .body import Body
    from .space import Space
from ._chipmunk_cffi import ffi
from ._chipmunk_cffi import lib as cp
from ._pickle import PickleMixin, _State
from ._typing_attr import TypingAttrMixing
from .bb import BB
from .contact_point_set import ContactPointSet
from .query_info import PointQueryInfo, SegmentQueryInfo
from .shape_filter import ShapeFilter
from .transform import Transform
from .vec2d import Vec2d
    def _set_filter(self, f: ShapeFilter) -> None:
        cp.cpShapeSetFilter(self._shape, f)

    filter = property(
        _get_filter,
        _set_filter,
        doc="""Set the collision :py:class:`ShapeFilter` for this shape.
        """,
    )

    def _get_elasticity(self) -> float:
        return cp.cpShapeGetElasticity(self._shape)

    def _set_elasticity(self, e: float) -> None:
        cp.cpShapeSetElasticity(self._shape, e)

    elasticity = property(
        _get_elasticity,
        _set_elasticity,
        doc="""Elasticity of the shape.

        A value of 0.0 gives no bounce, while a value of 1.0 will give a
        'perfect' bounce. However due to inaccuracies in the simulation
        using 1.0 or greater is not recommended.
        """,
    )

    def _get_friction(self) -> float:
        return cp.cpShapeGetFriction(self._shape)

    def _set_friction(self, u: float) -> None:
        cp.cpShapeSetFriction(self._shape, u)

    friction = property(
        _get_friction,
        _set_friction,
        doc="""Friction coefficient.

        Pymunk uses the Coulomb friction model, a value of 0.0 is
        frictionless.

        A value over 1.0 is perfectly fine.

        Some real world example values from Wikipedia (Remember that
        it is what looks good that is important, not the exact value).

        ==============  ======  ========
        Material        Other   Friction
        ==============  ======  ========
        Aluminium       Steel   0.61
        Copper          Steel   0.53
        Brass           Steel   0.51
        Cast iron       Copper  1.05
        Cast iron       Zinc    0.85
        Concrete (wet)  Rubber  0.30
        Concrete (dry)  Rubber  1.0
        Concrete        Wood    0.62
        Copper          Glass   0.68
        Glass           Glass   0.94
        Metal           Wood    0.5
        Polyethene      Steel   0.2
        Steel           Steel   0.80
        Steel           Teflon  0.04
        Teflon (PTFE)   Teflon  0.04
        Wood            Wood    0.4
        ==============  ======  ========
        """,
    )

    def _get_surface_velocity(self) -> Vec2d:
        v = cp.cpShapeGetSurfaceVelocity(self._shape)
        return Vec2d(v.x, v.y)

    def _set_surface_velocity(self, surface_v: Vec2d) -> None:
        assert len(surface_v) == 2
        cp.cpShapeSetSurfaceVelocity(self._shape, surface_v)

    surface_velocity = property(
        _get_surface_velocity,
        _set_surface_velocity,
        doc="""The surface velocity of the object.

        Useful for creating conveyor belts or players that move around. This
        value is only used when calculating friction, not resolving the
        collision.
        """,
    )

    def _get_body(self) -> Optional["Body"]:
        return self._body

    def _set_body(self, body: Optional["Body"]) -> None:
        if self._body != None:
            self._body._shapes.remove(self)
        body_body = ffi.NULL if body is None else body._body
        cp.cpShapeSetBody(self._shape, body_body)
        if body is not None:
            body._shapes.add(self)
        self._body = body

    body = property(
        _get_body,
        _set_body,
        doc="""The body this shape is attached to. Can be set to None to
        indicate that this shape doesnt belong to a body.""",
    )

    def update(self, transform: Transform) -> BB:
        """Update, cache and return the bounding box of a shape with an
        explicit transformation.

        Useful if you have a shape without a body and want to use it for
        querying.
        """
        _bb = cp.cpShapeUpdate(self._shape, transform)
        return BB(_bb.l, _bb.b, _bb.r, _bb.t)

    def cache_bb(self) -> BB:
        """Update and returns the bounding box of this shape"""
        _bb = cp.cpShapeCacheBB(self._shape)

        return BB(_bb.l, _bb.b, _bb.r, _bb.t)