查找由给定线段穿过的数组中的单元格

时间:2016-03-04 23:05:24

标签: algorithm math intersection point line-segment

我有一个大小为10x10的2D单元格数组,以及多个浮点值对的点,如:(1.6,1.54),(4.53,3.23)。对(x,y)使得x <10且y <10

每个单元格采用坐标与单元格坐标具有相同整数部分的点。 所以arr [3] [7]将取x = {3 ... 3.99(9)}和y = {7 ... 7.99(9)}的点,例如(3.5,7.1)或(3.2,7.6) )。类似地(1.6,1.54)在arr [1] [1]中,(4.53,3.23)在arr [4] [3]等中。

每个点在数组中都有一个易于查找的指定位置,因为我只需要将x和y转换为int以除去小数点。

但我想找到阵列中哪些单元格被两个点A(x,y)和B(x,y)之间的线段穿过。

例如:A(1.5,2.5)和B(4.3,3.2)穿过具有索引[1] [2],[2] [2],[3,3]和[3,4]的数组中的单元格

有没有算法?

这是一个类似的问题: Cells in grid crossed by a line ( PHP )

3 个答案:

答案 0 :(得分:2)

让您的积分为AB,各自的坐标为(xA,yA)(xB,yB)

两点之间的线段的参数方程由下式给出:
A + t * (B-A) = (xA + t * (xB - xA), yA + t * (yB - yA)) 其中t将所有估值器的值介于0和1之间。

您需要考虑沿线段的任一坐标的所有积分值。这将为您提供线和单元格边的交点,因此您可以将与此边相邻的两个单元格标记为“遍历”。

以下是执行此操作的算法概要,沿着该行对交叉点进行排序:

  • 从小区A开始
  • 当你不在B小区时:
    • 找到您的细分与x轴的下一个交叉点
    • 找到您的细分与y轴的下一个交叉点
    • 取最近的一个,标记相邻的单元格,然后移动到它

有一些特殊情况,例如仅在一个角落触摸的细胞。要专门处理以前算法中的那些,您可以认识到两个潜在的未来交叉点都是相同的。

以下是a quick python demo,其中我将参数方程的所有t值按dx * dy缩放(乘以),因此您不必除以dx或{ {1}},除非你想要精确的交点坐标。

dy

如果您的单元格宽度为from math import floor def sign(n): return (n > 0) - (n < 0) def raytrace(A, B): """ Return all cells of the unit grid crossed by the line segment between A and B. """ (xA, yA) = A (xB, yB) = B (dx, dy) = (xB - xA, yB - yA) (sx, sy) = (sign(dx), sign(dy)) grid_A = (floor(A[0]), floor(A[1])) grid_B = (floor(B[0]), floor(B[1])) (x, y) = grid_A traversed=[grid_A] tIx = dy * (x + sx - xA) if dx != 0 else float("+inf") tIy = dx * (y + sy - yA) if dy != 0 else float("+inf") while (x,y) != grid_B: # NB if tIx == tIy we increment both x and y (movx, movy) = (tIx <= tIy, tIy <= tIx) if movx: # intersection is at (x + sx, yA + tIx / dx^2) x += sx tIx = dy * (x + sx - xA) if movy: # intersection is at (xA + tIy / dy^2, y + sy) y += sy tIy = dx * (y + sy - yA) traversed.append( (x,y) ) return traversed 且坐标为w的单元格从0, 0开始(即(x0, y0)),则在调用函数时将其标准化,即的

[x0 , x0 + w] * [y0, y0 + w]

使用

raytrace( (1,1.5) , (5,2.5) )

答案 1 :(得分:2)

Amanatides和Woo A Fast Voxel Traversal Algorithm for Ray Tracing的方法允许枚举所有相交的单元格 Here is实际执行。

工作示例(相交和触摸的单元格是彩色的) enter image description here

答案 2 :(得分:1)

尝试使用具有python package的Bresenham的线条绘制算法。代码如下:

from bresenham import bresenham


cells = list(bresenham(96, 280, 95, 275))
print(cells)

我收到了 [(96, 280), (96, 279), (96, 278), (95, 277), (95, 276), (95, 275)]