有没有办法找到与另一个向量有已知角度的向量?

时间:2019-07-08 07:29:48

标签: python numpy vector trigonometry hermite

我正在尝试使用numpy实现综合优化的几何Hermite(COH)曲线。这是我正在使用的论文:http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.104.1622&rep=rep1&type=pdf

制作两段式COH曲线的方法1的一部分是找到一个向量,使其为p0和p1之间距离的长度的1/3 ,并与向量p0p1形成角度phi / 2。 / strong>此向量的端点位于p1。

对于2D情况,我想这只是这个伪代码: (length of p0p1 / 3) * [cos(phi/2-angle(p0p1)), sin(phi/2-angle(p0p1))] 对于3D情况,我想这些向量有无限的集合。我想要一个z = 0

我的问题是:是否有一种优雅的方式来做到这两个?

# paper:
# http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.104.1622&rep=rep1&type=pdf

import numpy as np
import matplotlib.pyplot as plt


def unit_vector(V):
    """Returns the unit vector of the vector."""
    return V / np.linalg.norm(V)

def angle_between_vectors(a, b):
    """Returns the angle in radians between vectors a and b"""
    a_u = unit_vector(a)
    b_u = unit_vector(b)
    return np.linalg.norm(np.arccos(np.clip(np.dot(a_u.T, b_u), -1.0, 1.0)))

def OGH(p0, p1, v0, v1, t0, t1, t):
    """Optimized geometric Hermite curve."""
    s = (t-t0)/(t1-t0)
    a0 = (6*np.dot((p1-p0).T, v0)*np.dot(v1.T, v1) - 3*np.dot((p1-p0).T, v1)*np.dot(v0.T, v1)) / ((4*np.dot(v0.T, v0)*np.dot(v1.T, v1) - np.dot(v0.T, v1)*np.dot(v0.T, v1))*(t1-t0))
    a1 = (3*np.dot((p1-p0).T, v0)*np.dot(v0.T, v1) - 6*np.dot((p1-p0).T, v1)*np.dot(v0.T, v0)) / ((np.dot(v0.T, v1)*np.dot(v0.T, v1) - 4*np.dot(v0.T, v0)*np.dot(v1.T, v1))*(t1-t0))
    h0 = (2*s+1)*(s-1)*(s-1)
    h1 = (-2*s+3)*s*s
    h2 = (1-s)*(1-s)*s
    h3 = (s-1)*s*s
    return h0*p0 + h1*p1 + h2*v0*a0 + h3*v1*a1

def COH(p0, p1, v0, v1, t0, t1, t):
    """Composite optimized geometric Hermite curve."""
    # theta is the counterclockwise angle from the vector p0p1 to v0.
    # phi is the counterclockwise angle from the vector p0p1 to v1.
    theta = angle_between_vectors(p1-p0, v0)
    phi = angle_between_vectors(p1-p0, v1)

    # If tangent direction preserving conditions are met, use an OGH.
    if 3*np.cos(theta) > np.cos(theta - 2*phi) and 3*np.cos(phi) > np.cos(phi - 2*theta):
        return OGH(p0, p1, v0, v1, t0, t1, t)

    # Method M1 for generating two-segment COH.
    elif (0 <= theta <= np.pi/6) and (np.pi/3 <= phi <= 2*np.pi/3):
        angle_p0p1 = np.arctan2((p1-p0)[0],(p1-p0)[1])
        T = p1 - (np.linalg.norm(p1-p0)/3) * np.array([np.cos(phi/2 - angle_p0p1), np.sin(phi/2 - angle_p0p1)])
        # vT = ?
        # np.concatenate((OGH(p0,T,v0,vT,t0,t1,t),OGH(T,vT,p1,v1,t0,t1,t)))


p0 = np.array([[-1], [0]])
v0 = np.array([[5], [1]])

p1 = np.array([[1], [0]])
v1 = np.array([[0], [1]])

t0 = 0
t1 = 3

v0 = v0 / np.linalg.norm(v0)
v1 = v1 / np.linalg.norm(v1)

n = 100
a = np.linspace(t0, t1, n)
b = COH(p0, p1, v0, v1, t0, t1, a)

# Plots curve
plt.plot(b[0], b[1])

# Plots tangents
plt.plot([p0[0], (p0+v0)[0]], [p0[1], (p0+v0)[1]])
plt.plot([p1[0], (p1+v1)[0]], [p1[1], (p1+v1)[1]])

plt.show()

寻找T = p1 - (np.linalg ...。其他代码用于上下文。

我的T计算方法似乎太长了。有更好的方法吗?

P.S:如果您发现其他任何改进,也请按照我的方式发送。 :)

1 个答案:

答案 0 :(得分:0)

原来我的代码是一团糟。这似乎适用于2D情况。

import numpy as np
import matplotlib.pyplot as plt

def angle_between_vectors(a, b):
    """Returns the angle in radians between vectors a and b"""
    angle_a = np.arctan2(a[1], a[0])
    angle_b = np.arctan2(b[1], b[0])
    return abs(angle_b - angle_a)[0]

def vector_from_angle(angle : float, magnitude : float = 1):
    """Returns a vector with a given angle and length"""
    return magnitude * np.array([np.cos(angle),np.sin(angle)])

def OGH(p0, p1, v0, v1, t0, t1, t):
    """Optimized geometric Hermite curve."""
    s = (t-t0)/(t1-t0)
    a0 = (6*np.dot((p1-p0).T,v0)*np.dot(v1.T,v1) - 3*np.dot((p1-p0).T,v1)*np.dot(v0.T,v1)) / ((4*np.dot(v0.T,v0)*np.dot(v1.T,v1) - np.dot(v0.T,v1)*np.dot(v0.T,v1))*(t1-t0))
    a1 = (3*np.dot((p1-p0).T,v0)*np.dot(v0.T,v1) - 6*np.dot((p1-p0).T,v1)*np.dot(v0.T,v0)) / ((np.dot(v0.T,v1)*np.dot(v0.T,v1) - 4*np.dot(v0.T,v0)*np.dot(v1.T,v1))*(t1-t0))
    h0 = (2*s+1)*(s-1)*(s-1)
    h1 = (-2*s+3)*s*s
    h2 = (1-s)*(1-s)*s
    h3 = (s-1)*s*s
    return h0*p0 + h1*p1 + h2*v0*a0 + h3*v1*a1

def COH(p0, p1, v0, v1, t0, t1, t):
    """Composite optimized geometric Hermite curve."""
    # theta is the counterclockwise angle from the vector p0p1 to v0.
    # phi is the counterclockwise angle from the vector p0p1 to v1.
    theta = angle_between_vectors(p1-p0, v0)
    phi = angle_between_vectors(p1-p0, v1)

    print("theta: {}pi".format(theta/np.pi))
    print("phi: {}pi".format(phi/np.pi))

    # If tangent direction preserving conditions are met, use an OGH.
    if 3*np.cos(theta) > np.cos(theta - 2*phi) and 3*np.cos(phi) > np.cos(phi - 2*theta):
        return OGH(p0, p1, v0, v1, t0, t1, t)

    # Method M1 for generating two-segment COH.
    elif (0 <= theta <= np.pi/6) and (np.pi/3 <= phi <= 2*np.pi/3):
        pT = p1 - vector_from_angle(phi/2 + np.arctan2((p1-p0)[1],(p1-p0)[0]), np.linalg.norm(p1-p0)/3)
        ang = angle_between_vectors(pT-p0, p1-pT)
        vT = vector_from_angle(ang/2 + np.arctan2((p1-p0)[1],(p1-p0)[0]))
        return np.concatenate([OGH(p0,pT,v0,vT,t0,t1,t),OGH(pT,p1,vT,v1,t0,t1,t)],axis=1)

# Parameters
p0 = np.array([[-1], [-2]])
v0 = np.array([[1], [3]])

p1 = np.array([[1], [0]])
v1 = np.array([[-2], [1]])

t0 = 0
t1 = 1

v0 = v0 / np.linalg.norm(v0)
v1 = v1 / np.linalg.norm(v1)

n : int = 1000
a = np.linspace(t0, t1, n)
b = COH(p0, p1, v0, v1, t0, t1, a)

# Plots curve.
plt.plot(b[0], b[1])

# Plots tangents.
plt.plot([p0[0], (p0+v0)[0]], [p0[1], (p0+v0)[1]], '-r')
plt.plot([p1[0], (p1+v1)[0]], [p1[1], (p1+v1)[1]], '-r')

# Plots p0p1
plt.plot([p0[0],p1[0]], [p0[1],p1[1]], '-b')

plt.show()