Changeset - 5bf35728ab2b
[Not reviewed]
default
0 2 0
Laman - 8 years ago 2017-04-08 15:46:56

imgView fix: grid stays on its place on resize. refactored Corners a little
2 files changed with 23 insertions and 18 deletions:
0 comments (0 inline, 0 general)
src/corners.py
Show inline comments
 
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)<minDist:
 
				index,minDist=i,a.dist(c)
 
 
		self.corners[index]=a
 
 
 
	## 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 permutations. KLMN ~ LMNK ~ MNKL ~ NKLM.
 
	#
 
	#  We determine which of the points' triplets are oriented clockwise and which counter-clockwise (minus/plus in the table below)
 
	#  and swap them so that all triangles turn counter-clockwise.
 
	#
 
	#  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 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)
 
		abc=doubleTriangleArea(a,b,c)
 
		abd=doubleTriangleArea(a,b,d)
 
		acd=doubleTriangleArea(a,c,d)
 
		bcd=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]))
 
			slope=abs(getSlope(corner,self.corners[ii]))
 
			if corner.x>self.corners[ii].x and (slope<lowestSlope or (slope==lowestSlope and corner.y<self.corners[ii].y)):
 
				kIndex=ii
 
				lowestSlope=slope
 
 
		self.corners=self.corners[kIndex:]+self.corners[:kIndex] # rotate the upper left corner to the first place
 
 
		return True # success
 
 
	def scale(self,scale):
 
		self.corners=[c*scale for c in self.corners]
 
 
 
## 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 getSlope(a,b):
 
	if(b.x==a.x): return float("inf")
 
	return (b.y-a.y)/(b.x-a.x)
src/gui/imgview.py
Show inline comments
 
@@ -38,50 +38,53 @@ class ImgView(ResizableCanvas):
 
			self.markPoint(corner.x,corner.y)
 

	
 
		if self._boardGrid!=None and config.gui.showGrid:
 
			for r in range(19):
 
				a=self._boardGrid.intersections[r][0]
 
				b=self._boardGrid.intersections[r][-1]
 
				self.create_line(a.x,a.y,b.x,b.y,fill='#00ff00')
 
			for c in range(19):
 
				a=self._boardGrid.intersections[0][c]
 
				b=self._boardGrid.intersections[-1][c]
 
				self.create_line(a.x,a.y,b.x,b.y,fill='#00ff00')
 

	
 
		if self._boardGrid!=None and config.gui.showBigPoints:
 
			for r in range(19):
 
				for c in range(19):
 
					((r1,c1),(r2,c2))=imageanalyzer.relevantRect(self._boardGrid.intersections[r][c], *(self._boardGrid.stoneSizeAt(r, c)))
 
					self.create_rectangle(r1,c1,r2,c2,outline="#00ffff")
 

	
 
	def setImg(self,img):
 
		w=int(self._width)
 
		h=int(self._height)
 
		wo,ho=img.size # o for original
 
		widthRatio=wo/w
 
		heightRatio=ho/h
 
		self._imgSizeCoef=max(widthRatio,heightRatio)
 

	
 
		self._img=img
 

	
 
	## Stores a grid corner located at x,y coordinates.
 
	def addCorner(self,x,y):
 
		self._corners.add(x,y)
 
		log.debug("click on %d,%d",x,y)
 
		log.debug("sizeCoef: %f",self._imgSizeCoef)
 
		if self._corners.canonizeOrder():
 
			# transform corners from show coordinates to real coordinates
 
			log.debug(self._corners.corners)
 
			self._boardGrid=Grid(self._corners.corners)
 
			corners=[(c*self._imgSizeCoef) for c in self._corners.corners]
 
			self._parent.sendMsg("setCorners",(corners,))
 

	
 
		self.redraw()
 

	
 
	## Marks a point at the image with a green cross. Used for corners.
 
	def markPoint(self,x,y):
 
		self.create_line(x-3,y-3,x+4,y+4,fill="#00ff00")
 
		self.create_line(x-3,y+3,x+4,y-4,fill="#00ff00")
 

	
 
	def _onResize(self,event):
 
		w=self._width
 
		super()._onResize(event)
 
		self._corners.scale(self._width/w)
 
		self._boardGrid=Grid(self._corners.corners)
 
		self.redraw()
0 comments (0 inline, 0 general)