# -*- coding: UTF-8 -*-
from math import sqrt,acos,pi
from decimal import Decimal,getcontext
import pdb
getcontext().prec = 15 # 上下文的 prec 属性控制着作为算术运算结果所创建的新值的精度。
class Vector:
"""向量实体"""
def __init__(self, coordinate):
"""初始化函数"""
try:
if not coordinate:
raise ValueError
self.coordinate = tuple([Decimal(x) for x in coordinate])
self.dimension = len(coordinate)
except ValueError:
raise ValueError("向量坐标不能为空!")
except TypeError:
raise TypeError("坐标类型需为可迭代对象")
def __str__(self):
"""toString"""
return "Vector:{}".format(self.coordinate)
def __eq__(self,v):
return self.coordinate == v.coordinate
def plus(self,v):
"""向量相加"""
return Vector([x+y for x,y in zip(self.coordinate,v.coordinate)])
def minus(self,v):
"""向量相减"""
return Vector([x-y for x,y in zip(self.coordinate,v.coordinate)])
def times_scalar(self,c):
"""乘标量"""
new_coordinates = [Decimal(c)*x for x in self.coordinate]
return Vector(new_coordinates)
def magnitude(self):
"""向量大小"""
return Decimal(sqrt(sum([x**2 for x in self.coordinate])))
def normalized(self):
try:
return self.times_scalar(Decimal('1.0')/self.magnitude())
except ZeroDivisionError:
raise Exception("不能标准化零向量")
向量点积
def dot(self,v):
"""点积"""
return sum([x*y for x,y in zip(self.coordinate,v.coordinate)])
def angle_with(self,v,in_degrees=False):
"""两向量夹角"""
u1 = self.normalized()
u2 = v.normalized()
angle_in_radians = acos(u1.dot(u2))
if(in_degrees):
degress_per_radian = 180./pi
return angle_in_radians * degress_per_radian
else:
return angle_in_radians
平行向量:
平行向量,也叫共线向量。是指方向相同或相反的非零向量。零向量和任何向量平行。
def is_zero(self,tolerance=1e-10):
"""
是否为零向量
Parameters:
tolerance:当向量模小于该数时,判断为0
"""
return self.magnitude() < tolerance
def is_parallel_to(self,v):
"""
两向量是否平行
1)零向量与任一向量平行
2)两向量夹角为0或π时,两向量平行
"""
return (self.is_zero() or
v.is_zero() or
self.angle_with(v) == 0 or
self.angle_with(v) == pi)
正交向量
“正交向量”是一个数学术语,指点积为零的两个或多个向量。几何向量的概念在线性代数中经由抽象化,得到更一般的向量概念。此处向量定义为向量空间的元素,要注意这些抽象意义上的向量不一定以数对表示,大小和方向的概念亦不一定适用。在三维向量空间中, 两个向量的内积如果是零, 那么就说这两个向量是正交的。正交最早出现于三维空间中的向量分析。 换句话说, 两个向量正交意味着它们是相互垂直的。若向量α与β正交,则记为α⊥β。
def is_orthogonal_to(self,v,tolerance=1e-10):
"""两向量是否正交"""
return abs(self.dot(v)) < tolerance
向量投影
计算投影的方法
def proj_with(self,basis):
"""求投影向量"""
try:
u = basis.normalized()
proj_magnitude = self.dot(u) #向量v在基向量上投影的大小等于向量v与标准化基向量的点积
return u.times_scalar(proj_magnitude)
except Exception as e:
raise Exception("不能标准化零向量")
def orthogoal_with(self,basis):
"""求正交向量"""
try:
proj = self.proj_with(basis)
return self.minus(proj)
except Exception as e:
raise Exception("不能标准化零向量")
向量积(来自百度百科)
def cross(self,v):
"""向量积"""
try:
x_1,y_1,z_1 = self.coordinate
x_2,y_2,z_2 = v.coordinate
return Vector([y_1*z_2 - y_2*z_1,
-(x_1*z_2 - x_2*z_1),
x_1*y_2 - x_2*y_1])
except ValueError as e:
msg = str(e)
if msg == 'need more than 2 values to unpack':
self_embedded_in_R3 = Vector(self.coordinate + ('0',))
v_embedded_in_R3 = Vector(v.coordinate + ('0',))
return self_embedded_in_R3.cross(v_embedded_in_R3)
elif(msg == 'too many values to unpack' or
msg == 'need more than 1 value to unpack'):
raise Exception("仅支持两维或三维的向量积运算")
else:
raise e
def area_of_parallelogram_with(self,v):
"""平行四边形面积"""
new_coordinates = self.cross(v)
return new_coordinates.magnitude()