查找两个 3D 向量的所有正负组合之间的角度

Finding the angle between all positive and negative combinations of two 3D vectors

根据 this problem 计算两个 3D 角度之间的角度,我想扩展它以计算角度的所有可能的正负组合。

例如,我从计算 (1,1,5) 和 (-1,1,2) 之间的角度的相同 link 中获得以下代码:

import numpy as np
import vg

vec1 = np.array([1, 1, 5])
vec2 = np.array([-1, 1, 2])

angle= vg.angle(vec1, vec2)
print(angle)

现在我想要一个小函数来计算每个向量的所有可能的正负组合,并给出所有角度的列表。

例如,它计算以下对:(1,1,5)(-1,1,2), (1,1,-5)(-1,1,2), (1,- 1,-5)(-1,1,2) 等。这看起来很简单,但我想不通。

附带问题:我如何通过 input() 函数获取向量?我知道它如何处理字符串和数字,但你能要求它从用户那里获取特殊格式的输入数据吗?喜欢 (1,2,3)?

更新:在为每个向量创建 8 个变体后,itertools.product() 用于查找所有变体的所有成对组合。每个组合中的两个项目首先转换回 np.arrays,然后再送入 vg.angle() 以构造所有角度。

import itertools as it
import numpy as np
import vg

vector1 = np.array([1,1,5])
vector2 = np.array([-1,-1,2])

def vector_variants(vector):
    pairs = [[i, -i] for i in vector]
    return [[i,j,k] for i in pairs[0] for j in pairs[1] for k in pairs[2]]

v1_variants = vector_variants(vector1)
v2_variants = vector_variants(vector2)

combos = list(it.product(v1_variants, v2_variants))
angles = [vg.angle(np.array(item[0]), np.array(item[1])) for item in combos]

最后,所有 64 个矢量组合及其对应的角度都可以作为 Pandas 数据帧很好地置换:

import pandas as pd

df = pd.DataFrame([(item[0], item[1], vg.angle(np.array(item[0]), np.array(item[1])))
                   for item in combos],columns=['v1', 'v2','angle'])
print(df)

#output:
              v1            v2       angle
0      [1, 1, 5]   [-1, -1, 2]   51.057559
1      [1, 1, 5]  [-1, -1, -2]  160.528779
2      [1, 1, 5]    [-1, 1, 2]   38.216923
3      [1, 1, 5]   [-1, 1, -2]  141.783077
4      [1, 1, 5]    [1, -1, 2]   38.216923
..           ...           ...         ...
59  [-1, -1, -5]   [-1, 1, -2]   38.216923
60  [-1, -1, -5]    [1, -1, 2]  141.783077
61  [-1, -1, -5]   [1, -1, -2]   38.216923
62  [-1, -1, -5]     [1, 1, 2]  160.528779
63  [-1, -1, -5]    [1, 1, -2]   51.057559

[64 rows x 3 columns]

vec_comb[:,:3] 具有 vec1 的所有组合,而 vec_comb[:,3:] 具有 vec2

的所有组合
import numpy as np
import vg
import itertools


vec1 = np.array([1, 1, 5])
vec2 = np.array([-1, 1, 2])

vec_concat = np.hstack((vec1, vec2))


l = [1,-1]
comb = np.array(list(itertools.product(l, repeat=vec_concat.shape[0])))

vec_comb = np.einsum('i, ji -> ji', vec_concat, comb)
angle_comb = vg.angle(vec_comb[:,:3], vec_comb[:, 3:])
print(angle_comb)

输出:

[ 38.2169233  141.7830767   51.05755873 160.52877937  19.47122063
 128.94244127  38.2169233  141.7830767  141.7830767   38.2169233
 160.52877937  51.05755873 128.94244127  19.47122063 141.7830767
  38.2169233   51.05755873 160.52877937  38.2169233  141.7830767
  38.2169233  141.7830767   19.47122063 128.94244127 160.52877937
  51.05755873 141.7830767   38.2169233  141.7830767   38.2169233
 128.94244127  19.47122063  19.47122063 128.94244127  38.2169233
 141.7830767   38.2169233  141.7830767   51.05755873 160.52877937
 128.94244127  19.47122063 141.7830767   38.2169233  141.7830767
  38.2169233  160.52877937  51.05755873  38.2169233  141.7830767
  19.47122063 128.94244127  51.05755873 160.52877937  38.2169233
 141.7830767  141.7830767   38.2169233  128.94244127  19.47122063
 160.52877937  51.05755873 141.7830767   38.2169233 ]

除非某些分量为零,否则每个向量都会通过改变符号产生八个不同的向量。

这显然会产生 8 x 8 = 64 种组合,但实际上只有 32 种不同,因为 u、v 之间的角度和 -u、-v 之间的角度相同。

为了实现,我会简单地在两个列表中手动硬编码选项(符号中的一个未更改)并在对上进行双循环。