欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

固定一个点A,让点B (结构式) 围绕点A旋转,使A, B, C在同一直线上Python实现

程序员文章站 2022-03-02 10:56:24
...

直接上代码

import numpy as np

#结构式旋转的函数。只需要四个参数即可。这几个参数的意义:
    #p1: 固定不动的那个点。p1不要求是坐标原点,可以是任意坐标。
    #p2: 要移动的那个点。
    #p3: 移动的目标点。这个点与p2移动之后的点不一定是重合的,但p1, p2'(p2移动后的点), p3一定是在同一直线上的
    #listPoint: 要旋转的结构式
    #具体原理:根据p1, p2, p3,计算出旋转矩阵。有了旋转矩阵之后,旋转公式与每一个点都点乘,即可得到旋转之后的坐标,
    #对于整个结构式而言,得到的是旋转之后的结构式,且每个点的相对位置保持不变,且移动到所希望的位置。
    @staticmethod
    def structureRoate_fixOnePoint(p1, p2, p3, listPoint):
        #计算旋转矩阵
        rotationMatrix = Move_and_Rotation.calculationRoationMatrixByThreePoints(p1, p2, p3)

        listPoint2 = []
        for point in listPoint:
            #起始位置。注意,- p1.x,         - p1.y和- p1.z的目的是让p1点变成坐标原点,计算完之后再加上这些数据即可。
            #如果p1不是坐标原点,计算结果是错误的
            resourceMatrix = np.array([point.x - p1.x, point.y - p1.y, point.z - p1.z]).T
            
            #利用旋转矩阵对原始坐标进行旋转
            targetMatrix = np.dot(rotationMatrix, resourceMatrix)
            
            #point旋转之后得到point2,其坐标如下。记得要加上p1的坐标
            point2 = Point(targetMatrix[0] + p1.x, targetMatrix[1] + p1.y, targetMatrix[2] + p1.z)
            listPoint2.append(point2)
            
        return listPoint2
        
    #矩阵的叉乘。这里其实是向量的叉乘
    @staticmethod
    def crossProduct(a, b):
        c = []
        c.append(a[1] * b[2] - a[2] *b[1])
        c.append(a[2] * b[0] - a[0] *b[2])
        c.append(a[0] * b[1] - a[1] *b[0])
        return c

    #矩阵的点乘。这里其实是向量的点乘
    @staticmethod
    def dotProduct(a, b):
        c = a[0] * b[0] + a[1] * b[1] + a[2] *b[2]
        return c    
    
    #矩阵的Normalize。这里求的是向量的长度,用来将向量转化成单位向量
    @staticmethod
    def normalize(v):
        return math.sqrt(v[0]**2 + v[1]**2 + v[2]**2)    
    
    #根据罗德里格斯旋转公式,计算旋转矩阵。
    #注意,得到旋转矩阵之后,可以进一步计算出绕x轴、y轴、z轴的角度是多少。虽然这些角度在本例中没有意义
    #angle: 两个空间向量之间的角度; u:三个坐标轴
    @staticmethod
    def getRotationMatrix(angle, u):
        norm = Move_and_Rotation.normalize(u)
        rotationMatrix = []
        u[0] /= norm #转换成单位向量
        u[1] /= norm #转换成单位向量
        u[2] /= norm #转换成单位向量
        
        cos = math.cos(angle)
        sin = math.sin(angle)
        
        #布置好矩阵的size
        for i in range(3):
            rotationMatrix.append([])
            for j in range(3):
                rotationMatrix[-1].append([])
        
        rotationMatrix[0][0] = cos + u[0] * u[0] * (1 - cos)
        
        #https://www.cnblogs.com/xpvincent/archive/2013/02/15/2912836.html中的评论提到
        #rotatinMatrix[0, 1]里的括号似乎也有点小问题.
        #原来的表达式为:
        #rotationMatrix[0][1] = u[0] * u[1] * (1 - cos - u[2] * sin)
        #应该修改为如下表达式: 
        rotationMatrix[0][1] = u[0] * u[1] * (1 - cos) - u[2] * sin
        rotationMatrix[0][2] = u[1] * sin + u[0] * u[2] * (1 - cos)
         
        rotationMatrix[1][0] = u[2] * sin + u[0] * u[1] * (1 - cos)
        rotationMatrix[1][1] = cos + u[1] * u[1] * (1 - cos)
        rotationMatrix[1][2] = -u[0] * sin + u[1] * u[2] * (1 - cos)
 
        rotationMatrix[2][0] = -u[1] * sin + u[0] * u[2] * (1 - cos)
        rotationMatrix[2][1] = u[0] * sin + u[1] * u[2] * (1 - cos)
        rotationMatrix[2][2] = cos + u[2] * u[2] * (1 - cos)

        return rotationMatrix
        
    #根据两个向量,计算旋转矩阵。外部代码不要直接调用本函数
    #根据旋转前后的向量值求旋转矩阵: https://wenku.baidu.com/view/d914b9b96137ee06eff9189f.html
    @staticmethod
    def calculationRoationMatrixByTwoVector(vectorBefore, vectorAfter):   
        rotationAxis = Move_and_Rotation.crossProduct(vectorBefore, vectorAfter)
        rotationAngle=math.acos(Move_and_Rotation.dotProduct(vectorBefore,vectorAfter) /Move_and_Rotation.normalize(vectorBefore) /Move_and_Rotation.normalize(vectorAfter))
        
        rotationMatrix = Move_and_Rotation.getRotationMatrix(rotationAngle, rotationAxis)
        return rotationMatrix
        
    #根据3个Point,计算旋转矩阵,
    #其中p1是固定不动的点,p2经过一定的角度后移动到p2'。 p1, p2', p3等三个点在同一直线上
    #其中     p2' 是虚拟点。参数列表中只给出p1, p2, p3等三个点。由于在后续计算中将两个向量都转化成单位向量了,所以不需要计算出 p2'的坐标
    #另外,这里p1必须是坐标原点,也就是(0, 0, 0),如果不是坐标原点,会导致计算错误
    #外部代码调用本函数
    @staticmethod
    def calculationRoationMatrixByThreePoints(p1, p2, p3):
        vectorBefore = [p2.x - p1.x, p2.y - p1.y, p2.z - p1.z]
        vectorAfter =  [p3.x - p1.x, p3.y - p1.y, p3.z - p1.z]
        #print(p1.toString())
        rotationMatrix = np.array(Move_and_Rotation.calculationRoationMatrixByTwoVector(vectorBefore, vectorAfter)) 
        return rotationMatrix

ps: 结构式平移、结构式绕着空间中一条直线旋转、结构式转向一个点,这三块代码花了我一两个月的时间。其中艰难不必多言,以此文纪念那段时间。

相关标签: 几何学