Connexion élèves

Choisir le(s) module(s) à installer :

TP : partition de l'espace

Ou voir qu'un arbre n'est pas forcément binaire !...

Introduction

Le problème de la partition de l'espace se pose en informatique dans de nombreux domaines, dès lors que l'on a une grande quantité de données à considérer dans un espace donné, comme par exemple :

Nous allons prendre l'exemple de la gestion des collisions : si le nombre de sprites à l'écran est très élevé, il va être très coûteux de tester la collision avec chacun de ces sprites; il serait plus judicieux de ne tester la collision qu'avec ceux qui sont dans le voisinage le plus proche...mais alors, comment déterminer ceux-ci ?

Principe

Partition de l'espace

On utilise une structure de donnée arbre quaternaire ( = quadtree en anglais ), c'est à dire un arbre de degré 4 ( chaque nœud, sauf les feuilles, a 4 enfants ).

L'idée va être de découper récursivement l'espace en zone de plus en plus petites, et de placer les points qui sont dans ces zones comme données stockées dans le quadtree.

Considérons les 3 cartes ci-dessous :

Quadtree

Et ainsi de suite, et ce de même pour toutes les autres zones : en arrivant à la zone de plus petite division ( voir ci-dessous le cas de base de cette découpe ), on stockera alors dans une feuille de l'arbre les points qui sont dans cette zone

Dans cette structure, seules les feuilles stockent donc des données, pas les nœuds de hauteur inférieure.

Quadtree de points

Implémentation Python d'un quadtree

On choisira l'implémentation POO suivante :


class QuadTree:

    def __init__(self, x0, y0, l, h):
        self.x0 = x0 # coordonnées du sommet en bas à gauche de la zone correspondant à ce quadtree
        self.y0 = y0
        self.l = l # largeur de la zone
        self.h = h # hauteur de la zone
        self.NO = None # les 4 fils de ce quadtree, initialisés à None (NO = nord-ouest, NE = nord-est, etc...)
        self.NE = None
        self.SE = None
        self.SO = None
        self.points = [] # la liste des points stockés dans ce quadtree, donc appartenant à la zone correspondante
			
4 zones d'un quadtree

Quand on arrive sur une feuille, les quatre pointeurs vers les Quadtree fils seront None.
Comme ces pointeurs seront soit tous nuls, soit tous non nuls, pour vérifier qu'un nœud est une feuille, il suffira donc de regarder le premier fils, et voir s'il est None ou pas.

Algorithme de découpage

Comment découper un Quadtree ? Jusqu'où continuer à découper ?

L'idée est de définir une constante MAX_POINTS, qui sera le nombre maximal de points qu'on veut stocker dans une zone "élémentaire" ( = celle de plus petite taille ).
Par exemple, on voudra stocker au maximum 10 points, parce que l'on va chercher à tester les collisions sur les 10 voisins les plus proches.

Cependant, la répartition des points étant aléatoire, on n'aura pas forcément MAX_POINTS points dans chaque feuille, c'est un maximum ...

Bien entendu, la construction d'un quadtree peut prendre du temps; mais, pour la carte des objets fixes dans un jeu vidéo, la construction peut se faire une fois pour toutes au chargement de la carte, voire même le quadtree peut être stocké avec la carte directement.

Utilisation du quadtree pour la recherche des plus proches voisins

Une fois le quadtree créé, il est évident de l'utiliser pour déterminer les MAX_POINTS plus proches voisins : il faut "descendre" récursivement dans l'arbre, jusqu'à atteindre la feuille correspondant à la zone dans laquelle se trouve le point; à ce moment, on renvoie simplement la liste des points stockés dans le quadtree correspondant.

Application

Téléchargez et enregistrez le fichier quadtree_eleve.py qui vous servira de base de départ.

Dans ce fichier on trouve :

Construction du quadtree

On considérera un espace plan de taille 256 x 256; la coordonnée (0, 0) se trouve en bas à gauche de cet espace.

Détermination des plus proches voisins

Prolongement

Vous pouvez prolonger ce travail en écrivant une fonction qui implémente une recherche "naïve" de n plus proches voisins dans une liste de points, et comparer à l'aide du module timeit le temps d’exécution de chacune des deux approches vues dans ce TP.

Quelle est la complexité de chacun des algorithmes de recherche utilisé ?

Correction

Une correction possible pour ce TP.