Changeset - 7c268e382b96
[Not reviewed]
default
0 2 2
Laman - 6 years ago 2019-02-14 17:18:55

geometry: rewritten Line
4 files changed with 102 insertions and 47 deletions:
0 comments (0 inline, 0 general)
exp/board_detect.py
Show inline comments
 
@@ -13,7 +13,7 @@ import scipy.cluster
 
import scipy.ndimage
 
import scipy.signal
 

	
 
from geometry import Line, point2lineDistance
 
from geometry import Line
 
from polar_hough import PolarHough
 
from annotations import DataFile,computeBoundingBox
 
from hough import show,prepareEdgeImg,HoughTransform
exp/geometry.py
Show inline comments
 
import math
 

	
 
import numpy as np
 

	
 
from analyzer.epoint import EPoint, homogenize
 
from analyzer.grid import transformPoint
 
from analyzer.epoint import EPoint
 

	
 

	
 
class Line():
 
	def __init__(self,a,b):
 
		self.a=a
 
		self.b=b
 
		self.points={a,b}
 
class Line:
 
	def __init__(self,alpha,d):
 
		self._alpha=alpha
 
		self._d=d
 
		self._sin=math.sin(alpha)
 
		self._cos=math.cos(alpha)
 

	
 
	def getSortedPoints(self):
 
		return tuple(sorted(self.points))
 
	@staticmethod
 
	def fromNormal(a,b,c):
 
		"""ax + by + c = 0"""
 
		norm=-c/abs(c)*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_)
 

	
 
	def computeAngle(self,line):
 
		ab=self.a-self.b
 
		cd=line.a-line.b
 
		alpha=math.atan(ab.y/ab.x)
 
		gamma=math.atan(cd.y/cd.x)
 
		fi=max(alpha,gamma)-min(alpha,gamma)
 
		return min(fi,math.pi-fi)
 
	@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 intersect(self,line):
 
		p=self.toProjective()
 
		q=line.toProjective()
 
		return EPoint.fromProjective(np.cross(p,q))
 

	
 
	def toProjective(self):
 
		return homogenize(np.cross(self.a.toProjective(),self.b.toProjective()))
 

	
 
	def transform(self,matrix):
 
		a=EPoint.fromProjective(transformPoint(self.a.toProjective(),matrix))
 
		b=EPoint.fromProjective(transformPoint(self.b.toProjective(),matrix))
 
		if a is None or b is None: return None
 
		return Line(a,b)
 
		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 score(self,points):
 
		score=len(self.points)
 
		for a in self.points:
 
			closest=sorted(points,key=lambda b: a.dist(b))[:4]
 
			score+=sum(0.01 for b in closest if b in self.points)
 
		return score
 
	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 __str__(self): return "({0},{1})".format(self.a,self.b)
 
	def __repr__(self): return "Line({0},{1})".format(repr(self.a),repr(self.b))
 

	
 

	
 
def point2lineDistance(a,b,p):
 
	# https://en.wikipedia.org/wiki/Point-line_distance#Line_defined_by_two_points
 
	ab=b-a
 
	num=abs(ab.y*p.x - ab.x*p.y + b.x*a.y - a.x*b.y)
 
	denum=math.sqrt(ab.y**2+ab.x**2)
 
	return num/denum # double_area / side_length == height
 
	def __str__(self): return "({0},{1})".format(self._alpha,self._d)
 
	def __repr__(self): return "Line({0},{1})".format(repr(self._alpha),repr(self._d))
 

	
 

	
 
def angleDiff(alpha,beta):
exp/tests/__init__.py
Show inline comments
 
new file 100644
exp/tests/test_geometry.py
Show inline comments
 
new file 100644
 
import math
 
import random
 
from unittest import TestCase
 

	
 
from geometry import Line,EPoint
 

	
 
random.seed(361)
 

	
 

	
 
class TestLine(TestCase):
 
	def testFromNormal(self):
 
		p=Line.fromNormal(1,0,-1) # x-1=0
 
		self.assertEqual(p._alpha,0)
 
		self.assertEqual(p._d,1)
 

	
 
		q=Line.fromNormal(1,1,-2) # x+y-2=0
 
		self.assertAlmostEqual(q._alpha,math.pi/4)
 
		self.assertAlmostEqual(q._d,math.sqrt(2))
 

	
 
		r=Line.fromNormal(0,1,1) # y+1=0
 
		self.assertAlmostEqual(r._alpha,math.pi*3/2)
 
		self.assertEqual(r._d,1)
 

	
 
	def testFromPoints(self):
 
		ab=Line.fromPoints(EPoint(1,3),EPoint(1,-1))
 
		self.assertEqual(ab._alpha,0)
 
		self.assertEqual(ab._d,1)
 

	
 
		cd=Line.fromPoints(EPoint(0,2),EPoint(-1,3))
 
		self.assertAlmostEqual(cd._alpha,math.pi/4)
 
		self.assertAlmostEqual(cd._d,math.sqrt(2))
 

	
 
		ef=Line.fromPoints(EPoint(-2,-1),EPoint(-4,-1))
 
		self.assertAlmostEqual(ef._alpha,math.pi*3/2)
 
		self.assertEqual(ef._d,1)
 

	
 
	def testIntersect(self):
 
		for i in range(10):
 
			a=EPoint(random.randint(-100,100),random.randint(-100,100))
 
			b=EPoint(random.randint(-100,100),random.randint(-100,100))
 
			c=EPoint(random.randint(-100,100),random.randint(-100,100))
 
			ab=Line.fromPoints(a,b)
 
			ac=Line.fromPoints(a,c)
 
			a_=ab.intersect(ac)
 
			self.assertAlmostEqual(a.x,a_.x)
 
			self.assertAlmostEqual(a.y,a_.y)
 

	
 
	def testDistanceTo(self):
 
		p=Line(0,1)
 
		q=Line(math.pi/4,math.sqrt(2))
 
		r=Line(math.pi*3/2,1)
 

	
 
		a=EPoint(0,0)
 
		b=EPoint(1,0)
 
		c=EPoint(-1,-1)
 

	
 
		self.assertAlmostEqual(p.distanceTo(a),1)
 
		self.assertAlmostEqual(p.distanceTo(b),0)
 
		self.assertAlmostEqual(p.distanceTo(c),2)
 

	
 
		self.assertAlmostEqual(q.distanceTo(a),math.sqrt(2))
 
		self.assertAlmostEqual(q.distanceTo(b),math.sqrt(2)/2)
 
		self.assertAlmostEqual(q.distanceTo(c),2*math.sqrt(2))
 

	
 
		self.assertAlmostEqual(r.distanceTo(a),1)
 
		self.assertAlmostEqual(r.distanceTo(b),1)
 
		self.assertAlmostEqual(r.distanceTo(c),0)
0 comments (0 inline, 0 general)