关于#java#的问题:获取不规则多边形顶点坐标

问题描述:
坐标系中有一个不规则多边形,如图所示: 不规则多边形可能是凹多边形也可能是凸多边形。
已经知道多边形的内的点和多边形的顶点所在的坐标点,且坐标点是整数点。
要求:
获取顶点坐标 。
使用Java/C#代码

如图所示:

img

img

【以下回答由 GPT 生成】

解决方案

要获取不规则多边形的顶点坐标,可以使用几何算法来实现。下面是一个可以用Java代码来实现的解决方案:

  1. 创建一个名为Polygon的类,并在类中定义一个List<Point>类型的字段来存储多边形顶点的坐标。
import java.awt.Point;
import java.util.List;

public class Polygon {
    private List<Point> vertices;

    public Polygon(List<Point> vertices) {
        this.vertices = vertices;
    }

    // 其他方法和属性...
}
  1. Polygon类中创建一个方法getVertices,用于计算和返回不规则多边形的顶点坐标。该方法使用Java的几何库来计算多边形的顶点坐标,并返回一个集合。
import java.awt.Point;
import java.awt.Polygon;
import java.util.ArrayList;
import java.util.List;

public class Polygon {
    private List<Point> vertices;

    public Polygon(List<Point> vertices) {
        this.vertices = vertices;
    }

    public Polygon getVertices() {
        List<Point> result = new ArrayList<>();

        // 将顶点坐标转换为数组
        int[] xPoints = new int[vertices.size()];
        int[] yPoints = new int[vertices.size()];

        for (int i = 0; i < vertices.size(); i++) {
            Point vertex = vertices.get(i);
            xPoints[i] = vertex.x;
            yPoints[i] = vertex.y;
        }

        // 使用Java的几何库来计算多边形的顶点坐标
        java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, vertices.size());
        for (int i = 0; i < polygon.npoints; i++) {
            result.add(new Point(polygon.xpoints[i], polygon.ypoints[i]));
        }

        return result;
    }

    // 其他方法和属性...
}
  1. 在你的主程序中,使用以下代码来获取不规则多边形的顶点坐标。
import java.awt.Point;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        // 创建不规则多边形的顶点
        List<Point> vertices = Arrays.asList(
                new Point(0, 0),
                new Point(0, 10),
                new Point(10, 10),
                new Point(10, 5),
                new Point(5, 5),
                new Point(5, 0));

        // 创建多边形对象
        Polygon polygon = new Polygon(vertices);

        // 获取多边形的顶点坐标
        List<Point> polygonVertices = polygon.getVertices();

        // 打印多边形的顶点坐标
        for (Point vertex : polygonVertices) {
            System.out.println("(" + vertex.x + ", " + vertex.y + ")");
        }
    }
}

在上述示例中,我们通过创建一个Polygon对象,并传入多边形的顶点坐标列表来初始化多边形对象。然后,我们调用getVertices方法来计算并返回多边形的顶点坐标。最后,我们在主程序中打印出顶点坐标。请将多边形的顶点坐标替换为您自己的坐标。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

凸包和凹包算法可以解决


在Java中,你可以使用Polygon类来表示多边形,并通过遍历多边形的顶点来获取顶点坐标。次程序可以再把输出的坐标画出几何图形,对比分析判断是否正确

首先,你需要将多边形的顶点坐标传递给Polygon对象。假设你已经有一个整数数组xPoints和yPoints分别表示多边形顶点的x坐标和y坐标,可以使用如下代码创建Polygon对象:

java
Copy Code
Polygon polygon = new Polygon(xPoints, yPoints, xPoints.length);
接下来,你可以通过遍历多边形的顶点来获取顶点坐标,并输出它们:

java
Copy Code
for (int i = 0; i < polygon.npoints; i++) {
    int x = polygon.xpoints[i];
    int y = polygon.ypoints[i];
    System.out.println("顶点坐标: (" + x + ", " + y + ")");
}
这样,你就可以获取多边形的顶点坐标并输出它们。

要绘制多边形,你可以使用Java提供的绘图工具,如Graphics类。以下是一个简单的示例代码,展示如何使用Polygon对象和Graphics类绘制多边形:

java
Copy Code
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;

public class PolygonDrawing extends JPanel {
    private Polygon polygon;

    public PolygonDrawing(Polygon polygon) {
        this.polygon = polygon;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        // 绘制多边形
        g.drawPolygon(polygon);
    }

    public static void main(String[] args) {
        // 创建多边形对象
        int[] xPoints = { 100, 200, 300, 250 };
        int[] yPoints = { 100, 150, 200, 250 };
        Polygon polygon = new Polygon(xPoints, yPoints, xPoints.length);

        // 创建绘图窗口
        JFrame frame = new JFrame("Polygon Drawing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);

        // 添加多边形绘图面板
        PolygonDrawing panel = new PolygonDrawing(polygon);
        frame.add(panel);

        // 显示窗口
        frame.setVisible(true);
    }
}
运行以上代码,你将看到一个绘制了多边形的窗口。通过对比输出的顶点坐标和绘制的多边形,你可以分析是否正确。

精确性要求不高的话用边界框法 高的用分治法

引用chatgpt内容作答:
要获取不规则多边形的顶点坐标,你可以使用凸包算法。凸包算法可以从给定的点集中找出一个最小凸多边形,该凸多边形包含了所有给定点,并且顶点就是所需的多边形的顶点。

在C#中,你可以使用以下代码来实现凸包算法:

using System;
using System.Collections.Generic;

namespace ConvexHullAlgorithm
{
    public class Point
    {
        public int X { get; set; }
        public int Y { get; set; }

        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }
    }

    public class ConvexHull
    {
        // 计算两点间的距离的平方
        private static int DistanceSquared(Point p1, Point p2)
        {
            int dx = p1.X - p2.X;
            int dy = p1.Y - p2.Y;
            return dx * dx + dy * dy;
        }

        // 判断三个点的方向:逆时针、顺时针或共线
        private static int Orientation(Point p1, Point p2, Point p3)
        {
            int val = (p2.Y - p1.Y) * (p3.X - p2.X) - (p2.X - p1.X) * (p3.Y - p2.Y);
            if (val == 0) return 0; // 共线
            return (val > 0) ? 1 : -1; // 逆时针或顺时针
        }

        // 找到最左下角的点
        private static Point FindStartingPoint(List<Point> points)
        {
            Point startPoint = points[0];
            foreach (var point in points)
            {
                if (point.Y < startPoint.Y || (point.Y == startPoint.Y && point.X < startPoint.X))
                {
                    startPoint = point;
                }
            }
            return startPoint;
        }

        // 实现凸包算法
        public static List<Point> GetConvexHull(List<Point> points)
        {
            int n = points.Count;
            if (n < 3) throw new ArgumentException("凸包至少需要3个点");

            // 找到最左下角的点作为起始点
            Point startingPoint = FindStartingPoint(points);

            // 按照极角排序,如果极角相同则按距离排序
            points.Sort((p1, p2) =>
            {
                int orientation = Orientation(startingPoint, p1, p2);
                if (orientation == 0) // 共线的情况,选择更近的点
                    return DistanceSquared(startingPoint, p1) - DistanceSquared(startingPoint, p2);
                return orientation;
            });

            List<Point> convexHull = new List<Point>();
            convexHull.Add(points[0]);
            convexHull.Add(points[1]);

            for (int i = 2; i < n; i++)
            {
                // 逆时针方向则加入凸包,顺时针方向则需要删除前一个点
                while (convexHull.Count >= 2 &&
                       Orientation(convexHull[convexHull.Count - 2], convexHull[convexHull.Count - 1], points[i]) <= 0)
                {
                    convexHull.RemoveAt(convexHull.Count - 1);
                }
                convexHull.Add(points[i]);
            }

            return convexHull;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 假设你已经有了多边形的顶点坐标和内部点坐标
            List<Point> points = new List<Point>
            {
                new Point(0, 0),
                new Point(3, 2),
                new Point(1, 5),
                new Point(4, 6),
                new Point(6, 3),
                new Point(5, 1),
                new Point(2, 3)
            };

            // 获取凸包顶点坐标
            List<Point> convexHull = ConvexHull.GetConvexHull(points);

            // 输出凸包顶点坐标
            Console.WriteLine("凸包顶点坐标:");
            foreach (var point in convexHull)
            {
                Console.WriteLine($"({point.X}, {point.Y})");
            }
        }
    }
}

这里的points列表应包含所有的顶点和内部点。代码会返回凸包的顶点坐标,这些坐标即为所需的不规则多边形的顶点坐标。类似就是凹包算法,这里就不举例了。

img




在Java中,你可以使用Polygon类来表示多边形,并通过遍历多边形的顶点来获取顶点坐标。次程序可以再把输出的坐标画出几何图形,对比分析判断是否正确
首先,你需要将多边形的顶点坐标传递给Polygon对象。假设你已经有一个整数数组xPoints和yPoints分别表示多边形顶点的x坐标和y坐标,可以使用如下代码创建Polygon对象:
java
Copy Code
Polygon polygon = new Polygon(xPoints, yPoints, xPoints.length);
接下来,你可以通过遍历多边形的顶点来获取顶点坐标,并输出它们:
java
Copy Code
for (int i = 0; i < polygon.npoints; i++) {
    int x = polygon.xpoints[i];
    int y = polygon.ypoints[i];
    System.out.println("顶点坐标: (" + x + ", " + y + ")");
}
这样,你就可以获取多边形的顶点坐标并输出它们。
要绘制多边形,你可以使用Java提供的绘图工具,如Graphics类。以下是一个简单的示例代码,展示如何使用Polygon对象和Graphics类绘制多边形:
java
Copy Code
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
public class PolygonDrawing extends JPanel {
    private Polygon polygon;
    public PolygonDrawing(Polygon polygon) {
        this.polygon = polygon;
    }
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 绘制多边形
        g.drawPolygon(polygon);
    }
    public static void main(String[] args) {
        // 创建多边形对象
        int[] xPoints = { 100, 200, 300, 250 };
        int[] yPoints = { 100, 150, 200, 250 };
        Polygon polygon = new Polygon(xPoints, yPoints, xPoints.length);
        // 创建绘图窗口
        JFrame frame = new JFrame("Polygon Drawing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        // 添加多边形绘图面板
        PolygonDrawing panel = new PolygonDrawing(polygon);
        frame.add(panel);
        // 显示窗口
        frame.setVisible(true);
    }
}
运行以上代码,你将看到一个绘制了多边形的窗口。通过对比输出的顶点坐标和绘制的多边形,你可以分析是否正确。

首先,您需要确定不规则多边形的边界框,这将帮助您确定多边形的顶点坐标。可以使用以下步骤:

找到所有顶点坐标中的最小和最大 x 和 y 坐标值,以确定边界框的大小。
使用这些最小和最大值创建矩形,该矩形将包含不规则多边形。
在矩形的四个角上找到坐标点,这些点将成为多边形的顶点。
接下来,您可以使用以下步骤获取多边形的顶点坐标:

遍历所有顶点坐标,找到在边界框之外的点。这些点将不会成为多边形的顶点。
对于剩余的点,使用一些算法(如射线法或扫描线法)进行测试,以确定它们是否是多边形的顶点。
将所有顶点坐标存储在一个数组或列表中。

不知道您说的顶点是指对变形的最小外接矩形的顶点么?推荐一些工具库,Java可以参考下Geotools工具库,JavaScript可以参考下Turf.js工具库,希望能帮助到您。

要获取不规则多边形的顶点坐标,可以使用以下步骤:

  1. 创建一个表示多边形的数据结构,可以使用数组或链表来存储顶点的坐标。每个顶点的坐标可以使用一个二维整数数组或一个包含两个整数的自定义类来表示。

  2. 遍历所有内部点的坐标。对于每个内部点,判断它是否在多边形内部。可以使用射线法或点在多边形边界上的投影法来判断点是否在多边形内部。

  3. 如果一个内部点在多边形内部,将其添加到顶点数组或链表中。

  4. 最后,顶点数组或链表中存储的坐标即为不规则多边形的顶点坐标。

以下是一个示例的Java代码,用于获取不规则多边形的顶点坐标:

import java.util.ArrayList;
import java.util.List;

public class PolygonVertices {
    public static void main(String[] args) {
        // 假设已知的多边形内部点的坐标
        int[][] internalPoints = {{2, 3}, {4, 5}, {6, 7}, {8, 9}};

        // 假设已知的多边形顶点的坐标
        int[][] vertexPoints = {{1, 1}, {1, 10}, {10, 10}, {10, 1}};

        List<int[]> polygonVertices = new ArrayList<>();

        for (int[] vertex : vertexPoints) {
            boolean isInternal = true;

            for (int[] internalPoint : internalPoints) {
                if (!isPointInsidePolygon(internalPoint, vertexPoints)) {
                    isInternal = false;
                    break;
                }
            }

            if (isInternal) {
                polygonVertices.add(vertex);
            }
        }

        // 输出多边形顶点坐标
        for (int[] vertex : polygonVertices) {
            System.out.println("Vertex: (" + vertex[0] + ", " + vertex[1] + ")");
        }
    }

    // 判断点是否在多边形内部
    private static boolean isPointInsidePolygon(int[] point, int[][] polygon) {
        int i, j;
        boolean isInside = false;
        int n = polygon.length;

        for (i = 0, j = n - 1; i < n; j = i++) {
            if (((polygon[i][1] > point[1]) != (polygon[j][1] > point[1])) &&
                    (point[0] < (polygon[j][0] - polygon[i][0]) * (point[1] - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0])) {
                isInside = !isInside;
            }
        }

        return isInside;
    }
}

请注意,这只是一个简单的示例代码,仅适用于凸多边形。对于凹多边形,可能需要使用更复杂的算法来判断点是否在多边形内部。

java计算不规则多边形的面积

/**
 * 计算多边形面积
 */
public class JisuanMianji {
    /**
     * 求出多边形的面积
     * @param xy
     * @return
     */
    public static float mianji(String xy)
    {
        int i=0;
        float temp=0;
        //进行循环计算,
        for(;i<xy.split(";").length-1;i++)
        {
            temp+=(Float.valueOf(xy.split(";")[i].split(":")[0])-Float.valueOf(xy.split(";")[i+1].split(":")[0]))*
                    (Float.valueOf(xy.split(";")[i].split(":")[1])+Float.valueOf(xy.split(";")[i+1].split(":")[1]));
        }
        //最后在对尾点坐标和首点坐标进行计算
        temp+=(Float.valueOf(xy.split(";")[i].split(":")[0])-Float.valueOf(xy.split(";")[0].split(":")[0]))*
                (Float.valueOf(xy.split(";")[i].split(":")[1])+Float.valueOf(xy.split(";")[0].split(":")[1]));
        return temp/2;
    }
    /**
     * 求出多边形的周长
     * @param xy
     * @return
     */
    public static double zhouchang(String xy)
    {
        int i=0;
        double temp=0;
        //进行循环计算,
        for(;i<xy.split(";").length-1;i++)
        {
            //采用两两坐标进行勾股定理的方式计算,添加了绝对值的方式,避免负数,再用开根号的方式获取两点距离,
            temp+=Math.sqrt(Math.pow(Math.abs(
                    Double.valueOf(xy.split(";")[i].split(":")[0])-
                            Double.valueOf(xy.split(";")[i+1].split(":")[0])
                    ),2)+
                  Math.pow(Math.abs(
                          Double.valueOf(xy.split(";")[i].split(":")[1])-
                                  Double.valueOf(xy.split(";")[i+1].split(":")[1])
                  ),2));
        }
        //最后在对尾点坐标和首点坐标进行计算
        temp+=Math.sqrt(Math.pow(Math.abs(
                Double.valueOf(xy.split(";")[i].split(":")[0])-
                        Double.valueOf(xy.split(";")[0].split(":")[0])
        ),2)+
                Math.pow(Math.abs(
                        Double.valueOf(xy.split(";")[i].split(":")[1])-
                                Double.valueOf(xy.split(";")[0].split(":")[1])
                ),2));
        return temp/2;
    }
    public void main(String args[])
    {
      //多边形坐标字符串,每一个分号代表一个点的多边形的坐标。每一个冒号代表一个横坐标和一个纵坐标
        String xy="12:23;24:35;56:67;78:89;45:67";//多边形最少三个点,示例数据仅供参考。
        System.out.println("多边形面积是:"+mianji(xy));
        System.out.println("多边形周长是:"+zhouchang(xy));
    }
}

Mongoose是一个非常流行的Node.js ORM(Object-Relational Mapping,对象关系映射)库,它与MongoDB数据库紧密集成,提供了一种简便的方法来在Node.js应用程序中操作MongoDB数据库。然而,当我们在高并发的情况下使用Mongoose时,可能会遇到一些挑战。在这篇文章中,我们将探讨Mongoose高并发和数据库操作过慢的问题,并提供一些解决方案。

  1. Mongoose高并发问题

Mongoose在处理高并发时可能会面临以下问题:

  1. 内存泄漏

Mongoose在执行数据库操作时会创建很多对象,这些对象需要占用内存。如果许多并发请求同时进行,每个请求都会创建许多对象,这可能导致内存泄漏并最终导致应用程序崩溃。

  1. 连接池过度使用

Mongoose使用连接池来管理和重用MongoDB连接。但是,如果许多并发请求同时使用连接池,连接池可能会过度使用,导致应用程序响应缓慢或崩溃。

  1. 锁定问题

在高并发应用程序中,许多请求可能同时尝试读取或写入相同的数据。如果没有正确处理锁定问题,可能会导致数据不一致或并发请求之间的竞争条件。

  1. 数据库操作过慢问题

除了高并发问题之外,Mongoose还可能面临数据库操作过慢问题:

  1. 查询缓慢

当数据库中的数据量增加时,查询可能会变得缓慢。如果查询涉及大量数据或需要进行搜索或排序等操作,则可能会导致查询时间过长。

  1. 写入缓慢

写入操作可能会受到许多因素的影响,例如数据库性能、磁盘速度、网络延迟等。如果写入操作变得缓慢,可能会导致应用程序响应缓慢或停止响应。

  1. 索引问题

MongoDB使用索引来提高查询性能。如果没有正确使用索引或索引过多,可能会导致查询时间变得缓慢。

  1. 解决方案

以下是一些解决Mongoose高并发和数据库操作过慢问题的解决方案:

  1. 内存泄漏

为了避免内存泄漏问题,我们可以使用Mongoose的一个插件叫做mquery。mquery提供了一个链式API,允许我们在查询操作中使用连续的回调函数,而不是创建许多中间对象。这意味着我们可以减少在内存中创建的对象数量,从而避免内存泄漏问题。

  1. 连接池过度使用

我们可以限制连接池的大小以避免过度使用。这可以通过在应用程序的配置中指定最大连接数来实现。

  1. 锁定问题

为了解决锁定问题,我们可以使用Mongoose的乐观并发控制。乐观并发控制允许多个请求同时读取和写入相同的数据,但在保存更改时,它会检查已保存数据的版本是否与预期的版本匹配。如果版本不匹配,则表示其他请求已经修改了数据,并且必须重新读取数据并重试操作。

  1. 查询缓慢

为了解决查询缓慢问题,我们可以使用索引来提高查询性能。我们还可以使用Mongoose的限制和分页功能来限制查询返回的结果数量,从而避免查询时间过长。

  1. 写入缓慢

为了解决写入缓慢问题,我们可以将写入操作异步处理。我们还可以使用Mongoose的批量写入操作来将多个记录一次写入数据库。

  1. 索引问题

为了解决索引问题,我们可以使用适当的索引来提高查询性能。我们可以使用Mongoose的索引定义功能来定义索引并确保只使用必要的索引。

总结

Mongoose是一个非常流行的Node.js ORM库,它在处理MongoDB数据库时提供了方便的方法。但是,在高并发和大量数据的情况下,我们可能会面临一些挑战,例如内存泄漏、连接池过度使用、锁定问题、查询缓慢、写入缓慢和索引问题。为了解决这些问题,我们可以使用Mongoose提供的一些功能和解决方案,例如mquery插件、限制连接池大小、使用乐观并发控制、使用索引、批量写入操作和定义适当的索引。

你好,定义好x轴和y轴,参考代码如下

img

public static double calculateArea(double[] x, double[] y) {
            int n = x.length;
            double area = 0.0;
            for (int i = 0; i < n; i++) {
                int j = (i + 1) %n;area += x[i] * y[j];
                area -= y[i] * x[j];
            }
            area = Math.abs(area) / 2.0;
            return area;

    }

    public static void main(String[] args) {
        double[] x = {0.0,0.,0.,1.0,2.0,2.0,2.0,1.0, 0.0, 0.0};
        double[] y = {0.0,1.0, 2.0, 2.0,2.0,1.0,0.0, 0.0, 0.0};
        double area = calculateArea(x,y);System.out.println("多边形的面积为:" + area);
    }

我记得上周这个问题已经被解答过了,为什么会被删除呢

为了实现子窗体自适应分辨率,需要在子窗体的代码中进行以下操作:

  1. 在子窗体的Load事件中添加代码,使窗体随着分辨率自适应大小:
this.AutoSize = true;
this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
  1. 在子窗体的Resize事件中添加代码,使控件随着窗体大小改变而自适应大小和位置:
foreach (Control control in this.Controls)
{
    control.Left = (this.Width - control.Width) / 2;
    control.Top = (this.Height - control.Height) / 2;
    control.Anchor = AnchorStyles.None;
    control.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
}

这段代码会遍历所有控件,设定控件的位置和锚定方式,以保证控件随着窗体变化而自适应。

  1. 在父窗体中的代码中,添加切换子窗体的逻辑,同时让子窗体随父窗体的大小改变而自适应:
private void switchChildForm(Form form)
{
    panel.Controls.Clear();
    form.TopLevel = false;
    form.AutoSize = true;
    form.AutoSizeMode = AutoSizeMode.GrowAndShrink;
    panel.Controls.Add(form);
    form.Show();
}

private void MainForm_Resize(object sender, EventArgs e)
{
    foreach (Control control in panel.Controls)
    {
        control.Left = (panel.Width - control.Width) / 2;
        control.Top = (panel.Height - control.Height) / 2;
        control.Anchor = AnchorStyles.None;
        control.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
    }
}

private void button1_Click(object sender, EventArgs e)
{
    Form1 form1 = new Form1();
    switchChildForm(form1);
}

在switchChildForm函数中,先将子窗体的AutoSize和AutoSizeMode设为true,再使用panel.Controls.Add方法添加到父窗体的panel中,并调用form.Show()方法显示子窗体。

在MainForm_Resize事件中,遍历panel中所有控件,设定控件的位置和锚定方式,以保证控件随着panel的变化而自适应。

最后,在button1_Click事件中,调用switchChildForm函数切换子窗体。

以上是实现子窗体自适应分辨率的基本操作,希望能对您有所帮助。

要先确定多边形的路径。参考下这个资料,看下是否对你有所帮助吧:
java代码获取多边形的中心点:https://blog.csdn.net/weixin_30951743/article/details/99138833
以及这个:https://www.cnpython.com/java/1145776

用geotools,生成几何后,获取面积

在Java中计算不规则多边形面积,可以通过坐标,确定顶点的顺序,然后使用面积公式计算每个三角形的面积,并将其累加到总面积中

用geotools库计算

import java.util.ArrayList;
import java.util.List;
public class VerticesTest {
    public static List<Point> getPointList(List<Point> points) {
        List<Point> pointList = new ArrayList<>();
        Point leftmost = points.get(0);
        for (int i = 1; i < points.size(); i++) {
            if (points.get(i).x < leftmost.x) {
                leftmost = points.get(i);
            }
        }
        Point current = leftmost;
        Point next;
        do {
            pointList.add(current);
            next = points.get(0);
            for (int i = 1; i < points.size(); i++) {
                if (points.get(i) == current) {
                    continue;
                }
                int crossProduct = crossProduct(current, next, points.get(i));
                if (next == current || crossProduct > 0 ||
                        (crossProduct == 0 && distance(current, points.get(i)) > distance(current, next))) {
                    next = points.get(i);
                }
            }
            current = next;
        } while (current != leftmost);
        return pointList;
    }

    private static int crossProduct(Point a, Point b, Point c) {
        return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
    }

    private static int distance(Point a, Point b) {
        return (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y);
    }

    public static void main(String[] args) {
        List<Point> points = new ArrayList<>();
        points.add(new Point(0, 0));
        points.add(new Point(1, 1));
        points.add(new Point(2, 2));
        points.add(new Point(3, 1));
        points.add(new Point(2, 0));

        List<Point> pointList = getPointList(points);

        System.out.println("顶点坐标:");
        for (Point point : pointList) {
            System.out.println("(" + point.x + ", " + point.y + ")");
        }
    }
}
class Point {
    int x;
    int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}