"""
Defines a point in N-dimension
:githublink:`%|py|5`
"""
import math
[docs]class GeometryException(Exception):
"""
raises when an issue arises with class GeometryPoint
:githublink:`%|py|12`
"""
pass
[docs]class GeometryPoint:
"""
one point
:githublink:`%|py|19`
"""
__slots__ = ["_x"]
[docs] def __init__(self, *x):
"""
:param x: is a vector
:githublink:`%|py|25`
"""
if isinstance(x, (tuple, list)):
if len(x) == 0:
raise ValueError("empty dimension")
if isinstance(x[0], GeometryPoint) and len(x) == 1:
self._x = x[0]._x
else:
self._x = tuple(x)
else:
raise TypeError("Unexpected type %r." % type(x))
[docs] def __eq__(self, x):
"""
is equal
:githublink:`%|py|39`
"""
return self._x == x
[docs] def __neq__(self, x):
"""
is different
:githublink:`%|py|45`
"""
return not self.__eq__(x)
[docs] def __len__(self):
"""
returns the dimension
:githublink:`%|py|51`
"""
return len(self._x)
[docs] def __str__(self):
"""
converts into string
:githublink:`%|py|57`
"""
if len(self) == 2:
s = "({0},{1})".format(*self._x)
return s.replace(".000000", "")
format = ", ".join(["{}" for _ in self._x])
t = format.format(*self._x)
s = "(%s)" % t
return s.replace(".000000", "")
[docs] def __repr__(self):
"""
``eval(__repr__)`` should return the same object
:githublink:`%|py|70`
"""
return "GeometryPoint(%s)" % ", ".join(str(_) for _ in self._x)
[docs] def __iadd__(self, x):
"""
addition
:githublink:`%|py|76`
"""
if len(self) != len(x):
raise GeometryException("dimension problem %d != %d" %
(len(self), len(x)))
if len(self) == 2:
self._x = (self._x[0] + x._x[0], self._x[1] + x._x[1])
else:
self._x = tuple(a + b for a, b in zip(self._x, x._x))
return self
[docs] def __add__(self, x):
"""
addition
:githublink:`%|py|89`
"""
if len(self) != len(x):
raise GeometryException("dimension problem %d != %d" %
(len(self), len(x)))
if len(self) == 2:
return GeometryPoint(self._x[0] + x._x[0], self._x[1] + x._x[1])
else:
return GeometryPoint(a + b for a, b in zip(self._x, x._x))
[docs] def __sub__(self, x):
"""
substraction
:githublink:`%|py|101`
"""
if len(self) != len(x):
raise GeometryException("dimension problem %d != %d" %
(len(self), len(x)))
if len(self) == 2:
return GeometryPoint(self._x[0] - x._x[0], self._x[1] - x._x[1])
return GeometryPoint(a - b for a, b in zip(self._x, x._x))
[docs] def __imul__(self, k):
"""
multiplication by a scalar
:githublink:`%|py|112`
"""
if len(self) == 2:
self._x = (self._x[0] * k, self._x[1] * k)
else:
self._x = tuple(_ * k for _ in self._x)
return self
[docs] def __mul__(self, k):
"""
multiplication by a scalar
:githublink:`%|py|122`
"""
if len(self) == 2:
return GeometryPoint(self._x[0] * k, self._x[1] * k)
else:
return GeometryPoint(_ * k for _ in self._x)
[docs] def scalar(self, x):
"""
scalar product
:githublink:`%|py|131`
"""
if len(self) != len(x):
raise GeometryException("dimension problem %d != %d\n%s ? %s" % (len(self), len(x),
str(self), str(x)))
r = 0.
for a, b in zip(self._x, x._x):
r += a * b
return r
[docs] def __cmp__(self, x):
"""
comparison
:githublink:`%|py|143`
"""
if len(self) != len(x):
raise GeometryException("dimension problem %d != %d" %
(len(self), len(x)))
for a, b in zip(self._x, x._x):
t = -1 if a < b else (0 if a == b else 1)
if t != 0:
return t
return 0
[docs] def __lt__(self, x):
"""
inferior
:githublink:`%|py|156`
"""
return self.__cmp__(x) == -1
[docs] def product(self, x):
"""
vectoriel product, dimension 2 only
:githublink:`%|py|162`
"""
if len(self) != 2:
raise GeometryException(
"this function only exists if len(self) == 2")
return self._x[1] * x._x[0] - self._x[0] * x._x[1]
[docs] def cossin(self):
"""
return the cos, sin of a vector (dimension 2 only)
:githublink:`%|py|172`
"""
n = self.norm2()
if n == 0.:
return 1., 0.
n = n ** 0.5
p = GeometryPoint(1., 0.)
cos = self.scalar(p) / n
sin = self.product(p) / n
return cos, sin
[docs] def norm2(self):
"""
return the norm
:githublink:`%|py|185`
"""
return self.scalar(self)
[docs] def angle(self):
"""
return the angle
:githublink:`%|py|191`
"""
cos, sin = self.cossin()
if cos == 0:
if sin == 0:
return 0
elif sin > 0:
return math.pi / 2
else:
return -math.pi / 2
else:
t = sin / cos
a = math.atan(t)
if cos < 0:
return a - math.pi
else:
return a