我有一套积分。每个点都有三个坐标:X,Y和Z.我希望能够检测到矩形的四个点(!不是立方体!):
记住:“所有这些矩形的点”=“四个矩形的角落”。
我编写了一个检测四个矩形角的算法,但目前它仅适用于具有2个坐标(X和Y)的点。
算法是:
A
采取了一点,我认为它是一个角落B
(如果X和Y与A
的不同),我认为它是对角线C
,检查其X或Y是否与A
或B
各自的X或Y相同:如果是,我认为这是第三个角落。我再次为第四个角落做这件事。这就是要点。现在,源代码(最后有一些解释)。
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
等其他类似内容。
答案 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])创建两个向量,创建一个新点,即由这两个向量转换角点。
这可以通过以下观察来实现:如果你取任何一点,两个矢量的单独平移产生的两个点和两个矢量平移所产生的一个点,这些点将形成一个平行四边形。
在我们的例子中,两个矢量已经建立为垂直(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个点与输入中任何剩余点之间的距离是否低于某个阈值,得出这个剩余点与其他三个点形成一个矩形的结论。