自定义类 实现 向量 点积/ 弧度/角度

时间:2021-05-28 10:16:17
# coding=utf-8
import math
class Vector(object):
    """docstring for Vector"""
    """根据坐标轴列表输入 创建向量, 并创建该向量所处的空间维度"""
    def __init__(self, coordinates):
        super(Vector, self).__init__()
        try:
            if not coordinates:
                raise ValueError
            self.coordinates = tuple(coordinates)
            self.dimension = len(coordinates)    
        except ValueError:
            raise ValueError('The coordinates must be nonempty')
        except TypeError:
            raise TypeError('The coordinates must be an iterable')

    # '''能够使python的内置print函数 输出向量坐标轴'''

    def __str__(self):
        return 'Vector: {}'.format(self.coordinates)

   
    # 点积
    def dot(self, v):
        new_cordinates = [x*y for x,y in zip(self.coordinates,v.coordinates)]
        return sum(new_cordinates)
 
    # 弧度
    def radian(self,v):
        vectorDot = self.dot(v)
        result = vectorDot / (self.magnitude()*v.magnitude())
        return math.acos(result)

    # 角度
    def angle(self,v):
        vectorRadian = self.radian(v)
        result = 180 / math.pi * vectorRadian
        return result
    
v1 = Vector([7.887, 4.138])
v2 = Vector([-8.802, 6.776])
print(v1.dot(v2))

v3 = Vector([-5.955, -4.904, -1.874])
v4 = Vector([-4.496, -8.755, 7.103])
print(v3.dot(v4))

v5 = Vector([3.183, -7.627])
v6 = Vector([-2.668, 5.319])
print(v5.radian(v6))

v7 = Vector([7.35,0.221,5.188])
v8 = Vector([2.751,8.259,3.985])
print(v7.angle(v8))

# 输出结果
# -41.382286
# 56.397178
# 3.07202630984
# 60.2758112052
# [Finished in 0.1s]

优化后

# coding=utf-8
from math import sqrt, acos, pi
from decimal import Decimal, getcontext

class Vector(object):
    """docstring for Vector"""
    """根据坐标轴列表输入 创建向量, 并创建该向量所处的空间维度"""
    CANNOT_NORMALIZE_ZERO_VECTOR_MSG = 'Cannot normalize the zero vector'
    def __init__(self, coordinates):
        super(Vector, self).__init__()
        try:
            if not coordinates:
                raise ValueError
            self.coordinates = tuple([Decimal(x) for x in coordinates])
            self.dimension = len(coordinates)    
        except ValueError:
            raise ValueError('The coordinates must be nonempty')
        except TypeError:
            raise TypeError('The coordinates must be an iterable')

    # '''能够使python的内置print函数 输出向量坐标轴'''

    def __str__(self):
        return 'Vector: {}'.format(self.coordinates)

   
    # 计算向量长度
    def magnitude(self):
        coordinates_squared = [x**2 for x in self.coordinates]
        return sqrt(sum(coordinates_squared))

    # 将向量归一化
    def normalized(self):
        try:
            magnitude = self.magnitude()
            return  Vector([Decimal(x) *(Decimal(1.0)/ Decimal(magnitude)) for x in self.coordinates])
        except ZeroDivisionError:
            raise Exception('Cannot normalized the zero myVector2')


   
    # 点积
    def dot(self, v):
        return sum([x*y for x,y in zip(self.coordinates, v.coordinates)])

    # 角度弧度
    def angle_with(self,v,in_degress=False):
        try:
            u1 = self.normalized()
            u2 = v.normalized()
            angle_in_radians = acos(u1.dot(u2))
            if in_degress:
                degrees_per_radian = 180./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 
        
        # 为什么要处理这些小数, 如果两个向量指向同一方向,它们的点积则是二者大小的点积
        # 但是有时候,因为计算精度丢失 使比例不对, 这样就会在acos函数中产生范围错误


v1 = Vector([7.887, 4.138])
v2 = Vector([-8.802, 6.776])
print(v1.dot(v2))

v3 = Vector([-5.955, -4.904, -1.874])
v4 = Vector([-4.496, -8.755, 7.103])
print(v3.dot(v4))

v5 = Vector([3.183, -7.627])
v6 = Vector([-2.668, 5.319])
print(v5.angle_with(v6, in_degress = False))

v7 = Vector([7.35,0.221,5.188])
v8 = Vector([2.751,8.259,3.985])
print(v7.angle_with(v8,in_degress = True))

# 输出结果
-41.38228599999999454398391663
56.39717800000000569975711073
3.07202630984
60.2758112052
[Finished in 0.2s]