Ich bin mir sicher, dass es bereits einen Algorithmus gibt, der das tut, was ich brauche, aber ich bin mir nicht sicher, welcher Satz für Google oder welche Algorithmuskategorie es ist.
Hier ist mein Problem: Ich habe ein Polyeder, das aus mehreren kontaktierenden Blöcken (Hyperslabs) besteht, d. e. Die Kanten sind achsversetzt und die Winkel zwischen den Kanten sind 90 °. Es kann Löcher im Polyeder geben.
Ich möchte dieses konkave Polyeder in so wenig konvexen, rechtwinklig achsengleich ausgerichteten ganzen Blöcken aufbrechen (wenn das ursprüngliche Polyeder konvex ist und keine Löcher hat, dann ist es schon ein solcher Block und damit die Lösung). Zur Veranschaulichung, einige 2D-Bilder habe ich gemacht (aber ich brauche die Lösung für 3-D, und vorzugsweise, N-D):
Ich habe diese Geometrie:
Eine mögliche Aufteilung in Blöcke ist dies:
Aber die eine, die ich will, ist diese (mit so wenigen Blöcken wie möglich):
Ich habe den Eindruck, dass ein genauer Algorithmus zu teuer sein kann (ist dieses Problem NP-schwer?), so dass ein approximativer Algorithmus geeignet ist.
Ein Detail, das das Problem vielleicht einfacher macht, so dass es einen geeigneteren / spezialisierten Algorithmus geben könnte, dass alle Kanten Größen von mehreren festen Werten haben (Sie können denken, dass alle Kantengrößen ganze Zahlen sind, oder dass die Geometrie besteht aus gleichförmigen kleinen Quadraten oder Voxeln.
Hintergrund: Dies ist die strukturierte Rasterdiskretisierung einer PDE-Domäne.
Welcher Algorithmus kann dieses Problem lösen? Welche Klasse von Algorithmen sollte ich Suche nach?
Update: Bevor Sie diese Antwort upvoten, möchte ich darauf hinweisen, dass meine Antwort leicht vom Thema abweicht. Das Originalplakat hat eine Frage nach der Zerlegung eines Polyeders mit achsgerechten Flächen. Angesichts dieser Art von Polyeder ist es die Frage, es in konvexe Teile zu zerlegen. Und die Frage ist in 3D, möglicherweise nD. Meine Antwort bezieht sich auf die Zersetzung eines allgemeinen Polyeders. Wenn ich also eine Antwort mit einer gegebenen Implementierung gebe, gilt diese Antwort für den Spezialfall der Ausrichtung der Polyederachse, aber es könnte sein, dass es eine bessere Implementierung für achsenausgerichtete Polyeder gibt. Und wenn meine Antwort sagt, dass ein Problem für generisches Polyeder NP-vollständig ist, könnte es sein, dass es eine polynomische Lösung für den Spezialfall achsenausgerichteten Polyeders gibt. Ich weiß es nicht.
Hier ist nun meine (etwas off-topic) Antwort, unter der horizontalen Regel ...
Die CGAL C ++ - Bibliothek hat einen Algorithmus, der bei einem 2D-Polygon die optimale konvexe Zerlegung dieses Polygons berechnen kann. Die Methode wird in dem Teil 2D-Polygonpartitionierung des Handbuchs erwähnt. Die Methode heißt CGAL::optimal_convex_partition_2
. Ich zitiere das Handbuch:
Diese Funktion bietet eine Implementierung von Greenes dynamischem Programmieralgorithmus für optimale Partitionierung [2]. Dieser Algorithmus erfordert im schlechtesten Fall O (n <4 ) Zeit und O (n <3>) Raum.
In der Bibliographie dieses CGAL-Kapitels ist der Artikel [2]:
[2] Daniel H. Greene. Die Zerlegung von Polygonen in konvexe Teile. In Franco P. Preparata, Herausgeber, Computational Geometry , Band 1 von Adv. Comput. Res. , Seiten 235-259. JAI Press, Greenwich, Conn., 1983.
Es scheint genau das zu sein, wonach Sie suchen.
Beachten Sie, dass im selben Kapitel des CGAL-Handbuchs auch eine Annäherung erwähnt wird, die daher nicht optimal ist und in O (n) läuft: CGAL::approx_convex_partition_2
.
Bearbeiten, über den 3D-Fall:
In 3D hat CGAL ein weiteres Kapitel über Konvexe Dekomposition von Polyedern . Im zweiten Absatz des Kapitels heißt es: "Dieses Problem ist bekanntlich NP-schwer [1] ". Die Referenz [1] ist:
[1] Bernard Chazelle. Konvexe Partitionen von Polyedern: ein optimaler Algorithmus für den unteren und den größten Fall. SIAM J. Comput. , 13: 488-507, 1984.
CGAL hat eine Methode CGAL::convex_decomposition_3
, die eine nicht optimale Zerlegung berechnet.
Ich habe das Gefühl, dass dein Problem NP-schwer ist. Ich schlage vor, dass ein erster Schritt darin bestehen könnte, die Figur in Unterrechtecke entlang aller Hyperebenen aufzuteilen. In Ihrem Beispiel wären also drei Hyperebenen (Linien) und vier resultierende Rechtecke vorhanden. Dann wird das Problem darin bestehen, Rechtecke in größere Rechtecke zu kombinieren, um die endgültige Anzahl von Rechtecken zu minimieren. Vielleicht 0-1 Ganzzahl Programmierung?
Ich denke dynamische Programmierung könnte dein Freund sein.
Der erste Schritt, den ich sehe, besteht darin, das Polyeder in eine triviale Sammlung von Blöcken zu unterteilen, so dass jedes mögliche Gesicht verfügbar ist (d. h. es wird in kleinste Stücke geschnitten und in Würfel geschnitten). Dies sollte trivial sein, da alles eine Achse-ausgerichtete Box ist, so dass k-Baum-ähnliche Lösungen ausreichen sollten.
Das erscheint vernünftig, weil ich auf seine Kosten schauen kann. Die Kosten dafür sind, dass ich die ursprüngliche Konfiguration von Hyperslabs "vergesse", indem ich sie durch eine neue Reihe von Hyperslabs ersetze. Der einzige Weg, der mich in die Irre führen könnte, ist, wenn die ursprüngliche Konfiguration etwas für die Lösung zu bieten hat. Da Sie eine "optimale" Lösung für alle Konfigurationen wünschen, müssen wir davon ausgehen, dass die ursprüngliche Struktur nicht sehr hilfreich ist. Ich weiß nicht, ob es bewiesen werden kann, dass diese ursprüngliche Information nutzlos ist, aber ich werde diese Annahme in dieser Antwort machen.
Das Problem wurde nun auf ein Grafikproblem reduziert, das einem Constrained-Spanning-Forest-Problem ähnelt. Ich denke, die natürlichste Art, das Problem zu betrachten, besteht darin, es als ein Graphik-Färbungsproblem zu betrachten (so lange man es vermeiden kann, es mit dem bekannteren Graph-Färbungsproblem zu verwechseln, wenn man versucht, eine Karte ohne zwei Zustände der gleichen Farbgebung zu färben eine Grenze). Ich habe ein Diagramm von Knoten (kleine Blöcke), denen ich jeweils eine Farbe zuweisen möchte (die schließlich das "Hyperslab" sein wird, das diesen Block abdeckt). Ich habe die Einschränkung, dass ich Farben in hyperslab Formen zuweisen muss.
Nun eine wichtige Beobachtung ist, dass nicht alle Möglichkeiten berücksichtigt werden müssen. Nimm das letzte farbige Diagramm, das wir sehen wollen. Wir können diesen Graphen beliebig partitionieren, indem wir ein Hyperslab, das die Partition in zwei Teile teilt, aufbrechen. Nicht jede Partition ist jedoch sinnvoll. Die einzigen Partitionen, die Sinn ergeben, sind Achsen-ausgerichtete Schnitte, die ein Hyper-Slab immer in zwei Hyper-Slabs aufspalten (im Gegensatz zu irgendeiner komplizierteren Form, die auftreten könnte, wenn der Schnitt nicht mit der Achse ausgerichtet wäre).
Jetzt ist dieser Schnitt die Umkehrung des Problems, das wir wirklich zu lösen versuchen. Dieses Schneiden ist eigentlich das, was wir im ersten Schritt gemacht haben. Wir möchten zwar den optimalen Algorithmus zum Zusammenführen finden und diese Schnitte rückgängig machen. Dies zeigt jedoch ein Schlüsselmerkmal, das wir bei der dynamischen Programmierung verwenden werden: Die einzigen Merkmale, die für das Zusammenführen wichtig sind, sind auf der freiliegenden Oberfläche eines Schnitts. Sobald wir die optimale Art gefunden haben, die zentrale Region zu bilden, spielt sie im Allgemeinen keine Rolle.
Beginnen wir also damit, eine Sammlung von Hyperslab-Räumen zu erstellen, die nicht nur ein einfaches Hyperslab definieren können, sondern auch beliebige Konfigurationen von Hyperslabs wie solchen mit Löchern. Jeder hyperslab-Raum zeichnet auf:
Wir definieren dann eine "merge" -Regel, um zwei oder mehr benachbarte hyperslab-Räume in eins zu verwandeln:
Jetzt ist das genug, um das Problem mit roher Gewalt zu lösen. Die Lösung wird mit Sicherheit NP-vollständig sein. Wir können jedoch eine zusätzliche Regel hinzufügen, die diese Kosten dramatisch senkt: "Ein Hyperslab-Raum wird als" besser "angesehen als ein anderer, wenn er den gleichen Raum abdeckt und genau dieselben Merkmale auf seiner Oberfläche hat mit weniger Hyperslabs drin ist es die bessere Wahl. "
Nun ist die Idee hier, dass Sie früh im Algorithmus alle Arten von Kombinationen im Auge behalten müssen, nur für den Fall, dass sie am nützlichsten sind. Da jedoch der Zusammenführungsalgorithmus die Dinge größer und größer macht, wird es weniger wahrscheinlich, dass interne Details auf der Oberfläche des Hyperslab-Raums exponiert werden. Bedenken Sie
%Vor%Sieh dir die linke Seitenbox an, die ich in stärkeren Linien markieren durfte. Wenn es darum geht, Boxen mit dem Rest der Welt zu verschmelzen, ist die AB: XY-Oberfläche alles, worauf es ankommt. Daher gibt es nur eine Handvoll von Zusammenführungsmustern, die an dieser Oberfläche auftreten können
Es gibt viele Möglichkeiten, das 3x3-Quadrat zu bedecken (mindestens ein paar Dutzend).Wir müssen uns jedoch nur daran erinnern, wie Sie diese Merge-Prozesse am besten erreichen können. Sobald wir diesen Punkt in der dynamischen Programmierung erreicht haben, können wir alle anderen möglichen Kombinationen vergessen und uns nur auf den besten Weg konzentrieren, um die einzelnen Oberflächenfunktionen zu erreichen.
Tatsächlich stellt dies das Problem für einen leicht gierigen Algorithmus dar, der untersucht, welche Zusammenführungen das beste Versprechen zur Verringerung der Anzahl von Hyperslabs liefern, wobei immer daran erinnert wird, wie eine gegebene Menge von Oberflächenmerkmalen am besten erreicht werden kann. Wenn der Algorithmus fertig zusammengeführt wird, ist der optimale Layout, unabhängig vom endgültigen Hyperlab-Raum.
Ich weiß nicht, ob es beweisbar ist, aber mein Bauchgefühl glaubt, dass dies ein O (n ^ d) -Algorithmus sein wird, wobei d die Anzahl der Dimensionen ist. Ich denke, die Worst-Case-Lösung wäre eine Sammlung von Hyperslabs, die zusammen ein großes Hyperslab bilden. In diesem Fall glaube ich, dass der Algorithmus sich schließlich in die Umkehrung eines k-Baum-Algorithmus einarbeiten wird. Auch hier gibt es keinen Beweis ... es ist nur mein Bauchgefühl.
Können Sie die Gleichungen für jede Linie bestimmen? Wenn ja, können Sie vielleicht die Kreuzung (Punkte) zwischen diesen Linien bekommen. Wenn Sie dann eine Achse nehmen und nach einem Wert suchen, der mehr als zwei Punkte hat (diesen Wert teilen), dann sollten Sie eine Linie "zeichnen". (Zu Beginn des Sweeps gibt es null Punkte, dann zwei (Ihr erstes Paar) und wenn Sie mehr als zwei Punkte finden, können Sie bestimmen, welche Punkte vom ersten und welche vom zweiten Polygon sind.
Wenn Sie beispielsweise folgende Zeilen haben:
Verticals (rot):
x = 0, x = 2, x = 5
horizontals (gelb):
y = 0, y = 2, y = 3, y = 5
und du fängst an, durch die X-Achse zu fegen, du wirst p1 und p2 bekommen (und wir wissen, zu welcher Liniengleichung sie gehören), dann wirst du p3, p4, p5 und p6 bekommen !! Hier können Sie überprüfen, welche dieser Punkte die gleiche Zeile von p1 und p2 haben. In diesem Fall p4 und p5. Ihr erstes neues Polygon ist also p1, p2, p4, p5. Jetzt speichern wir das "neue" Punktepaar (p3, p6) und fahren mit dem Sweep bis zu den nächsten Punkten fort. Hier haben wir p7, p8, p9 und p10, suchen nach den Punkten, die die Linie der vorherigen Punkte teilen (p3 und p6) und wir erhalten p7 und p10. Das sind die Punkte deines zweiten Polygons.
Wenn wir die Übung für die Y-Achse wiederholen, erhalten wir zwei Punkte (p3, p7) und dann nur drei (p1, p2, p8)! In diesem Fall sollten wir den weitesten Punkt (p8) in der gleichen Zeile des neu entdeckten Punktes verwenden.
Da wir Linien Gleichungen und Punkte 2 oder mehr Dimensionen verwenden, sollte das Verfahren sehr ähnlich sein
ps, Entschuldigung für mein Englisch: S
Ich hoffe, das hilft:)
Tags und Links algorithm partitioning computational-geometry