import math from analyzer.epoint import EPoint class Line: def __init__(self,alpha,d): self._alpha=alpha self._d=d self._sin=math.sin(alpha) self._cos=math.cos(alpha) @staticmethod def fromNormal(a,b,c): """ax + by + c = 0""" sign=-c/abs(c) if c!=0 else 1 norm=sign*math.sqrt(a**2+b**2) (a_,b_,c_)=(a/norm,b/norm,c/norm) alpha=math.acos(a_) if b_>=0 else 2*math.pi-math.acos(a_) return Line(alpha,-c_) @staticmethod def fromPoints(a,b): return Line.fromNormal(a.y-b.y, b.x-a.x, (b.y-a.y)*a.x+(a.x-b.x)*a.y) def toNormal(self): # https://en.wikipedia.org/wiki/Line_(mathematics)#In_normal_form """ax + by + c = 0""" return (self._cos, self._sin, -self._d) def toPoints(self): (a,b,c)=self.toNormal() assert a!=0 or b!=0 if a==0: y=-c/b return (EPoint(0,y),EPoint(10,y)) elif b==0: x=-c/a return (EPoint(x,0),EPoint(x,10)) else: return (EPoint(0,-c/b),EPoint(-c/a,0)) def intersect(self,line): if self._alpha==line._alpha: return None (a,b,c)=self.toNormal() (d,e,f)=line.toNormal() x=(b*f-c*e)/(a*e-b*d) y=(c*d-a*f)/(a*e-b*d) return EPoint(x,y) def distanceTo(self,point): # https://en.wikipedia.org/wiki/Point-line_distance#Line_defined_by_an_equation (a,b,c)=self.toNormal() return abs(a*point.x+b*point.y+c) # a**2 + b**2 == 1 for Hesse normal form def shiftBasis(self,newBasis): (a,b,c)=self.toNormal() if a!=0: point=EPoint(-c/a,0) else: point=EPoint(0,-c/b) (x_,y_)=point-newBasis c_=-a*x_-b*y_ return Line.fromNormal(a,b,c_) def transform(self,matrix): transformed=(p.transform(matrix) for p in self.toPoints()) return Line.fromPoints(*transformed) @property def alpha(self): return self._alpha @property def d(self): return self._d def __str__(self): return "Line({0},{1})".format(round(self._alpha,3),round(self._d)) def __repr__(self): return "Line({0},{1})".format(self._alpha,self._d) def angleDiff(alpha,beta): diff=abs(alpha-beta) if diff>math.pi: diff=2*math.pi-diff return diff