【问题标题】:Finding the interior points of a convex hull without computing the hull first在不先计算凸包的情况下找到凸包的内部点
【发布时间】:2015-05-24 14:36:30
【问题描述】:

我正在尝试使用四个嵌套的四个循环来计算凸包的内部点。但是,这给了我正确的坐标,但是这些坐标被重复了很多次。我不确定我做错了什么。

下面是我的方法

public final List<Point> interiorPoints(List<Point> TestPoints){
        int n = points.size();

        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(j != i){
                    for(int k = 0; k < n; k++){
                        if(k != j && j != i && i != k){
                            for(int L = 0; L < n; L++){
                                if(L != k && k != j && j != i && i != k && L != i && L != j){
                                    if(pointIsInsideTriangle(points.get(i), points.get(j), points.get(k), points.get(L)) == true){
                                        InsidePoints.add(points.get(L));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return InsidePoints;
    }

如果点 L 位于三角形 i,j,k 内,则 pointIsInside 方法返回 true

当我使用以下点集进行测试时:

        TestPoints.add(new Point(300,200));
        TestPoints.add(new Point(600,500));
        TestPoints.add(new Point(100,100));
        TestPoints.add(new Point(200,200));
        TestPoints.add(new Point(100,500));
        TestPoints.add(new Point(600,100));

我明白了

(200.0, 200.0)
(200.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(200.0, 200.0)
(200.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(300.0, 200.0)
(200.0, 200.0)
(300.0, 200.0)

这意味着只有 (200.0, 200.0) 和 (300.0, 200.0),但我不知道如何解决这个问题。

这是我实现此方法的伪代码。

Algorithm: INTERIOR POINTS
for each i do
      for each j = i do
           for each k = j = i do
       for each L = k = j = i do 
        if pL in triangle(pi, pj, pk)
            then pL is non extreme

这是我的积分课程

public class Point 
{
    private final double x, y;

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

    public double getX() 
    {
        return x;
    }

    public double getY()
    {
        return y;
    }

    public void setX(double x)
    {
        return this.x;
    }

    public void setY(double y)
    {
        return this.y;
    }

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (!(obj instanceof Point)) {
        return false;
    }
    Point other = (Point) obj;
    EqualsBuilder equalsBuilder = new EqualsBuilder();
    equalsBuilder.append(x, other.x);
    equalsBuilder.append(y, other.y);
    return equalsBuilder.isEquals();
}

@Override
public int hashCode() {
    HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
    hashCodeBuilder.append(x);
    hashCodeBuilder.append(y);
    return hashCodeBuilder.toHashCode();
}
}

下面是我的观点是在课堂上

public boolean pointIsInsideTriangle(Point P, Point Q, Point r, Point t) {

        final double sum;
        //Area of triangle PQr
        double Area_PQr = AreaOfTriangle(P, Q, r);

        // Area of triangle PQr
        double Area_tQr = AreaOfTriangle(t, Q, r);

        // Area of triangle PQr
        double Area_Ptr = AreaOfTriangle(P, t, r);

        // Area of triangle PQr
        double Area_PQt = AreaOfTriangle(P, Q, t);

        // sum of Area_tQr, Area_Ptr and Area_PQt
        sum = Area_tQr + Area_Ptr + Area_PQt;

        if (Area_PQr == sum) {
            System.out.println("Point t Lies inside the triangle");
            return true;
        }

        System.out.println("Point t does not Lie inside the triangle");
        return false;
    }

感谢您的帮助。

【问题讨论】:

  • Thanks for our help. 可能不是你想的那样
  • 如果您将 InsidePoints 设为 Set 而不是 List,则只会返回一个实例。如果这没有帮助,您能否发布 Point 类和 pointIsInsideTriangle 函数。
  • 我添加了Point类和pointIsInsideTriangle函数

标签: java algorithm list convex-hull


【解决方案1】:

在您的示例中,点 (200, 200) 在三个三角形内,由点定义:

[(100, 100), (100, 500), (300, 200)]
[(100, 100), (100, 500), (600, 100)]
[(100, 100), (100, 500), (600, 500)]

请注意,上述三角形的点的任何排列都将代表同一个三角形。这意味着每次L == 3 都会将(200, 200) 添加到您的列表中,并且ijk 的值是以下的一些排列:

[2, 4, 0]
[2, 4, 5]
[2, 4, 1]

n 元素的排列数由n! 给出,因此我们将在6 + 6 + 6 = 18 的情况下将(200, 200) 插入InsidePoints 列表中。如果您计算它,您会看到 18 是 (200, 200) 在您的输出中出现的确切次数。同样的理由也适用于(300, 200)

如果您需要每个点在结果中只出现一次,您可以通过将InsidePoints 设为Set 而不是List 来轻松实现:

Set<Point> InsidePoints = new HashSet<>();

当然,您还需要为 Point 类实现 equals()hashCode()。不过你还是会做很多无用的计算。

为了使代码更高效,除了将InsidePoints 转换为Set 之外,您还可以检查一个点是否只在每个三角形内一次。这意味着 jk 应该从比前一个索引大 1 的值开始,如下所示:

for (int i = 0; i < n; i++) {
    for (int j = i + 1; j < n; j++) {
        for (int k = j + 1; k < n; k++) {
            for (int L = 0; L < n; L++) {
                if (L != i && L != j && L != k) {
                    if (pointIsInsideTriangle(
                            points.get(i),
                            points.get(j),
                            points.get(k),
                            points.get(L))) {
                        InsidePoints.add(points.get(L));
                    }
                }
            }
        }
    }
}

要检查这是否有效,您只需为每次迭代打印ijk 的值,并验证没有一行是另一行的排列。

【讨论】:

  • 我将如何实现一个集合而不是一个列表
  • 更新了显示如何操作的答案。如果您还没有重写 Point equals() 和 hashCode(),请不要忘记。
  • 我设法在不使用套装的情况下解决了这个问题。我基本上检查了 InsidePoints 是否已经包含 points.get(L) ,如果包含,则继续。另一方面,如果没有,则将 points.get(L) 添加到 InsidePoints。我不知道为什么我想不出这个。但是感谢@Anderson Vieira
  • 对于大量点来说,一组可能会更快,但你的也是一个有效的解决方案。很高兴为您提供帮助!
  • 我无法使用集合,因为我在 GUI 中使用列表,而且我不知道如何操作集合中的值。但是感谢您的帮助,这绝对有帮助。
猜你喜欢
  • 2021-10-23
  • 2017-04-21
  • 2011-06-21
  • 2016-06-10
  • 2020-12-21
  • 2017-05-01
  • 2015-06-06
  • 2011-01-08
  • 2018-12-29
相关资源
最近更新 更多