2009-07-10 6 views
2

Angenommen, ich verwende ein Kachel-basiertes System mit 16x16 Pixeln. Wie würden Sie herausfinden, welche Kacheln von einem Rechteck bedeckt sind, das durch Gleitkomma-Pixeleinheiten definiert ist?Ermitteln der Koordinaten von Kacheln, die von einem Rechteck mit x-, y-, w- und h-Pixelkoordinaten abgedeckt werden

für zB

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) 

Die einzige Art, wie ich dies sicher tun kann, ist durch eine Schleife verwenden. Gibt es einen besseren Weg? Die Division durch 16 gibt mir die falsche Antwort auf Randfälle. Hier einige Beispiel-Code ich in Python verwenden:

#!/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) 

Antwort

0

hier ist die eine, die Ihre Testfälle geht, mir sagen, ob es eine Kante Fall ist

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) 

Ich bin jetzt explizit für den Rand Fall überprüft Beachten Sie jedoch, dass der Gleitkommavergleich manchmal nicht offensichtlich erscheint und das Ergebnis möglicherweise nicht wie erwartet ist.

+0

Dieser auf dem folgenden Fall in der Frage angegeben ausfällt: (x, y) = 16.0,16.0 (w, h) = 16,1, 16.1 – Mathieu

+0

siehe den bearbeiteten Code –

+0

Ist die Ceil/Floor-Lösung nicht eleganter für die gleichen Ergebnisse? Das ist die Lösung, die ich in der Vergangenheit immer benutzt habe. – Mathieu

0

Sie könnten versuchen Sie Ausrichten Pixelkoordinaten ot ganze Zahlen, bevor sie von Kachelbreite Teilung:

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

Dies ist wahrscheinlich ein bisschen mehr verdichtet werden könnte, aber hier gehen Sie.

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

Matts Lösung mit Bug-Fixes:

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 
Verwandte Themen