2009-07-10 6 views
2

Disons que j'ai un système de mosaïque utilisant des pixels 16x16. Comment voulez-vous savoir quelles sont les tuiles couvertes par un rectangle défini par des unités de pixels à virgule flottante?Recherche des coordonnées de carreaux recouverts d'un rectangle avec les coordonnées de pixels x, y, w, h

pour exemple,

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) 

La seule façon que je peux faire est de manière fiable à l'aide d'une boucle. Y a-t-il un meilleur moyen? En divisant par 16 me donne la mauvaise réponse sur les cas de bord. Voici quelques exemples de code que j'utilise en 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) 

Répondre

0

ici est celui qui passe vos cas de test, dites-moi s'il y a un cas limite

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) 

Je suis maintenant vérifie explicitement le cas de bord , mais sachez que la comparaison à virgule flottante peut parfois ne pas sembler évidente et que le résultat peut ne pas être conforme aux attentes.

+0

Cela échoue sur le cas suivant indiqué dans la question: (x, y) = 16.0,16.0 (w, h) = 16,1, 16.1 – Mathieu

+0

voir le code édité –

+0

La solution plafond/sol n'est-elle pas plus élégante pour obtenir les mêmes résultats? C'est la solution que j'ai toujours utilisée par le passé. – Mathieu

0

Vous pouvez essayer d'aligner vous des coordonnées en pixels entiers ot avant de diviser par la largeur de la tuile:

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

Cela pourrait probablement être condensé un peu plus, mais voilà.

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 
1

solution de Matt avec des corrections de bugs:

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 
Questions connexes