Java中如何正确判断两个Rhombus(菱形)是否重叠?
Java中判断两个菱形重叠的正确实现
你的原始代码存在两个核心问题:
- 用单个int存储顶点,完全错误——菱形的顶点是二维坐标,需要用(x,y)表示;
- 仅通过顶点是否重合判断重叠,漏判了顶点在对方内部、边相交、一个菱形完全包含另一个这些常见的重叠场景。
以下是正确的实现思路和代码:
1. 重构菱形类的顶点表示
首先用二维坐标(Point类)存储菱形的四个顶点,确保顶点按顺时针或逆时针顺序排列(凸多边形判断依赖有序顶点):
import java.awt.Point; public class Rhombus { private Point[] vertices; // 构造方法:传入按顺序排列的四个顶点(顺时针/逆时针) public Rhombus(Point p1, Point p2, Point p3, Point p4) { this.vertices = new Point[]{p1, p2, p3, p4}; } // 如果不想依赖AWT的Point类,可以自定义坐标类 /* static class Point { int x, y; Point(int x, int y) { this.x = x; this.y = y; } } */ }
2. 实现点在菱形内部的判断
对于凸多边形(菱形属于凸多边形),可以通过叉积判断点是否在所有边的同侧:
// 判断点是否在菱形内部(包含边界) private boolean isPointInside(Point point) { boolean inside = true; int vertexCount = vertices.length; for (int i = 0; i < vertexCount; i++) { Point current = vertices[i]; Point next = vertices[(i + 1) % vertexCount]; // 计算叉积:(next - current) × (point - current) int cross = (next.x - current.x) * (point.y - current.y) - (next.y - current.y) * (point.x - current.x); // 若顶点按逆时针排列,内部点的叉积需≥0(包含边界) if (cross < 0) { inside = false; break; } } return inside; }
3. 实现线段相交的判断
需要判断两个菱形的任意边是否相交,包括端点重合的边界情况:
// 判断两条线段是否相交(包含端点重合) private boolean doSegmentsIntersect(Point a1, Point a2, Point b1, Point b2) { int ccw1 = crossProduct(a1, a2, b1); int ccw2 = crossProduct(a1, a2, b2); int ccw3 = crossProduct(b1, b2, a1); int ccw4 = crossProduct(b1, b2, a2); // 标准相交:两条线段互相跨立对方 if ((ccw1 * ccw2 < 0) && (ccw3 * ccw4 < 0)) { return true; } // 检查端点是否在另一条线段上 return isPointOnSegment(b1, a1, a2) || isPointOnSegment(b2, a1, a2) || isPointOnSegment(a1, b1, b2) || isPointOnSegment(a2, b1, b2); } // 计算三个点的叉积:(b - a) × (c - a) private 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); } // 判断点p是否在线段ab上(包含端点) private boolean isPointOnSegment(Point p, Point a, Point b) { // 先判断是否在ab的包围盒内 if (p.x < Math.min(a.x, b.x) || p.x > Math.max(a.x, b.x) || p.y < Math.min(a.y, b.y) || p.y > Math.max(a.y, b.y)) { return false; } // 叉积为0说明共线 return crossProduct(a, b, p) == 0; }
4. 整合重叠判断逻辑
两个菱形重叠的条件满足任意一条即可:
- 任意一个顶点在对方菱形内部/边界;
- 任意两条边相交;
- 一个菱形完全包含另一个(此情况已被第一个条件覆盖,因为包含的话所有顶点都在对方内部)。
public boolean overlaps(Rhombus other) { // 检查任意顶点是否在对方内部 for (Point v : this.vertices) { if (other.isPointInside(v)) { return true; } } for (Point v : other.vertices) { if (this.isPointInside(v)) { return true; } } // 检查任意两条边是否相交 int thisVertexCount = this.vertices.length; int otherVertexCount = other.vertices.length; for (int i = 0; i < thisVertexCount; i++) { Point a1 = this.vertices[i]; Point a2 = this.vertices[(i + 1) % thisVertexCount]; for (int j = 0; j < otherVertexCount; j++) { Point b1 = other.vertices[j]; Point b2 = other.vertices[(j + 1) % otherVertexCount]; if (doSegmentsIntersect(a1, a2, b1, b2)) { return true; } } } // 所有条件都不满足,说明不重叠 return false; }
5. 测试示例
public static void main(String[] args) { // 示例1:菱形1完全在菱形2内部 Rhombus rhombus1 = new Rhombus( new Point(2, 3), new Point(3, 4), new Point(4, 3), new Point(3, 2) ); Rhombus rhombus2 = new Rhombus( new Point(1, 1), new Point(5, 1), new Point(5, 5), new Point(1, 5) ); System.out.println(rhombus1.overlaps(rhombus2)); // 输出true // 示例2:两条边相交 Rhombus rhombus3 = new Rhombus( new Point(0, 0), new Point(0, 4), new Point(4, 4), new Point(4, 0) ); Rhombus rhombus4 = new Rhombus( new Point(2, -1), new Point(2, 5), new Point(6, 5), new Point(6, -1) ); System.out.println(rhombus3.overlaps(rhombus4)); // 输出true // 示例3:无重叠 Rhombus rhombus5 = new Rhombus( new Point(0, 0), new Point(0, 2), new Point(2, 2), new Point(2, 0) ); Rhombus rhombus6 = new Rhombus( new Point(3, 3), new Point(3, 5), new Point(5, 5), new Point(5, 3) ); System.out.println(rhombus5.overlaps(rhombus6)); // 输出false }
内容的提问来源于stack exchange,提问作者KEK LOL
相关产品推荐
相关产品推荐

