菱形算法不起作用(从JS到JAVA重写代码) [英] Diamond-square algorithm not working (rewrite code from JS to JAVA)

查看:81
本文介绍了菱形算法不起作用(从JS到JAVA重写代码)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 JS 重写代码到 Java 。代码是Diamond square算法。



来源是:



你可以玩 r randomnes初始值和调整值以更改行为。你也可以改变初始的拐角值。



小心我的程序中的本地 int xs,ys 变量持有2值的功率不是2 +1的功率!!!


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:

And this is how it should look

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

解决方案

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);

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 !!!

这篇关于菱形算法不起作用(从JS到JAVA重写代码)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆