简体   繁体   English

查找由具有x,y,w,h像素坐标的矩形覆盖的图块的坐标

[英]Finding the coordinates of tiles that are covered by a rectangle with x,y,w,h pixel coordinates

Say I have a tile based system using 16x16 pixels. 假设我有一个使用16x16像素的基于图块的系统。 How would you find out what tiles are covered by a rectangle defined by floating point pixel units? 您如何找出由浮点像素单位定义的矩形覆盖的图块?

for eg, 例如

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)

The only way I can do this reliably is by using a loop. 我可靠地做到这一点的唯一方法是使用循环。 Is there a better way? 有没有更好的办法? Dividing by 16 gives me the wrong answer on edge cases. 除以16会给我关于边缘情况的错误答案。 Here's some example code I use in python: 这是我在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)

Matt's solution with bug-fixes: 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

here is the one which passes your test cases, tell me if there is any edge case 这是通过您的测试用例的,告诉我是否有边缘情况

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)

I am now explicitly checking for the edge case, but be aware that floating point comparison sometime may not seem obvious and result may not be as expected. 我现在正在明确检查边缘情况,但是请注意,有时浮点比较似乎并不明显,并且结果可能不符合预期。

You could try aligning you pixel coordinates ot integers before dividing by tile width: 您可以先将像素坐标ot整数对齐,然后再除以图块宽度:

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

This could probably be condensed a bit more, but here you go. 这可能会更浓缩一些,但是在这里。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM