Dieses Problem betrifft tatsächlich Rollover. Ich werde es im Folgenden als solches verallgemeinern:
Ich habe eine 2D-Ansicht und eine Reihe von Rechtecken in einem Bereich auf dem Bildschirm. Wie verteile ich diese Felder so, dass sie sich nicht überlappen, sondern nur mit minimaler Bewegung anpassen?
Die Positionen der Rechtecke sind dynamisch und hängen von den Eingaben des Benutzers ab, sodass ihre Positionen überall sein können.
Angehängte Bilder zeigen das Problem und die gewünschte Lösung
Das eigentliche Problem betrifft eigentlich Überschläge.
Antworten auf die Fragen in den Kommentaren
Die Größe der Rechtecke ist nicht festgelegt und hängt von der Länge des Texts im Rollover ab
In Bezug auf die Bildschirmgröße denke ich, dass es im Moment besser ist anzunehmen, dass die Größe des Bildschirms für die Rechtecke ausreicht. Wenn es zu viele Rechtecke gibt und der Algo keine Lösung liefert, muss ich nur den Inhalt optimieren.
Die Anforderung, sich nur minimal zu bewegen, ist für die Asethetik mehr als eine absolute technische Anforderung. Man könnte zwei Rechtecke ausräumen, indem man einen großen Abstand zwischen ihnen hinzufügt, aber es sieht als Teil der GUI nicht gut aus. Die Idee ist, den Rollover / das Rechteck so nah wie möglich an seine Quelle zu bringen (die ich dann mit einer schwarzen Linie mit der Quelle verbinden werde). Es ist also in Ordnung, entweder nur eine für x oder beide für die Hälfte von x zu verschieben.
Antworten:
Ich habe ein bisschen daran gearbeitet, da ich auch etwas Ähnliches brauchte, aber ich hatte die Algorithmusentwicklung verzögert. Du hast mir geholfen, einen Impuls zu bekommen: D.
Ich brauchte auch den Quellcode, also hier ist er. Ich habe es in Mathematica ausgearbeitet, aber da ich die Funktionsmerkmale nicht stark genutzt habe, wird es wahrscheinlich einfach sein, in eine prozedurale Sprache zu übersetzen.
Eine historische Perspektive
Zuerst habe ich beschlossen, den Algorithmus für Kreise zu entwickeln, da der Schnittpunkt einfacher zu berechnen ist. Es kommt nur auf die Zentren und Radien an.
Ich konnte den Mathematica-Gleichungslöser verwenden, und er lief gut.
Schau einfach:
Es war einfach. Ich habe gerade den Solver mit folgendem Problem geladen:
So einfach wie das, und Mathematica hat die ganze Arbeit gemacht.
Ich sagte "Ha! Es ist einfach, jetzt lass uns zu den Rechtecken gehen!". Aber ich habe mich getäuscht ...
Rechteckiger Blues
Das Hauptproblem bei den Rechtecken besteht darin, dass das Abfragen der Kreuzung eine unangenehme Funktion ist. Etwas wie:
Als ich versuchte, Mathematica mit vielen dieser Bedingungen für die Gleichung zu versorgen, lief es so schlecht, dass ich mich entschied, etwas prozedurales zu tun.
Mein Algorithmus endete wie folgt:
Möglicherweise stellen Sie fest, dass die Bedingung "kleinste Bewegung" nicht vollständig erfüllt ist (nur in eine Richtung). Aber ich fand heraus, dass das Bewegen der Rechtecke in eine beliebige Richtung, um sie zu befriedigen, manchmal zu einer verwirrenden Kartenänderung für den Benutzer führt.
Während ich eine Benutzeroberfläche entwerfe, verschiebe ich das Rechteck etwas weiter, aber vorhersehbarer. Sie können den Algorithmus ändern, um alle Winkel und alle Radien zu untersuchen, die seine aktuelle Position umgeben, bis eine leere Stelle gefunden wird, obwohl dies viel anspruchsvoller ist.
Auf jeden Fall sind dies Beispiele für die Ergebnisse (vorher / nachher):
Bearbeiten> Weitere Beispiele hier
Wie Sie vielleicht sehen, ist die "minimale Bewegung" nicht zufriedenstellend, aber die Ergebnisse sind gut genug.
Ich werde den Code hier veröffentlichen, da ich Probleme mit meinem SVN-Repository habe. Ich werde es entfernen, wenn die Probleme gelöst sind.
Bearbeiten:
Sie können auch R-Bäume verwenden, um Rechteckkreuzungen zu finden, aber es scheint ein Overkill für den Umgang mit einer kleinen Anzahl von Rechtecken zu sein. Und ich habe die Algorithmen noch nicht implementiert. Vielleicht kann Sie jemand anderes auf eine vorhandene Implementierung auf der Plattform Ihrer Wahl verweisen.
Warnung! Code ist ein erster Ansatz. Noch keine gute Qualität und hat sicherlich einige Fehler.
Es ist Mathematica.
Main
HTH!
Bearbeiten: Mehrwinkelsuche
Ich habe eine Änderung im Algorithmus implementiert, die es ermöglicht, in alle Richtungen zu suchen, wobei jedoch die durch die geometrische Symmetrie auferlegte Achse bevorzugt wird.
Auf Kosten von mehr Zyklen führte dies zu kompakteren endgültigen Konfigurationen, wie Sie hier unten sehen können:
Weitere Beispiele hier .
Der Pseudocode für die Hauptschleife wurde geändert in:
Der Kürze halber füge ich den Quellcode nicht hinzu, aber frage einfach danach, wenn du denkst, dass du ihn verwenden kannst. Ich denke, wenn Sie diesen Weg gehen, ist es besser, zu R-Bäumen zu wechseln (hier sind viele Intervalltests erforderlich).
quelle
Hier ist eine Vermutung.
Suchen Sie die Mitte C des Begrenzungsrahmens Ihrer Rechtecke.
Für jedes Rechteck R, das ein anderes überlappt.
Dadurch werden die Rechtecke schrittweise voneinander und von der Mitte aller Rechtecke weg verschoben. Dies wird beendet, weil die Komponente von v aus Schritt 4 sie schließlich von selbst genug verteilt.
quelle
Ich denke, diese Lösung ist der von cape1232 ziemlich ähnlich, aber sie ist bereits implementiert, es lohnt sich also, sie sich anzusehen :)
Folgen Sie dieser reddit-Diskussion: http://www.reddit.com/r/gamedev/comments/1dlwc4/procedural_dungeon_generation_algorithm_explained/ und lesen Sie die Beschreibung und Implementierung. Da kein Quellcode verfügbar ist, ist hier meine Herangehensweise an dieses Problem in AS3 (funktioniert genauso, behält jedoch die Rechtecke in der Auflösung des Rasters bei):
quelle
velocity
ist die Summe der Vektoren zwischen seiner Mitte und der Mitte der anderen Räume, wenn alle Räume mit der gleichen Mitte gestapelt sind,velocity.length == 0
für alle Räume und nichts wird sich jemals bewegen. Wenn zwei oder mehr Räume dasselbe Rechteck mit derselben Mitte haben, bewegen sie sich auf die gleiche Weise zusammen, bleiben jedoch gestapelt.Die Implementierung von b005t3r gefällt mir sehr gut! Es funktioniert in meinen Testfällen, aber mein Repräsentant ist zu niedrig, um einen Kommentar mit den 2 vorgeschlagenen Korrekturen zu hinterlassen.
Sie sollten Räume nicht in Schritten mit einer Auflösung übersetzen, sondern mit der Geschwindigkeit, die Sie gerade berechnet haben! Dies macht die Trennung organischer, da tief geschnittene Räume bei jeder Iteration mehr voneinander trennen als nicht so tief schneidende Räume.
Sie sollten nicht davon ausgehen, dass Velociites unter 0,5 bedeuten, dass Räume getrennt sind, da Sie in einem Fall stecken bleiben können, in dem Sie niemals getrennt sind. Stellen Sie sich vor, 2 Räume kreuzen sich, können sich jedoch nicht selbst korrigieren, da jedes Mal, wenn einer der beiden versucht, die Penetration zu korrigieren, die erforderliche Geschwindigkeit mit <0,5 berechnet wird, sodass sie endlos iterieren.
Hier ist eine Java-Lösung (: Cheers!
quelle
Hier ist ein Algorithmus, der mit Java für die Behandlung eines Clusters nicht gedrehter
Rectangle
s geschrieben wurde. Sie können das gewünschte Seitenverhältnis des Layouts festlegen und den Cluster mithilfe einesRectangle
als Ankerpunkt parametrisierten Parameters positionieren , an dem sich alle vorgenommenen Übersetzungen orientieren. Sie können auch eine beliebige Menge an Polsterung angeben, um die Sie dasRectangle
s verteilen möchten.}}
Hier ist ein Beispiel mit einem
AspectRatio
von1.2
, einemFillPercentage
von0.8
und einemPadding
von10.0
.Dies ist ein deterministischer Ansatz, bei dem Abstände um den Anker herum auftreten können, während die Position des Ankers selbst unverändert bleibt. Auf diese Weise kann das Layout überall dort ausgeführt werden, wo sich der Point of Interest des Benutzers befindet. Die Logik zum Auswählen einer Position ist ziemlich simpel, aber ich denke, die umgebende Architektur, die Elemente nach ihrer Anfangsposition zu sortieren und sie dann zu iterieren, ist ein nützlicher Ansatz zur Implementierung einer relativ vorhersehbaren Verteilung. Außerdem verlassen wir uns nicht auf iterative Schnittpunkttests oder ähnliches, sondern bauen nur einige Begrenzungsrahmen auf, um einen umfassenden Hinweis darauf zu erhalten, wo die Dinge ausgerichtet werden müssen. Danach ist das Auftragen von Polstern ganz natürlich.
quelle
Hier ist eine Version, die die Antwort von cape1232 übernimmt und ein eigenständiges ausführbares Beispiel für Java ist:
quelle