如何检测3D世界中的矩形?

时间:2017-04-24 11:53:38

标签: java algorithm detection rectangles

我有一套积分。每个点都有三个坐标:X,Y和Z.我希望能够检测到矩形的四个点(!不是立方体!):

  1. 所有这些矩形的点可以具有相同的Z(因此,矩形不是深度绘制的,只有X和Y更改)
  2. 所有这些矩形的点都可以具有相同的Y(因此,矩形是深度绘制的,只有X和Z更改)
  3. 特别是,所有这些矩形的点都可以改变X,Y和Z(即:矩形以“对角线”绘制)。
  4. 记住:“所有这些矩形的点”=“四个矩形的角落”。

    我的解决方案(仅适用于2D世界)

    我编写了一个检测四个矩形角的算法,但目前它仅适用于具有2个坐标(X和Y)的点。

    算法是:

    1. 我对该集合A采取了一点,我认为它是一个角落
    2. 我接受集合的下一个点B(如果X和Y与A的不同),我认为它是对角线
    3. 我接下一个点C,检查其X或Y是否与AB各自的X或Y相同:如果是,我认为这是第三个角落。我再次为第四个角落做这件事。
    4. 这就是要点。现在,源代码(最后有​​一些解释)。

          List<Point> returned_rectangle = new ArrayList<>();
          List<StorableData> sorted_abscissa_aligned_points = this.preTreatment();
      
          Point current_point_not_delete, neighbour_cupple_of_current_point, absc, ord, other_point;
          for(StorableData current_store_data : sorted_abscissa_aligned_points) { // Diagonal's points
      
              current_point_not_delete = (Point) current_store_data;
      
              for (StorableData neighbour_storable_data_of_current_cupple : sorted_abscissa_aligned_points) { // Diagonal's points
              if(neighbour_storable_data_of_current_cupple == null) {
              continue;
              }
      
              neighbour_cupple_of_current_point = (Point) neighbour_storable_data_of_current_cupple;
      
              if(Math.abs(neighbour_cupple_of_current_point.getNumber(0) - current_point_not_delete.getNumber(0)) <= PRECISION_DIAGONAL
              || Math.abs(neighbour_cupple_of_current_point.getNumber(1) - current_point_not_delete.getNumber(1)) <= PRECISION_DIAGONAL) {
                continue;
              }
      
      
              absc = null;
              ord = null;
      
              for(StorableData other_point_storable_data : sorted_abscissa_aligned_points) { // Abs and ord rectangle's points
                  other_point = (Point) other_point_storable_data;
                  if(other_point == null) {
                  continue;
                  }
      
                  if(Math.abs(other_point.getNumber(0) - current_point_not_delete.getNumber(0)) <= PRECISION
                  && Math.abs(other_point.getNumber(1) - neighbour_cupple_of_current_point.getNumber(1)) <= PRECISION) {
      
                      absc = other_point;
      
                  } else if(Math.abs(other_point.getNumber(0) - neighbour_cupple_of_current_point.getNumber(0)) <= PRECISION
                  && Math.abs(other_point.getNumber(1) - current_point_not_delete.getNumber(1)) <= PRECISION) {
      
                      ord = other_point;
      
                  }
      
                  if(absc != null && ord != null) {
                      break;
                  }
              }
      
              if(absc != null && ord != null) {
                      returned_rectangle.add(absc);
                      returned_rectangle.add(current_point_not_delete);
                      returned_rectangle.add(ord);
                      returned_rectangle.add(neighbour_cupple_of_current_point);
                      return returned_rectangle;
              }
      
              }
      
              sorted_abscissa_aligned_points.set(sorted_abscissa_aligned_points.indexOf(current_point_not_delete), null);
          }
      

      检测确实在第三个for中完成(从代码顶部开始计算)。 getNumber(0)表示“读取X坐标”,getNumber(1)表示Y,2:Z。

      我的问题

      如您所知,如果在X和Y坐标中绘制矩形,但我的算法效果很好,但不考虑深度(Z)。

      我该如何扩展呢?也许我将不得不使用cos等其他类似内容。

1 个答案:

答案 0 :(得分:1)

首先一点点评论。我相信您当前的算法仅适用于检测2D空间中的矩形,其中边与x / y轴平行/垂直。换句话说,将无法检测到已经“旋转”的矩形(对角线,正如您所描述的那样)。

我建议使用可在2D和3D中使用的不同算法。以下是代码的草稿:

List<Point> points;
// Assign list ...

// Iterate for first point...
for (int i = 0; i < points.size() - 3; ++i) {
    // Second point...
    for (int j = i + 1; j < points.size() - 2; ++j) {
        // Third point...
        for (int k = j + 1; k < points.size() - 1; ++k) {
            // Get the three points
            Point p1 = points.get(i);
            Point p2 = points.get(j);
            Point p3 = points.get(k);
            // Array for corner point and its two adjacent points if there's a 90° angle
            Point[] angle;
            if ((angle = checkRightAngle(p1, p2, p3)) != null) {
                // Calculate which point would form a rectangle with the given 3 points
                Point remainingCorner = translate(angle[0], angle[1], angle[2]);
                // Check the remaining points and see if any match the remaining corver
                for (int l = k + 1; l < points.size(); ++l) {
                    Point p4 = points.get(l);
                    if (distanceWithinPrecision(remainingCorner, p4) {
                        // p1, p2, p3 and p4 form a rectangle; use the result as needed
                    }
                }
            }
        }
    }
}

Point[] checkRightAngle(Point p1, Point p2, Point p3) {
    // For each of the three points, check if it forms a 90° angle with the other two points
    // If such a point is found, return an array with the corner point in the first index 
    // and the remaining to points in the other indexes
    // If no such point is found, return null
}

Point translate(Point source, Point other1, Point other2) {
    // Calculate the vectors from source to other1 and source to other2
    // Create a new Point that has the coordinates resulting from translating source by
    // the two vectors and return it
}

让我们稍微讨论一下。三个循环将导致经历三个点的每个组合减去最后一个(稍后将检查),而不重复一组点。检查组合中的三个点是否形成直角。

方法checkRightAngle应检查给定的3个点中的每个点是否与其他两个点形成90°角。如果没有90°角,它只返回null。如果存在这样的90°角,它应该返回一个Point数组,第一个元素是位于90°角的Point,第二个和第三个元素是另外两个Point(它们的顺序无关紧要)。要计算3个维度中两个相交线段之间的角度,您应该可以在线轻松找到公式。请注意,这里有一个小优化的机会。假设您已经检查了2个点的角度作为角落而且都没有90°,那么您可以检查它们的总和是否为90°;在三角形中,所有三个角度角的总和是180°,因此如果两个角具有90°的作为角度,则剩余的角度必须是90°。所以你最多需要检查两个角度。

如果三个点形成直角,则使用方法translate来确定形成矩形的剩余点应该是什么。你这样做的方法是取90°角(角[0]数组元素)的角点,使用剩下的两个点(角度1和角度[2])创建两个向量,创建一个新点,即由这两个向量转换角点。

这可以通过以下观察来实现:如果你取任何一点,两个矢量的单独平移产生的两个点和两个矢量平移所产生的一个点,这些点将形成一个平行四边形。

vector translations in parallelogram

在我们的例子中,两个矢量已经建立为垂直(90°角),因此结果将是一个矩形。

实际上,您需要做的就是在角点和其中一个非角点之间建立向量,然后将其添加到另一个角点。因此在上面的例子中,假设p1具有坐标(x1,y1,z2),p2具有坐标(x2,y2,z2)并且p3具有坐标(x3,y3,z3)。然后,从p1到p2的矢量是(x2-x1,y2-y1,z2-z1)。您将其添加到(x3,y3,z3),产生(x2 - x1 + x3,y2 - y1 + y3,z2 - z1 + z3)。这会产生剩余的矩形点。

最后要做的是计算这个所需的第4个点与输入中任何剩余点之间的距离是否低于某个阈值,得出这个剩余点与其他三个点形成一个矩形的结论。