相交的矩形

时间:2010-07-14 06:04:18

标签: java algorithm swing

这是一个分析几何类型的问题。我不确定我是否可以在这里发布。但是我必须提出一个Java函数来执行此功能。我在页面/ swing容器中有多个矩形。我知道矩形的边界。现在我需要找到哪些矩形相互交叉。这里交叉矩形的一件好事将始终具有相同的y分量,并且所有矩形都具有相同的高度。我必须根据它们的x坐标配对矩形和宽度

例如

Rect1 has bounds:20,10,50,20
Rect2 has bounds:60,10,30,20
Rect3 has bounds:40,10,40,20
Rect4 has bounds 20,30,40,20
Rect5 has bounds 20,50,30,20

现在我的方法应该返回

Rect1 and Rect2
Rect2 and Rect3
Rect3 and Rect1

是否有任何算法或之前有人试过?提出您的建议

编辑:更具体地说,我的矩形实际上是一个JLabel。我将标签放在表格的行中。

4 个答案:

答案 0 :(得分:3)

1)首先,我同意其他人指出这实际上是一个一维问题:给定一组,找到所有相交的对。

2)请注意,在最坏的情况下,你不能保证比O(N ^ 2)更好的东西,因为这些段可能彼此重叠。

3)假设矩形的数量很大,并且在N中交叉点的数量并不总是有问题,我会使用扫描技术:

A)按递增顺序对所有段起点和终点进行排序。

B)遍历列表,并在途中收集交叉点。每次迭代都代表一块被扫描的轴,其中很容易确定覆盖它的线段。

4)请注意,如果您只需要数字的交叉点,那么您可以在O(N log N)时间内完成。

这是一个有效完成工作的通用实用程序。在底部,您可以找到一个用法示例。请记住,只有在您不期望许多交叉路口时,此解决方案才有意义。此外,对于少数细分市场来说这是一种过度杀戮(我想这是你的情况 - 因为你正在使用N< 100 UI项目)。但是,我把它写成一个练习并享受它:)

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.AbstractMap.SimpleEntry;


public class SegmentSet <T> {   
    private List<Segment> segments = new ArrayList<Segment>();  

    //note that x2 is inclusive
    public void add(int x1, int x2, T identity) {
        segments.add(new Segment(x1,x2, identity));
    }

    public List<SimpleEntry<T, T>> getAllIntersectingPairs() {
        // Build a list of all segment edges
        ArrayList<Edge> edges = new ArrayList<Edge>(2 * segments.size());
        int i=0;
        for(Segment seg : segments) {
            edges.add(new Edge(EdgeType.START, seg.x1, seg));
            edges.add(new Edge(EdgeType.END, seg.x2, seg));
        }

        // Sort the edges in ascending order
        Collections.sort(edges);

        // Sweep
        ArrayList<SimpleEntry<T, T>> res = new ArrayList<SimpleEntry<T, T>>();
        HashMap<Segment, Object> currSegments = new HashMap<Segment, Object>();
        for (Edge edge : edges) {
            if (edge.type == EdgeType.START) {
                for (Segment seg : currSegments.keySet())
                    res.add(new SimpleEntry<T, T>(edge.seg.identity, seg.identity));
                currSegments.put(edge.seg, null);
            } else {
                currSegments.remove(edge.seg);
            }
        }

        return res;
    }

    public class Segment {
        public final int x1;
        public final int x2;
        public final T identity;

        public Segment(int x1, int x2, T identity) {
            this.x1 = x1;
            this.x2 = x2;
            this.identity = identity;
        }
    }

    private enum EdgeType {START, END};

    private class Edge implements Comparable<Edge>{
        public final EdgeType type;
        public final int x;
        public Segment seg;

        public Edge(EdgeType type, int x, Segment seg) {
            this.type = type;
            this.x = x;
            this.seg = seg;
        }

        @Override
        public int compareTo(Edge o) {
            if (x > o.x)
                return 1;
            if (x < o.x)
                return -1;
            // A start Edge will come before an end edge in case of equal X value
            return type.ordinal() - o.type.ordinal();
        }
    }

    public static void main(String[] args) {
        SegmentSet<String> set = new SegmentSet<String>();
        set.add(10,100,"A");
        set.add(110,200,"B");
        set.add(0,400,"C");
        System.out.println(set.getAllIntersectingPairs());
    }
}

答案 1 :(得分:2)

如果相交的矩形将始终具有相同的y坐标,则这实际上不是二维重叠问题。它是一组一维重叠检查,每个不同的y坐标集一个。

检查一个维度的重叠真的很容易。

答案 2 :(得分:2)

您可以使用sweep line algorithm。基本上,将所有x - 坐标转储到一个数组中,并使用与它们关联的矩形进行注释,以及它们是否是该矩形的开头或结尾。然后只需对数组进行排序,并从头到尾进行扫描,在遇到其起始点时将每个矩形添加到“当前集”,并在找到终点时将其删除。只要当前集中有多个矩形,这些矩形就会重叠。

答案 3 :(得分:1)

AWT的Rectangle类确实有一些方法(例如,检查intersects

如果是JLabel,那就更容易了。只需做rect1.getBounds()。intersects(rect2.getBounds())