从用于计算三角形和外接圆的 Swingworker 中重新绘制小程序

发布于 2024-12-29 10:07:29 字数 4981 浏览 0 评论 0原文

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

我正在使用 SwingWorker 类创建包含算法的 Triangulate 类的实例。我在 for 循环中调用 triangulate 方法,当单击 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();
            }
        });

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

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 个其他类

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

    现在,这是我的一些担忧

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

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

谢谢, 柴塔尼亚

I am trying to replicate the applet found here as a part of an exercise. The applet is using Fortune's algorithm to generate both; a Voronoi diagram and Delaunay triangulation. I am just interested in generating the Delaunay Triangulation in a plane and thus, would be using the incremental algorithms i.e. adding 1 point at a time. I intend to show the triangles being generated at every stage when a sample point is added.

I am using a SwingWorker class to create an instance of the Triangulate class which contains the algorithm. I am calling the triangulate method inside a for loop which iterates through the set of sample points when the start button on the GUI is clicked.

Here's the code for that:

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();
            }
        });

Here is the Triangulate class which computes a Delanuay Triangulation of a set of points:

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
    }
}

I have 3 other classes

  1. PlanarPoint - sub-class of Point2D.Double which implements Comparable to provide a y-co-ordinate based sorting
  2. Triangle - A class which determines a circum-circle and circum-radius for the triangle and determines whether a point lies inside the circumcircle of the triangle
  3. Edge - A class which represents Edge as the one having 2 PlanarPoints as its end-points.
  4. DrawingPanel - A class which acts as the surface on which points are added at click events and drawn on the screen.

    Now, here are a few concerns which I have

    1. Is there a better way to show the triangles and possibly circum-circles by iterating over a set of points and then calling a function of the Triangulate class to get the existing circum-circles and triangles
    2. Should all the drawing be restricted to the DrawingPanel class since in the code snippets above I am painting in the class which extends JApplet/JFrame and thus whenever the window is resized, the drawn triangles are lost? Is there a design pattern which I can follow?
    3. Is the usage of SwingWorker over spawning another thread justified over here except for the fact that the time to compute the DT of a set of points is a time-consuming task?

If I have missed any details, please let me know

Thanks,
Chaitanya

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

把回忆走一遍 2025-01-05 10:07:29

建议:

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

Suggestions:

  • Don't use getGraphics() to get a Graphics object since the Graphics object obtained won't persist if any repaint is performed (something out of your control). Instead draw to a BufferedImage and have the JPanel or JComponent draw the BufferedImage in its paintComponent override, or add your image data to a Collection of some sort, and have the paintComponent override method iterate through the Collection using the information to draw your images.
  • Don't draw directly in a top level window such as a JFrame or JApplet, but instead in a component that derives from JComponent, often either JComponent itself or JPanel.
  • Read the Swing graphics tutorials as they will explain all of this and more.
  • SwingWorker is fully justified since you want to create a thread that is background to a Swing application yet interacts with the Swing application -- the very situation that SwingWorkers were created for.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文