'How would I get the angle between 2 3D vectors A & B on the plane normal to a 3rd vector C (preferably but not necessarily in Python)?

Something I pieced together with stuff I found online already is:


import cmath
import math
import numpy
# from mathutils import Vector
class Vector(list):
    pass # Im actually using "Vector" from mathutils as above, where mathutils is a library provided by Blender Bpy. But as thats not available as a Python package  we can substitute this class by a list.


class fastVectorMath():
    "provides tools for when working with vectors. Do not instanciate me"
    def vectorSubtract(v1,v2):
        try:
            return ([v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2],])
        except:
            return ([v1[0]-v2[0], v1[1]-v2[1]])

    def radiansToDegrees(radians: float) -> float:
        return radians*180/cmath.pi
        

    def normalizeVector(vector):
        """ Returns the normalized (unit vector) of the vector.  """
        return vector / numpy.linalg.norm(vector)

    def getAngleBetweenV1andV2AroundOriginInDegrees(v1: Vector, v2: Vector, origin: Vector): # Tested and works
        """ Returns the angle in degrees between vectors 'v1' and 'v2 in the range of 0 to 360'::

                >>> angle_between((1, 0, 0), (0, 1, 0))
                90,00000000022325
                >>> angle_between((1, 0, 0), (1, 0, 0))
                0.0
                >>> angle_between((1, 0, 0), (-1, 0, 0))
                180,0000000004465
        """
        v1 = fastVectorMath.vectorSubtract(v1, origin)
        v2 = fastVectorMath.vectorSubtract(v2, origin)
        v1_u = fastVectorMath.nNormalizeVector(v1)
        v2_u = fastVectorMath.normalizeVector(v2)
        # v1_u = unit_vector(v1 - origin)
        # v2_u = unit_vector(v2 - origin)
        # print()
        angleInDegreesUnsigned = fastVectorMath.radiansToDegrees(numpy.arccos(numpy.clip(numpy.dot(v1_u, v2_u), -1.0, 1.0)))
        # print(f"CROOOOSSSS {numpy.cross(v1_u, v2_u)}")
        angleInDegreesSigned = angleInDegreesUnsigned + 180 if (float((numpy.cross(v1_u, v2_u)[-1] > 0)-0.5)*2) else 0
        return angleInDegreesSigned

Where I have my method def getAngleBetweenV1andV2AroundOriginInDegrees(v1: Vector, v2: Vector, origin: Vector), which takes 2 vectors and an origin point. Now I would like to basically add a 3rd input to it, namely a 3rd vector to get the rotation about.

To make it more clear what I want, my question is essentially the same as https://math.stackexchange.com/questions/511370/how-to-rotate-one-vector-about-another , except Im not actually looking for the final vector, but instead get the angle based on the 3 vectors.

Thanks!



Solution 1:[1]

The orthogonal projection of A parallelly to C can be obtained from A' = A + k C and A'.C = A.C + k C² = 0, giving A' = A - (A.C / C²) C. Repeat for B' and take the cosine by cos ? = A'.B'/|A'||B'|.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Yves Daoust