Source code for mrmath.vecmat3d

# -*- coding: utf-8 -*-
# pylint: disable=too-many-lines

r"""Klassen für dreidimensionale Vektoren und 3*3-Matrizen.

.. moduleauthor:: Michael Rippstein <info@comlab.ch>

Idea and parts of the source from [Montenbruck2004a]_.


For the classes `Vec3D` and `Mat3D` the following operation are definde.

===========  =========  =========  ========  ===================  ============================
Funktion     Arg_1 (a)  Arg_2 (b)  Wert (c)  Notation             Bedeutung
===========  =========  =========  ========  ===================  ============================
`-`          `Vec3D`               `Vec3D`   .. math:: c = -a     Unäres Minus
\            `Mat3D`               `Mat3D`   .. math:: C = -A
`-`          `Vec3D`    `Vec3D`    `Vec3D`   .. math:: c = a - b  Vektor-Subtraktion
\            `Mat3D`    `Mat3D`    `Mat3D`   .. math:: C = A - B  Matrix-Subtraktion
`+`          `Vec3D`    `Vec3D`    `Vec3D`   .. math:: c = a + b  Vektor-Addition
\            `Mat3D`    `Mat3D`    `Mat3D`   .. math:: C = A + B  Matrix-Addition
`*`          `int`      `Vec3D`    `Vec3D`   .. math:: c = ab     Skalar-Multiplikation
\            `float`    `Vec3D`    `Vec3D`   .. math:: c = ab
\            `Vec3D`    `int`      `Vec3D`   .. math:: c = ab
\            `Vec3D`    `float`    `Vec3D`   .. math:: c = ab
\            `int`      `Mat3D`    `Mat3D`   .. math:: C = aB
\            `float`    `Mat3D`    `Mat3D`   .. math:: C = aB
\            `Mat3D`    `int`      `Mat3D`   .. math:: C = Ab
\            `Mat3D`    `float`    `Mat3D`   .. math:: C = Ab
`*`          `Mat3D`    `Vec3D`    `Vec3D`   .. math:: c = Ab     Matrix/Vektor-Multiplikation
`/`          `Vec3D`    `int`      `Vec3D`   .. math:: c = a/b    Skalar-Division
\            `Vec3D`    `float`    `Vec3D`   .. math:: c = a/b
\            `Mat3D`    `int`      `Mat3D`   .. math:: C = A/b
\            `Mat3D`    `float`    `Mat3D`   .. math:: C = A/b
`abs`        `Vec3D`               `float`   .. math:: c = |a|
`dot`        `Vec3D`    `Vec3D`    `float`   .. math:: c = ab     Skalarprodukt
`cross` `@`  `Vec3D`    `Vec3D`    `Vec3D`   .. math:: c = a × b  Vektorprodukt, Kreuzprodukt
`tranp`      `Mat3D`               `Mat3D`   .. math:: C = A^T    Transponierte
`einmat`                           `Mat3D`                        Einheitsmatrix
`rotmatx`    `float`               `Mat3D`                        Elementare Drehmatrix
`rotmaty`    `float`               `Mat3D`
`rotmatz`    `float`               `Mat3D`
`==`         `Vec3D`    `Vec3D`    `bool`
===========  =========  =========  ========  ===================  ============================

Bedeutung der Winkel bei den Kugelkoordinaten
---------------------------------------------
.. todo:: Korekte winkel bezeichungen im den bilder!

.. image:: _static/sphere.png
   :scale: 50 %

References
----------
.. [Montenbruck2004a] Montenbruck, Oliver; Pfleger, Thomas:
                      "Astronomie mit dem Personal
                      Computer"; 4. Auflage; Springer-Verlag; Berlin,
                      Heidelberg 2004
"""

import math
from typing import List, Optional, Tuple, Union

import numpy as np

__all__ = ['Vec3D', 'Mat3D', 'cross', 'dot', 'transp', 'einmat', 'rotmatx', 'rotmaty', 'rotmatz', 'polar2kart']

_TYPEERRORTEXT = "unsupported operand type(s) for '{}': '{}' and '{}'"


[docs]class Vec3D: r"""Dreidimensionaler Vector. Der Aufruf ohne die angabe von Parameter initialisiert einen Null-Vector. .. code-block:: python null_vector = Vec3D() Parameters ---------- \**kwargs siehe unten arg siehe unten .. code-block:: python Vec3D([x, y, z]) Vec3D((x, y, z)) Keyword Arguments ----------------- phi, theta, r Polarkoordinaten .. code-block:: python Vec3D(theta=, phi=, r=) az, elev Polarkoordinaten .. code-block:: python Vec3D(az=, elev=) az, elev, r : float Polarkoordinaten .. code-block:: python Vec3D(az=, elev=, r=) Raises ------ TypeError Examples -------- .. testsetup:: vec import math from mrmath.vecmat3d import Vec3D .. doctest:: vec >>> nullvector = Vec3D() >>> print(nullvector) Vec3D([0, 0, 0]) >>> print(nullvector.xyz) [0, 0, 0] >>> repr(nullvector.array) 'array([[0],\n [0],\n [0]])' >>> print("x: {}, y: {}, z: {}".format(nullvector.x, nullvector.y, nullvector.z)) x: 0, y: 0, z: 0 >>> print("phi: {}, theta: {}, r: {}".format(nullvector.phi, ... nullvector.theta, ... nullvector.r)) phi: 0, theta: 0, r: 0 >>> print(Vec3D([1, 2, 3])) Vec3D([1, 2, 3]) >>> print(Vec3D([1.0, 2.0, 3.0])) Vec3D([1.0, 2.0, 3.0]) >>> vector = Vec3D() >>> vector.x = 9.9 >>> vector.y = 5 >>> vector.z = 1.1 >>> print(vector) Vec3D([9.9, 5, 1.1]) >>> polar = Vec3D(theta=math.pi/2, phi=math.pi/2, r=1) >>> '{:.3f}, {:.3f}, {:.3f}'.format(polar.x, polar.y, polar.z) '0.000, 0.000, 1.000' >>> vector.x = 'text' Traceback (most recent call last): ... TypeError: unsupported type for setter: '<class 'str'>' """ # pylint: disable=too-many-instance-attributes def __init__( # pylint: disable=too-many-branches self, arg: Union[None, Tuple, List] = None, **kwargs: Optional[float] ) -> None: self.__x = 0.0 self.__y = 0.0 self.__z = 0.0 #: Komponenten des Vektors self.__phi: float #: Polarwinkel (Azimut) self.__theta: float #: Polarwinkel (Elevation) self.__r: float #: Betrag des Vektors self.__polarvalid = False #: zeigt, ob Polarkomponenten gueltig sind if (arg is None) and not kwargs: # initialisierung: null vector self.__x = 0 self.__y = 0 self.__z = 0 #: Komponenten des Vektors self.__phi = 0 #: Polarwinkel (Azimut) self.__theta = 0 #: Polarwinkel (Elevation) self.__r = 0 #: Betrag des Vektors self.__polarvalid = True #: zeigt, ob Polarkomponenten gueltig sind elif isinstance(arg, (list, tuple)) and len(arg) == 3: self.x = arg[0] self.y = arg[1] self.z = arg[2] elif (arg is None) and 'phi' in kwargs and 'theta' in kwargs and 'r' in kwargs: if ( isinstance(kwargs['phi'], (int, float)) and isinstance(kwargs['theta'], (int, float)) and isinstance(kwargs['r'], (int, float)) ): self.__phi = kwargs['phi'] self.__theta = kwargs['theta'] self.__r = kwargs['r'] self.__polarvalid = True self.x = self.__r * math.cos(self.__phi) * math.cos(self.__theta) self.y = self.__r * math.sin(self.__phi) * math.cos(self.__theta) self.z = self.__r * math.sin(self.__theta) else: raise TypeError elif (arg is None) and 'az' in kwargs and 'elev' in kwargs: if isinstance(kwargs['az'], (int, float)) and isinstance(kwargs['elev'], (int, float)): self.__phi = kwargs['az'] self.__theta = kwargs['elev'] if 'r' in kwargs: if isinstance(kwargs['r'], (int, float)): self.__r = kwargs['r'] else: raise TypeError else: self.__r = 1.0 self.__polarvalid = True self.x = self.__r * math.cos(self.__phi) * math.cos(self.__theta) self.y = self.__r * math.sin(self.__phi) * math.cos(self.__theta) self.z = self.__r * math.sin(self.__theta) else: raise TypeError else: raise TypeError @property def xyz(self) -> List[float]: """Gibt die kartesischen Koordinaten zurück. Returns ------- List[float] Kartesischekoordinaten ``[x, y, z]`` """ return [self.__x, self.__y, self.__z] @property def polar(self) -> List[float]: """Gibt die polar Koordinaten zurück. Returns ------- List[float] Polarkoordinaten: ``[phi, theta, r]`` """ return [self.phi, self.theta, self.r] @property def array(self) -> np.ndarray: """Gibt die kartesischen Koordinaten als Spaltenvector in einem `numpy.array` zurück. Returns ------- numpy.ndarray Spaltenvektor ``[[x][y][z]]`` """ return np.array([[self.__x], [self.__y], [self.__z]]) @property def x(self) -> float: """x-axis in the cartesian coordinate system. Returns ------- float x-axis """ return self.__x @x.setter def x(self, value: float) -> None: if isinstance(value, (int, float)): self.__x = value self.__polarvalid = False else: raise TypeError("unsupported type for setter: '{}'".format(type(value))) @property def y(self) -> float: """y-axis in the cartesian coordinate system.""" return self.__y @y.setter def y(self, value: float) -> None: if isinstance(value, (int, float)): self.__y = value self.__polarvalid = False else: raise TypeError("unsupported type for setter: '{}'".format(type(value))) @property def z(self) -> float: """z-axis in the cartesian coordinate system.""" return self.__z @z.setter def z(self, value: float) -> None: if isinstance(value, (int, float)): self.__z = value self.__polarvalid = False else: raise TypeError("unsupported type for setter: '{}'".format(type(value))) @property def phi(self) -> float: """Azimut in den Polarkoordinaten.""" if not self.__polarvalid: self._calcpolar() return self.__phi @property def theta(self) -> float: """Elevation in den Polarkoordinaten.""" if not self.__polarvalid: self._calcpolar() return self.__theta @property def r(self) -> float: """Radius in den Polarkoordinaten.""" if not self.__polarvalid: self._calcpolar() return self.__r
[docs] def __abs__(self) -> float: """Betrag (Radius). Returns ------- float Betrag des Vektors Examples -------- .. testsetup:: vecabs from mrmath.vecmat3d import Vec3D .. doctest:: vecabs >>> vector = Vec3D([1, 0, 0]) >>> print('{:.4f}'.format(abs(vector))) 1.0000 >>> vector = Vec3D([1, 1, 0]) >>> print('{:.4f}'.format(abs(vector))) 1.4142 >>> vector = Vec3D([1, 0, 1]) >>> print('{:.4f}'.format(abs(vector))) 1.4142 """ return self.r
[docs] def __getitem__(self, key: int) -> float: """Implement the ``self[key]`` call. Returns ------- float for key = 0: x for key = 1: y for key = 2: z Raises ------ IndexError When key outside of 0…2 Examples -------- .. testsetup:: vecitem from mrmath.vecmat3d import Vec3D .. doctest:: vecitem >>> vector = Vec3D([3, 7, 13]) >>> print(vector[0]) 3 >>> print(vector[1]) 7 >>> print(vector[2]) 13 >>> print(vector[3]) Traceback (most recent call last): ... IndexError: list index out of range >>> for m in vector: ... print(m) 3 7 13 """ if key == 0: return self.x if key == 1: return self.y if key == 2: return self.z raise IndexError('list index out of range')
[docs] def __setitem__(self, key: int, value: float) -> None: """Implement the assignment to ``self[key]``. Parameters ---------- key Schlüssel value Wert Raises ------ IndexError: When key outside of 0…2 Examples -------- .. testsetup:: vecitem from mrmath.vecmat3d import Vec3D .. doctest:: vecitem >>> vector = Vec3D() >>> vector[0] = 3 >>> vector[1] = 7 >>> vector[2] = 13 >>> print(vector) Vec3D([3, 7, 13]) >>> vector[3] = 17 Traceback (most recent call last): ... IndexError: list index out of range >>> for m in vector: ... print(m) 3 7 13 """ if key == 0: self.x = value elif key == 1: self.y = value elif key == 2: self.z = value else: raise IndexError('list index out of range')
[docs] def _calcpolar(self) -> None: """Berechne polare Komponenten. Berechnet die polaren Komponenten des Vektors mit den aktuellen kartesischen Daten. Setzt `__polarvalid` auf `True`. Examples -------- .. testsetup:: veccalpol from mrmath.vecmat3d import Vec3D .. doctest:: veccalpol >>> vector1 = Vec3D([1, 0, 0]) >>> print("phi: {}, theta: {}, r: {}".format(vector1.phi, ... vector1.theta, ... vector1.r)) phi: 0.0, theta: 0.0, r: 1.0 >>> vector2 = Vec3D([0, 1, 0]) >>> print("phi: {:.4f}, theta: {}, r: {}".format(vector2.phi, ... vector2.theta, ... vector2.r)) phi: 1.5708, theta: 0.0, r: 1.0 >>> vector3 = Vec3D([0, 0, 1]) >>> print("phi: {}, theta: {:.4f}, r: {}".format(vector3.phi, ... vector3.theta, ... vector3.r)) phi: 0.0, theta: 1.5708, r: 1.0 >>> vector4 = Vec3D([-1, -1, -1]) >>> print("phi: {:.4f}, theta: {:.4f}, r: {:.4f}".format(vector4.phi, ... vector4.theta, ... vector4.r)) phi: 3.9270, theta: -0.6155, r: 1.7321 """ # Laenge der Projektion des Vektors in die x-y-Ebene rho_sqr = self.__x ** 2 + self.__y ** 2 # Betrag des Vektors self.__r = math.sqrt(rho_sqr + self.__z ** 2) # Azimut des Vektors if (self.__x == 0.0) and (self.__y == 0.0): self.__phi = 0.0 else: self.__phi = math.atan2(self.__y, self.__x) if self.__phi < 0.0: self.__phi += math.tau # Elevation des Vektors rho = math.sqrt(rho_sqr) if (self.__z == 0.0) and (rho == 0.0): self.__theta = 0.0 else: self.__theta = math.atan2(self.__z, rho) self.__polarvalid = True
[docs] def __repr__(self) -> str: """Reprentation des Vectors. Returns ------- str Reprepresantation """ return 'Vec3D([{}, {}, {}])'.format(self.x, self.y, self.z)
[docs] def __neg__(self) -> 'Vec3D': """Negation: `-self`. Returns ------- Vec3D inverted vector Examples -------- .. testsetup:: vecneg from mrmath.vecmat3d import Vec3D .. doctest:: vecneg >>> vector = Vec3D([1, 2, 3]) >>> print(-vector) Vec3D([-1, -2, -3]) >>> vector = Vec3D([-1, -2, -3]) >>> print(-vector) Vec3D([1, 2, 3]) """ return Vec3D([-self.__x, -self.__y, -self.__z])
[docs] def __add__(self, other: Union['Vec3D', float]) -> 'Vec3D': """Addition: ``self + other``. Parameters ---------- other Summand Returns ------- Vec3D Summe Examples -------- .. testsetup:: vecadd from mrmath.vecmat3d import Vec3D .. doctest:: vecadd >>> summand = Vec3D([2, 6, 20]) >>> summe = summand + -9 >>> print(summe) Vec3D([-7, -3, 11]) >>> summand1 = Vec3D([2, 6, 20]) >>> summand2 = Vec3D([-9.0, -9.0, -9.0]) >>> summe = summand1 + summand2 >>> print(summe) Vec3D([-7.0, -3.0, 11.0]) """ if isinstance(other, self.__class__): tempx = self.__x + other.x tempy = self.__y + other.y tempz = self.__z + other.z elif isinstance(other, (int, float)): tempx = self.__x + other tempy = self.__y + other tempz = self.__z + other else: return NotImplemented return Vec3D([tempx, tempy, tempz])
[docs] def __radd__(self, other: Union['Vec3D', float]) -> 'Vec3D': """Addition: ``other + self``. Parameters ---------- other Summand Returns ------- Vec3D Summe Examples -------- .. testsetup:: vecadd from mrmath.vecmat3d import Vec3D .. doctest:: vecadd >>> summand = Vec3D([2, 6, 20]) >>> summe = -9 + summand >>> print(summe) Vec3D([-7, -3, 11]) """ # if isinstance(other, self.__class__): # tempx = other.x + self.__x # tempy = other.y + self.__y # tempz = other.z + self.__z if isinstance(other, (int, float)): tempx = other + self.__x tempy = other + self.__y tempz = other + self.__z else: return NotImplemented return Vec3D([tempx, tempy, tempz])
[docs] def __iadd__(self, other: Union['Vec3D', float]) -> 'Vec3D': """Addition: ``self += other``. Parameters ---------- other Summand Returns ------- Vec3D Summe Examples -------- .. testsetup:: vecadd from mrmath.vecmat3d import Vec3D .. doctest:: vecadd >>> summe = Vec3D([2, 6, 20]) >>> summe += -9 >>> print(summe) Vec3D([-7, -3, 11]) >>> summe = Vec3D([2, 6, 20]) >>> summand = Vec3D([-9.0, -9.0, -9.0]) >>> summe += summand >>> print(summe) Vec3D([-7.0, -3.0, 11.0]) """ if isinstance(other, self.__class__): self.__x += other.x self.__y += other.y self.__z += other.z self.__polarvalid = False elif isinstance(other, (int, float)): self.__x += other self.__y += other self.__z += other self.__polarvalid = False else: return NotImplemented return self
[docs] def __sub__(self, other: Union['Vec3D', float]) -> 'Vec3D': """Subtraktion: `self - other`. Parameters ---------- other Subtrahend Returns ------- Vec3D Differenz Examples -------- .. testsetup:: vecsub from mrmath.vecmat3d import Vec3D .. doctest:: vecsub >>> minuend = Vec3D([4, 8, 16]) >>> subtrahend = Vec3D([3, 9, 27]) >>> differenz = minuend - 2 >>> print(differenz) Vec3D([2, 6, 14]) >>> differenz = minuend - subtrahend >>> print(differenz) Vec3D([1, -1, -11]) """ if isinstance(other, self.__class__): tempx = self.__x - other.x tempy = self.__y - other.y tempz = self.__z - other.z elif isinstance(other, (int, float)): tempx = self.__x - other tempy = self.__y - other tempz = self.__z - other else: return NotImplemented return Vec3D([tempx, tempy, tempz])
[docs] def __rsub__(self, other: Union['Vec3D', float]) -> 'Vec3D': """Subraktion: `other - self`. Parameters ---------- other Minuend Returns ------- Vec3D Differenz Examples -------- .. testsetup:: vecsub from mrmath.vecmat3d import Vec3D .. doctest:: vecsub >>> minuend = Vec3D([4, 8, 16]) >>> subtrahend = Vec3D([3, 9, 27]) >>> differenz = 2 - subtrahend >>> print(differenz) Vec3D([-1, -7, -25]) >>> differenz = minuend - subtrahend >>> print(differenz) Vec3D([1, -1, -11]) """ if isinstance(other, self.__class__): tempx = other.x - self.__x tempy = other.y - self.__y tempz = other.z - self.__z elif isinstance(other, (int, float)): tempx = other - self.__x tempy = other - self.__y tempz = other - self.__z else: return NotImplemented return Vec3D([tempx, tempy, tempz])
[docs] def __isub__(self, other: Union['Vec3D', float]) -> 'Vec3D': """Subtraktion: `self -= other`. Parameters ---------- other Subtrahend Returns ------- Vec3D Differenz Examples -------- .. testsetup:: vecsub from mrmath.vecmat3d import Vec3D .. doctest:: vecsub >>> differenz = Vec3D([4, 8, 16]) >>> differenz -= 2 >>> print(differenz) Vec3D([2, 6, 14]) """ if isinstance(other, self.__class__): self.__x -= other.x self.__y -= other.y self.__z -= other.z self.__polarvalid = False elif isinstance(other, (int, float)): self.__x -= other self.__y -= other self.__z -= other self.__polarvalid = False else: return NotImplemented return self
[docs] def __mul__(self, other: Union['Mat3D', float]) -> 'Vec3D': """Multiplikation `self * other`. Parameters ---------- other Multiplikatand Returns ------- Vec3D Produkt Examples -------- .. testsetup:: vecmul from mrmath.vecmat3d import Vec3D .. doctest:: vecmul >>> faktor1 = Vec3D((2,4,6)) >>> produkt = faktor1 * 3.75 >>> print(produkt) Vec3D([7.5, 15.0, 22.5]) >>> produkt = faktor1 * 'text' Traceback (most recent call last): ... TypeError: unsupported operand type(s) for '*': '<class '__main__.Vec3D'>' and '<class 'str'>' """ if isinstance(other, (int, float)): tempx = self.__x * other tempy = self.__y * other tempz = self.__z * other result = [tempx, tempy, tempz] elif isinstance(other, Mat3D): result = [0, 0, 0] for j in range(3): scalp = 0.0 for i in range(3): scalp += self[i] * other._mat[i][j] result[j] = scalp else: return NotImplemented return Vec3D(result)
[docs] def __rmul__(self, other: Union['Mat3D', float]) -> 'Vec3D': """Multiplikation `other * self`. Parameters ---------- other Multiplikator Returns ------- Vec3D Produkt Examples -------- .. testsetup:: vecmul from mrmath.vecmat3d import Vec3D .. doctest:: vecmul >>> faktor2 = Vec3D((2,4,6)) >>> produkt = 3.75 * faktor2 >>> print(produkt) Vec3D([7.5, 15.0, 22.5]) >>> produkt = faktor2 * 'text' Traceback (most recent call last): ... TypeError: ... """ if isinstance(other, (int, float)): tempx = other * self.__x tempy = other * self.__y tempz = other * self.__z result = [tempx, tempy, tempz] elif isinstance(other, Mat3D): result = [0, 0, 0] for i in range(3): scalp = 0.0 for j in range(3): scalp += other._mat[i][j] * self[j] result[i] = scalp else: return NotImplemented return Vec3D(result)
[docs] def __imul__(self, other: Union['Mat3D', float]) -> 'Vec3D': """Multiplikation: `self = self * other`. Parameters ---------- other Multiplikand Returns ------- Vex3D Produkt Examples -------- .. testsetup:: vecmul import math from mrmath.vecmat3d import Vec3D, rotmatx .. doctest:: vecmul >>> faktor1 = Vec3D((2, 4, 6)) >>> produkt = faktor1 * 3.75 >>> print(produkt) Vec3D([7.5, 15.0, 22.5]) >>> faktor1 = Vec3D((2, 4, 6)) >>> faktor2 = rotmatx(0.5 * math.pi) >>> produkt = faktor1 * faktor2 >>> print(produkt) Vec3D([2, -4, 6]) >>> produkt = faktor1 * 'text' Traceback (most recent call last): ... TypeError: unsupported operand type(s) for '*': '<class '__main__.Vec3D'>' and '<class 'str'>' """ if isinstance(other, (int, float)): self.__x *= other self.__y *= other self.__z *= other self.__polarvalid = False elif isinstance(other, Mat3D): result = [0.0, 0.0, 0.0] for j in range(3): scalp = 0.0 for i in range(3): scalp += other._mat[i][j] * self[i] result[j] = scalp self.__x *= result[0] self.__y *= result[1] self.__z *= result[2] self.__polarvalid = False else: return NotImplemented return self
[docs] def __truediv__(self, other: float) -> 'Vec3D': """Division `self / other`. Parameters ---------- other Divisor Returns ------- Vec3D Quotient Examples -------- .. testsetup:: vecdiv from mrmath.vecmat3d import Vec3D .. doctest:: vecdiv >>> dividend = Vec3D([1, 2, 3]) >>> quotient = dividend / 2 >>> print(quotient) Vec3D([0.5, 1.0, 1.5]) """ if isinstance(other, (int, float)): tempx = self.__x / other tempy = self.__y / other tempz = self.__z / other else: return NotImplemented return Vec3D([tempx, tempy, tempz])
[docs] def __itruediv__(self, other: Union[int, float]) -> 'Vec3D': """Division `self /= other`. Parameters ---------- other Divisor Returns ------- Vec3D Quotient Examples -------- .. testsetup:: vecdiv from mrmath.vecmat3d import Vec3D .. doctest:: vecdiv >>> quotient = Vec3D([1, 2, 3]) >>> quotient /= 2 >>> print(quotient) Vec3D([0.5, 1.0, 1.5]) >>> quotient /= 'string' Traceback (most recent call last): ... TypeError: unsupported operand type(s) for '/=': '<class '__main__.Vec3D'>' and '<class 'str'>' """ if isinstance(other, (int, float)): self.__x /= other self.__y /= other self.__z /= other self.__polarvalid = False else: return NotImplemented return self
[docs] def __eq__(self, other: object) -> bool: """Comparisons ``self == other``.""" if not isinstance(other, Vec3D): return NotImplemented return self.__x == other.x and self.__y == other.y and self.__z == other.z
[docs]class Mat3D: """3x3 Matrix.""" def __init__(self, args: List) -> None: # noqa: D107 self._mat = args # [[None, None, None], [None, None, None], [None, None, None]]
[docs] def __getitem__(self, key: int) -> float: """FIXME! briefly describe function.""" return self._mat[key]
# def __setitem__(self, key: int, value: Union[int, float]) -> None: # """FIXME! briefly describe function. # # :param key: # :type: int or (int, int) # :param value: # :type: int or float # # """ # pass
[docs] def __repr__(self) -> str: """FIXME! briefly describe function.""" return 'Mat3D([[{},{},{}],[{},{},{}],[{},{},{}]])'.format( # noqa: F524 self._mat[0][0], self._mat[1][0], self._mat[2][0], self._mat[0][1], self._mat[1][1], self._mat[2][1], self._mat[0][2], self._mat[1][2], self._mat[2][2], )
[docs] def __mul__(self, other: Union['Mat3D', int, float]) -> 'Mat3D': """Multiplikation: 'self * other'. Parameters ---------- other Multiplikator Returns ------- Mat3D Produkt """ if isinstance(other, Mat3D): res = Mat3D([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(3): for j in range(3): for k in range(3): res._mat[i][k] += self._mat[i][j] * other._mat[j][k] return res if isinstance(other, (int, float)): # res = Mat3D(self._mat * other) return NotImplemented return NotImplemented
# def __rmul__(self, other): # """Multiplikation: 'other * self'. # # :param other: Multiplikator # :type other: int, float or Mat3D # :returns: Produkt # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = Mat3D(other._mat * self._mat) # elif isinstance(other, (int, float)): # res = Mat3D(other * self._mat) # else: # return NotImplemented # return res # # def __imul__(self, other): # """Multiplikation: 'self *= other'. # # :param other: Multiplikator # :type other: int, float or Mat3D # :returns: Produkt # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # self.__mat = self.__mat * other._mat # elif isinstance(other, (int, float)): # self.__mat = self.__mat * other # else: # return NotImplemented # return self # # def __truediv__(self, other): # """Division: 'self / other'. # # :param other: Divisor # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = Mat3D(self._mat / other._mat) # elif isinstance(other, (int, float)): # res = Mat3D(self._mat / other) # else: # return NotImplemented # return res # # def __rtruediv__(self, other): # """Division: 'other / self'. # # :param other: Dividend # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = Mat3D(other._mat / self._mat) # elif isinstance(other, (int, float)): # res = Mat3D(other / self._mat) # else: # return NotImplemented # return res # # def __itruediv__(self, other): # """Division: 'self /= other'. # # :param other: Divisor # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # self.__mat = self.__mat / other._mat # elif isinstance(other, (int, float)): # self.__mat = self._mat / other # else: # return NotImplemented # return self # # def __floordiv__(self, other): # """Ganzzahlige Division: 'self // other'. # # :param other: Divisor # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = Mat3D(self._mat // other._mat) # elif isinstance(other, (int, float)): # res = Mat3D(self._mat // other) # else: # return NotImplemented # return res # # def __rfloordiv__(self, other): # """Ganzzahlige Division: 'other // self'. # # :param other: Dividend # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = Mat3D(other._mat // self._mat) # elif isinstance(other, (int, float)): # res = Mat3D(other // self._mat) # else: # return NotImplemented # return res # # def __ifloordiv__(self, other): # """Ganzzahlige Division: 'self //= other'. # # :param other: Divisor # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # self.__mat = self.__mat // other._mat # elif isinstance(other, (int, float)): # self.__mat = self._mat // other # else: # return NotImplemented # return self # # def __mod__(self, other): # """Division mit Rest: 'self % other'. # # :param other: Divisor # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = Mat3D(self._mat % other._mat) # elif isinstance(other, (int, float)): # res = Mat3D(self._mat % other) # else: # return NotImplemented # return res # # def __rmod__(self, other): # """Division mit Rest: 'other % self'. # # :param other: Dividend # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = Mat3D(other._mat % self._mat) # elif isinstance(other, (int, float)): # res = Mat3D(other % self._mat) # else: # return NotImplemented # return res # # def __imod__(self, other): # """Division mit Rest: 'self %= other'. # # :param other: Divisor # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # self.__mat = self.__mat % other._mat # elif isinstance(other, (int, float)): # self.__mat = self._mat % other # else: # return NotImplemented # return self # # def __divmod__(self, other): # """Ganzzahlige Division mit Rest: 'divmod(self, other)'. # # :param other: Divisor # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = divmod(self._mat % other._mat) # elif isinstance(other, (int, float)): # res = divmod(self._mat % other) # else: # return NotImplemented # return res # # def __rdivmod__(self, other): # """Ganzzahlige Division mit Rest: 'divmod(other, self)'. # # :param other: Dividend # :type other: int, float or Mat3D # :returns: Quotient # :rtype: Mat3D # """ # if isinstance(other, Mat3D): # res = divmod(other._mat % self._mat) # elif isinstance(other, (int, float)): # res = divmod(other % self._mat) # else: # return NotImplemented # return res # -- funktionen
[docs]def cross(left: Vec3D, right: Vec3D) -> Vec3D: """Vektorprodukt (Kreuzprodukt). Parameters ---------- left Linker Vektor right Rechter Vektor Returns ------- Vec3D Kreuzprodukt Raises ------ TypeError If `left` or `right` is not from type :class:`Vec3D` """ if isinstance(left, Vec3D) and isinstance(right, Vec3D): cross_x = left.y * right.z - left.z * right.y cross_y = left.z * right.x - left.x * right.z cross_z = left.x * right.y - left.y * right.x return Vec3D((cross_x, cross_y, cross_z)) raise TypeError(_TYPEERRORTEXT.format('cross', type(left), type(right)))
[docs]def dot(left: Vec3D, right: Vec3D) -> float: """Skalarprodukt zweier Vektoren. Parameters ---------- left Linker Vektor right Rechter Vektor Returns ------- float Skalarprodukt Raises ------ TypeError If `left` or `right` is not from type :class:`Vec3D` """ if isinstance(left, Vec3D) and isinstance(right, Vec3D): return left.x * right.x + left.y * right.y + left.z * left.z raise TypeError(_TYPEERRORTEXT.format('dot', type(left), type(right)))
[docs]def transp(matrix: Mat3D) -> Mat3D: """Transponierte einer Matrix. Parameters ---------- matrix Originalmatrix Returns ------- Mat3D Transponierte Matrix """ return Mat3D( [ [ # pylint: disable=protected-access # noqa: E501 matrix._mat[0][0], matrix._mat[1][0], matrix._mat[2][0], ], [ # pylint: disable=protected-access # noqa: E501 matrix._mat[0][1], matrix._mat[1][1], matrix._mat[2][1], ], [ # pylint: disable=protected-access # noqa: E501 matrix._mat[0][2], matrix._mat[1][2], matrix._mat[2][2], ], ] )
[docs]def einmat() -> Mat3D: """Einheitsmatrix. Returns ------- Mat3D Einheitsmatrix """ return Mat3D([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
[docs]def rotmatx(alpha: float) -> Mat3D: """Matrix für die rotation um die x-achse. .. image:: _static/rotmatx.png :scale: 20 % Parameters ---------- alpha Drehwinkel Returns ------- Mat3D Rotationsmatrix Examples -------- .. testsetup:: rotmatx import math from mrmath.vecmat3d import rotmatx, Vec3D .. doctest:: rotmatx >>> a = rotmatx(0.25 * math.pi) >>> a._mat [[1, 0, 0], [0, 0.7071067811865476, 0.7071067811865475], [0, -0.7071067811865475, 0.7071067811865476]] >>> a = rotmatx(0.5 * math.pi) >>> b = Vec3D((0.0, 1.0, 0.0)) >>> a * b Vec3D([0.0, 6.123233995736766e-17, -1.0]) """ return Mat3D([[1, 0, 0], [0, math.cos(alpha), math.sin(alpha)], [0, -math.sin(alpha), math.cos(alpha)]])
[docs]def rotmaty(alpha: float) -> Mat3D: """Matrix für die rotation um die y-achse. .. image:: _static/rotmaty.png :scale: 20 % Parameters ---------- alpha Drehwinkel Returns ------- Mat3D Rotationsmatrix """ return Mat3D([[math.cos(alpha), 0, -math.sin(alpha)], [0, 1, 0], [math.sin(alpha), 0, math.cos(alpha)]])
[docs]def rotmatz(alpha: float) -> Mat3D: """Matrix für die Rotation um die Z-Achse. .. image:: _static/rotmatz.png :scale: 20 % Parameters ---------- alpha Drehwinkel Returns ------- Mat3D Rotationsmatrix """ return Mat3D([[math.cos(alpha), math.sin(alpha), 0], [-math.sin(alpha), math.cos(alpha), 0], [0, 0, 1]])
[docs]def polar2kart(phi: float, theta: float, r: float) -> Tuple[float, float, float]: """Polarkoordinaten zu Kartesischenkoordinaten. .. image:: _static/sphere.png :scale: 50 % Parameters ---------- phi winkel zwischen z-achse und vektor theta winkel zwischen x-achse und vektor r länge des vector Returns ------- (x, y, z) kart.-koord. """ x = r * math.cos(phi) * math.cos(theta) y = r * math.sin(phi) * math.cos(theta) z = r * math.sin(theta) return x, y, z