1

I am rendering terrain using a quad-tree system. I need to split a height-map into four sections using the method splitHeightmap(float[] originalMap, int quadrant) with the quadrant being a number from 0-3. The map needs to be split into quarters so if 0 is passed as the quadrant, the bottom left quarter of the array is returned as a new float array. I have a little base code, but I'm not sure how to actually sample the map depending on the desired quadrant:

protected float[] splitHeightMap(float[] heightMap, TerrainQuadrant quadrant) {
    float[] newHeightMap = new float[size >> 1];
    int newSize = size >> 1;

    for (int i = 0; i < newSize; i++)
        for (int j = 0; j < newSize; j++)
            newHeightMap[i * newSize + j] = sampleHeightAt(heightMap, i, j);


    return newHeightMap;
}

protected float sampleHeightAt(float[] heightMap, int x, int z) {
    return heightMap[z + x * size];
}

Edit: I have written what I think should work, but am getting a ArrayIndexOutOfBoundsException for index 65792 (with a original heightmap of 512x512):

    protected float[] splitHeightMap(float[] heightMap, TerrainQuadrant quadrant) {
    float[] newHeightMap = new float[(size >> 1) * (size >> 1)];
    int newSize = size >> 1;

    int xOffset = 0, zOffset = 0;
    int xCount = 0, yCount = 0;

    switch (quadrant) {
        case BottomRight:
            xOffset = newSize;
            break;
        case TopLeft:
            zOffset = newSize; 
            break;
        case TopRight:
            xOffset = newSize;
            zOffset = newSize;
            break;
        default:
            break;
    }

    for (int x = xOffset; x < xOffset + newSize; x++)
        for (int z = zOffset; z < zOffset + newSize; z++) {
            newHeightMap[xCount + yCount * newSize] = heightMap[z + x * size];  // should this be 'z + x * size' or 'x + z * size'?

            xCount++;
            yCount++;
        }

    return newHeightMap;
}
Isaac Woods
  • 1,114
  • 1
  • 17
  • 28

1 Answers1

2

If I understand you correctly, then you have to use two-dimensional array. With such type of array it's easy to fetch any area of the array.

Your heightMap now gona be float[][] type, so you must correct your code, where you fill this array.

I have implemented one examlpe for you and used 4x4 array:

| 2 2 3 3 |
| 2 2 3 3 | 
| 0 0 1 1 | 
| 0 0 1 1 |

As I understand you want to fetch areas like all '0', all '1', all '2' and all '3'.

    public static void main ( String[] args )
    {
        //setting up initial array 'heightMap' (you can name it like you want)
        float[][] f = { { 2, 2, 3, 3 }, { 2, 2, 3, 3 }, { 0, 0, 1, 1 }, { 0, 0, 1, 1 } };

        float[][] f2 = splitHeightMap ( f, TerrainQuadrant.BotttomRight );
        for ( float[] floats : f2 )
        {
            System.out.println ( Arrays.toString ( floats ) );
        }
    }

    protected static float[][] splitHeightMap ( float[][] heightMap, TerrainQuadrant quadrant )
    {
        //this gives you half of the 'heightMap' length
        int newSize = heightMap.length >> 1;
        float[][] newHeightMap = new float[ newSize ][ newSize ];

        //its your offsets, indicating from what place to start iteration
        int xOffset = 0;
        int yOffset = newSize;

        //its max values to reach while iterating
        int xRestriction = newSize;
        int yRestriction = heightMap.length;

        //setting up params according to 'quadrant'
        switch ( quadrant )
        {
            case BottomRight:
                xOffset = newSize;
                yOffset = newSize;

                xRestriction = heightMap.length;
                break;
            case TopLeft:
                yOffset = 0;

                yRestriction = newSize;
                break;
            case TopRight:
                yOffset = 0;
                xOffset = newSize;

                xRestriction = heightMap.length;
                yRestriction = newSize;
                break;
            default:
                break;
        }

        //counters not to reach new array bounds
        int xCount = 0, yCount = 0;
        for ( int y = yOffset; y < yRestriction; y++ )
        {
            //taking row at 'y' position
            float[] row = heightMap[ y ];
            for ( int x = xOffset; x < xRestriction; x++ )
            {
                //taking value from 'y' row at 'x' position.
                float value = row[ x ];

                //set fetched value to new map.
                newHeightMap[ yCount ][ xCount ] = value;

                //increase x position, but do not touch row
                xCount++;
            }

            //new row - new 'x' position
            xCount = 0;
            yCount++;
        }
        return newHeightMap;
    }

This implementation shows you :

| 1 1 |
| 1 1 |

To change it - change main method.

Michael Zhavzharov
  • 1,727
  • 13
  • 26
  • 1
    Its my pleasure. According to this http://stackoverflow.com/a/2512168/2168532 answer, differences in linear read and write is so insignificant, that they almost won't affect the performance. – Michael Zhavzharov Aug 15 '14 at 13:28