[[nichteuklidische_geometrie|← Back to project page]]
====== Sourcecode ======
Download the release version here:\\
{{:ss20: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: ====
**[[neg_sourcecode|Root]]:** [[neg_sourcecode#readme|README]], [[neg_sourcecode#main|main]]
* **[[neg_datatypes|Datatypes]]:** [[neg_datatypes#vector|Vector]], [[neg_datatypes#matrix|Matrix]]
* **[[neg_drawables|Drawables]]:** [[neg_drawables#drawable|drawable]], [[neg_drawables#ray|Ray]], [[neg_drawables#polygon|Polygon]], [[neg_drawables#floor|Floor]], [[neg_drawables#portal|Portal]]
* **[[neg_utility|Utility]]:** [[neg_utility#colors|colors]], [[neg_utility#generate|generate]], [[neg_utility#draw|draw]]
===== Datatypes =====
----
==== Vector ====
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 '""'."""
return f"<{tuple.__repr__(self)[1:-1]}>"
def __repr__(self):
"""Return a string representing 'self' in style of '""'."""
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
[[#top|↑ Back to top]]
----
==== Matrix ====
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 '""'."""
return f"<{tuple.__repr__(self)[1:-1]}>"
def __repr__(self):
"""Return a string representing 'self' in style of '""'."""
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
[[#top|↑ Back to top]]