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.add(acceleration) 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 theta = np.deg2rad(theta_deg) 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) angle = np.rad2deg(angle) 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": """adds vector `other` from self. 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": """adds vector `other` to self. Args: other (Vector): other Vector Returns: `self` + `other` Examples: Add two vectors: .. code-block:: python v = Vector(3, 1) u = Vector(2, 5) print(u.add(v)) # (5, 6) 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