问题
我需要计算两条线之间的差异(即从另一条线中减去一条线),这应该会产生一条输出线。
输入线和输出线可能包括垂直部分。 IE。线的 X 值可能不是单调递增的(尽管它们不会自行返回)。
这可能是最容易用示例来演示的:
输入:
# lines represented as arrays of (X,Y) coordinates
line1 = [ (0,2), (4,2), (5,10), (15,10), (16,0), (20,0) ]
line2 = [ (0,2), (5,2), (10,5), (15,5), (15,0), (20,0) ]
这由以下图表表示(用 Excel 制作):
输出:
理想情况下,我正在寻找一个可以将
line1
和 line2
作为输入的库,并输出代表线之间差异的顶点(又名 line1
减去 line2
)。所以对于这个例子:
[ (0,0), (4,0), (5,8), (10,5), (15,5), (15,10), (16,0), (20,0) ]
再次,用图表可能更容易可视化 - 但请注意,我正在寻找一个将结果输出为 Python 对象的库 - 理想情况下是顶点或类似的 - 而不是一个只绘制图表的库:
有关输入和输出数据的注释:
line1
和 line2
不包含所有相同的 X 值line2
在 X=15 处包含重复点,因为从 (X=15,Y=5)
到 (X=15,Y=0)
有一条垂直线。我研究过的潜在解决方案
我对Python生态系统相对较新,并且不是数学/几何/图形专家。我尝试过研究各种 Python 库,但这些库的文档通常大量使用数学术语,因此我完全有可能遗漏了一些明显的东西。
Pandas Series - 看起来这会完美地工作if我有单调递增的X值...但我不...
SymPy Geometry - 它may可以用SymPy以我想要的方式减去2d线/多边形,但我无法在文档中找到任何明显的东西...
SciPy - 这个 StackOverflow 答案 使用
scipy.interpolate.interp1d
做几乎我想做的事...
据我所知,您可以提供
interp1d
一系列点包括重复的X值,它将正确地表示线条的形状:
>>> x_values = [0,1,1]
>>> y_values = [0,0,10]
>>> curve = sc.interpolate.interp1d(x_values, y_values)
>>> curve(0)
array(0.)
>>> curve(1)
array(10.)
>>> curve(0.9999)
array(0.)
X=1 处有一条垂直线,因此获取 X 处的 Y 值<1 gives 0, while X=1 gives 10.
但是,如果我要做类似上面链接的 Stack Overflow 答案的事情:
# This would lose the duplicates representing the vertical line
all_x_values = sorted(set(line1_x_values + line2_x_values))
# Even if we had maintained all the X values, in our original example we would
# have two X=15 values here... The first call to line1(15) would need to return
# Y = 5, the second call to line1(15) would need to return Y = 0...
new_line_y_values = [line1(x) - line2(x) for x in all_x_values]
# And if we got this far with everything working, how do we extract the vertices
# from the new line - including multiple points at the same X-value for any vertical
# lines?
new_line = scipy.interpolate.interp1d(all_x_values, new_line_y_values)
AFAIK,库中没有预建函数,但你可以做纯Python:
line3 = [
(i, t1[1]-t2[1])
for i in set(x for x,y in [xy for xy in [*line1, *line2]])
for t1 in [(x,y) for x,y in line1 if x==i] or [(0, i)]
for t2 in [(x,y) for x,y in line2 if x==i] or [(0, t1[1])]
]
输出:
line3 # [(0, 0), (4, 0), (5, 8), (10, 5), (15, 5), (15, 10), (16, 0), (20, 0)]