Changeset - 97de46a7c740
[Not reviewed]
default
0 2 0
Laman - 10 years ago 2015-08-31 22:19:53

minor Corners refactoring
_canonizeOrder renamed to canonizeOrder due to being used publicly
comments changes
2 files changed with 16 insertions and 31 deletions:
0 comments (0 inline, 0 general)
src/corners.py
Show inline comments
 
from epoint import *
 
 
 
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)<minDist:
 
        index,minDist=i,a.dist(c)
 
    
 
    self.corners[index]=a
 
    self._canonizeOrder()
 
  
 
  
 
  ## Computes twice the area of a triangle formed by points a,b,c.
 
  ## Computes twice the area of the triangle formed by points a,b,c.
 
  #  
 
  #  @return positive value for points oriented counter-clockwise, negative for clockwise, zero for degenerate cases.
 
  def _doubleTriangleArea(a,b,c):
 
    return (a.x-b.x)*(c.y-a.y)-(c.x-a.x)*(a.y-b.y)
 
  
 
  
 
  def _slope(a,b):
 
    if(b.x==a.x): return float("inf")
 
    return (b.y-a.y)/(b.x-a.x)
 
 
    
 
  ## Order the corners (0,1,2,3) so they make a quadrangle with vertices KLMN in counter-clockwise order, K being in the upper left.
 
  #  
 
  #  For four points ABCD, there are 24 possible permutations corresponding to the desired KLMN.
 
  #  When we relax the condition of K being the upper left one, we get six groups of four equivalent permuations. KLMN ~ LMNK ~ MNKL ~ NKLM.
 
  #  When we relax the condition of K being the upper left one, we get six groups of four equivalent permutations. KLMN ~ LMNK ~ MNKL ~ NKLM.
 
  #  
 
  #  xxxx -> 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 or degenerate cases.
 
  def _canonizeOrder(self):
 
  #  @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=(x for x in self.corners)
 
    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]
 
    
 
@@ -84,14 +85,14 @@ class Corners:
 
        kIndex=ii
 
        lowestSlope=slope
 
    
 
    self.corners=self.corners[kIndex:]+self.corners[:kIndex] # rotate the upper left corner to the first place
 
        
 
    return True # success
 
 
# import itertools
 
# points=[(10,8),(8,10),(12,10),(10,12)]
 
# for perm in itertools.permutations(points):
 
  # corn=Corners()
 
  # for p in perm: corn.add(p[0],p[1])
 
  # print(corn._canonizeOrder())
 
  # print(corn.canonizeOrder())
 
  # print(corn.corners)
src/gui.py
Show inline comments
 
import tkinter as tk
 
from PIL import ImageTk
 
import PIL
 
import math
 
from epoint import *
 
from corners import *
 
from grid import *
 
 
 
class Application(tk.Frame):
 
  def __init__(self, master=None):
 
    self.corners=[]
 
    self.corners=Corners()
 
    self.boardGrid=None
 
    
 
    tk.Frame.__init__(self, master)
 
    self.grid(column=0,row=0)
 
    self.createWidgets()
 
 
  def createWidgets(self):
 
    # a captured frame with overlay graphics
 
    self.imgView=tk.Canvas(self)
 
    self.imgView.configure(width=480,height=360)
 
    imgOrig=PIL.Image.open("../images/1.jpg")
 
    self.img=ImageTk.PhotoImage(imgOrig.resize((int(self.imgView['width']),int(self.imgView['height'])),resample=PIL.Image.BILINEAR))
 
    
 
    self.imgView.bind('<1>',lambda e: self.addCorner(e.x,e.y))
 
    self.redrawImgView()
 
    
 
    self.imgView.grid(column=0,row=0)
 
    
 
    # board with detected stones
 
    self.boardView=BoardView(self)
 
    self.boardView.grid(column=1,row=0)
 
  
 
  ## Stores a grid corner located at x,y coordinates.
 
  def addCorner(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
 
        # print(self.corners)
 
        self.redrawImgView()
 
        return
 
    
 
    if len(self.corners)<4: # add a new corner
 
      self.corners.append(a)
 
      # print(self.corners)
 
      self.redrawImgView()
 
    
 
    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)<minDist:
 
        index,minDist=i,a.dist(c)
 
    
 
    self.corners[index]=a
 
    # print(self.corners)
 
    self.corners.add(x,y)
 
    if self.corners.canonizeOrder():
 
      self.boardGrid=Grid(self.corners)
 
    
 
    self.redrawImgView()
 
    
 
  ## Redraws the current image and its overlay.
 
  def redrawImgView(self):
 
    self.imgView.create_image(2,2,anchor="nw",image=self.img)
 
    for corner in self.corners:
 
    for corner in self.corners.corners:
 
      self.markPoint(corner.x,corner.y)
 
    
 
    self.imgView.grid()
 
    
 
  ## Marks a point at the image with a green cross. Used for corners.
 
  def markPoint(self,x,y):
 
    self.imgView.create_line(x-3,y-3,x+4,y+4,fill="#00ff00")
 
    self.imgView.create_line(x-3,y+3,x+4,y-4,fill="#00ff00")
 
    
 
    self.imgView.grid()
 
 
0 comments (0 inline, 0 general)