我正在尝试使用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:如果您发现其他任何改进,也请按照我的方式发送。 :)
答案 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()