[C#] Extending a 1D array gives incorrect results when accessed as 3D array

Started by
5 comments, last by Spa8nky 13 years, 7 months ago
If I have an array:

int[] array = new int[]


I can then access the array like a 3D array using:

int index = x * width * height + y * width + z;array[index]


The problem is that when I extend an array dimension (in this case the width) using the following set property:

                width = value;                // Create a temporary array using the new dimensions                int[] tempArray = new int[depth * height * width];                if (width > oldWidth)                {                    // Copy the current tiles to that array                    array.CopyTo(tempArray, 0);                }                else                {                    for (int i = 0; i < tempArray.Length; ++i)                    {                        tempArray = array;                    }                }                array = tempArray;


the indices of the elements are no longer valid.

How can I adjust a dimension of the 1D array and assign the original elements so they can be accessed in the same way?
Advertisement
Imagine 2D array (for simplicity) of a 3x3 elements:
123456789
When written as 1D array, it looks like this:
123456789


When such an array is resized to 4x4, using the algorithm above, the 1D array looks like this:
123456789000000


If this is displayed as 2D array, it looks like this:
1234567890000000


Does this explain the problem?
That explains the problem I am having perfectly.

So I need to find a way to copy the old dimensional structure to the new dimensions... Is this method over the top?

                // Create a temporary array using the new dimensions                int[] tempArray = new int[width * height * depth];                for (int x = 0; x < depth; ++x)                {                    for (int y = 0; y < height; ++y)                    {                        for (int z = 0; z < oldWidth; ++z)                        {                            int i0 = x * width * height + y * width + z;                            int i1 = x * oldWidth * height + y * oldWidth + z;                            tempArray[i0] = array[i1];                        }                    }                } 
Quote:Original post by Spa8nky
So I need to find a way to copy the old dimensional structure to the new dimensions... Is this method over the top?


It's straightforward. A "more efficient" algorithm would be possible, but those quickly become convoluted.

 int i1 = x * oldWidth * height + y * oldWidth + z;
height should be oldHeight.

for (int y = 0; y < height; ++y)
Same here.

There is no reason to write same algorithm for each of dimensions being changed.
Quote:Original post by Antheus
There is no reason to write same algorithm for each of dimensions being changed.


Something like this method then:

        private void Resize(int oldWidth, int oldHeight, int oldDepth, int width, int height, int depth)        {            // Create a temporary array using the new dimensions            int[] tempArray = new int[width * height * depth];            for (int x = 0; x < oldDepth; ++x)            {                for (int y = 0; y < oldHeight; ++y)                {                    for (int z = 0; z < oldWidth; ++z)                    {                        int i0 = x * width * height + y * width + z;                        int i1 = x * oldWidth * oldHeight + y * oldWidth + z;                        tempArray[i0] = array[i1];                    }                }            }            array = tempArray;        }


Shouldn't I add the following lines to the top of the method to handle cases where the new dimension is smaller than the old one?

            oldDepth = Math.Min(oldDepth, depth);            oldHeight = Math.Min(oldHeight, height);            oldWidth = Math.Min(oldWidth, width);
That would cause "int i1 = x * oldWidth * oldHeight + y * oldWidth + z;" to be the wrong index again. You just want to clamp the region you are looping over, nothing else.
Like so?

            int xEnd = Math.Min(oldDepth, depth);            int yEnd = Math.Min(oldHeight, height);            int zEnd = Math.Min(oldWidth, width);            // Create a temporary array using the new dimensions            int[] tempArray = new Tile3D[width * height * depth];            for (int x = 0; x < xEnd; ++x)            {                for (int y = 0; y < yEnd; ++y)                {                    for (int z = 0; z < zEnd; ++z)                    {                        int i0 = x * width * height + y * width + z;                        int i1 = x * oldWidth * oldHeight + y * oldWidth + z;                        tempArray[i0] = array[i1];                    }                }            }

This topic is closed to new replies.

Advertisement