Python 3.x 如何在python中检查向量何时旋转一圈

Python 3.x 如何在python中检查向量何时旋转一圈,python-3.x,computational-geometry,Python 3.x,Computational Geometry,我实际上是在处理表示2d空间中(大致)嘈杂圆圈的数据。我一次采集一个点的数据,目标是知道这些点何时形成一个圆 为了做到这一点,我将每个连续的点视为只有一个稍微转动的向量。为了知道什么时候转了一圈(也就是说什么时候形成了圆),我检查了x和y坐标是否两次改变了符号(也就是说向量已经转了2*0.5圈=1圈)。然后我再等半圈来补偿启动错误。事实上,这取决于它在最初的四分之一空间中的起始位置,它可能没有完成一个完整的转弯 我不需要非常精确。所以这对我来说很好,但我想知道是否有另一种方法更有效,可以告诉我实

我实际上是在处理表示2d空间中(大致)嘈杂圆圈的数据。我一次采集一个点的数据,目标是知道这些点何时形成一个圆

为了做到这一点,我将每个连续的点视为只有一个稍微转动的向量。为了知道什么时候转了一圈(也就是说什么时候形成了圆),我检查了x和y坐标是否两次改变了符号(也就是说向量已经转了2*0.5圈=1圈)。然后我再等半圈来补偿启动错误。事实上,这取决于它在最初的四分之一空间中的起始位置,它可能没有完成一个完整的转弯

我不需要非常精确。所以这对我来说很好,但我想知道是否有另一种方法更有效,可以告诉我实际的圈数。这可能会加快一点过程,因为积分到达的速度很慢(避免我再等一个无用的半圈)

重要的一点是,我只能使用Numpy

编辑:更精确地说,每个点之间的距离不是规则的。首先,圆圈开始慢慢形成,然后加速。因此,开始时的点比结束时的点更密集。另一件事是,(0,0)点甚至可能不包含在圆中。最后,我说的是大致呈圆形,因为它往往是省略号形状,但形状不是很糟糕,只是有噪音


很抱歉,我不能提供数据,至少现在是这样。我将告诉您这周是否可行。

如果保证每个新数据点的极角大于前一个,即圆以增量形式形成,且过程中没有任何点“后退”,然后,对于每一对连续的点,你可以计算它们之间的角度,然后当总和达到2π时,你可以停止。例如:

angle = 0
points = [next(generator)]  # 'generator' produces the data points
while angle < 2*pi:
    points.append(next(generator))
    angle += np.arccos(
        np.dot(points[-2], points[-1]) / 
        (np.linalg.norm(points[-2]) * np.linalg.norm(points[-1]))
    )
del points[-1]  # optionally delete the last point in order to stay below 2 pi
角度=0
points=[next(generator)]#“generator”生成数据点
当角度<2*pi时:
添加点(下一个(生成器))
角度+=np.arccos(
np.点(点[-2],点[-1])/
(np.linalg.norm(点[-2])*np.linalg.norm(点[-1]))
)
删除点[-1]#可选择删除最后一点,以保持在2π以下
以下是使用上述方法绘制的示例图:

以及示例代码:

from math import pi
import random

import matplotlib.pyplot as plt
import numpy as np


def generate():
    angle = 0
    angle_upper_lim = 0.002
    while True:
        angle += 2*pi * random.uniform(0.001, angle_upper_lim)
        radius = random.uniform(0.95, 1.05)
        yield radius*np.cos(angle), radius*np.sin(angle)
        angle_upper_lim *= 1.03  # make the circle fill faster


generator = generate()

angle = 0
points = [next(generator)]  # 'generator' produces the data points
while angle < 2*pi:
    points.append(next(generator))
    angle += np.arccos(
        np.dot(points[-2], points[-1]) / 
        (np.linalg.norm(points[-2]) * np.linalg.norm(points[-1]))
    )
del points[-1]  # optionally delete the last point in order to stay below 2 pi

fig, ax = plt.subplots()
ax.scatter(*np.stack(points, axis=1), s=5)
ax.set_title(f'Total angle: {angle/pi:.2f} pi')
ax.plot([0, points[ 0][0]], [0, points[ 0][1]], '--s', ms=8, label='First point', color='#2ca02c')
ax.plot([0, points[-1][0]], [0, points[-1][1]], '--*', ms=12, label='Last point', color='#ff7f0e')
ax.legend()

plt.show()
from math import pi
import random

import matplotlib.pyplot as plt
import numpy as np


def generate():
    angle = pi/4
    angle_upper_lim = 0.002
    while True:
        angle += 2*pi * random.uniform(0.001, angle_upper_lim)
        radius = 1
        yield np.array([3 + radius*np.cos(angle), 5 + radius*np.sin(angle)])
        angle_upper_lim *= 1.03  # make the circle fill faster


generator = generate()

angle = 0
offset = next(generator)  # 'generator' produces the data points
points = [next(generator) - offset]
while angle <= pi:
    points.append(next(generator) - offset)
    angle += np.arccos(
        np.dot(points[-2], points[-1]) / 
        (np.linalg.norm(points[-2]) * np.linalg.norm(points[-1]))
    )
del points[-1]  # optionally delete the last point in order to stay below pi

fig, ax = plt.subplots(figsize=(4.8, 4.8))
ax.scatter(*np.stack(points, axis=1), s=5, c=np.arange(len(points)))
ax.set_title(f'Total angle: {angle/pi:.2f} pi')
ax.plot(*points[ 0], 's', ms=8, label='First point', color='#2ca02c')
ax.plot(*points[-1], '*', ms=12, label='Last point', color='#ff7f0e')
ax.legend()

plt.show()
from math import pi
import random

import matplotlib.pyplot as plt
import numpy as np


def generate():
    angle = pi/4
    angle_upper_lim = 0.002
    while True:
        angle += 2*pi * random.uniform(0.001, angle_upper_lim)
        # radius = random.uniform(0.95, 1.05)
        radius = 1
        yield np.array([3 + radius*np.cos(angle), 5 + radius*np.sin(angle)])
        angle_upper_lim *= 1.03  # make the circle fill faster


generator = generate()


def next_point(n=1):
    """n: number of points per group"""
    return sum(next(generator) for __ in range(n)) / n


distances = []
points = [next_point()]
while True:  # break below
    points.append(next_point())
    distances.append(np.linalg.norm(points[-1] - points[0]))
    if len(distances) >= 3:
        left = distances[-2] - distances[-3]
        right = distances[-1] - distances[-2]
        if left < 0 and right > 0:  # minimum detected
            break
del points[-1], distances[-1]  # optionally delete the last point in order to leave the circle open

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.8, 4.8))
plt.subplots_adjust(wspace=0.11)
ax1.set_title('Data points')
ax1.scatter(*np.stack(points, axis=1), s=5, c=np.arange(len(points)))
ax1.plot(*points[ 0], 's', ms=8, label='First point', color='#2ca02c')
ax1.plot(*points[-1], '*', ms=12, label='Last point', color='#ff7f0e')
ax1.legend(loc='center')

ax2.set(title='Distance of circle points to first point', xlabel='Point #', ylabel='Distance')
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right')
ax2.plot(distances, '-o', ms=4)
ax2.plot(len(distances)-1, distances[-1], '*', ms=10, label='circle closed')
ax2.legend()

plt.show()
从数学导入pi
随机输入
将matplotlib.pyplot作为plt导入
将numpy作为np导入
def generate():
角度=0
角度_上_直线=0.002
尽管如此:
角度+=2*pi*随机均匀(0.001,角度上界)
半径=随机均匀(0.95,1.05)
屈服半径*np.cos(角度),半径*np.sin(角度)
角度_upper_lim*=1.03#使圆填充速度更快
生成器=生成()
角度=0
points=[next(generator)]#“generator”生成数据点
当角度<2*pi时:
添加点(下一个(生成器))
角度+=np.arccos(
np.点(点[-2],点[-1])/
(np.linalg.norm(点[-2])*np.linalg.norm(点[-1]))
)
删除点[-1]#可选择删除最后一点,以保持在2π以下
图,ax=plt.子批次()
最大散射(*np.叠加(点,轴=1),s=5)
ax.set_title(f'总角度:{angle/pi:.2f}pi')
ax.plot([0,点[0][0]],[0,点[0][1]],'-s',ms=8,label='First point',color='2ca02c')
ax.plot([0,点[-1][0]],[0,点[-1][1]],'-*',ms=12,label='Last point',color='#ff7f0e')
ax.图例()
plt.show()

您可以使用第一个点作为偏移量,该偏移量将从所有点中减去。这会将圆的边移动到原点。现在想象一条与圆相切的直线(在任意点,但我们将使用原点),然后圆完全位于切线的一侧。切线本身跨越180度,如果我们从原点开始沿着圆走,总是测量连续向量之间的角度,那么一旦我们回到原点,我们将总共测量180度(如果圆上的点之间的间隔是无限小的)。这允许计算角度的累积和,并在达到180度(=π)时停止。现在,由于实际上这些点的间距是有限的,我们将错过圆的起点和终点(原点的w.r.t.)180度的一部分。这意味着,当我们达到180度时,我们收集的点将略多于闭合圆所需的点;OP表示这是所需的行为,即圆必须闭合(有些重叠比不闭合好)

这是算法的相关代码:

angle = 0
offset = next(generator)  # 'generator' produces the data points
points = [next(generator) - offset]
while angle <= pi:
    points.append(next(generator) - offset)
    angle += np.arccos(
        np.dot(points[-2], points[-1]) / 
        (np.linalg.norm(points[-2]) * np.linalg.norm(points[-1]))
    )
del points[-1]  # optionally delete the last point in order to stay below pi
distances = []
points = [next_point()]
while True:  # break below
    points.append(next_point())
    distances.append(np.linalg.norm(points[-1] - points[0]))
    if len(distances) >= 3:
        left = distances[-2] - distances[-3]
        right = distances[-1] - distances[-2]
        if left < 0 and right > 0:  # minimum detected
            break
del points[-1], distances[-1]  # optionally delete the last point in order to leave the circle open
角度=0
偏移量=下一个(生成器)#“生成器”生成数据点
点=[下一个(生成器)-偏移]

当角度时,您可以监控每个点到第一个点的距离,当该距离达到最小值时,表示圆已闭合。下图显示了到圆上第一个点的点距离图:

这是算法的相关代码:

angle = 0
offset = next(generator)  # 'generator' produces the data points
points = [next(generator) - offset]
while angle <= pi:
    points.append(next(generator) - offset)
    angle += np.arccos(
        np.dot(points[-2], points[-1]) / 
        (np.linalg.norm(points[-2]) * np.linalg.norm(points[-1]))
    )
del points[-1]  # optionally delete the last point in order to stay below pi
distances = []
points = [next_point()]
while True:  # break below
    points.append(next_point())
    distances.append(np.linalg.norm(points[-1] - points[0]))
    if len(distances) >= 3:
        left = distances[-2] - distances[-3]
        right = distances[-1] - distances[-2]
        if left < 0 and right > 0:  # minimum detected
            break
del points[-1], distances[-1]  # optionally delete the last point in order to leave the circle open
距离=[] 点=[下一个点()] 如果为True:#请在下面打断 points.append(next_point()) 距离.附加(np.linalg.norm(点[-1]-点[0])) 如果len(距离)>=3: 左=距离[-2]-距离[-3] 右=距离[-1]-距离[-2] 如果左侧<0且右侧>0:#检测到最小值 打破 删除点[-1],距离[-1]#可以选择删除最后一个点,以保持圆打开
在改变角度差和半径的数据集上进行测试,得到以下结果:

以下是完整的示例代码:

from math import pi
import random

import matplotlib.pyplot as plt
import numpy as np


def generate():
    angle = 0
    angle_upper_lim = 0.002
    while True:
        angle += 2*pi * random.uniform(0.001, angle_upper_lim)
        radius = random.uniform(0.95, 1.05)
        yield radius*np.cos(angle), radius*np.sin(angle)
        angle_upper_lim *= 1.03  # make the circle fill faster


generator = generate()

angle = 0
points = [next(generator)]  # 'generator' produces the data points
while angle < 2*pi:
    points.append(next(generator))
    angle += np.arccos(
        np.dot(points[-2], points[-1]) / 
        (np.linalg.norm(points[-2]) * np.linalg.norm(points[-1]))
    )
del points[-1]  # optionally delete the last point in order to stay below 2 pi

fig, ax = plt.subplots()
ax.scatter(*np.stack(points, axis=1), s=5)
ax.set_title(f'Total angle: {angle/pi:.2f} pi')
ax.plot([0, points[ 0][0]], [0, points[ 0][1]], '--s', ms=8, label='First point', color='#2ca02c')
ax.plot([0, points[-1][0]], [0, points[-1][1]], '--*', ms=12, label='Last point', color='#ff7f0e')
ax.legend()

plt.show()
from math import pi
import random

import matplotlib.pyplot as plt
import numpy as np


def generate():
    angle = pi/4
    angle_upper_lim = 0.002
    while True:
        angle += 2*pi * random.uniform(0.001, angle_upper_lim)
        radius = 1
        yield np.array([3 + radius*np.cos(angle), 5 + radius*np.sin(angle)])
        angle_upper_lim *= 1.03  # make the circle fill faster


generator = generate()

angle = 0
offset = next(generator)  # 'generator' produces the data points
points = [next(generator) - offset]
while angle <= pi:
    points.append(next(generator) - offset)
    angle += np.arccos(
        np.dot(points[-2], points[-1]) / 
        (np.linalg.norm(points[-2]) * np.linalg.norm(points[-1]))
    )
del points[-1]  # optionally delete the last point in order to stay below pi

fig, ax = plt.subplots(figsize=(4.8, 4.8))
ax.scatter(*np.stack(points, axis=1), s=5, c=np.arange(len(points)))
ax.set_title(f'Total angle: {angle/pi:.2f} pi')
ax.plot(*points[ 0], 's', ms=8, label='First point', color='#2ca02c')
ax.plot(*points[-1], '*', ms=12, label='Last point', color='#ff7f0e')
ax.legend()

plt.show()
from math import pi
import random

import matplotlib.pyplot as plt
import numpy as np


def generate():
    angle = pi/4
    angle_upper_lim = 0.002
    while True:
        angle += 2*pi * random.uniform(0.001, angle_upper_lim)
        # radius = random.uniform(0.95, 1.05)
        radius = 1
        yield np.array([3 + radius*np.cos(angle), 5 + radius*np.sin(angle)])
        angle_upper_lim *= 1.03  # make the circle fill faster


generator = generate()


def next_point(n=1):
    """n: number of points per group"""
    return sum(next(generator) for __ in range(n)) / n


distances = []
points = [next_point()]
while True:  # break below
    points.append(next_point())
    distances.append(np.linalg.norm(points[-1] - points[0]))
    if len(distances) >= 3:
        left = distances[-2] - distances[-3]
        right = distances[-1] - distances[-2]
        if left < 0 and right > 0:  # minimum detected
            break
del points[-1], distances[-1]  # optionally delete the last point in order to leave the circle open

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.8, 4.8))
plt.subplots_adjust(wspace=0.11)
ax1.set_title('Data points')
ax1.scatter(*np.stack(points, axis=1), s=5, c=np.arange(len(points)))
ax1.plot(*points[ 0], 's', ms=8, label='First point', color='#2ca02c')
ax1.plot(*points[-1], '*', ms=12, label='Last point', color='#ff7f0e')
ax1.legend(loc='center')

ax2.set(title='Distance of circle points to first point', xlabel='Point #', ylabel='Distance')
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right')
ax2.plot(distances, '-o', ms=4)
ax2.plot(len(distances)-1, distances[-1], '*', ms=10, label='circle closed')
ax2.legend()

plt.show()
从数学导入pi
随机输入
将matplotlib.pyplot作为plt导入
将numpy作为np导入
def generate():
角度=π/4
角度_上_直线=0.002
尽管如此:
角度+=2*pi*随机均匀(0.001,角度上界)
#半径=随机均匀(0.95,1.05)
半径=