2017-04-03 33 views
2

你好堆栈社区,钻石广场不当执行

我想了很长时间,很难发布这看到因为我不想吸引另一个“重复”线程。然而,我已经没有想法,也不知道任何论坛或其他堆栈,我可以发布这个来获得一些帮助。

我写这个应用程序作为一个有趣的项目,试图生成一些高度图。然而,无论何时我尝试一次生成多个高度图,我的所有副本都会显示为黑色空洞,或者如果变量足够低,则表示白色空洞。 (实施例16 & & 33创建白色空隙,1025创建黑)出现

我的输出文件夹,如下所示:low value VRS higher value

low value

high value

这是为什么?我是否在凌晨3点15分失踪,这仅仅是一种数学侥幸? 我写了printMap专门用于检查地图数据值的功能,并且它们在指定它们为黑/白的范围内。我认为没有理由在第一次迭代后持续存在。

只是为了好玩,我打印了44张地图,第一张以后都是黑色的,MAP_SIZE设置为1025.随意自己检查一下。

我创建从这里基于了我的阅读我的菱形方算法:http://www.gameprogrammer.com/fractal.html#heightmaps

和约单纯的噪声地图一个旧的堆栈溢出线程我greyWriteImage。

编辑 感谢我能解决我的问题,原来它只是一个简单的事实,每一个新的地图,你试图使用populateMap功能我忘了avgOffset重置为1。从本质上创建问题在于你将avgOffset连续分成2个越来越小的结果,这总是会以某种方式进行。

下面我已经包含了我完成的源代码,用于任何想要使用我的算法和输出的人。玩的开心。

import java.awt.Color; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
import javax.imageio.ImageIO; 
import java.util.concurrent.ThreadLocalRandom; 

public class generateHeightMap { 

    // https://stackoverflow.com/questions/43179809/diamond-square-improper-implementation 

    private static final Random RAND = new Random(); 
    // Size of map to generate, must be a value of (2^n+1), ie. 33, 65, 129 
    // 257,1025 are fun values 
    private static final int MAP_SIZE = 1025; 
    // initial seed for corners of map 
    private static final double SEED = ThreadLocalRandom.current().nextInt(0, 1 + 1); 
    // average offset of data between points 
    private static double avgOffSetInit = 1; 

    private static final String PATH = "C:\\Users\\bcm27\\Desktop\\grayScale_export"; 
    private static String fileName = "\\grayscale_map00.PNG"; 

    public generateHeightMap(int howManyMaps) { 
     System.out.printf("Seed: %s\nMap Size: %s\nAverage Offset: %s\n", 
       SEED, MAP_SIZE, avgOffSetInit); 
     System.out.println("-------------------------------------------"); 

     for(int i = 1; i <= howManyMaps; i++){ // how many maps to generate 

      double[][] map = populateMap(new double[MAP_SIZE][MAP_SIZE]); 
      //printMap(map);   
      generateHeightMap.greyWriteImage(map); 
      fileName = "\\grayscale_map0" + i + ".PNG"; 

      System.out.println("Output: " + PATH + fileName); 
     } 
    } 
    /************************************************************************************* 
    * @param requires a 2d map array of 0-1 values, and a valid file path 
    * @post creates a image file saved to path + file_name 
    ************************************************************************************/ 
    private static void greyWriteImage(double[][] data) { 
     BufferedImage image = 
       new BufferedImage(data.length, data[0].length, BufferedImage.TYPE_INT_RGB); 

     for (int y = 0; y < data[0].length; y++) 
     { 
      for (int x = 0; x < data.length; x++) 
      {// for each element in the data 

       if (data[x][y]>1){ 
        // tells the image whether its white 
        data[x][y]=1; 
       } 
       if (data[x][y]<0){ 
        // tells the image whether its black 
        data[x][y]=0; 
       } 
       Color col = // RBG colors 
         new Color((float)data[x][y], 
           (float)data[x][y], 
           (float)data[x][y]); 
       // sets the image pixel color equal to the RGB value 
       image.setRGB(x, y, col.getRGB()); 
      } 
     } 

     try { 
      // retrieve image 
      File outputfile = new File(PATH + fileName); 
      outputfile.createNewFile(); 
      ImageIO.write(image, "png", outputfile); 

     } catch (IOException e) { 
      throw new RuntimeException("I didn't handle this very well. ERROR:\n" + e); 
     } 
    } 

    /**************************************************************************** 
    * @param requires map double[MAPSIZE][MAPSIZE] 
    * @return returns populated map 
    * 
    * [1] Taking a square of four points, generate a random value at the square 
    *  midpoint, where the two diagonals meet. The midpoint value is calcul- 
    *  ated by averaging the four corner values, plus a random amount. This 
    *  gives you diamonds when you have multiple squares arranged in a grid. 
    * 
    * [2] Taking each diamond of four points, generate a random value at the 
    *  center of the diamond. Calculate the midpoint value by averaging the 
    *  corner values, plus a random amount generated in the same range as 
    *  used for the diamond step. This gives you squares again. 
    *  
    *  '*' equals a new value 
    *  '=' equals a old value 
    *  
    *  * - - - *  = - - - = = - * - = = - = - = = * = * = 
    *  - - - - -  - - - - - - - - - - - * - * - * = * = *  
    *  - - - - -  - - * - - * - = - * = - = - = = * = * = 
    *  - - - - -  - - - - - - - - - - - * - * - * = * = *     
    *  * - - - *  = - - - = = - * - = = - = - = = * = * = 
    *   A    B   C   D   E 
    *   
    *  A: Seed corners 
    *  B: Randomized center value 
    *  C: Diamond step 
    *  D: Repeated square step 
    *  E: Inner diamond step 
    *  
    *  Rinse and repeat C->D->E until data map is filled 
    *   
    ***************************************************************************/ 
    private static double[][] populateMap(double[][] map) {  

     // assures us we have a fresh map each time 
     double avgOffSet = avgOffSetInit; 

     // assigns the corners of the map values to SEED 
     map[0][0] = 
     map[0][MAP_SIZE-1] = 
     map[MAP_SIZE-1][0] = 
     map[MAP_SIZE-1][MAP_SIZE-1] = SEED; 

     // square and diamond loop start 
     for(int sideLength = MAP_SIZE-1; sideLength >= 2; sideLength /=2,avgOffSet/= 2.0) { 

      int halfSide = sideLength/2; 
      double avgOfPoints; 

      /******************************************************************** 
      *   [1]   SQUARE FRACTAL    [1] 
      *********************************************************************/ 
      // loops through x & y values of the height map 
      for(int x = 0; x < MAP_SIZE-1; x += sideLength) { 
       for(int y = 0; y <MAP_SIZE-1; y += sideLength) { 

        avgOfPoints = map[x][y] +     //top left point 
          map[x + sideLength][y] +   //top right point 
          map[x][y + sideLength] +   //lower left point 
          map[x + sideLength][y + sideLength];//lower right point 

        // average of surrounding points 
        avgOfPoints /= 4.0; 

        // random value of 2*offset subtracted 
        // by offset for range of +/- the average 
        map[x+halfSide][y+halfSide] = avgOfPoints + 
          (RAND.nextDouble()*2*avgOffSet) - avgOffSet; 
       } 
      } 

      /******************************************************************** 
      *   [2]   DIAMOND FRACTAL   [2] 
      *********************************************************************/ 
      for(int x=0; x < MAP_SIZE-1; x += halfSide) { 
       for(int y = (x + halfSide) % sideLength; y < MAP_SIZE-1; 

         y += sideLength) { 
        avgOfPoints = 
          map[(x - halfSide + MAP_SIZE) % MAP_SIZE][y] +//left of center 
          map[(x + halfSide) % MAP_SIZE][y] +   //right of center 
          map[x][(y + halfSide) % MAP_SIZE] +   //below center 
          map[x][(y - halfSide + MAP_SIZE) % MAP_SIZE]; //above center 

        // average of surrounding values 
        avgOfPoints /= 4.0; 

        // in range of +/- offset 
        avgOfPoints += (RAND.nextDouble()*2*avgOffSet) - avgOffSet; 

        //update value for center of diamond 
        map[x][y] = avgOfPoints; 

        // comment out for non wrapping values 
        if(x == 0) map[MAP_SIZE-1][y] = avgOfPoints; 
        if(y == 0) map[x][MAP_SIZE-1] = avgOfPoints; 

       } // end y 
      } // end x 
     } // end of diamond 
     return map; 
    } // end of populateMap 

    /************************************************************************************* 
    * @param requires a 2d map array to print the values of at +/-0.00 
    ************************************************************************************/ 
    @SuppressWarnings("unused") 
    private static void printMap(double[][] map) { 
     System.out.println("---------------------------------------------");  

     for (int x = 0; x < map.length; x++) { 
      for (int y = 0; y < map[x].length; y++) { 
       System.out.printf("%+.2f ", map[x][y]);    
      } 
      System.out.println(); 
     }  
    } 

} // end of class 

回答

2

难道avgOffSet必须在创建每个地图(的populateMap开始)之前被初始化?

它被除以2,但从不重置为1.我想每个映射都是独立的,也就是说,不依赖于前一个映射,所以没有理由不重置变量。但我不知道这个算法,没有时间学习它... [: - |

private static double[][] populateMap(double[][] map) { 

    avgOffSet = 1; // missing this one 

    map[0][0] = ... 

如果这是正确的我会建议avgOffset应该是一个变量;最终用初始值(而不是当前字段)创建一个字段avgOffsetInitial

+0

如果您好奇,我添加了算法的说明。我想我的错误纯粹是数学的,可能等到我睡了之后再发布。 – bcm27

+0

@ bcm27谢谢,我必须*用*算法有时[:-) –

+0

没问题,我甚至更新了我的源代码给你。干杯 – bcm27