线段与多边形相交的点的坐标如何获取

4
我希望找到一条线与多边形相交的点。我使用这个thread中提供的凹多边形轮廓计算方法得到了该多边形。
import alphashape
from shapely.geometry import LineString
import matplotlib.pyplot as plt
from descartes import PolygonPatch

points = [(17, 158),(15, 135),(38, 183),(43, 19),(93, 88),(96, 140),(149, 163),(128, 248),(216, 265),(248, 210),(223, 167),(256, 151),(331, 214),(340, 187),(316, 53),(298, 35),(182, 0),(121, 42)]
points = np.array(points)

alpha = 0.99 * alphashape.optimizealpha(points)
hull = alphashape.alphashape(points, alpha)
hull_pts = hull.exterior.coords.xy
path = PolygonPatch(hull, fill=False, color='green')
print(path.contains_point([128,248]))

fig, ax = plt.subplots()
ax.scatter(hull_pts[0], hull_pts[1], color='red')
ax.scatter(points[:,0], points[:,1], color='red')

p = np.array([[350, 100],[0, 100]])
ax.plot(p[:, 0], p[:, 1], color='blue')
ax.add_patch(path)

enter image description here

到目前为止,我尝试使用以下方式定义一条线:

l = LineString(p)
inters = l.intersection(hull)

但是inters.xy会返回一个NotImplemented错误,所以我不确定如何获得线与多边形相交的点的坐标。

找到线段 y=mx+n 的方程以及每个线段的方程。将这些方程组合起来。平行线没有解。对于有解的线段,您需要检查解是否落在形成该线段的两个点之间。 - user2261062
这条线是水平的吗? - user1196549
@YvesDaoust 它是水平的,也可以是垂直的,但不能倾斜。不过如果答案也允许倾斜线条会更好。 - azerila
2个回答

3

交集函数返回一个MultilineString,也就是一个LineStrings列表。我们可以从每个Linestring中检索坐标,例如:

import alphashape
from shapely.geometry import LineString
import matplotlib.pyplot as plt
import numpy as np

#replicating your example
fig, ax = plt.subplots()

line_xy = [[350, 100],[0, 120]]
points = np.asarray([(17, 158),(15, 135),(38, 183),(43, 19),(93, 88),(96, 140),(149, 163),(128, 248),(216, 265),(248, 210),(223, 167),(256, 151),(331, 214),(340, 187),(316, 53),(298, 35),(182, 0),(121, 42)])

alpha = 0.99 * alphashape.optimizealpha(points)
hull = alphashape.alphashape(points, alpha)
hull_pts = hull.exterior.coords.xy

p = LineString(line_xy)

ax.plot(*hull_pts, c="green")
ax.scatter(points[:,0], points[:,1], marker="o", color="red")
ax.scatter(*hull_pts, marker="s", color="red")

ax.plot(*p.coords.xy, color='blue')

#retrieving intersection 
inters = hull.intersection(p)

#checking for object type to retrieve all intersection coordinates
if inters.type == "LineString":
    coords = np.asarray([inters.coords.xy])
elif inters.type == "MultiLineString":
    coords = np.asarray([l.coords.xy for l in inters.geoms])
    
#reshaping array point coordinates into a form that does not make my head hurt
coords = coords.transpose(1, 0, 2).reshape(2, -1)
print(coords)

plt.show()

使用 coords[:, i] 可以返回交点 i 的 x-y 值。

样例输出:

[[324.67707894 234.24811338 176.4217078   18.88111888]
 [101.44702406 106.61439352 109.91875955 118.92107892]]

enter image description here

奇怪的是,shapely认为像300, 100这样的线段点在外壳内部是一个交点。严格来说,必须检查已确定的点中是否有任何一个位于外壳多边形内部。

而且,alphashape(此处使用的是1.3.1版本)应该更新它们的例程,因为alphashape.alphashape(points, alpha)生成错误消息ShapelyDeprecationWarning: Iteration over multi-part geometries is deprecated and will be removed in Shapely 2.0. Use the geoms property to access the constituent parts of a multi-part geometry.


0

当一条边的端点纵坐标(设为ab)跨越了一条水平线的纵坐标(设为Y),则该边与该线相交。因此,交点测试非常简单。要获取交点本身,请使用以下方法:

Xi = Xa + (Y - Ya) (Xb - Xa) / (Yb - Ya)
Yi = Y

Y = Ya = Yb取决于应用程序时,该怎么办。


如果直线是垂直的,只需交换 XY 的角色。

如果直线是斜的,您可以使用旋转使该线水平。这在复数中方便地通过变换表示:

Z = z e^(-iΘ)

虽然您不需要复数来实现这个,而且获得旋转系数的方式取决于线的指定方式。

计算交点后,您需要进行反向旋转。


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