from epoint import EPoint class Corners: def __init__(self): self.corners=[] ## Adds a new corner if there are less than four, replaces the closest otherwise. def add(self,x,y): a=EPoint(x,y) # for i,c in enumerate(self.corners): # move an improperly placed point # if a.dist(c)<20: # self.corners[i]=a # return if len(self.corners)<4: # add a new corner self.corners.append(a) if len(self.corners)<4: return index,minDist=0,float('inf') # replace the corner closest to the clicked point for i,c in enumerate(self.corners): if a.dist(c) KLMN | ABC | ABD | ACD | BCD | index | swap # ------------ | :-: | :-: | :-: | :-: | ----: | ---- # A BCD | + | + | + | + | 15 | 0 # A BDC | + | + | - | - | 12 | CD # A CBD | - | + | + | - | 6 | BC # A CDB | - | - | + | + | 3 | AB # A DBC | + | - | - | + | 9 | AD # A DCB | - | - | - | - | 0 | BD # # For every non-degenerate quadrangle, there must be 1-3 edges going right-left (from a higher to a lower x coordinate). # From these pick the one with the lowest slope (dy/dx) and declare its ending point the upper left corner. For the same slope pick the one further left. # # @return True for a convex quadrangle, False for concave and degenerate cases. def canonizeOrder(self): if len(self.corners)!=4: return False # erroneus call a,b,c,d=self.corners abc=Corners._doubleTriangleArea(a,b,c) abd=Corners._doubleTriangleArea(a,b,d) acd=Corners._doubleTriangleArea(a,c,d) bcd=Corners._doubleTriangleArea(b,c,d) if any(x==0 for x in (abc,abd,acd,bcd)): return False # collinear degenerate swaps=[(1,3),(0,1),(1,2),(0,3),(2,3),(0,0)] index=(8 if abc>0 else 0)|(4 if abd>0 else 0)|(2 if acd>0 else 0)|(1 if bcd>0 else 0) if index%3!=0: return False # concave degenerate swap=swaps[index//3] self.corners[swap[0]], self.corners[swap[1]] = self.corners[swap[1]], self.corners[swap[0]] # counter-clockwise order kIndex=None lowestSlope=float("inf") for i,corner in enumerate(self.corners): # find the NK edge: going right-left with the lowest slope, secondarily the one going down ii=(i+1)%4 slope=abs(Corners._slope(corner,self.corners[ii])) if corner.x>self.corners[ii].x and (slope