【发布时间】:2016-03-06 17:25:28
【问题描述】:
我正在尝试做一些 GIS 工作。我需要能够渲染大量信息(例如,130 万个三角形,加上每个三角形内渲染的图形)。我在 JavaFX 下测试了保留模式图形,但在这种规模下它的性能不够好,所以我尝试了画布。
下面的代码创建了一个平面二十面体(20 面图形)并递归地将其细分为越来越小的三角形。
在递归级别 0 到 4(GIS.java 的第 36 行),一切正常。但是,一旦我达到 5 个或更多,我开始看到非常奇怪的画布渲染。该图形被渲染到 y 轴的右侧(最左边的三角形 x=0),并且似乎在很大的部分中覆盖了自身。
我将此代码音译为 .Net,它运行良好(就像它在 Java 中的递归 0 到 4 一样),所以我不认为这是一个逻辑/算法问题。
提前为代码的长度道歉。我尽可能地删除了所有内容,但它仍然有相当多的代码。
有两个文件 - GIS.java 是主窗体,HexGrid.java 是创建网格并将其呈现到画布上的类。
还有一个有趣的注释:HexGrid.java 的第 98 到 105 行画了红线来显示 x 轴和 y 轴。我试图查看画布认为轴在哪里,因为渲染远远超出预期的位置。如果您取消注释第 105 行的 gc.stroke() 并使用递归 4 或更高版本,这也会炸毁画布,并且渲染与预期的相差甚远。在 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 级。
-
有趣。它在我的 Windows 10 机器(JDK 8u72)和 MacBook Air(JDK 8u74)上都失败,输出相同(不正确)。输出顶部是否有五个三角形尖端?应该可以,但我的错误版本只显示了三个。
-
将我的 windows 机器更新到 8u74 并得到相同的结果。
-
我在顶部有五个提示,适用于所有级别。也许我应该注意我的机器中有 NVidia 卡,而不仅仅是 Intel 显卡。