import numbers
import operator
-from abc import ABC, abstractmethod
-from collections import OrderedDict
+from collections import OrderedDict, Mapping
+from .geometry import GeometricObject
from .linexprs import Symbol
]
-class Coordinates(ABC):
+class Coordinates:
__slots__ = (
'_coordinates',
)
- @abstractmethod
- def __new__(cls):
- super().__new__(cls)
+ def __new__(cls, coordinates):
+ if isinstance(coordinates, Mapping):
+ coordinates = coordinates.items()
+ self = object().__new__(cls)
+ self._coordinates = OrderedDict()
+ for symbol, coordinate in sorted(coordinates,
+ key=lambda item: item[0].sortkey()):
+ if not isinstance(symbol, Symbol):
+ raise TypeError('symbols must be Symbol instances')
+ if not isinstance(coordinate, numbers.Real):
+ raise TypeError('coordinates must be real numbers')
+ self._coordinates[symbol] = coordinate
+ return self
@property
def symbols(self):
yield symbol, func(coordinate1, coordinate2)
-class Point(Coordinates):
+class Point(Coordinates, GeometricObject):
"""
This class represents points in space.
"""
- def __new__(cls, coordinates=None):
- if isinstance(coordinates, dict):
- coordinates = coordinates.items()
- self = object().__new__(cls)
- self._coordinates = OrderedDict()
- for symbol, coordinate in sorted(coordinates,
- key=lambda item: item[0].sortkey()):
- if not isinstance(symbol, Symbol):
- raise TypeError('symbols must be Symbol instances')
- if not isinstance(coordinate, numbers.Real):
- raise TypeError('coordinates must be real numbers')
- self._coordinates[symbol] = coordinate
- return self
-
def isorigin(self):
return not bool(self)
return isinstance(other, Point) and \
self._coordinates == other._coordinates
+ def aspolyhedron(self):
+ from .polyhedra import Polyhedron
+ equalities = []
+ for symbol, coordinate in self.coordinates():
+ equalities.append(symbol - coordinate)
+ return Polyhedron(equalities)
+
class Vector(Coordinates):
"""
This class represents displacements in space.
"""
- __slots__ = (
- '_coordinates',
- )
-
def __new__(cls, initial, terminal=None):
- self = object().__new__(cls)
if not isinstance(initial, Point):
initial = Point(initial)
if terminal is None:
- self._coordinates = initial._coordinates
+ coordinates = initial._coordinates
elif not isinstance(terminal, Point):
terminal = Point(terminal)
- self._coordinates = terminal._map2(initial, operator.sub)
- return self
-
- @property
- def symbols(self):
- return tuple(self._coordinates)
-
- @property
- def dimension(self):
- return len(self.symbols)
-
- def coordinates(self):
- yield from self._coordinates.items()
-
- def coordinate(self, symbol):
- if not isinstance(symbol, Symbol):
- raise TypeError('symbol must be a Symbol instance')
- return self._coordinates[symbol]
-
- __getitem__ = coordinate
+ coordinates = terminal._map2(initial, operator.sub)
+ return super().__new__(cls, coordinates)
def isnull(self):
return not bool(self)
- def __bool__(self):
- return any(self._coordinates.values())
-
def __add__(self, other):
if isinstance(other, (Point, Vector)):
coordinates = self._map2(other, operator.add)
"""
if not isinstance(other, Vector):
raise TypeError('argument must be a Vector instance')
- cosinus = self.dot(other) / (self.norm() * other.norm())
+ cosinus = self.dot(other) / (self.norm()*other.norm())
return math.acos(cosinus)
def cross(self, other):
coordinates = self._map2(other, operator.sub)
return other.__class__(coordinates)
return NotImplemented
-
- def __repr__(self):
- string = ', '.join(['{!r}: {!r}'.format(symbol, coordinate)
- for symbol, coordinate in self.coordinates()])
- return '{}({{{}}})'.format(self.__class__.__name__, string)