import random from geometry import Line class LineBag: def __init__(self,capacity): self._capacity=capacity self._bag=[] def put(self,item): # early abort if self._bag and item>self._bag[-1]: return (v,p)=item # mostly filter duplicates for (i,(vi,pi)) in enumerate(self._bag): if abs(p.alpha-pi.alpha)<0.02 and abs(p.d-pi.d)<5: if vself._capacity: self._bag.pop() def pull(self,count=0): return self._bag[:count] if count else self._bag[:] class Ransac: def __init__(self,points): self._points=points def extract(self,count,iterations): bag=LineBag(count) for i in range(iterations): line=self._generateLine() score=self._scoreLine(line) bag.put((score+random.random()/1000,line)) return [line for (score,line) in bag.pull()] def _generateLine(self): (a,b)=random.sample(self._points,2) return Line.fromPoints(a,b) def _scoreLine(self,line): return sum(min(line.distanceTo(p),5) for p in self._points) class DiagonalRansac(Ransac): def __init__(self,points,sideLen): super().__init__(points) self._sideLen=sideLen def _generateLine(self): n=len(self._points) m=self._sideLen ka=random.randrange(0,n) kb=ka while ka//m==kb//m or ka%m==kb%m: kb=random.randrange(0,n) a=self._points[ka] b=self._points[kb] return Line.fromPoints(a,b)