java - 重新绘制来自用于计算三角形和外接圆的 swingworker 的小程序

标签 java swing graphics computational-geometry swingworker

我正在尝试复制找到的小程序 here作为练习的一部分。该小程序使用 Fortune 的算法生成两者; Voronoi 图和 Delaunay 三角剖分。我只对在平面上生成 Delaunay 三角剖分感兴趣,因此将使用增量算法,即一次添加 1 个点。我打算展示添加样本点时在每个阶段生成的三角形。

我正在使用 SwingWorker 类创建包含算法的 Triangulate 类的实例。我在 for 循环中调用三角剖分方法,当单击 GUI 上的开始按钮时,循环遍历样本点集。

代码如下:

JButton startButton = new JButton("Start");
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                SwingWorker<List<Triangle>, Triangle> worker = new SwingWorker<List<Triangle>, Triangle>() {
                    @Override
                    protected List<Triangle> doInBackground() throws Exception {
                        Triangulate dt = new Triangulate(drawingPanel.pointsList());
                        dt.preTriangulate(); //Set-up a bounding triangle and obtain a random permutation of the points
                        List<PlanarPoint> pointsList = dt.pointsList();
                        for (int i = 0; i < pointsList.size(); i++) {
                            PlanarPoint sample = pointsList.get(i);
                            dt.triangulate(sample); 
                            List<Triangle> list = dt.trianglesList(); //Obtaining the list of triangles at every stage. Good Idea??
                            for (int j = 0; j < list.size(); j++) {
                                publish(list.get(j));
                            }
                            Thread.sleep(500);
                        }
                        dt.removeTriangles(dt.trianglesList()); // Remove all the triangles containing bounding-triangle vertices
                        return dt.trianglesList();
                    }

                    protected void process(List<Triangle> triangles) {
                        for (Triangle triangle : triangles) {
                            g = drawingPanel.getGraphics();
                            PlanarPoint p1 = triangle.getVertex1();
                            PlanarPoint p2 = triangle.getVertex2();
                            PlanarPoint p3 = triangle.getVertex3();
                            g.drawLine((int) Math.ceil(p1.x), (int) Math.ceil(p1.y),
                                    (int) Math.ceil(p2.x), (int) Math.ceil(p2.y));
                            g.drawLine((int) Math.ceil(p2.x),(int) Math.ceil(p2.y),
                                    (int) Math.ceil(p3.x),(int) Math.ceil(p3.y));
                            g.drawLine((int) Math.ceil(p3.x),(int) Math.ceil(p3.y),
                                    (int) Math.ceil(p1.x),(int) Math.ceil(p1.y));
                        }
                    }
                };
                worker.execute();
            }
        });

这是计算一组点的 Delanuay 三角剖分的 Triangulate 类:

public class Triangulate {

    private List<PlanarPoint> pointsList;
    private List<Triangle> triangleList;
    private Triangle boundingTriangle;
    private List<Edge> edgeList;

    public Triangulate(List<PlanarPoint> pointsList) {
        this.pointsList = pointsList;
        this.triangleList = new ArrayList<Triangle>();
        this.edgeList = new ArrayList<Edge>();
    }

    public List<Triangle> trianglesList() {
        return triangleList;
    }

    public List<PlanarPoint> pointsList() {
        return pointsList;
    }

    public void preTriangulate() {
        boundingTriangle = getBoundingTriangle(pointsList);
        triangleList.add(boundingTriangle);
        randomPermutation(pointsList);
    }

    public void triangulate(PlanarPoint samplePoint) {
        // A procedure implementing the Bowyer - Watson algorithm
        // to calculate the DT of a set of points in a plane.
    }

    public void removeTriangles(List<Triangle> trianglesList) {
        // A procedure to remove all triangles from the list sharing
        // edges with the bounding-triangle
    }

    private Triangle getBoundingTriangle(List<PlanarPoint> pointsList) {
        //Obtains a bounding-triangle for a set of points
    }

    public void randomPermutation(List<PlanarPoint> pointsList) {
        //Obtains a random permutation of a set of points
    }
}

我还有其他 3 个类(class)

  1. PlanarPoint - Point2D.Double 的子类,实现 Comparable 以提供基于 y 坐标的排序
  2. Triangle - 确定三角形的外接圆和外接半径并确定点是否位于三角形外接圆内的类
  3. Edge - 一个将 Edge 表示为以 2 个 PlanarPoints 作为端点的类。
  4. DrawingPanel - 一个类,用作在单击事件时添加点并在屏幕上绘制点的表面。

    现在,这里有一些我担心的问题

    1. 是否有更好的方法来显示三角形和可能的外接圆,方法是遍历一组点,然后调用 Triangulate 类的函数来获取现有的外接圆和三角形
    2. 是否应该将所有绘图都限制在 DrawingPanel 类中,因为在上面的代码片段中,我在扩展 JApplet/JFrame 的类中绘图,因此无论何时调整窗口大小时,绘制的三角形都会丢失?有没有我可以遵循的设计模式?
    3. 除了计算一组点的 DT 是一项耗时的任务这一事实之外,在这里使用 SwingWorker 而不是生成另一个线程是否合理?

如果我遗漏了任何细节,请告诉我

谢谢, 柴坦尼亚

最佳答案

建议:

  • 不要使用 getGraphics() 获取 Graphics 对象,因为如果执行了任何重绘(您无法控制),所获取的 Graphics 对象将不会持续存在。而是绘制到 BufferedImage 并让 JPanel 或 JComponent 在其 paintComponent 覆盖中绘制 BufferedImage,或者将图像数据添加到某种 Collection 中,并让 paintComponent 覆盖方法使用信息遍历 Collection 来绘制图像。
  • 不要直接在 JFrame 或 JApplet 等顶级窗口中绘制,而是在派生自 JComponent 的组件中绘制,通常是 JComponent 本身或 JPanel。
  • 阅读 Swing 图形教程,因为它们将解释所有这些以及更多内容。
  • SwingWorker 是完全合理的,因为您想要创建一个作为 Swing 应用程序后台但又与 Swing 应用程序交互的线程——这正是创建 SwingWorkers 的情况。

关于java - 重新绘制来自用于计算三角形和外接圆的 swingworker 的小程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9013131/

相关文章:

java - 为什么屏幕不变色?

java - Strategy Pattern with strategies 包含相似的代码

java - 如何在 Spring 5.3 及更高版本中使用 Stomp 和 SockJS 处理 CORS 起源?

java - 使用 Java 连接到 Oracle DSN 时出错

java - Swing组件添加到ScrollPane(JavaFX)

java - 来自另一个线程的 Graphics.drawImage 不会在 Java Swing 中绘制任何内容

java - 限制自定义基本类型的接口(interface)大小,以便实现自定义类型遵循它

java - 用于包装 HTML 和 JavaScript/CSS 的独立应用程序

java - setter 似乎无法在主方法中工作

c# - C# 中的高效 AABB/三角形交集