c# .net arrays 3d flatten

c# - ¿Cómo “aplanar” o “indexar” la matriz 3D en una matriz 1D?



.net arrays (8)

Estoy tratando de aplanar la matriz 3D en la matriz 1D para el sistema "chunk" en mi juego. Es un juego de bloques en 3D y, básicamente, quiero que el sistema de trozos sea casi idéntico al sistema de Minecraft (sin embargo, este no es un clon de Minecraft en ningún sentido). En mis juegos 2D anteriores he accedido a la matriz aplanada con el siguiente algoritmo:

Tiles[x + y * WIDTH]

Sin embargo, esto obviamente no funciona con 3D ya que le falta el eje Z. No tengo idea de cómo implementar este tipo de algoritmo en el espacio 3D. El ancho, la altura y la profundidad son todas constantes (y el ancho es tan grande como la altura).

¿Es solo x + y*WIDTH + Z*DEPTH ? Soy bastante malo con las matemáticas y estoy empezando la programación en 3D, así que estoy bastante perdido: |

PD. La razón de esto es que estoy haciendo bucles y obteniendo cosas por índice bastante. Sé que las matrices 1D son más rápidas que las matrices multidimensionales (por razones que no puedo recordar: P). Aunque esto no sea necesario, quiero el mejor rendimiento posible :)


Aquí hay una solución en Java que te da ambas cosas:

  • de 3D a 1D
  • de 1D a 3D

A continuación se muestra una ilustración gráfica de la ruta que elegí para atravesar la matriz 3D, las celdas están numeradas en su orden de recorrido:

Funciones de conversión:

public int to1D( int x, int y, int z ) { return (z * xMax * yMax) + (y * xMax) + x; } public int[] to3D( int idx ) { final int z = idx / (xMax * yMax); idx -= (z * xMax * yMax); final int y = idx / xMax; final int x = idx % xMax; return new int[]{ x, y, z }; }


Creo que lo anterior necesita una pequeña corrección. Digamos que tiene una ALTURA de 10, y una ANCHO de 90, la matriz unidimensional será 900. Según la lógica anterior, si se encuentra en el último elemento de la matriz 9 + 89 * 89, obviamente es mayor que 900. El algoritmo correcto es:

Flat[x + HEIGHT* (y + WIDTH* z)] = Original[x, y, z], assuming Original[HEIGHT,WIDTH,DEPTH]

Irónicamente, si tiene el ALTURA> ANCHO, no experimentará un desbordamiento, solo complete los resultados descontrolados;)


El algoritmo correcto es:

Flat[ x * height * depth + y * depth + z ] = elements[x][y][z] where [WIDTH][HEIGHT][DEPTH]


El algoritmo es mayormente el mismo. Si tiene una matriz 3D Original[HEIGHT, WIDTH, DEPTH] , puede convertirla en Flat[HEIGHT * WIDTH * DEPTH] mediante

Flat[x + WIDTH * (y + DEPTH * z)] = Original[x, y, z]

Como un aparte, deberías preferir matrices de matrices sobre matrices multidimensionales en .NET. Las diferencias de rendimiento son significativas.


Para comprender mejor, la descripción de la matriz 3D en 1D sería (supongo que Profundidad en la mejor respuesta significa tamaño Y)

IndexArray = x + y * InSizeX + z * InSizeX * InSizeY; IndexArray = x + InSizeX * (y + z * InSizeY);


TL; DR

La respuesta correcta se puede escribir de varias maneras, pero me gusta más cuando se puede escribir de una manera que sea muy fácil de entender y visualizar. Aquí está la respuesta exacta:

(width * height * z) + (width * y) + x

TS; DR

Visualízalo:

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

someNumberToRepresentZ indica en qué matriz estamos ( depth ). Para saber en qué matriz estamos, debemos saber qué tan grande es cada matriz. Una matriz es de tamaño 2d como width * height , simple. La pregunta que debe hacerse es " ¿cuántas matrices hay antes de la matriz en la que estoy?" La respuesta es z :

someNumberToRepresentZ = width * height * z

someNumberToRepresentY indica en qué fila estamos ( height ). Para saber en qué fila estamos, debemos saber qué tan grande es cada fila: cada fila es 1d, dimensionada como width . La pregunta que debe hacerse es " ¿cuántas filas hay antes de la fila en la que estoy?". La respuesta es y :

someNumberToRepresentY = width * y

someNumberToRepresentX indica en qué columna estamos ( width ). Para saber en qué columna estamos, simplemente usamos x :

someNumberToRepresentX = x

Nuestra visualización entonces de

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

Se convierte

(width * height * z) + (width * y) + x


Ya casi estás ahí. Necesitas multiplicar Z por WIDTH y DEPTH :

Tiles[x + y*WIDTH + Z*WIDTH*DEPTH] = elements[x][y][z]; // or elements[x,y,z]


x + y*WIDTH + Z*WIDTH*DEPTH . Visualícelo como un sólido rectangular: primero recorre a lo largo de x , luego cada y es un width "línea", y cada z es un "plano" pasos WIDTH*DEPTH en el área.