2016-03-06 38 views
0

我正在嘗試做一些GIS工作。我需要能夠呈現大量信息(例如,130萬個三角形,以及每個內部渲染的圖形)。我在JavaFX下測試了保留模式的圖形,但在這個尺度下它表現不佳,所以我嘗試了畫布。渲染大量路徑時可能出現JavaFX Canvas Bug?

下面的代碼創建了一個平面二十面體(20面數字)並遞歸地將其細分爲更小和更小的三角形。

在遞歸0到4(GIS.java的第36行)級別,一切都很好。但是,一旦我達到5或更多,我開始看到非常奇怪的畫布渲染。該圖在y軸的右側(最左邊的三角形的x = 0)呈現得很遠,並且似乎在大部分中覆蓋自身。

我將此代碼轉譯爲.Net,並且它完美地工作(就像它在Java中遞歸0到4時那樣),所以我不相信這是邏輯/算法問題。

對代碼的長度提前道歉。我盡我所能,但它仍然有相當數量的代碼。

有兩個文件 - 主要是GIS.java,HexGrid.java是創建網格並將其呈現在畫布上的類。

另一個有趣的筆記:HexGrid.java的第98到105行繪製紅色線條以顯示x軸和y軸。由於渲染距離預期的地方太遠,我試圖看看畫布在哪裏認爲軸線在哪裏。如果你用第4行或更高的遞歸取消了第105行的gc.stroke(),那也會導致畫布和渲染的FAR與預期不同。在遞歸3或更低時,一切都按預期執行。

我希望我只是做錯了什麼!我真的希望在這個項目中堅持使用JavaFX。

在此先感謝。

********** GIS.java *******************

import javafx.application.Application; 
import javafx.geometry.Insets; 
import javafx.scene.*; 
import javafx.scene.layout.*; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class GIS extends Application{ 
    Pane drawPane; 


    @Override 
    public void start(Stage primaryStage) throws Exception { 
     BorderPane root = new BorderPane(); 
     Scene primaryScene = new Scene(root, 900, 800); 
     primaryStage.setScene(primaryScene); 
     primaryStage.setWidth(1000); 
     primaryStage.setHeight(700); 
     primaryStage.minWidthProperty().setValue(1000); 
     primaryStage.minHeightProperty().setValue(700); 

     drawPane = new Pane(); 
     drawPane.setId("drawPane"); 
     drawPane.setPrefSize(1000, 800); 
     drawPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); 
     drawPane.setBackground(new Background(new BackgroundFill(Color.ALICEBLUE, CornerRadii.EMPTY, Insets.EMPTY))); 
     root.setCenter(drawPane); 

     HexGrid hexGrid = new HexGrid(); 

     //LEVEL OF RECURSION 
     hexGrid.generate(5); 

     drawWorldCanvas(hexGrid); 
     primaryStage.show(); 

    } 

    public static void main(String[] args) { 
     launch(args); 

    } 

    private void drawWorldCanvas(HexGrid hexGrid) { 
     drawPane.getChildren().add(hexGrid.getCanvas()); 
    } 
} 

******* ********** HexGrid.java *******************

import javafx.geometry.Point2D; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.paint.Color; 

import java.io.*; 
import java.time.LocalDateTime; 
import java.util.ArrayList; 

public class HexGrid { 
    ArrayList<Point2D> _vertices = new ArrayList<>(1000); 
    int _index = 0; 
    FileWriter log; 

    int TRIANGLE_SIDE_LENGTH = 250; 

    private class TriangleFaceVertices { 
     public int v1; //these are indexes into the _vertices arrayList 
     public int v2; 
     public int v3; 

     private TriangleFaceVertices(int v1, int v2, int v3) { 
      this.v1 = v1; 
      this.v2 = v2; 
      this.v3 = v3; 
     } 
    } 

    ArrayList<TriangleFaceVertices> _faces = new ArrayList<>(1000); 

    public HexGrid() { 
     try { 
      log = new FileWriter("log1.txt"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 

    public void generate(int recursionLevel) { 
     _vertices.clear(); 
     _faces.clear(); 

     addVertices(); 
     addFaces(); 
     divideTriangles(recursionLevel); 
    } 

    private void divideTriangles(int recursionLevel) { 
     // refine triangles 
     for (int i = 0; i < recursionLevel; i++) 
     { 
      ArrayList<TriangleFaceVertices> faces2 = new ArrayList<>(200000); 
      for (TriangleFaceVertices face: _faces) 
      { 
       // replace triangle by 4 triangles 
       int a = getMiddlePoint(face.v1, face.v2); 
       int b = getMiddlePoint(face.v2, face.v3); 
       int c = getMiddlePoint(face.v3, face.v1); 

       faces2.add(new TriangleFaceVertices(face.v1, a, c)); 
       faces2.add(new TriangleFaceVertices(face.v2, b, a)); 
       faces2.add(new TriangleFaceVertices(face.v3, c, b)); 
       faces2.add(new TriangleFaceVertices(a, b, c)); 
      } 
      _faces = faces2; 
      System.out.println(LocalDateTime.now() + " : Iteration: " + i + " - Triangle Count: " + faces2.size()); 
     } 
    } 

    private int getMiddlePoint(int v1, int v2) 
    { 
     Point2D point1 = _vertices.get(v1); 
     Point2D point2 = _vertices.get(v2); 
     Point2D middle = new Point2D(
       (point1.getX() + point2.getX())/2.0, 
       (point1.getY() + point2.getY())/2.0); 

     return addVertex(middle); 
    } 

    private int addVertex(Point2D p) 
    { 
     _vertices.add(p); 
     return _index++; 
    } 

    public Canvas getCanvas() { 
     Canvas canvas = new Canvas(5000,2000); 
     GraphicsContext gc = canvas.getGraphicsContext2D(); 

     Color landColor = Color.BEIGE; 
     Color borderColor = Color.DARKKHAKI; 
     gc.setFill(landColor); 
     gc.setStroke(borderColor); 

     gc.beginPath(); 
     gc.moveTo(0,0); 
     gc.lineTo(2000,0); 
     gc.closePath(); 
     //gc.stroke(); 

     for (TriangleFaceVertices face:_faces) { 
      gc.beginPath(); 
      gc.moveTo(_vertices.get(face.v1).getX(), _vertices.get(face.v1).getY()); 
      gc.lineTo(_vertices.get(face.v2).getX(), _vertices.get(face.v2).getY()); 
      gc.lineTo(_vertices.get(face.v3).getX(), _vertices.get(face.v3).getY()); 
      gc.lineTo(_vertices.get(face.v1).getX(), _vertices.get(face.v1).getY()); 
      gc.closePath(); 
      gc.stroke(); 
      //gc.fill(); 
     } 
     return canvas; 
    } 

    private void addFaces() { 
     _faces.add(new TriangleFaceVertices(0, 2, 1)); //creates a triangle from vertices[0], [1], and [2] 
     _faces.add(new TriangleFaceVertices(1, 2, 3)); 
     _faces.add(new TriangleFaceVertices(1, 3, 4)); 
     _faces.add(new TriangleFaceVertices(3, 5, 4)); 
     _faces.add(new TriangleFaceVertices(1, 7, 6)); 
     _faces.add(new TriangleFaceVertices(1, 4, 7)); 
     _faces.add(new TriangleFaceVertices(7, 4, 8)); 
     _faces.add(new TriangleFaceVertices(4, 9, 8)); 
     _faces.add(new TriangleFaceVertices(10, 7, 11)); 
     _faces.add(new TriangleFaceVertices(7, 8, 11)); 
     _faces.add(new TriangleFaceVertices(11, 8, 12)); 
     _faces.add(new TriangleFaceVertices(8, 13, 12)); 
     _faces.add(new TriangleFaceVertices(14, 11, 15)); 
     _faces.add(new TriangleFaceVertices(11, 12, 15)); 
     _faces.add(new TriangleFaceVertices(15, 12, 16)); 
     _faces.add(new TriangleFaceVertices(12, 17, 16)); 
     _faces.add(new TriangleFaceVertices(18, 15, 19)); 
     _faces.add(new TriangleFaceVertices(15, 16, 19)); 
     _faces.add(new TriangleFaceVertices(19, 16, 20)); 
     _faces.add(new TriangleFaceVertices(16, 21, 20)); 
    } 

    private void addVertices(){ 
     float height = (float)(Math.sqrt(3.0)/2.0) * TRIANGLE_SIDE_LENGTH; 

     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH/2.0, 0));    //0 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH, height));    //1 
     addVertex(new Point2D(0, height));         //2 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH/2.0, height * 2.0)); //3 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 1.5, height * 2.0)); //4 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH, height * 3.0));   //5 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 1.5, 0));    //6 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 2.0, height));   //7 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 2.5, height * 2.0)); //8 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 2.0, height * 3.0)); //9 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 2.5, 0));    //10 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 3.0, height));   //11 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 3.5, height * 2.0)); //12 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 3.0, height * 3.0)); //13 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 3.5, 0));    //14 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 4.0, height));   //15 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 4.5, height * 2.0)); //16 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 4.0, height * 3.0)); //17 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 4.5, 0));    //18 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 5.0, height));   //19 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 5.5, height * 2.0)); //20 
     addVertex(new Point2D(TRIANGLE_SIDE_LENGTH * 5.0, height * 3.0)); //21 

    } 

} 
+0

你沒告訴我們哪個系統和Java版本,你得到的結果。我在帶有JDK 8u76的MacBook Pro Retina上試過,我沒有注意到任何奇怪的行爲。我只是想知道爲什麼你需要這麼大的畫布。在視網膜Mac上,這會產生10000x4000像素的圖像。但無論如何,它似乎仍然有效。我升到了8級。 – mipa

+0

有趣。它在我的Windows 10計算機(JDK 8u72)和MacBook Air(JDK 8u74)上出現相同(不正確)輸出時都失敗。產量是否在頂部有五個三角形提示?它應該,但我的不正確的版本只顯示三個。 – vocalionecho

+0

更新我的Windows機器到8u74並獲得相同的結果。 – vocalionecho

回答

1

確實存在問題。你應該提交一個錯誤報告。

關於你的問題:不要使用路徑,而是使用e。 G。 strokeLine。無論如何,它的速度更快。爲再現

簡單的例子:

import javafx.application.Application; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class Main extends Application { 

    double width = 1000; 
    double height = 1000; 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) { 
     primaryStage.setTitle("Drawing Operations Test"); 
     Group root = new Group(); 
     Canvas canvas = new Canvas(width, height); 
     GraphicsContext gc = canvas.getGraphicsContext2D(); 
     drawShapes(gc); 
     root.getChildren().add(canvas); 
     primaryStage.setScene(new Scene(root)); 
     primaryStage.show(); 
    } 

    private void drawShapes(GraphicsContext gc) { 

     double offset = 15; // <=== change this, e. g. 12 

     gc.setStroke(Color.BLACK); 
     gc.setFill(Color.BEIGE); 

     for(int x=0; x < width; x+=offset) { 
      for(int y=0; y < height; y+=offset) { 

       gc.setLineWidth(0.5); 

       gc.beginPath(); 
       gc.moveTo(x, y); 
       gc.lineTo(x+offset, y+offset); 
       gc.closePath(); 

       gc.stroke(); 
      } 

     } 

    } 
} 

你應該得到對角線。

enter image description here

一旦你降低了偏移,線消失。

enter image description here

+0

我從2降到2,減2,在我的機器上沒有看到任何奇怪的行爲。 – mipa

+0

現在嘗試在不同的機器上。 Win7和Java 1.8.u40一切都很好。在我試過的第一臺機器上遇到了Win7和Java 1.8.u60的問題。問題中的代碼也適用於其他機器。這真的很奇怪。 – Roland

+0

有問題的機器有什麼共同點? – mipa