#!/usr/bin/python
# -*- coding: utf-8 -*-

''' littlegeom.py

Defines a few primitives classes to perform basic geometric operations 
in 2D.
'''

import math

class Vector(list):
	''' 
	A 2D point, implemented as a specialized list.
	
	Handy to look like a duck when used in contexts that expects ducks (see
	the implementation notes of 'intersect2d.py' for instance).
	'''
	def __init__(self, x=0.0, y=0.0):
		if isinstance(x, list) or isinstance(x, tuple):
			if len(x) < 2:
				raise ValueError('list contructor requires a list of length >= 2')
			super(Vector,self).__init__([float(k) for k in x[:2]])
		else:
			super(Vector,self).__init__([float(x),float(y)])
		
	def get_x(self):
		return self[0]
	def set_x(self, value):
		self[0] = value
	def get_y(self):
		return self[1]
	def set_y(self, value):	
		self[1] = value
	
	x = property(get_x, set_x)
	y = property(get_y, set_y)
		
	def length(self):
		return math.sqrt(self.x*self.x+self.y*self.y)
	
	def normalize(self):
		l = self.length()
		self /= l
		return l

	def __iadd__(self, l):
		''' addition of 2 vectors '''
		self.x += l.x
		self.y += l.y
		return self
	def __add__(self, l):
		return Vector(self.x+l.x, self.y+l.y)
		
	def __isub__(self, l):
		''' subtraction of 2 vectors '''
		self.x -= l.x
		self.y -= l.y
		return self
	def __sub__(self, l):
		return Vector(self.x-l.x, self.y-l.y)
		
	def __imul__(self, s):
		''' vector * scalar multiplication '''
		self.x *= s
		self.y *= s
		return self
	def __mul__(self, s):
		return Vector(self.x*s, self.y*s)
		
	def __idiv__(self, s):
		''' vector / scalar multiplication '''
		self.x /= s
		self.y /= s
		return self
	def __div__(self, s):
		return Vector(self.x/s, self.y/s)
		
		
		
class Point(Vector): 
	'''
	An alias of Vector - therefore, a 2D point.
	
	Useful for pedantic guys like me, who like to distinguish between
	Points and Vector - even though the operations permitted on both
	types are the same, they are semantically different.
	'''
	pass



class Segment(list):
	'''
	A 2D segment.
	
	Uses the same trick as the Vector for clients expecting lists.
	'''
	def __init__(self, p1, p2=None):
		if p2 is None:
			if not isinstance(p1, list) or len(p1) != 2:
				raise ValueError('list contructor requires a list of length = 2')
			super(Segment,self).__init__([Point(x) for x in p1])
		else:
			super(Segment,self).__init__([Point(p1), Point(p2)])
		
	def get_p1(self):
		return self[0]
	def set_p1(self, value):
		self[0] = value
	def get_p2(self):
		return self[1]
	def set_p2(self, value):	
		self[1] = value
	
	p1 = property(get_p1, set_p1)
	p2 = property(get_p2, set_p2)
	