# Source code for miniworldmaker.positions.vector

```import math
from typing import Union

import numpy as np

import miniworldmaker.positions.direction as board_direction
import miniworldmaker.positions.position as board_position
import miniworldmaker.tokens.token as token_mod

[docs]class Vector:
"""Describes a two-dimensional vector.

It is used to describe a position, acceleration
or velocity.

Examples:

Create a circle which follows the mouse.

.. code-block:: python

from miniworldmaker import *
board = Board(800, 800)

mover = Circle()
mover.velocity = Vector(0, 0)
mover.topspeed = 10

@board.register
def act(self):
mouse_vec = Vector(board.get_mouse_x(), board.get_mouse_y())
location = Vector.from_token_position(mover)
acceleration = mouse_vec - location
acceleration.normalize() * 2

mover.velocity.limit(mover.topspeed)
mover.move_vector(mover.velocity)

board.run()

.. raw:: html

<video loop autoplay muted width=240>
<source src="../_static/mp4/vector_1.mp4" type="video/mp4">
<source src="../_static/vector_1.webm" type="video/webm">
Your browser does not support the video tag.
</video>

"""

def __init__(self, x: float, y: float):
self.vec = np.array([x, y])

def __getitem__(self, item):
if item == 0:
return self.vec[0]
else:
return self.vec[1]

@property
def angle(self):
"""describes the angle as miniworldmaker direction"""
return self.to_direction()

@property
def x(self) -> float:
"""the x compoonent of the vector"""
return self.vec[0]

@x.setter
def x(self, value: float):
self.vec = np.array([value, self.vec[1]])

@property
def y(self) -> float:
"""the y component of the vector"""
return self.vec[1]

@y.setter
def y(self, value: float):
self.vec = np.array([self.vec[0], value])

[docs]    @classmethod
def from_positions(cls, p1: Union["board_position.Position",tuple], p2: Union["board_position.Position",tuple]) -> "Vector":
"""Create a vector from token and position

The vector desribes is generated from:
token2.center - position
"""
p1 = board_position.Position.create(p1)
p2 = board_position.Position.create(p2)
x = p2.x - p1.x
y = p2.y - p1.y
return cls(x, y)

[docs]    @classmethod
def from_token_and_position(cls, t1: "token_mod.Token", pos) -> "Vector":
"""Create a vector from token and position

The vector desribes is generated from:
token2.center - position
"""
x = pos[0] - t1.center.x
y = pos[1] - t1.center.y
return cls(x, y)

[docs]    @classmethod
def from_tokens(cls, t1: "token_mod.Token", t2: "token_mod.Token") -> "Vector":
"""Create a vector from two tokens.

The vector desribes is generated from:
token2.center - token1.center
"""
x = t2.center.x - t1.center.x
y = t2.center.y - t1.center.y
return cls(x, y)

[docs]    @classmethod
def from_direction(cls, direction: Union[str, int, float, str, "board_direction.Direction"]) -> "Vector":
"""Creates a vector from miniworldmaker direction."""
if direction >= 90:
x = 0 + math.sin(math.radians(direction)) * 1
y = 0 - math.cos(math.radians(direction)) * 1
else:
x = 0 + math.sin(math.radians(direction)) * 1
y = 0 - math.cos(math.radians(direction)) * 1
return cls(x, y)

[docs]    @classmethod
def from_token_direction(cls, token: "token_mod.Token") -> "Vector":
"""Creates a vector from token direction

Examples:

Creates rotating rectangle

.. code-block:: python

from miniworldmaker import *

board = Board()

player = Rectangle((200,200),40, 40)
player.speed = 1
player.direction = 80

@player.register
def act(self):
v1 = Vector.from_token_direction(self)
v1.rotate(-1)
self.direction = v1

board.run()

.. raw:: html

<video loop autoplay muted width="400">
<source src="../_static/mp4/rotating_rectangle.mp4" type="video/mp4">
<source src="../_static/rotating_rectangle.webm" type="video/webm">
Your browser does not support the video tag.
</video>
"""
return Vector.from_direction(token.direction)

[docs]    @classmethod
def from_token_position(cls, token: "token_mod.Token") -> "Vector":
"""Creates a vector from token position"""
x = token.center.x
y = token.center.y
return cls(x, y)

[docs]    def rotate(self, theta: float) -> "Vector":
"""rotates Vector by theta degrees"""
theta_deg = theta % 360
rot = np.array([[math.cos(theta), -math.sin(theta)], [math.sin(theta), math.cos(theta)]])
self.vec = np.dot(rot, self.vec)
return self

[docs]    def to_direction(self) -> float:
"""Returns miniworldmaker direction from vector."""
if self.x > 0:
axis = np.array([0, -1])
else:
axis = np.array([0, 1])
unit_vector_1 = self.vec / np.linalg.norm(self.vec)
unit_vector_2 = axis / np.linalg.norm(axis)
dot_product = np.dot(unit_vector_1, unit_vector_2)
angle = np.arccos(dot_product)
if self.x > 0:
return angle
else:
return angle + 180

[docs]    def get_normal(self):
self.vec = np.array([- self.vec[1], self.vec[0]])
return self

[docs]    def normalize(self) -> "Vector":
"""sets length of vector to 1

Examples:

Normalized vector with length 1:

.. code-block:: python

w = Vector(4, 3)
print(w.length())     # 5
print(w.normalize()) #  (0.8, 0.6)
"""
norm = np.linalg.norm(self.vec)
if norm == 0:
self.vec = (0, 0)
return self
self.vec = self.vec / norm
return self

[docs]    def length(self) -> float:
"""returns length of vector

Examples:

Length of vector

.. code-block:: python

w = Vector(4, 3)
print(w.length())     # 5

"""
return np.linalg.norm(self.vec)

[docs]    def neg(self) -> "Vector":
"""returns -v for Vector v

Examples:

Inverse of vector:

.. code-block:: python

u = Vector(2, 4)
print(u.neg()) # (-2, 5)

Alternative:

.. code-block:: python

print(- u)  # (-2, 5)

"""
x = -self.x
y = -self.y
self.x, self.y = x, y
return self

[docs]    def multiply(self, other: Union[float, "Vector"]) -> Union[float, "Vector"]:
"""product self * other:
* returns product, if ``other`` is scalar (return-type: Vector)
* returns dot-product, if ``other`` is vector (return-type: float)
Args:
other : a scalar or vector

Examples:

Product and dot-product:

.. code-block:: python

a = 5
u1 = Vector(2, 4)
u2 = Vector(2, 4)
v = Vector(3, 1)
print(u1.multiply(a)) # (10, 25)
print(u2.multiply(v)) # 11

Alternative:

.. code-block:: python

print(u1 * a)  # 25
print(u1 * v) # 25
"""
if type(other) in [int, float]:
x = self.x * other
y = self.y * other
self.x, self.y = x, y
return Vector(x, y)
if type(other) == Vector:
dot_product = self.dot(other)
return dot_product

[docs]    def dot(self, other: "Vector") -> "Vector":
self.vec = np.dot(self.vec, other.vec)
return self

[docs]    def add_to_position(self, position: "board_position.Position") -> "board_position.Position":
position = board_position.Position.create(position)
return board_position.Position.create((self.x + position.x, self.y + position.y))

def __str__(self):
return f"({round(self.x, 3)},{round(self.y, 3)})"

def __neg__(self):
return self.neg()

def __mul__(self, other: Union[int, float, "Vector"]) -> "Vector":
if type(other) in [int, float]:
x = self.x * other
y = self.y * other
return Vector(x, y)
if type(other) == Vector:
dot_product = self.dot(other)
self.vec = dot_product
return self

def __add__(self, other: "Vector") -> "Vector":
if type(other) == Vector:
x = self.x + other.x
y = self.y + other.y
return Vector(x, y)

def __sub__(self, other: "Vector") -> "Vector":
if type(other) == Vector:
x = self.x - other.x
y = self.y - other.y
return Vector(x, y)

[docs]    def sub(self, other: "Vector") -> "Vector":

Args:
other (Vector): other Vector

Returns:
`self` + `other`

Examples:

Subtracts two vectors:

.. code-block:: python

v = Vector(3, 1)
u = Vector(2, 5)
print(u.sub(v)) # (1, -4)

Alternative:

.. code-block:: python

print(u - v)
"""
if type(other) == Vector:
x = self.x - other.x
y = self.y - other.y
self.x, self.y = x, y
return self

[docs]    def add(self, other: "Vector") -> "Vector":

Args:
other (Vector): other Vector

Returns:
`self` + `other`

Examples:

.. code-block:: python

v = Vector(3, 1)
u = Vector(2, 5)

Alternative:

.. code-block:: python

print(u + v)
"""
if type(other) == Vector:
x = self.x + other.x
y = self.y + other.y
self.x, self.y = x, y
return self

[docs]    def limit(self, value: float) -> "Vector":
"""limits length of vector to value"""
if self.length() > value:
self.normalize().multiply(value)
return self
```