Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

02.07.2015, 17:27

2D-Array in feiner werdenden Gittern iterieren

Hallo,

sagen wir, ich habe ein 4096x4096-2d-Array (wobei die Größe idealerweise beliebig sein kann) und möchte es zuerst in einem groben, dann sukzessive immer feineren, regelmäßigem Gitter iterieren und dabei jeden Index genau einmal besuchen. Für so was muss es doch irgendwo schon einen Algo geben, aber ich finde leider nichts. Für den 1D-Fall lässt sich das sehr simpel umsetzen, indem man Startindex und Schrittgröße geeignet wählt. Die Verallgemeinerung auf 2D funktioniert aber nicht mehr ohne Lücken oder Mehrfachbesuche. Und die Alternative, den 2D-Index erst auf 1D umzurechnen, dort den 1D-Algo auszuführen und dann wieder auf einen 2D-Index umzurechnen, ergibt kein regelmäßiges Gitter, weil dann zuerst ganze Spalten oder Zeilen vor anderen Bereichen des Arrays besucht werden.

Ideen? ;)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

02.07.2015, 18:15

Das geht rekursiv ganz prima. Die Frage ist eher: wozu?
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

3

02.07.2015, 18:22

Ich versteh leider nicht genau, was du willst. Wieso funktioniert das mit der Schrittgröße in 2D nicht mehr?

4

04.07.2015, 15:18

Das geht rekursiv ganz prima. Die Frage ist eher: wozu?


Um z.B. dem User ein Objekt anzuzeigen, was vorher an allen Punkten evaluiert werden muss. Und damit dieser nicht warten muss, bis alles komplett fertig ist, zeigt man ihm eben ein Schritt für Schritt feineres Raster an, damit er möglichst schnell reagieren kann. Eine rekursive Lösung ist mir auch schon eingefallen, aber rekursive Algos kann man eben nicht immer auf so großen Matrizen nehmen, weil es irgendwann zu viele Stackebenen gibt. In dem Fall allerdings halbiert er die Eingabegröße ja pro Schritt ja in beiden Dimensionen. Da müsste man also doch recht weit mit kommen... ;)

Ich versteh leider nicht genau, was du willst. Wieso funktioniert das mit der Schrittgröße in 2D nicht mehr?


Für 1d, der Einfachheit halber 1x8, würde das so aussehen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
bool arr[8] = {false};
for(int i = 3; i >= 0; --i)
{
  int start = (1 << i) -1;
  int step = (1 << (i+1));
  for(int u = start; u < 8; u += step)
    arr[u] = true;
}


Da kommt dann raus:
[_|_|_|_|_|_|_|_]
[_|_|_|_|_|_|_|x]
[_|_|_|x|_|_|_|x]
[_|x|_|x|_|x|_|x]
[x|x|x|x|x|x|x|x]

Und der Algo lässt sich jetzt eben nicht straight-forward auf 2d verallgemeinern, ohne dass man Indizes gar nicht oder doppelt besucht hat.

5

04.07.2015, 15:59

Suchst du vielleicht nach einem Interlacing-Algorithmus?

6

06.07.2015, 12:20

Ja, das ist schon ziemlich genau das, was ich suche. Ich würde mir jetzt nur wünschen, dass ich meine Iterationsgröße abhängig von der Eingangsgröße machen kann und nicht z.B. wie bei Adam7 alias dem PNG-Interlacing-Algo immer in fixen 8x8 Patches iterieren muss. Geht das auch irgendwie?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

06.07.2015, 15:34

Naja, dein Beispiel zeigt ja, wie man es für den 1D Fall machen kann. Nehmen wir also einfach an, dass unser 1D Index der Index in einer Linearisierung eines nD Arrays ist, nehmen wir beispielsweise eine Z-Kurve, und drehen diese Linearisierung um:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <cstdint>
#include <cmath>
#include <algorithm>
#include <iostream>



template <int N, int M>
void print(std::ostream& file, int(&b)[N][M])
{
    for (int j = 0; j < N; ++j)
    {
        file << '[';
        for (int i = 0; i < M; ++i)
            file << static_cast<char>(b[j][i] == 0 ? ' ' : '0' + b[j][i]);
        file << "]\n";
    }
}


template <unsigned int n, unsigned int i = 0, unsigned int j = 0, bool r = true>
struct ZCurveOrder;

template <unsigned int n, unsigned int i, unsigned int j>
struct ZCurveOrder<n, i, j, false>
{
    static std::uint32_t deZ(std::uint32_t x)
    {
        return 0U;
    }
};

template <unsigned int n, unsigned int i, unsigned int j, bool r>
struct ZCurveOrder
{
    static_assert(i < n, "invalid z-curve parameters");

    static std::uint32_t deZ(std::uint32_t x)
    {
        return ZCurveOrder<n, i, j + 1, n * (j + 1) + i < 31>::deZ(x) | (((x & (1U << (n * j + i))) >> (n * j + i)) << j);
    }
};

template <unsigned int n, unsigned int i>
std::uint32_t deZ(std::uint32_t x)
{
    return ZCurveOrder<n, i, 0>::deZ(x);
}


int main()
{
    const int w = 1 << 5;

    int blub[w][w] = {};

    for (int k = static_cast<int>(std::floor(std::log2(w * w))); k >= 0; --k)
    {
        int step = 1 << (k + 1);
        int start = (1 << k) - 1;

        for (int i = start; i < w * w; i += step)
        {
            int x = deZ<2, 0>(i);
            int y = deZ<2, 1>(i);

            //int y = i / w;
            //int x = i % w;

            ++blub[y][x];
        }

        print(std::cout, blub);
        std::cout << '\n';
    }

    return 0;
}

Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von »dot« (06.07.2015, 16:08)


8

09.07.2015, 15:31

Das sieht ziemlich abgefahren aus, wäre aber so ziemlich exakt das, was ich suche. Hast du das selbst geschrieben oder ist das von irgendwo kopiert?
Magst du mal erklären, was z.B. die ganzen Template-Parameter bedeuten. So ganz blick ich durch die abgefahrene Index-Berechnung noch nicht durch. :D

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

09.07.2015, 15:44

Das sieht ziemlich abgefahren aus, wäre aber so ziemlich exakt das, was ich suche. Hast du das selbst geschrieben oder ist das von irgendwo kopiert?

Das is einfach mal so hinimprovisiert, wenn ich dazu ne Quelle wüsste, hätt ich die einfach verlinked... :P

Magst du mal erklären, was z.B. die ganzen Template-Parameter bedeuten. So ganz blick ich durch die abgefahrene Index-Berechnung noch nicht durch. :D

Die Grundidee der Z-order Curve ist ja einfach, dass man den linearen Index bekommt, indem man die Bits der x-Koordinate und y-Koordinate interleaved, also z.B. die Bits von x kommen in die Bits 0, 2, 4, 6, ... und die Bits von y in die Bits 1, 3, 5, 7, ... des linearen Index. Was ich hier mache ist einfach die Umkehrung: Ich nehme deinen linearen 1D Index und nehm aus dem einfach die Bits 0, 2, 4, 6, ... um die x- und die Bits 1, 3, 5, 7, ... um die y-Koordinate zu bilden. Der Templatekram implementiert einfach das Rauskitzeln der Bits (nur gleich für den allgemeinen, n-Dimensionalen Fall; ZCurveOrder<n, i, j>::deZ(x) extrahiert aus x das j-te Bit der i-ten Koordinate bei n-Dimensionen, das bool Flag dient nur zum Abbrechen der Rekursion).

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (09.07.2015, 15:50)


TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

10

09.07.2015, 16:09

Warum nicht so?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
bool arr[8] = {false};
for(int i = 3; i > 0; --i)
{
  int start = (1 << i) -1;
  int step = (1 << (i+1));
  for(int u1 = start; u1 < 8; u1 += step)
     for(int u2 = start; u2 < 8; u2 += step)
    arr[u1][u2] = true;
}

Werbeanzeige