考虑到每一个点的位置和方向,如何连接这些点?

3
在附图中,我们可以看到一个点的运动的实际值(绿色)和估计值(红色)。圆圈旁的每个数字(=模式)对应一个时间。现在所有算法都已开发完毕,我想通过连接所有模式来提高可视化质量,考虑位置和方向(由条纹方向定义)。我试图找到一种方法来做到这一点,但没有找到。有人有想法吗?
补充说明:
  • 我希望按照每个模式旁边的数字的顺序连接所有模式
  • 我希望我的曲线经过每个模式的中心
  • 我希望每个模式上的曲线陡峭程度与绘制的条形相同。
关于信息:我拥有坐标(x,y)和角度,如果需要可以将其转换为导数。
总之,我正在寻找一种连接点并适合每个点所需陡度的绘制曲线的方法。

你需要更详细地解释“连接所有模式在一起”的意思,否则,没有人能够理解你想做什么。另外,实现这个目标的确切问题是什么?你尝试过什么,为什么不起作用?如果你不说明问题所在,这个问题很可能太广泛而无法回答。 - ImportanceOfBeingErnest
谢谢你的留言!我已经编辑过了。希望这能帮助理解我想要连接模式的方式。我的主要问题是找不到任何允许我做我想做的事情的函数。我期望有人曾经尝试过做同样的事情,可以给我一些提示,告诉我如何完成这个任务。 - Cyril Schmitt
我认为你不会找到一个预定义的函数来完成你想要的操作,因为问题是二维的(实际上你有二维梯度,而不是一维导数),因此连接这些点没有唯一的解。如果这是一个一维问题,像 scipy.interpolate.KroghInterpolator 这样的函数可能会帮助你。然而,在这种情况下,它将失败。 - ImportanceOfBeingErnest
请问您能否提供生成该图片所使用的代码(背景不需要),以及用于产生这5个点的数据? - Thomas Kühn
@Thomas 如果你想尝试一下,可以使用我在下面回答中提供的数据。如果有人对如何“拟合”贝塞尔曲线或采用不同的方法有想法,那肯定很有趣。 - ImportanceOfBeingErnest
1个回答

11
总结问题:您想通过多个点插值出平滑曲线。对于2D空间中的每个点,您都有坐标以及定义该点处曲线切线的角度。
一种解决方案可能是使用三阶贝塞尔曲线。这样的曲线由4个点定义;两个端点是绘图中的连续两个点,另外两个中间点定义了曲线的方向。贝塞尔曲线经常用于图形软件中,并且也被matplotlib内部用于绘制路径。

enter image description here

因此,我们可以定义一条贝塞尔曲线,其两个中间点位于沿着每个点的切线给定的角度。本质上没有提示这两个中间点应该位于该切线的何处,因此我们可以选择一些任意距离从两个端点开始。这就是下面代码中所谓的r。选择一个好的参数r的值对于获得平滑曲线非常关键。

import numpy as np
from scipy.special import binom
import matplotlib.pyplot as plt

bernstein = lambda n, k, t: binom(n,k)* t**k * (1.-t)**(n-k)

def bezier(points, num=200):
    N = len(points)
    t = np.linspace(0, 1, num=num)
    curve = np.zeros((num, 2))
    for i in range(N):
        curve += np.outer(bernstein(N - 1, i, t), points[i])
    return curve

class Segment():
    def __init__(self, p1, p2, angle1, angle2, **kw):
        self.p1 = p1; self.p2 = p2
        self.angle1 = angle1; self.angle2 = angle2
        self.numpoints = kw.get("numpoints", 100)
        method = kw.get("method", "const")
        if method=="const":
            self.r = kw.get("r", 1.)
        else:
            r = kw.get("r", 0.3)
            d = np.sqrt(np.sum((self.p2-self.p1)**2))
            self.r = r*d
        self.p = np.zeros((4,2))
        self.p[0,:] = self.p1[:]
        self.p[3,:] = self.p2[:]
        self.calc_intermediate_points(self.r)

    def calc_intermediate_points(self,r):
        self.p[1,:] = self.p1 + np.array([self.r*np.cos(self.angle1),
                                    self.r*np.sin(self.angle1)])
        self.p[2,:] = self.p2 + np.array([self.r*np.cos(self.angle2+np.pi),
                                    self.r*np.sin(self.angle2+np.pi)])
        self.curve = bezier(self.p,self.numpoints)


def get_curve(points, **kw):
    segments = []
    for i in range(len(points)-1):
        seg = Segment(points[i,:2], points[i+1,:2], points[i,2],points[i+1,2],**kw)
        segments.append(seg)
    curve = np.concatenate([s.curve for s in segments])
    return segments, curve


def plot_point(ax, xy, angle, r=0.3):
    ax.plot([xy[0]],[xy[1]], marker="o", ms=9, alpha=0.5, color="indigo")
    p = xy + np.array([r*np.cos(angle),r*np.sin(angle)])
    ax.plot([xy[0],p[0]], [xy[1],p[1]], color="limegreen")


if __name__ == "__main__":        
    #                   x    y    angle        
    points =np.array([[ 6.0, 0.5, 1.5],
                      [ 5.4, 1.2, 2.2],
                      [ 5.0, 1.7, 2.6],
                      [ 2.8, 2.4, 2.1],
                      [ 1.3, 3.2, 1.6],
                      [ 1.9, 3.9,-0.2],
                      [ 4.0, 3.0, 0.2],
                      [ 5.1, 3.7, 1.4]])

    fig, ax = plt.subplots()

    for point in points:
        plot_point(ax, point[:2],point[2], r=0.1)

    s1, c1 = get_curve(points, method="const", r=0.7)
    ax.plot(c1[:,0], c1[:,1], color="crimson", zorder=0, label="const 0.7 units")

    s2, c2 = get_curve(points, method="prop", r=0.3)
    ax.plot(c2[:,0], c2[:,1], color="gold", zorder=0, label="prop 30% of distance")
    plt.legend()
    plt.show()

enter image description here

在上面的图表中,比较了两种情况。一种是当r保持不变时为0.7个单位,另一种是当r相对于两点之间的距离增加30%时。

1
这正是我正在寻找的。非常感谢您详细的解释!这非常有帮助! - Cyril Schmitt
3
好的。请注意以下内容:这个问题本身的质量相当低,通常会被忽略或关闭(参见[ask]);我之所以在这里提供答案,仅仅是因为我自己发现深入探讨很有趣,因为我以前从未做过这样的事情。但我猜下次你问问题时不能指望这种情况再次发生。 - ImportanceOfBeingErnest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接