Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

ss20:neg_datatypes

← Back to project page

Sourcecode

Download the release version here:
neg-world-engine.zip

Or download the newest version from the Git repository:
https://gitlab.tubit.tu-berlin.de/srather/NEG-World-Engine.git

Folder Structure:

Datatypes


Vector

vector.py
import math
 
 
class Vector(tuple):
    """
    2d-Vector class for calculations. A 'Vector' object is a 2d-tuple
    with 'self[0]' and 'self[1]' accessable as 'self.x' and 'self.y'.
    There are also numerus methods to calculate with vectors.
    """
 
 
    def __new__(cls, x, y):
        """
        Return a new tuple '(x, y)' for parent of new 'Vector' object.
        """
 
        if type(x) in (int, float) and type(y) in (int, float):
            return tuple.__new__(cls, (x, y))
 
        try:
            return tuple.__new__(cls, (float(x), float(y)))
        except TypeError:
            raise TypeError(f"'x' and 'y' of vector have to be type 'int' or 'float'")
 
 
    def __getattr__(self, attr):
        """
        Return 'self[0]' and 'self[1]' as attribute 'x' and 'y'.
        """
 
        if attr == 'x':
            return self[0]
        if attr == 'y':
            return self[1]
 
        raise AttributeError(f"{self.__class__.__name__} has no Attribute {attr}.")
 
 
    def __copy__(self):
        """Return a copy of 'self'."""
        return Vector(*self)
 
    def __bool__(self):
        """Return 'True' if 'self' is nonzero."""
        return bool(round(self.x, 5)) or bool(round(self.y, 5))
 
 
    def __eq__(self, other):
        """
        Return 'True' if 'self' and 'other' are equal.
        """
 
        if type(other) is Vector:
            return round(self.x, 5) == round(other.x, 5) and round(self.y, 5) == round(other.y, 5)
        else:
            return False
 
 
    def __ne__(self, other):
        """Return 'True' if 'self' and 'other' are not equal."""
        return not self == other
 
 
    def __neg__(self):
        """Return the additive inverse of 'self'."""
        return Vector(-self.x, -self.y)
 
 
    def __invert__(self):
        """Swiches 'x' and 'y'."""
        return Vector(self.y, self.x)
 
 
    def __round__(self, d=None):
        """Return 'self' with both components rounded to 'd' decimal places."""
        return Vector(round(self.x, d), round(self.y, d))
 
 
    def __add__(self, other):
        """
        Return the sum of vectors 'self' and 'other'.
        """
 
        if type(other) is Vector:
            return Vector(self.x + other.x, self.y + other.y)
 
        if not bool(other): # for sum([vectors..]) to work
            return self
 
        return NotImplemented
 
 
    def __radd__(self, other):
        """Return the sum of vectors 'self' and 'other'."""
        return self + other
 
 
    def __sub__(self, other):
        """Return the difference of vectors 'self' and 'other'."""
        return self + (-other)
 
 
    def __mul__(self, other):
        """
        If other is a integer or float
        Return a scaled vector of 'self' by factor 'other'.
 
        If other is a vector:
        Multiplies both components individually.
        """
 
        if type(other) in (int, float):
            return Vector(self.x * other, self.y * other)
 
        if type(other) is Vector:
            return Vector(self.x * other.x, self.y * other.y)
 
        return NotImplemented
 
 
    def __rmul__(self, value):
        """Return a scaled vector of 'self' by factor 'value'."""
        return self * value
 
 
    def __truediv__(self, other):
        """
        If other is a integer or float:
        Return a scaled vector of 'self' by factor '1 / other'.
 
        If other is a vector:
        Return 'value' with 'other * value == self'.
        Return 'None' if both are linear independant.
        """
 
        if type(other) in (int, float):
            return self * (1 / other)
 
        if type(other) is Vector:
            value = 0
 
            if other.x != 0:
                value = self.x / other.x
            elif other.y != 0:
                value = self.y / other.y
 
            if round(other * value, 5) == round(self, 5):
                return value
 
            return None
 
        return NotImplemented
 
 
    def __str__(self):
        """Return a string representing 'self' in style of '"<x, y>"'."""
        return f"<{tuple.__repr__(self)[1:-1]}>"
 
 
    def __repr__(self):
        """Return a string representing 'self' in style of '"<x, y>"'."""
        return str(self)
 
 
    def length(self):
        """Return the euclidean length of vector 'self'."""
        return math.sqrt(self.x * self.x + self.y * self.y)
 
 
    def length2(self):
        """Return the inf-norm of vector 'self'."""
        return max(abs(self.x), abs(self.y))
 
 
    def multiple_of(self, other):
        """
        Return 'True', if vetors are linear depentant.
        """
 
        if type(other) is Vector:
            return round(self.x * other.y, 5) == round(self.y * other.x, 5) # determinant is zero
 
        raise TypeError(f"Expected a vector, but {other.__class__.__name__} found")
 
 
    def angle(self):
        """
        Return the angle of vector 'self' in radiants, starting at
        0 for positive x direction, incresing counterclockwise.
        """
 
        return math.atan2(self.y, self.x)
 
 
    def angle2(self):
        """
        Return the angle of vector 'self' in degree, starting at
        0 for positive x direction, incresing counterclockwise.
        """
 
        return math.atan2(self.y, self.x) / math.pi * 180
 
 
    def is_between(self, vec1, vec2):
        """
        Return 'True' if the angle of 'self' is between 2 other vectors.
        This starts at 'vec1' rotating counterclockwise, checking if the
        angle of 'self' is reched before the angle of 'vec2'.
        """
 
        if not self: # == 0
            return True
 
        if vec1 == self or vec2 == self:
            return True
 
        # vec1 <= self <= vec2
        if vec1.angle() <= self.angle() and self.angle() <= vec2.angle():
            return True
 
        # vec2 < vec1
        if vec2.angle() < vec1.angle():
            # !(vec2 < self < vec1)
            if self.angle() <= vec2.angle() or vec1.angle() <= self.angle():
                return True
 
        return False
 
 
    def dot(self, other):
        """Return the dot product of 'self' and 'other'."""
        return sum(self * other)
 
 
    def cross(self, other):
        """Return the cross product of 'self' and 'other'."""
        return self.x * other.y - self.y * other.x
 
 
    def normal(self):
        """Return a vector orthogonal to 'self'."""
        return Vector(-self.y, self.x)
 
 
    def normal2(self):
        """Return a vector orthogonal to 'self'."""
        return Vector(self.y, -self.x)
 
 
    def angle_to(self, other):
        """
        Return angle in degree from 'self' to 'other' counterclockwise.
        """
 
        if type(other) is Vector:
            if self.angle() <= other.angle():
                return other.angle2() - self.angle2()
            else:
                return other.angle2() + 360 - self.angle2()
 
        raise TypeError(f"Expected a vector, but {other.__class__.__name__} found")
 
 
    def normalised(self):
        """
        Return a vector of length '1' with the same angle as 'self'.
        """
 
        if self.length() == 0:
            return self
 
        return round(self / self.length(), 5)
 
 
    def onscreen(self, screen, offset):
        """
        Return 'True' if 'self' is within the rect 'screen' with given 'offset'.
        """
 
        rect = screen.get_rect()
        pos = round(self - offset + Vector(*rect[2:]) / 2)
 
        if pos.x < rect[0] or pos.y < rect[1] or pos.x >= rect[2] or pos.y >= rect[3]:
            return False
 
        return True

↑ Back to top


Matrix

matrix.py
from vector import *
 
 
class Matrix(tuple):
    """
    2d-Matrix class for calculations. A 'Matrix' object is a 2-element list
    of vectors with 'self[0]' and 'self[1]' accessable as 'self.i' and 'self.j'.
    There are also numerus methods to calculate with vectors.
    """
 
 
    def __new__(cls, i, j):
        """
        Return a new tuple '(i, j)' for parent of new 'Matrix' object.
        """
 
        try:
            return tuple.__new__(cls, (Vector(*i), Vector(*j)))
        except:
            raise TypeError(f"'i' and 'j' of matrix have to be type 'Vector'")
 
 
    def __getattr__(self, attr):
        """
        Return 'self[0]' and 'self[1]' as attribute 'i' and 'j'.
        """
 
        if attr == 'i':
            return self[0]
        if attr == 'j':
            return self[1]
 
        raise AttributeError(f"{self.__class__.__name__} has no Attribute {attr}.")
 
 
    def __copy__(self):
        """Return a copy of 'self'."""
        return Matrix(*self)
 
    def __bool__(self):
        """Return 'True' if 'self' is nonzero."""
        return bool(self.i) or bool(self.j)
 
 
    def __eq__(self, other):
        """
        Return 'True' if 'self' and 'other' are equal.
        """
 
        if type(other) is Matrix:
            return self.i == other.i and self.j == other.j
        else:
            return False
 
 
    def __ne__(self, other):
        """Return 'True' if 'self' and 'other' are not equal."""
        return not self == other
 
 
    def __neg__(self):
        """Return the additive inverse of 'self'."""
        return Matrix(-self.i, -self.j)
 
 
    def __invert__(self):
        """Swiches 'i' and 'j'."""
        return Matrix(self.j, self.i)
 
 
    def __round__(self, d=None):
        """Return 'self' with both components rounded to 'd' decimal places."""
        return Vector(round(self.i, d), round(self.j, d))
 
 
    def __add__(self, other):
        """
        Return the sum of matrices 'self' and 'other'.
        """
 
        if type(other) is Matrix:
            return Matrix(self.i + other.i, self.j + other.j)
 
        if type(other) in (int, float):
            return Matrix(self.i + Vector(other, 0), self.j + Vector(0, other))
 
        return NotImplemented
 
 
    def __radd__(self, other):
        """Return the sum of matrices 'self' and 'other'."""
        return self + other
 
 
    def __sub__(self, other):
        """Return the difference of matrices 'self' and 'other'."""
        return self + (-other)
 
 
    def __mul__(self, other):
        """
        If other is a integer or float
        Return a scaled matrix of 'self' by factor 'other'.
 
        If other is a matrix:
        Multiplies both components individually.
        """
 
        if type(other) in (int, float):
            return Matrix(self.i * other, self.j * other)
 
        if type(other) is Vector:
            return Matrix(self.i * other.i, self.j * other.j)
 
        return NotImplemented
 
 
    def __rmul__(self, value):
        """Return a scaled vector of 'self' by factor 'value'."""
        return self * value
 
 
    def __truediv__(self, other):
        """
        If other is a integer or float:
        Return a scaled vector of 'self' by factor '1 / other'.
 
        If other is a vector:
        Return 'value' with 'other * value == self'.
        Return 'None' if both are linear independant.
        """
 
        if type(other) in (int, float):
            return self * (1 / other)
 
        if type(other) is Vector:
            value = 0
 
            if other.x != 0:
                value = self.x / other.x
            elif other.y != 0:
                value = self.y / other.y
 
            if round(other * value, 5) == round(self, 5):
                return value
 
            return None
 
        return NotImplemented
 
 
    def __str__(self):
        """Return a string representing 'self' in style of '"<i, j>"'."""
        return f"<{tuple.__repr__(self)[1:-1]}>"
 
 
    def __repr__(self):
        """Return a string representing 'self' in style of '"<i, j>"'."""
        return str(self)
 
 
    def T(self):
        """Return the transposed matrix of 'self'."""
        return Matrix((self.i.x, self.j.x), (self.i.y, self.j.y))
 
 
    def det(self):
        """Return determinant of self."""
        return self.i.x * self.j.y - self.i.y * self.j.x
 
 
    def inverse(self):
        """Return the inverse of self."""
        return Matrix((-self.j.y, self.i.y), (self.j.x, -self.i.x)) / -self.det()
 
 
    def prod(self, other):
        """
        Return the matrix multiplication of 'self' and 'other'.
        """
 
        if type(other) is Vector:
            return Vector(self.T().i.dot(other), self.T().j.dot(other))
 
        if type(other) is Matrix:
            return Matrix(self.prod(other.i), self.prod(other.j))
 
        return NotImplemented

↑ Back to top

ss20/neg_datatypes.txt · Zuletzt geändert: 2020/09/11 14:20 von srather