Changeset - d07ae4bfa145
[Not reviewed]
default
0 3 0
Laman - 6 years ago 2019-03-06 18:03:44

transforming points and lines with a matrix
3 files changed with 40 insertions and 4 deletions:
0 comments (0 inline, 0 general)
exp/geometry.py
Show inline comments
 
@@ -19,47 +19,63 @@ class Line:
 
		alpha=math.acos(a_) if b_>=0 else 2*math.pi-math.acos(a_)
 
		return Line(alpha,-c_)
 

	
 
	@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 toPoints(self):
 
		(a,b,c)=self.toNormal()
 
		assert a!=0 or b!=0
 
		if a==0:
 
			y=-c/b
 
			return (EPoint(0,y),EPoint(10,y))
 
		elif b==0:
 
			x=-c/a
 
			return (EPoint(x,0),EPoint(x,10))
 
		else:
 
			return (EPoint(0,-c/b),EPoint(-c/a,0))
 

	
 
	def intersect(self,line):
 
		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 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 shiftBasis(self,newBasis):
 
		(a,b,c)=self.toNormal()
 
		if a!=0:
 
			point=EPoint(-c/a,0)
 
		else:
 
			point=EPoint(0,-c/b)
 
		(x_,y_)=point-newBasis
 
		c_=-a*x_-b*y_
 
		return Line.fromNormal(a,b,c_)
 

	
 
	def transform(self,matrix):
 
		transformed=(p.transform(matrix) for p in self.toPoints())
 
		return Line.fromPoints(*transformed)
 

	
 
	@property
 
	def alpha(self): return self._alpha
 

	
 
	@property
 
	def d(self): return self._d
 

	
 
	def __str__(self): return "Line({0},{1})".format(round(self._alpha,3),round(self._d))
 
	def __repr__(self): return "Line({0},{1})".format(self._alpha,self._d)
 

	
 

	
 
def angleDiff(alpha,beta):
 
	diff=abs(alpha-beta)
exp/tests/test_geometry.py
Show inline comments
 
import math
 
import random
 
from unittest import TestCase
 

	
 
import numpy as np
 

	
 
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
 
@@ -80,12 +82,24 @@ class TestLine(TestCase):
 

	
 
		newBasis=EPoint(-100,100)
 
		diag=100*math.sqrt(2)
 
		p=Line(math.pi*3/4,diag/2)
 
		p_=p.shiftBasis(newBasis)
 
		self.assertAlmostEqual(p_._alpha,math.pi*7/4)
 
		self.assertAlmostEqual(p_._d,diag/2)
 

	
 
		q=Line(math.pi*3/4,-diag/2)
 
		q_=q.shiftBasis(newBasis)
 
		self.assertAlmostEqual(q_._alpha,math.pi*7/4)
 
		self.assertAlmostEqual(q_._d,3/2*diag)
 

	
 
	def testTransform(self):
 
		rot90=np.array([[0,-1,0],[1,0,0],[0,0,1]])
 
		p=Line(math.pi/4,10)
 
		p_=p.transform(rot90)
 
		self.assertAlmostEqual(p_.alpha,math.pi*3/4)
 
		self.assertAlmostEqual(p_.d,p.d)
 

	
 
		shiftXY10=np.array([[1,0,10],[0,1,10],[0,0,1]])
 
		p_=p.transform(shiftXY10)
 
		self.assertAlmostEqual(p_.alpha,p.alpha)
 
		self.assertAlmostEqual(p_.d,10+10*math.sqrt(2))
src/analyzer/epoint.py
Show inline comments
 
import math
 

	
 
import numpy as np
 

	
 

	
 
def homogenize(v):
 
	for k in v:
 
	for k in reversed(v):
 
		if k!=0: return v/k
 
	return v
 

	
 

	
 
## Euclidean 2D plane point: (x,y).
 
class EPoint:
 
	def __init__(self,x,y):
 
		self._x=x
 
		self._y=y
 

	
 
	@property
 
	def x(self): return self._x
 
	
 
	@property
 
	def y(self): return self._y
 

	
 
	@staticmethod
 
	def fromProjective(point):
 
		if point.item(0)==0: return None
 
		return EPoint(point.item(1)/point.item(0),point.item(2)/point.item(0))
 
		if point.item(2)==0: return None
 
		return EPoint(point.item(0)/point.item(2),point.item(1)/point.item(2))
 

	
 
	@staticmethod
 
	def fromPolar(point,center):
 
		(alpha,length)=point
 
		x=math.cos(alpha)
 
		y=math.sin(alpha)
 
		return length*EPoint(x,y)+center
 

	
 
	def toProjective(self):
 
		return (1,self._x,self._y)
 
		return (self._x,self._y,1)
 

	
 
	def toPolar(self,center):
 
		v=self-center
 
		alpha=math.atan2(v.y,v.x)
 
		if alpha<0: alpha+=2*math.pi
 
		k=self.dist(center)
 
		return (alpha,k)
 

	
 
	def transform(self,matrix):
 
		transformed=np.matmul(matrix,np.array(self.toProjective()).transpose())
 
		return EPoint.fromProjective(transformed)
 

	
 
	def dist(self,a):
 
		return math.sqrt((self._x-a._x)**2+(self._y-a._y)**2)
 

	
 
	def __add__(self,a):
 
		return EPoint(self._x+a._x,self._y+a._y)
 

	
 
	def __sub__(self,a):
 
		return EPoint(self._x-a._x,self._y-a._y)
 

	
 
	def __mul__(self,k):
 
		return EPoint(self._x*k,self._y*k)
 

	
0 comments (0 inline, 0 general)