You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何正确判断两个Rhombus(菱形)是否重叠?

Java中判断两个菱形重叠的正确实现

你的原始代码存在两个核心问题:

  1. 用单个int存储顶点,完全错误——菱形的顶点是二维坐标,需要用(x,y)表示;
  2. 仅通过顶点是否重合判断重叠,漏判了顶点在对方内部、边相交、一个菱形完全包含另一个这些常见的重叠场景。

以下是正确的实现思路和代码:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 02:42:07