import math import numpy as np def homogenize(v): for k in reversed(v): if k!=0: return v/k return v ## Euclidean 2D plane point: (x,y). class EPoint: def __init__(self,x,y): self._x=x self._y=y @property def x(self): return self._x @property def y(self): return self._y @staticmethod def fromProjective(point): if point.item(2)==0: return None return EPoint(point.item(0)/point.item(2),point.item(1)/point.item(2)) @staticmethod def fromPolar(point,center): (alpha,length)=point x=math.cos(alpha) y=math.sin(alpha) return length*EPoint(x,y)+center def toProjective(self): return (self._x,self._y,1) def toPolar(self,center): v=self-center alpha=math.atan2(v.y,v.x) if alpha<0: alpha+=2*math.pi k=self.dist(center) return (alpha,k) def transform(self,matrix): transformed=np.matmul(matrix,np.array(self.toProjective()).transpose()) return EPoint.fromProjective(transformed) def dist(self,a): return math.sqrt((self._x-a._x)**2+(self._y-a._y)**2) def __add__(self,a): return EPoint(self._x+a._x,self._y+a._y) def __sub__(self,a): return EPoint(self._x-a._x,self._y-a._y) def __mul__(self,k): return EPoint(self._x*k,self._y*k) def __rmul__(self,k): return self*k def __truediv__(self,k): return EPoint(self._x/k,self._y/k) def __floordiv__(self,k): return EPoint(self._x//k,self._y//k) def __neg__(self): return EPoint(-self._x,-self._y) def __getitem__(self,key): if key==0: return self._x elif key==1: return self._y raise IndexError(key) def __hash__(self): return hash((self._x,self._y)) def __lt__(self,a): return self._xa._x or (self._x==a._x and self._y>a._y) def __ge__(self,a): return self._x>a._x or (self._x==a._x and self._y>=a._y) def __eq__(self,a): return self._x==a._x and self._y==a._y def __ne__(self,a): return self._x!=a._x or self._y!=a._y def __str__(self): return "({0},{1})".format(round(self._x,3),round(self._y,3)) def __repr__(self): return "EPoint({0},{1})".format(round(self._x,3),round(self._y,3))