簡體   English   中英

如何找到線與網格的交點?

[英]How to find intersection of a line with a mesh?

我有軌跡數據,其中每個軌跡由一系列坐標(x,y 點)組成,每個軌跡由唯一 ID 標識。

這些軌跡在x - y平面中,我想將整個平面分成大小相等的網格(方形網格)。 該網格顯然是不可見的,但用於將軌跡划分為子段。 每當軌跡與網格線相交時,它就會在那里被分割並成為一個帶有new_id的新子軌跡。

我已經包含了一個簡單的手工圖表來說明我的期望。

在此處輸入圖片說明

可以看出軌跡是如何在網格線的交叉點處划分的,並且這些段中的每一個都有新的唯一 id。

我正在研究 Python,並尋求一些 Python 實現鏈接、建議、算法,甚至是相同的偽代碼。

如果有任何不清楚的地方,請告訴我。

更新

為了將平面划分為網格,單元格索引如下:

#finding cell id for each coordinate
#cellid = (coord / cellSize).astype(int)
cellid = (coord / 0.5).astype(int)
cellid
Out[] : array([[1, 1],
              [3, 1],
              [4, 2],
              [4, 4],
              [5, 5],
              [6, 5]])
#Getting x-cell id and y-cell id separately 
x_cellid = cellid[:,0]
y_cellid = cellid[:,1]

#finding total number of cells
xmax = df.xcoord.max()
xmin = df.xcoord.min()
ymax = df.ycoord.max()
ymin = df.ycoord.min()
no_of_xcells = math.floor((xmax-xmin)/ 0.5)
no_of_ycells = math.floor((ymax-ymin)/ 0.5)
total_cells = no_of_xcells * no_of_ycells
total_cells
Out[] : 25 

由於飛機現在分為 25 個單元格,每個單元格都有一個cellid 為了找到交點,也許我可以檢查軌跡中的下一個坐標,如果cellid保持不變,那么軌跡的那一段在同一個單元格中並且與網格沒有交集。 假設,如果 x_cellid[2] 大於 x_cellid[0],則線段與垂直網格線相交。 盡管如此,我仍然不確定如何找到與網格線的交叉點並在交叉點上分割軌跡給他們新的 id。

這可以通過以下方式解決:

%matplotlib inline
import pylab as pl
from shapely.geometry import MultiLineString, LineString
import numpy as np
from matplotlib.collections import LineCollection

x0, y0, x1, y1 = -10, -10, 10, 10
n = 11

lines = []
for x in np.linspace(x0, x1, n):
    lines.append(((x, y0), (x, y1)))

for y in np.linspace(y0, y1, n):
    lines.append(((x0, y), (x1, y)))

grid = MultiLineString(lines)

x = np.linspace(-9, 9, 200)
y = np.sin(x)*x
line = LineString(np.c_[x, y])

fig, ax = pl.subplots()
for i, segment in enumerate(line.difference(grid)):
    x, y = segment.xy
    pl.plot(x, y)
    pl.text(np.mean(x), np.mean(y), str(i))

lc = LineCollection(lines, color="gray", lw=1, alpha=0.5)
ax.add_collection(lc);

結果:

在此處輸入圖片說明

不使用勻稱,並自己做:

import pylab as pl
import numpy as np
from matplotlib.collections import LineCollection

x0, y0, x1, y1 = -10, -10, 10, 10
n = 11
xgrid = np.linspace(x0, x1, n)
ygrid = np.linspace(y0, y1, n)
x = np.linspace(-9, 9, 200)
y = np.sin(x)*x
t = np.arange(len(x))

idx_grid, idx_t = np.where((xgrid[:, None] - x[None, :-1]) * (xgrid[:, None] - x[None, 1:]) <= 0)
tx = idx_t + (xgrid[idx_grid] - x[idx_t]) / (x[idx_t+1] - x[idx_t])

idx_grid, idx_t = np.where((ygrid[:, None] - y[None, :-1]) * (ygrid[:, None] - y[None, 1:]) <= 0)
ty = idx_t + (ygrid[idx_grid] - y[idx_t]) / (y[idx_t+1] - y[idx_t])

t2 = np.sort(np.r_[t, tx, tx, ty, ty])

x2 = np.interp(t2, t, x)
y2 = np.interp(t2, t, y)

loc = np.where(np.diff(t2) == 0)[0] + 1

xlist = np.split(x2, loc)
ylist = np.split(y2, loc)


fig, ax = pl.subplots()
for i, (xp, yp) in enumerate(zip(xlist, ylist)):
    pl.plot(xp, yp)
    pl.text(np.mean(xp), np.mean(yp), str(i))


lines = []
for x in np.linspace(x0, x1, n):
    lines.append(((x, y0), (x, y1)))

for y in np.linspace(y0, y1, n):
    lines.append(((x0, y), (x1, y)))

lc = LineCollection(lines, color="gray", lw=1, alpha=0.5)
ax.add_collection(lc);

你問了很多。 一旦你有了一個通用的方法,你應該自己攻擊大部分的設計和編碼。 Stack Overflow 的算法識別是合理的; 要求設計和參考鏈接不是

我建議您將點坐標放入列表中。 使用NumPySciKit功能來插入網格交叉點。 您可以將段存儲在列表中(在數據設計中定義段的任何內容)。 考慮制作一個字典,允許您通過網格坐標檢索段。 例如,如果線段僅由端點表示,而點是您的一個類,您可能會有這樣的事情,使用每個正方形的左下角作為其定義點:

grid_seg = {
    (0.5, 0.5): [p0, p1],
    (1.0, 0.5): [p1, p2],
    (1.0, 1.0): [p2, p3],
    ...
}

其中 p0、p1 等是插值的交叉點。

每個軌跡由一系列直線段組成。 因此,您需要一個例程將每條線段分成完全位於網格單元內的部分。 這種例程的基礎是數字差分分析器 (DDA)算法,但您需要修改基本算法,因為您需要每個單元格內的線端點,而不僅僅是訪問哪些單元格。

您必須注意以下幾點:

1) 如果您正在處理浮點數,請注意計算步長值時的舍入錯誤,因為這些錯誤會導致算法失敗。 出於這個原因,許多人選擇轉換為整數網格,顯然會損失精度。 是對這些問題的一個很好的討論,有一些工作代碼(雖然不是 python)。

2) 您需要決定單元格周圍的 4 條網格線中的哪一條屬於該單元格。 一種約定是使用底部和左側邊緣。 如果您考慮落在網格線上的水平線段,您可以看到問題 - 它的線段屬於上方的單元格還是下方的單元格?

干杯

data = list of list of coordinates
For point_id, point_coord in enumerate(point_coord_list):
   if current point & last point stayed in same cell:
        append point's index to last list of data
   else:
        append a new empty list to data
        interpolate the two points and add a new point
        that is on the grid lines.

數據存儲所有軌跡。 數據中的每個列表都是一個軌跡。

沿 x 和 y 軸( x_cell_idy_cell_id )的單元x_cell_id y_cell_id可以通過將點的坐標除以單元格的維度,然后舍入為整數來找到。 如果當前點的單元格索引與上一個點的單元格索引相同,則這兩個點在同一個單元格中。 list 適合插入新點,但它的內存效率不如數組。

為軌跡創建一個類可能是個好主意。 或者,如果坐標列表浪費太多內存,則使用內存緩沖區和稀疏數據結構代替列表和列表以及 xy 坐標數組。 將新點插入數組很慢,所以我們可以使用另一個數組來插入新點。

警告:我沒有想太多下面的事情。 它可能有錯誤,需要有人來填補空白。

# coord       n x 2 numpy array. 
#             columns 0, 1 are x and y coordinate. 
#             row n is for point n
# cell_size   length of one side of the square cell.
# n_ycells    number of cells along the y axis

import numpy as np
cell_id_2d = (coord / cell_size).astype(int)
x_cell_id = cell_id_2d[:,0]
y_cell_id = cell_id_2d[:,1]
cell_id_1d = x_cell_id + y_cell_id*n_x_cells

# if the trajectory exits a cell, its cell id changes
# and the delta_cell_id is not zero.
delta_cell_id = cell_id_1d[1:] - cell_id_1d[:-1]

# The nth trajectory should contains the points from
# the (crossing_id[n])th to the (crossing_id[n + 1] - 1)th
w = np.where(delta_cell_id != 0)[0]
crossing_ids = np.empty(w.size + 1)
crossing_ids[1:] = w
crossing_ids[0] = 0

# need to interpolate when the trajectory cross cell boundary.
# probably can replace this loop with numpy functions/indexing
new_points = np.empty((w.size, 2))
for i in range(1, n):
    st = coord[crossing_ids[i]]
    en = coord[crossing_ids[i+1]]
    # 1. check which boundary of the cell is crossed
    # 2. interpolate
    # 3. put points into new_points

# Each trajectory contains some points from coord array and 2 points 
# in the new_points array.

對於檢索,請創建一個包含坐標數組中起點索引的稀疏數組。

如果像元大小很大,線性插值可能看起來很糟糕。

進一步解釋:

網格描述

For n_xcells = 4, n_ycells = 3, the grid is:

   0   1   2   3   4
0 [  ][  ][  ][  ][  ]
1 [  ][  ][  ][* ][  ]
2 [  ][  ][  ][  ][  ]

[* ] has an x_index of 3 and a y_index of 1.

網格中有 ( n_x_cells * n_y_cells ) 個單元格。

點與單元格的關系

包含軌跡i點的單元格具有x_cell_id[i]的 x_index 和x_cell_id[i]x_cell_id[i] 我通過將點的 xy 坐標除以單元格的長度然后截斷為整數來進行離散化。

The cell_id_1d of the cells are the number in [  ]

   0   1   2   3   4
0 [0 ][1 ][2 ][3 ][4 ]
1 [5 ][6 ][7 ][8 ][9 ]
2 [10][11][12][13][14]

cell_id_1d[i] = x_cell_id[i] + y_cell_id[i]*n_x_cells

我將第 i點的單元索引對(x_cell_id[i], y_cell_id[i])為一個名為cell_id_1d索引。

如何找到軌跡是否在第 i點退出單元格

現在,第 i(i + 1)點在同一個單元格中,當且僅當 (x_cell_id[i], y_cell_id[i]) == (x_cell_id[i + 1], y_cell_id[i + 1])還有 cell_id_1d[i] == cell_id[i + 1] 和 cell_id[i + 1] - cell_id[i] == 0。delta_cell_ids[i] = cell_id_1d[i + 1] - cell_id[i],即當且僅第 i個點(i + 1)點在同一單元格中時為零。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM