【问题标题】:Finding the coordinates of tiles that are covered by a rectangle with x,y,w,h pixel coordinates查找由具有 x,y,w,h 像素坐标的矩形覆盖的图块的坐标
【发布时间】:2009-07-10 11:01:03
【问题描述】:

假设我有一个使用 16x16 像素的基于图块的系统。您如何找出由浮点像素单元定义的矩形所覆盖的图块?

例如,

rect(x=16.0,y=16.0, w=1.0, h=1.0) -> tile(x=1, y=1, w=1, h=1)
rect(x=16.0,y=16.0, w=16.0, h=16.0) -> tile(x=1, y=1, w=1, h=1) (still within same tile)
rect(x=24.0,y=24.0, w=8.0, y=8.0) -> (x=1,y=1,w=1,h=1) (still within same tile)
rect(x=24.0,y=24.0, w=8.1, y=8.1) -> (x=1,y=1,w=2,h=2)

我可以可靠地做到这一点的唯一方法是使用循环。有没有更好的办法?除以 16 给我在边缘情况下的错误答案。这是我在 python 中使用的一些示例代码:

#!/usr/bin/env python

import math

TILE_W = 16
TILE_H = 16

def get_tile(x,y,w,h):
    t_x = int(x / TILE_W)
    t_x2 = t_x
    while t_x2*TILE_W < (x+w):
        t_x2 += 1
    t_w = t_x2-t_x

    t_y = int( y / TILE_H)
    t_y2 = t_y
    while t_y2*TILE_H < (y+h):
        t_y2 += 1
    t_h = t_y2-t_y

    return t_x,t_y,t_w,t_h

(x,y) = 16.0,16.0
(w,h) = 1.0, 1.0
assert get_tile(x,y,w,h) == (1,1,1,1)

(x,y) = 16.0,16.0
(w,h) = 15.0, 15.0
assert get_tile(x,y,w,h) == (1,1,1,1)

(x,y) = 16.0,16.0
(w,h) = 16.0, 16.0
assert get_tile(x,y,w,h) == (1,1,1,1)

(x,y) = 16.0,16.0
(w,h) = 16.1, 16.1
assert get_tile(x,y,w,h) == (1,1,2,2)

(x,y) = 24.0, 24.0
(w,h) = 1.0, 1.0
assert get_tile(x,y,w,h) == (1,1,1,1)

(x,y) = 24.0, 24.0
(w,h) = 8.0, 8.0
assert get_tile(x,y,w,h) == (1,1,1,1)

(x,y) = 24.0, 24.0
(w,h) = 8.1, 8.1
assert get_tile(x,y,w,h) == (1,1,2,2)

(x,y) = 24.0, 24.0
(w,h) = 9.0, 9.0
assert get_tile(x,y,w,h) == (1,1,2,2)

【问题讨论】:

    标签: python algorithm math geometry coordinates


    【解决方案1】:

    Matt 的错误修复解决方案:

    from __future__ import division
    import math
    
    TILE_W = TILE_H = 16
    
    def get_tile(x,y,w,h):
        x1 = int(math.floor(x/TILE_W))
        x2 = int(math.ceil((x + w)/TILE_W))
        y1 = int(math.floor(y/TILE_H))
        y2 = int(math.ceil((y + h)/TILE_H))
        return x1, y1, x2-x1, y2-y1
    

    【讨论】:

      【解决方案2】:

      您可以尝试在除以平铺宽度之前将像素坐标与整数对齐:

      xlower = int(floor(x))
      xupper = int(ceil(x + w))
      

      【讨论】:

        【解决方案3】:

        这是通过你的测试用例的,告诉我是否有任何边缘情况

        TILE_W = TILE_H = 16
        
        from math import floor, ceil
        
        def get_tile2(x,y,w,h):
            x1 = int(x/TILE_W)
            y1 = int(y/TILE_H)
            x2 = int((x+w)/TILE_W)
            y2 = int((y+h)/TILE_H)
            if (x+w)%16 == 0: #edge case
                x2-=1
            if (y+h)%16 == 0: #edge case
                y2-=1
            tw = x2-x1 + 1
            th = y2-y1 + 1
            return x1, y1, tw, th
        
        (x,y) = 16.0, 16.0
        (w,h) = 1.0, 1.0
        assert get_tile2(x,y,w,h) == (1,1,1,1)
        
        (x,y) = 16.0, 16.0
        (w,h) = 15.0, 15.0
        assert get_tile2(x,y,w,h) == (1,1,1,1)
        
        (x,y) = 16.0, 16.0
        (w,h) = 16.0, 16.0
        assert get_tile2(x,y,w,h) == (1,1,1,1)
        
        (x,y) = 16.0, 16.0 
        (w,h) = 16.1, 16.1
        assert get_tile2(x,y,w,h) == (1,1,2,2)
        

        我现在明确检查边缘情况,但请注意,浮点比较有时可能看起来并不明显,结果可能与预期不符。

        【讨论】:

        • 这在问题中所述的以下情况下失败:(x,y) = 16.0,16.0 (w,h) = 16.1, 16.1
        • 对于相同的结果,天花板/地板解决方案不是更优雅吗?这是我过去一直使用的解决方案。
        • 地板和天花板是不够的,因为当瓷砖边缘正好是瓷砖宽度/高度的倍数时会发生边缘情况。
        • @Eric:你能举一个你正在考虑的边缘情况的例子吗?此处发布的两个解决方案都通过了问题中所述的案例。
        【解决方案4】:

        这可能会更浓缩一点,但你去吧。

        def get_tile(x,y,w,h):
        
            x1 = int(x / TILE_W)
            x2 = (x + w) / TILE_W
        
            y1 = int(y / TILE_H)
            y2 = (x + w) / TILE_H
        
            if int(x2) == x2:
                x2 = int(x2 - 1)
            else:
                x2 = int(x2)
        
            if int(y2) == y2:
                y2 = int(y2 - 1)
            else:
                y2 = int(y2)
        
            tw = x2 - x1 + 1
            th = y2 - y1 + 1
        
            return x1, y1, tw, th
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-26
          • 1970-01-01
          • 2010-10-14
          • 1970-01-01
          • 1970-01-01
          • 2023-03-30
          • 2021-07-10
          • 1970-01-01
          相关资源
          最近更新 更多