2017-04-03 61 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