Diamond-square algorithm not working (rewrite code from JS to JAVA)

I am trying rewrite code from JS to Java. The code is Diamond square algorithm.

Source is: http://www.playfuljs.com/realistic-terrain-in-130-lines/

I rewrite code, but my code not working...

Output is bad.

My code in Java is:

public class MapGenerator {

    public static void main(String[] args) {
        MapGenerator mg = new MapGenerator(9);
        mg.generate();
        mg.printMap();
    }

    private int size, max;
    double[] map;
    int[][] matrix;

    public MapGenerator(int detail) {
        this.size = (int) Math.pow(2, detail) + 1;
        this.max = this.size - 1;
        this.map = new double[this.size * this.size];
    }

    private double get(int x, int y) {
        if (x < 0 || x > this.max || y < 0 || y > this.max) {
            return -1;
        }
        return this.map[x + this.size * y];
    }

    private void set(int x, int y, double val) {
        this.map[x + this.size * y] = val;
    }

    public void generate() {
        set(0, 0, max);
        set(this.max, 0, max / 2);
        set(this.max, this.max, 0);
        set(0, this.max, max / 2);
        divide(this.max);

        buildMatrix();
        saveTerrain(0, 0, 0, 0, matrix, "vystup.ter");
    }

    private void buildMatrix() {
        matrix = new int[size][size];

        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                matrix[i][j] = (int) map[i + j];
            }
        }

    }

    private void divide(int size) {
        //? 
        double roughness = 0.7;

        int x, y, half = size / 2;
        double scale = roughness * size;

        if (half < 1) {
            return;
        }
        for (y = half; y < max; y += size) {
            for (x = half; x < max; x += size) {
                square(x, y, half, Library.randInt(0, 100) * scale * 2 - scale);
            }
        }
        for (y = 0; y <= max; y += half) {
            for (x = (y + half) % size; x <= max; x += size) {
                diamond(x, y, half, Library.randInt(0, 100) * scale * 2 - scale);
            }
        }
        divide(size / 2);
    }

    private void square(int x, int y, int size, double offset) {

        double tmp_1 = get(x, y - size);   // top
        double tmp_2 = get(x + size, y);      // right
        double tmp_3 = get(x, y + size);     // bottom
        double tmp_4 = get(x - size, y);       // left

        set(x, y, ((tmp_1 + tmp_2 + tmp_3 + tmp_4) / 4.0) + offset);
    }

    private void diamond(int x, int y, int size, double offset) {
        double tmp_1 = get(x, y - size);      // top
        double tmp_2 = get(x + size, y);      // right
        double tmp_3 = get(x, y + size);      // bottom
        double tmp_4 = get(x - size, y);      // left

        set(x, y, ((tmp_1 + tmp_2 + tmp_3 + tmp_4) / 4.0) + offset);
    }

    public void printMap() {
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println("");
        }
    }

    public void saveTerrain(int canonX, int canonY, int targetX, int targetY,
            int[][] terrain, String fName) {
        int height = terrain.length;
        int width = terrain[0].length;

        DataOutputStream fout = null;
        try {
            // Samotný zápis dat
            fout = new DataOutputStream(new FileOutputStream(fName));

            fout.writeInt(width);
            fout.writeInt(height);
            fout.writeInt(canonX);
            fout.writeInt(canonY);
            fout.writeInt(targetX);
            fout.writeInt(targetY);

            for (int y = 0; y < height; ++y) {
                for (int x = 0; x < width; ++x) {
                    fout.writeInt(terrain[y][x]);
                }
            }
        } /*
         * Následuje pouze zav?ení souboru a ošetrení výjimek
         */ catch (FileNotFoundException e) {
            System.err.println("Nepovedlo se otevrit vystupni soubor.");
        } catch (IOException e) {
            System.err.println("Nepovedlo se zapsat vystupni soubor.");
        } finally {
            try {
                if (fout != null) {
                    fout.close();
                }
            } catch (IOException e) {
                System.err.println("Nepovedlo se uzavrit vystupni soubor.");
            }
        }
    }
}

Can anyone help me?

Output of algo is int[][] which i visualise using another program to image..

Visualise of output:

OUTPUT IMAGE LINK

And this is how it should look

OUTPUT IMAGE LINK

I am not getting error, but the output is wrong. Thanks for help.

Answers:

Answer

I was coding this same thing yesterday (from the same source) and the recursive approach is really tricky due to square step overlaps of the subdivided areas and the irregularities in the same step. So I decided to do this from scratch the iterative way (which is much faster due to no heap/stack trashing in my programing environment) as you can see I am down from 130 lines to around 50 with comments.

This is how I do it (non recursively) in C++:

void diamond_square(int size)
    {
    picture pic;
    int x,y,xx,yy,xs,ys,d,d2,r;
    for (xs=1;xs<size;xs<<=1); xs>>=1; ys=xs;   // align  to power of 2
    pic.resize(xs+1,ys+1); pic.pf=_pf_u;        // resize image to power of 2 +1
    d=xs; d2=d>>1; r=128;                       // init step,half step and randomness
    Randomize();
    pic.p[ 0][ 0].dd=r;                         // set corners values (should be random but I want this)
    pic.p[ 0][xs].dd=r;
    pic.p[ys][ 0].dd=r;
    pic.p[ys][xs].dd=r;
    for (;d2;d=d2,d2>>=1)                       // subdivide step until full image is filled
        {
        // diamond
        for (y=d2,yy=ys-d2;y<=yy;y+=d)
         for (x=d2,xx=xs-d2;x<=xx;x+=d)
          pic.p[y][x].dd=((pic.p[y-d2][x-d2].dd+pic.p[y-d2][x+d2].dd+pic.p[y+d2][x-d2].dd+pic.p[y+d2][x+d2].dd)>>2)+Random(r);
        // square
        for (y=d2,yy=ys-d2;y<=yy;y+=d)
         for (x=d ,xx=xs-d ;x<=xx;x+=d)
          pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)>>2)+Random(r);
        for (y=d ,yy=ys-d ;y<=yy;y+=d)
         for (x=d2,xx=xs-d2;x<=xx;x+=d)
          pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)>>2)+Random(r);
        for (x=d2,xx=xs-d2;x<=xx;x+=d)
            {
            y= 0; pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y+d2][x].dd)/3)+Random(r);
            y=ys; pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y-d2][x].dd)/3)+Random(r);
            }
        for (y=d2,yy=ys-d2;y<=yy;y+=d)
            {
            x= 0; pic.p[y][x].dd=((pic.p[y][x+d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)/3)+Random(r);
            x=xs; pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)/3)+Random(r);
            }
        // adjust randomness
        r=(r*220)>>8; if (r<2) r=2;
        }
    // here pic holds the terrain map
    }

I use my own picture class so here some members:

  • resize(xs,ys) resize image to new resolution
  • p[ys][xs].dd is pixel access in form of 32 unsigned ints DWORD
  • pf is pixel format (you can ignore this)

This is the result for diamond_square(513);

example

You can play with the r randomnes initial and adjustment values to change behavior. Also you can change the initial corner values.

Beware the local int xs,ys variables in my program holds the power of 2 values not the power of 2 +1 !!!

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.