Über Nachbarfelder einer Matrix iterieren
-
Guten Tag,
ich habe in meinem Code eine Matrix die folgendermaßen realisiert ist:
std::vector<std::vector<std::unique_ptr<MyField>>>Jedes der Felder besitzt einen Wert, welcher sich durch alle direkten Nachbarfelder ergibt (horizontal, vertikal, diagonal).
Ich möchte jetzt für jedes Feld über dessen Nachbarfelder iterieren um auf diese zugreifen zu können. Dabei stellen sich mir einige Probleme bezüglich des Abprüfens der Indexgrenzen.
Gibt es dafür elegante Lösungen? Momentan sieht das in etwa so bei mir aus:
[...] if (i - 1 > 0) result += pitch[i - 1][k]->getWeight(); if (i + 1 < size) result += pitch[i + 1][k]->getWeight(); if (i - 1 > 0 && k + 1 < size) result += pitch[i - 1][k + 1]->getWeight(); if (i + 1 < size && k - 1 > 0) result += pitch[i + 1][k - 1]->getWeight();Das finde ich dermaßen unschön, hat da jemand Verbesserungsvorschläge?
-
using matrix = std::vector<std::vector<std::unique_ptr<MyField>>>; double getWeightSafe(matrix const &m, size_t i, size_t j, double defaultValue = 0) { if (i >= m.size() || j >= m[i].size()) { return defaultValue; } return m[i][j]->getWeight(); } // ... result += getWeightSafe(pitch, i, j);
-
Gibt es einen speziellen Grund, wieso du
std::vector<std::vector<std::unique_ptr<MyField>>>anstatt
std::vector<MyField>verwendest?
-
matrix as linked list schrieb:
Gibt es einen speziellen Grund, wieso du
std::vector<std::vector<std::unique_ptr<MyField>>>anstatt
std::vector<MyField>verwendest?
Edit: ich bezieh mich auf den unique_ptr.
Vielleicht weiß er vorher nicht wie groß die Matrix wird und die einzelnen Objekte sind zu "schwer" für das Copy beim vector resize.Wäre jetzt der einzige Grund der mir im Moment einfallen würde.
-
Von MyField erben zwei Klassen die die virtuelle Methode getWeight() überschreiben, daher der unique_ptr.
An sich finde ich den oberen Ansatz deutlich besser, am liebsten hätte ich jetzt aber sowas:
for (std::size_t i = 0; i < pitch.size(); ++i) { for (std::size_t k; k < pitch.size(); ++k) { NeighbourIterator<FieldPtr> it(&pitch[i][k]); auto result = std::accumulate(std::begin(it), std::end(it), 0, calculator); it->setValue(result); } }Es wird also für jedes Element in der Matrix über alle Nachbarn iteriert und über meinen Funktor calculate die *getWeight()*s der Nachbarfelder zusammengezählt und in dem aktuellen Feld gespeichert.
Diesen NeighbourIterator muss ich jetzt natürlich selber implementieren, und da fehlt mir definitiv das Detailwissen über die STL-Iteratoren. Kann mir da jemand Tipps/Links geben?
Insbesondere die Tatsache, wie ich den operator++() überschreiben muss um quasi "einmal im Kreis" auf alle Nachbarn zu verweisen bereitet mir momentan noch Kopfschmerzen.
-
skhdfglshjgl schrieb:
An sich finde ich den oberen Ansatz deutlich besser, am liebsten hätte ich jetzt aber sowas:
bsist du dir sicher dass das notwendig ist?
wenn du das gut (= wieder verwendbar) für 2D faltung machen willst solltest man die "kreis"-größe einstellen können (also nicht nur über direkte nachbarn, spndern auch über deren nachbarn etc. laufen können).außerdem muss man verschiedene randbedingungen unterbringen: ich hab in meinem beispiel die simpelste angenommen, nämlich einfach alles 0 was außerhalb der matrix ist. Gerade bei faltungs-operationen sind aber andere viel interessanter (spiegeln etc.). weiß nicht wie man das mit iteratoren sauber lösen würde, schließlich müsstest du in den iteratoren speichern ob diese auf ein äußeres element zeigen oder nicht und dann in deinem calculator functor den iterator entsprechend spiegeln - geht wahrscheinlich schon irgendwie, ist aber bestimmt nicht so einfach.
mit zwei for-schleifen und ein bisschen index-rechnen ist das dagegen sehr leicht, also überlegs dir gut
