Skip to content

Instantly share code, notes, and snippets.

@chris-pws
Last active November 23, 2017 02:19
Show Gist options
  • Save chris-pws/d493d93ffc6f5227d794e1037ccedb34 to your computer and use it in GitHub Desktop.
Save chris-pws/d493d93ffc6f5227d794e1037ccedb34 to your computer and use it in GitHub Desktop.
import itertools
import math
from decimal import Decimal, getcontext
getcontext().prec = 30
class Vector:
CANNOT_NORMALIZE_ZERO_VECTOR_MSG = 'Cannot normalize the zero vector'
def __init__( self, coordinates ):
try:
if not coordinates:
raise ValueError
self.coordinates = tuple([Decimal(x) for x in coordinates])
self.dimension = len(self.coordinates)
except ValueError:
raise ValueError( 'The coordinates must be nonempty' )
except TypeError:
raise TypeError( 'The coordinates must be an iterable' )
def __str__(self):
return 'Vector: {}'.format(
tuple([float('{0:.3f}'.format(n)) for n in self]) )
def __iter__(self):
for i in self.coordinates:
yield Decimal(i)
def __getitem__( self, index ):
return self.coordinates[index]
def __eq__( self, v ):
return self.coordinates == v.coordinates
def __add__( self, v ):
try:
pairs = itertools.zip_longest( self, v, fillvalue=0.0)
return Vector([a + b for a, b in pairs])
except TypeError as te:
raise NotImplemented from te
def __sub__( self, v ):
try:
pairs = itertools.zip_longest( self, v, fillvalue=0.0 )
return Vector([a - b for a, b in pairs])
except TypeError as te:
raise NotImplemented from te
def __mul__( self, scalar ):
return Vector([Decimal(scalar) * n for n in self])
def magn(self):
# acquiring distance/magnitude
squares = Vector([n**2 for n in self])
return math.sqrt( sum(squares) )
def unit(self):
# here we are normalizing to a unit vector
# to capture direction
try:
magnitude = self.magn()
return self * ( Decimal('1.0') / Decimal(magnitude) )
except ZeroDivisionError:
raise Exception(self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG)
def dot( self, v ):
pairs = zip( self, v )
return sum( a * b for a, b in pairs )
def angle_with( self, v, in_degrees=False ):
try:
u1 = self.unit()
u2 = v.unit()
angle_in_radians = math.acos( round( u1.dot(u2), 10 ) )
if in_degrees:
degrees_per_radian = 180. / math.pi
return angle_in_radians * degrees_per_radian
else:
return angle_in_radians
except Exception as e:
if str(e) == self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG:
raise Exception('Cannot compute an angle with the zero vector')
else:
raise e
def parallel_to( self, v ):
#pairs = zip( self, v )
#div = (self.coordinates[0] / v.coordinates[0])
#return all( ( (a / b) == div ) for a, b in pairs )
return ( self.is_zero() or
v.is_zero() or
self.angle_with(v) == 0 or
self.angle_with(v) == math.pi )
def orthog_to( self, v, tolerance=1e-10 ):
return abs( self.dot(v) ) < tolerance
def is_zero( self, tolerance=1e-10 ):
return self.magn() < tolerance
def projected_on( self, b ):
b_unit = b.unit()
weight = Decimal( self.dot(b_unit) )
parallel = b_unit * weight
return parallel
def orthog_proj( self, b ):
projection = self.projected_on(b)
orthog_comp = self - projection
return orthog_comp
def cross_product_with( self, v ):
return Vector([( self[1] * v[2] ) - ( v[1] * self[2] ),
-abs( ( self[0] * v[2] ) - ( v[0] * self[2] ) ),
( self[0] * v[1] ) - ( v[0] * self[1] )])
def cp_parallelgm_area( self, v ):
cross = self.cross_product_with(v)
return cross.magn()
def cp_triangle_area( self, v ):
cross = self.cross_product_with(v)
return cross.magn() / 2
v1 = Vector([1.5,9.547,3.691])
v2 = Vector([-6.007,0.124,5.772])
b1 = Vector([6.404,-9.144,2.759,8.718])
v4 = Vector([1,8])
print (v1.cp_triangle_area(v2))
#print ( v3.is_orthog(v4) )
#print ( v4.parallel_to(v1) )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment