Zunächst einmal, ich denke, es ist eine Überlegung wert, was Ihre wirkliche Anforderung ist.Ich vermute, dass es nicht nur ist, "die aktiven Punkte und keine der anderen so platzsparend wie möglich zu speichern", sondern auch eine gewisse Menge an "benachbarten Punkten in nahegelegenen Speicherorten zu speichern, damit Sie ein gutes Caching-Verhalten bekommen" und "speichert Punkte in einer Weise, für die Nachschläge effizient durchgeführt werden können".
Mit diesem gesagt, hier ist, was ich vorschlagen würde. Teilen Sie die gesamte 3D-Region in kubische Blöcke gleicher Größe auf. Speichern Sie für jeden Block alle Punkte im Block in dichten Arrays, einschließlich eines booleschen isTissue-Arrays, ob sich jeder Punkt in der Gewebezone befindet oder nicht. Ordnen Sie nur die Blöcke zu, die Punkte enthalten. Erstellen Sie ein (dichtes) Array von Zeigern auf Blöcke mit NULL-Zeigern für nicht zugeordnete Blöcke.
Um also den Punkt bei (i, j) zu finden, berechnen Sie zunächst ii = i/blockside, jj = j/blocksize, und dann in der Pointer-to-Block-Tabelle bei (ii, jj) nach finde den Block, der deinen Punkt enthält. Wenn dieser Zeiger NULL ist, ist Ihr Punkt nicht im Gewebe. Wenn es nicht null ist, sehen Sie (i mod blocksize, j mod blocksize) in diesem Block, und da ist Ihr Punkt (i, j). Sie können sein isTissue-Flag überprüfen, um zu sehen, ob es ein "gegenwärtiger" Punkt ist oder nicht.
Sie sollten die Blockgröße als Ausgleich zwischen der Minimierung der Anzahl der Berechnungen benachbarter Punkte, die Blockgrenzen überschreiten, und der Minimierung der Anzahl der Punkte in Blöcken, aber nicht im Gewebebereich, wählen. Ich nehme an, dass mindestens eine Zeile des Blocks eine Cache-Zeile lang sein soll. Wahrscheinlich ist das Optimum eher größer als das, obwohl es zumindest etwas von Ihrer Geometrie abhängen wird.
Um über alle Punkte in einer 3D-Box zu iterieren, würden Sie entweder nur nach jedem Punkt suchen oder (effizienter) herausfinden, welche Blöcke die Box berührt und iterieren über die Bereiche in diesen Blöcken Box, überspringt die, wo isTissue falsch ist.
Wenn Sie viele Zuweisungen und Neuzuweisungen von Blöcken durchführen, möchten Sie wahrscheinlich Blöcke "aufheben", indem Sie sie in einen "unbenutzten" Pool ablegen und dann Blöcke aus diesem Pool herausziehen, anstatt sie neu zuzuweisen . Dies hat auch den Vorteil, dass für diese Blöcke bereits alle Punkte auf "nicht vorhanden" gesetzt sind (weil Sie den Block deshalb deklariert haben), so dass Sie sie nicht initialisieren müssen.
Der erfahrene Leser wird wahrscheinlich Ähnlichkeiten zwischen diesen und Möglichkeiten zum Auslegen von Daten für parallele Berechnungen erkennen; Wenn Sie eine wirklich große Simulation haben, können Sie die Blöcke problemlos über mehrere Knoten verteilen, und Sie müssen nur für die Kreuzblockberechnungen übergreifend kommunizieren. Für diese Art von Anwendung kann es nützlich sein, verschachtelte Ebenen von Blöcken zu machen, bei denen Sie Metablöcke (für die Kreuzknoten-Kommunikation) mit kleineren Blöcken (für die Geometrie) haben.
Ich bin nur neugierig ... Verwenden Sie die Gewebegeometrie Daten, um irgendeine Art von Rendering zu tun? –
Ich bin mir nicht ganz klar, was deine Geometrie hier ist. Sie erwähnen, dass jeder Punkt orthogonale Nachbarn hat, was ein regelmäßiges Gitter von Punkten impliziert, aber dann beziehen Sie sich auf sparse Daten. Habe ich recht, wenn ich verstehe, dass Ihre Punktmenge im Wesentlichen eine (verbundene) Teilmenge der Punkte in einem regelmäßigen Gitter ist? –