Quadtree en Python --2

La dernière fois J'ai remarqué qu'il faut O (nombre de zones) pour savoir à quelle zone appartient un certain point, alors je le réimplémente. fait

Cette fois, j'ai essayé de diviser tout en maintenant la structure arborescente correctement

De cette façon, vous pouvez trouver à quelle région appartient un point de données avec O (profondeur de l'arbre).

Ou plutôt c'est normal

la mise en oeuvre

Puisqu'il est possible que la division soit répétée indéfiniment s'il y a plusieurs points de données identiques, le nombre maximum de divisions («maxdivision») est donné.

quadtree.py


# -*- coding: utf-8 -*-
class Quadtree:
    def __init__(self,data,x1,y1,x2,y2,maxpoints,maxdivision):
        self.data = data
        self.sequential_id = 0
        self.leaves = {}
        self.root = self.divide(self.init_area(data,x1,y1,x2,y2),maxpoints,maxdivision)

    def __iter__(self):
        for aid in self.leaves:
            yield self.leaves[aid]

    def init_area(self,data,x1,y1,x2,y2):
        initial = Area(x1,y1,x2,y2)
        for d in data:
            initial.append(d)
        return initial

    def subdivide(self,area):
        division = []

        """Longueur de chaque côté après division"""
        xl = (area.x2 - area.x1)/2
        yl = (area.y2 - area.y1)/2

        """Générer une zone après la division"""
        for dx in [0,1]:
            for dy in [0,1]:
                """
                0 2
                1 3
Commande
                """
                sub_area = Area(area.x1+dx*xl, area.y1+dy*yl, area.x1+(1+dx)*xl, area.y1+(1+dy)*yl)
                division.append(sub_area)

        """Attribuer des points de données appartenant à la zone avant division à la zone après division"""
        for p in area.points():
            for sub_area in division:
                if sub_area.cover(p):
                    sub_area.append(p)
                    break

        return division

    def divide(self, area, maxpoints, division_left):
        """Division donnée en argument_Répéter le fractionnement uniquement les temps restants"""
        if division_left == 0 or area.number_of_points() <= maxpoints:
            """Si le nombre de points de données inclus dans la zone ne dépasse pas maxpoints, la division se termine"""
            area.set_fixed(self.sequential_id)
            area.calc_center() #Calculer le centre de gravité des points de données appartenant à la zone
            self.leaves[self.sequential_id] = area
            self.sequential_id += 1
            return area
        else:
            """Si le nombre de points de données inclus dans la zone dépasse maxpoints, divisez-le en quatre"""
            next_level = self.subdivide(area)
            """Divisez davantage chaque zone enfant"""
            for i in range(4):
                child = self.divide(next_level[i],maxpoints,division_left-1)
                area.set_child(i,child)
            """Renvoie la zone fractionnée"""
            return area

    def get_area_id(self,p):
        return self.root.covered(p)

class Area:
    def __init__(self,x1,y1,x2,y2):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.points_ = []
        self.fixed = False
        """
        0 2
        1 3
        """
        self.children = [None,None,None,None]

    def calc_center(self):
        if self.number_of_points() == 0:
            self.center = (self.x1 + (self.x2-self.x1)/2, self.y1 + (self.y2-self.y1)/2)
        else:
            sumx = 0.
            sumy = 0.
            for p in self.points_:
                sumx += p[0]
                sumy += p[1]
            self.center = (sumx/len(self.points_), sumy/len(self.points_))

    def append(self, p):
        """Ajouter des points de données à la zone"""
        self.points_.append(p)

    def points(self):
        """Renvoie les points de données appartenant à la région"""
        return self.points_

    def number_of_points(self):
        return len(self.points_)

    def is_fixed(self):
        """Si la scission est terminée"""
        return self.fixed

    def set_fixed(self,aid):
        """Définissez le drapeau indiquant que la division est terminée"""
        self.fixed = True
        """Donner une pièce d'identité à la zone"""
        self.aid = aid

    def set_child(self,n,area):
        self.children[n] = area

    def covered(self,p):
        if self.cover(p):
            if self.fixed:
                return self.aid
            else:
                """Calculez l'ID de la zone enfant"""
                cid = 0
                if self.x1 + (self.x2 - self.x1) / 2 < p[0]:
                    """ Right """
                    cid += 2
                if self.y1 + (self.y2 - self.y1) / 2 < p[1]:
                    """ Down """
                    cid += 1
                return self.children[cid].covered(p)
        else:
            return None

    def cover(self, p):
        """Si un point de données p est couvert dans cette zone"""
        if self.x1 < p[0] and self.y1 < p[1] and self.x2 >= p[0] and self.y2 >= p[1]:
            return True
        else:
            return False

if __name__ == '__main__':
    import sys

    def read_data(file_name):
        data = []
        for line in open(file_name, 'r'):
            entries = line.rstrip().split(' ')
            lat = float(entries[0])
            lng = float(entries[1])
            data.append((lat,lng))
        return data

    x1 = float(sys.argv[1])
    y1 = float(sys.argv[2])
    x2 = float(sys.argv[3])
    y2 = float(sys.argv[4])
    maxpoints = int(sys.argv[5])
    maxdivision = int(sys.argv[6])
    data = read_data(sys.argv[7])

    """Divisé"""
    qtree = Quadtree(data,x1,y1,x2,y2,maxpoints,maxdivision)

    """résultat"""
    for a in qtree:
        print a.aid,a.x1,a.y1,a.x2,a.y2,a.center

    p = (0.37,0.55)
    print p,qtree.get_area_id(p)

Exemple d'exécution

Les arguments sont donnés dans l'ordre x, y de la coordonnée supérieure gauche de la zone cible, x, y de la coordonnée inférieure droite, le nombre maximum de données pouvant appartenir à la zone, le nombre maximum de divisions et le fichier de données.

$ cat data
0.567603099626 0.410160220857
0.405568042222 0.555583016695
0.450289054963 0.252870772505
0.373657009068 0.549501477427
0.500192599714 0.352420542886
0.626796922 0.422685113179
0.527521290061 0.483502904656
0.407737520746 0.570049935936
0.578095278433 0.6959689898
0.271957975882 0.450460115198
0.56451369371 0.491139311353
0.532304354436 0.486931064003
0.553942716039 0.51953331907
0.627341495722 0.396617894317
0.454210189397 0.570214499065
0.327359895038 0.582972137899
0.422271372537 0.560892624101
0.443036148978 0.434529240506
0.644625936719 0.542486338813
0.447813648487 0.575896033203
0.534217713171 0.636123087401
0.348346109137 0.312959224746
0.484075186327 0.289521849258
0.588417643962 0.387831556678
0.613422176662 0.665770829308
0.60994411786 0.399778040078
0.425443751505 0.402619561402
0.504955932504 0.610015349003
0.402852203978 0.382379275531
0.387591801531 0.452180343665

$ python quadtree 0 0 1 1 3 3 data
0 0.0 0.0 0.25 0.25 (0.125, 0.125)
1 0.0 0.25 0.25 0.5 (0.125, 0.375)
2 0.25 0.0 0.5 0.25 (0.375, 0.125)
3 0.25 0.25 0.375 0.375 (0.348346109137, 0.312959224746)
4 0.25 0.375 0.375 0.5 (0.271957975882, 0.450460115198)
5 0.375 0.25 0.5 0.375 (0.467182120645, 0.2711963108815)
6 0.375 0.375 0.5 0.5 (0.414730976498, 0.417927105276)
7 0.0 0.5 0.25 0.75 (0.125, 0.625)
8 0.0 0.75 0.25 1.0 (0.125, 0.875)
9 0.25 0.5 0.375 0.625 (0.35050845205299996, 0.566236807663)
10 0.25 0.625 0.375 0.75 (0.3125, 0.6875)
11 0.375 0.5 0.5 0.625 (0.42752015467779997, 0.5665272218)
12 0.375 0.625 0.5 0.75 (0.4375, 0.6875)
13 0.25 0.75 0.5 1.0 (0.375, 0.875)
14 0.5 0.0 0.75 0.25 (0.625, 0.125)
15 0.5 0.25 0.625 0.375 (0.500192599714, 0.352420542886)
16 0.5 0.375 0.625 0.5 (0.5650506999425, 0.44322384960416666)
17 0.625 0.25 0.75 0.375 (0.6875, 0.3125)
18 0.625 0.375 0.75 0.5 (0.627069208861, 0.40965150374799997)
19 0.75 0.0 1.0 0.25 (0.875, 0.125)
20 0.75 0.25 1.0 0.5 (0.875, 0.375)
21 0.5 0.5 0.625 0.625 (0.5294493242714999, 0.5647743340365)
22 0.5 0.625 0.625 0.75 (0.5752450560886667, 0.6659543021696667)
23 0.625 0.5 0.75 0.625 (0.644625936719, 0.542486338813)
24 0.625 0.625 0.75 0.75 (0.6875, 0.6875)
25 0.5 0.75 0.75 1.0 (0.625, 0.875)
26 0.75 0.5 1.0 0.75 (0.875, 0.625)
27 0.75 0.75 1.0 1.0 (0.875, 0.875)
(0.37, 0.55) 9

En conséquence, il a été divisé en 28 zones (le nombre de nœuds feuilles dans l'arbre).

En regardant la dernière ligne des résultats, nous pouvons voir que la région à laquelle appartient le point de données donné est correctement déterminée.

Recommended Posts

Quadtree en Python --2
Quad-tree en Python
Python en optimisation
CURL en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Méta-analyse en Python
Unittest en Python
Époque en Python
Discord en Python
Allemand en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
Constante en Python
FizzBuzz en Python
Sqlite en Python
Étape AIC en Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Réflexion en Python
Chimie avec Python
Hashable en Python
DirectLiNGAM en Python
LiNGAM en Python
Aplatir en Python
Aplatir en python
AtCoder # 36 quotidien avec Python
Texte de cluster en Python
Daily AtCoder # 32 en Python
Daily AtCoder # 6 en Python
Daily AtCoder # 18 en Python
Modifier les polices en Python
Motif singleton en Python
Opérations sur les fichiers en Python
Lire DXF avec python
Daily AtCoder # 53 en Python
Séquence de touches en Python
Utilisez config.ini avec Python
Daily AtCoder # 33 en Python
Résoudre ABC168D en Python
Distribution logistique en Python
AtCoder # 7 tous les jours avec Python
Décomposition LU en Python