渲染大量路径时可能出现JavaFX Canvas Bug?

时间:2016-03-06 17:25:28

标签: canvas javafx

我正在尝试做一些GIS工作。我需要能够渲染大量信息(例如,1.3M三角形,以及每个内部渲染的图形)。我在JavaFX下测试了保留模式图形,但它在这个规模上表现不佳,所以我尝试了画布。

下面的代码创建了一个平面二十面体(20边形图)并递归地将其细分为越来越小的三角形。

在递归0到4的级别(GIS.java的第36行),一切都很好。但是,一旦我去了5或者更多,我开始看到非常奇怪的画布渲染。该图呈现在y轴的右侧(对于最左边的三角形,x = 0),并且看起来在大部分中覆盖自身。

我将此代码音译为.Net并且它完美地运行(就像在递归0到4时在Java中一样)所以我不相信它是逻辑/算法问题。

提前为代码长度道歉。我剥夺了我能做的一切,但它仍然有相当数量的代码。

有两个文件 - 作为主窗体的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

    }

}

1 个答案:

答案 0 :(得分: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