我正在嘗試做一些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
}
}
你沒告訴我們哪個系統和Java版本,你得到的結果。我在帶有JDK 8u76的MacBook Pro Retina上試過,我沒有注意到任何奇怪的行爲。我只是想知道爲什麼你需要這麼大的畫布。在視網膜Mac上,這會產生10000x4000像素的圖像。但無論如何,它似乎仍然有效。我升到了8級。 – mipa
有趣。它在我的Windows 10計算機(JDK 8u72)和MacBook Air(JDK 8u74)上出現相同(不正確)輸出時都失敗。產量是否在頂部有五個三角形提示?它應該,但我的不正確的版本只顯示三個。 – vocalionecho
更新我的Windows機器到8u74並獲得相同的結果。 – vocalionecho