Ich habe eine große Spiel-Engine und möchte eine Funktion zum Ermitteln des nächsten Punktes aus einer Liste.
Ich könnte einfach den Satz von Pythagoras verwenden , um jede Entfernung zu finden und die Mindestentfernung zu wählen, aber dazu müssen alle durchlaufen werden.
Ich habe auch ein Kollisionssystem, bei dem ich Objekte in kleinere Objekte auf einem kleineren Gitter verwandle (ähnlich einer Minikarte) und nur dann, wenn Objekte im selben Gitterraum existieren, auf Kollisionen prüfe. Ich könnte das tun, nur den Rasterabstand vergrößern, um auf Nähe zu prüfen. (Anstatt jedes einzelne Objekt zu überprüfen.) Dies würde jedoch zusätzliche Einstellungen in meiner Basisklasse erfordern und das bereits überfüllte Objekt unübersichtlich machen. Lohnt es sich?
Gibt es etwas Effizientes und Genaues, mit dem ich anhand einer Liste von Punkten und Größen feststellen kann, welches Objekt am nächsten ist?
Antworten:
Das Problem mit einem Quad / Octree bei der Suche nach nächsten Nachbarn besteht darin, dass das nächstgelegene Objekt möglicherweise genau über der Unterteilung zwischen Knoten liegt. Bei Kollisionen ist dies in Ordnung, da es uns egal ist, ob es sich nicht um einen Knoten handelt. Aber betrachten Sie dieses 2D-Beispiel mit einem Quadtree:
Hier ist der schwarze Gegenstand dem blauen Gegenstand am nächsten, obwohl sich der schwarze Gegenstand und der grüne Gegenstand im selben Knoten befinden. Die Antwort von ultifinitus kann nur den nächsten Nachbarn garantieren, nur jedes Element in Ihrem Baum wird in den kleinstmöglichen Knoten gestellt, der es enthalten könnte, oder in einen eindeutigen Knoten - dies führt zu ineffizienten Quadtrees. (Beachten Sie, dass es viele verschiedene Möglichkeiten gibt, eine Struktur zu implementieren, die als Quad / Octree bezeichnet werden kann. Strengere Implementierungen funktionieren in dieser Anwendung möglicherweise besser.)
Eine bessere Option wäre ein kd-Baum . Kd-Bäume haben einen sehr effizienten Algorithmus für die Suche nach nächsten Nachbarn , den Sie implementieren können, und können eine beliebige Anzahl von Dimensionen enthalten (daher "k" Dimensionen).
Eine großartige und informative Animation von Wikipedia:
Das größte Problem bei der Verwendung von kd-trees ist, wenn ich mich recht entsinne, dass es schwieriger ist, Elemente einzufügen / daraus zu entfernen, während das Gleichgewicht erhalten bleibt. Daher würde ich empfehlen, einen kd-Baum für statische Objekte wie Häuser und Bäume zu verwenden, der sehr ausgewogen ist, und einen anderen, der Spieler und Fahrzeuge enthält, die regelmäßig ausgewogen werden müssen. Suchen Sie das nächste statische Objekt und das nächste mobile Objekt und vergleichen Sie diese beiden.
Schließlich sind kd-trees relativ einfach zu implementieren, und ich bin sicher, dass Sie mit ihnen eine Vielzahl von C ++ - Bibliotheken finden können. Soweit ich mich erinnere, sind R-Bäume viel komplizierter und wahrscheinlich übertrieben, wenn Sie nur eine einfache Suche nach dem nächsten Nachbarn benötigen.
quelle
sqrt()
ist monoton oder ordnungserhaltend für nicht negative Argumente, also:Und umgekehrt.
Wenn Sie also nur zwei Entfernungen vergleichen möchten, aber nicht an deren tatsächlichen Werten interessiert sind, können Sie einfach die
sqrt()
-Stufe aus Ihrem Pythagoras-Zeug herausschneiden:Es ist nicht so effizient wie das Oct-Tree-Ding, aber es ist einfacher zu implementieren und erhöht die Geschwindigkeit zumindest ein wenig
quelle
Sie müssen eine räumliche Partitionierung durchführen. In diesem Fall erstellen Sie eine effiziente Datenstruktur (normalerweise ein Octree). In diesem Fall befindet sich jedes Objekt in einem oder mehreren Räumen (Würfeln). Wenn Sie wissen, in welchen Räumen Sie sich befinden, können Sie O (1) nachschlagen, welche Räume Ihre Nachbarn sind.
In diesem Fall können Sie das nächstgelegene Objekt finden, indem Sie zunächst alle Objekte in Ihrem eigenen Raum durchlaufen und nach dem nächstgelegenen suchen. Wenn niemand da ist, kannst du deine ersten Nachbarn überprüfen, wenn niemand da ist, kannst du ihre Nachbarn überprüfen, etc ...
Auf diese Weise können Sie leicht das nächste Objekt finden, ohne alle Objekte in Ihrer Welt durchlaufen zu müssen. Wie üblich erfordert dieser Geschwindigkeitsgewinn ein wenig Buchhaltung, aber er ist wirklich nützlich für alle Arten von Dingen. Wenn Sie also eine große Welt haben, lohnt es sich definitiv, räumliche Partitionierung und einen Octree zu implementieren.
Siehe auch den Wikipedia-Artikel: http://en.wikipedia.org/wiki/Octree
quelle
Vielleicht versuchen Sie , Ihre räumlichen Daten in einer RTree Organisation, die Art wie ein btree für Sachen im Raum und ermöglicht Abfragen wie „nächste N Nachbarn“ etc ... http://en.wikipedia.org/wiki/Rtree
quelle
Hier ist meine Java-Implementierung, um aus einem QuadTree den nächstgelegenen zu erhalten. Es befasst sich mit dem Problem, das dlras2 beschreibt:
Ich denke, die Operation ist wirklich effizient. Es basiert auf der Entfernung zu einem Quad, um zu vermeiden, dass in Quads weiter gesucht wird als in der aktuell nächstgelegenen.
quelle