Find cells in array that are crossed by a given line segment

别说谁变了你拦得住时间么 提交于 2019-11-29 18:02:19

Let your points be A and B, with respective coordinates (xA,yA) and (xB,yB).

A parametric equation for the line segment between both points is given by:
A + t * (B-A) = (xA + t * (xB - xA), yA + t * (yB - yA)) where ttakes all valuers between 0 and 1.

You need to consider all the integral values of either coordinate, along the line segment. This will give you the point of intersection of your line and a cell's side, so you can mark both cells adjacent to this side as "traversed".

Here is the outline of an algorithm to do this, sorting intersection points along the line:

  • start at cell A
  • while you're not at cell B:
    • find the next intersection of your segment with an x axis
    • find the next intersection of your segment with a y axis
    • take the closest one, mark the adjacent cell, and move to it

There are some special cases, like cells that are only touched at one corner. To treat those specially in the previous algorithm, you can recognize the that both potential future intersections are the same.


Here is a quick python demo, where I scaled (multiplied) all t values of the parametric equation by dx * dy so you don't have to divide by dx or dy, except if you want the exact intersection coordinates.

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

If your cell width is w and the cell with coordinates 0, 0 starts at (x0, y0) (that is [x0 , x0 + w] * [y0, y0 + w]) then normalize for that when calling the function, i.e. instead of

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

use

raytrace( ((1 - x0) / w, (1.5 - y0) / w) , ((4 - x0) / w, (1.5 - y0) / w) )

Method of Amanatides and Woo A Fast Voxel Traversal Algorithm for Ray Tracing allows to enumerate all intersected cells.
Here is practical implementation.

An example of work (intersected and touched cells are colored)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!