如何在给定坐标数组的情况下合并两个矩形?

时间:2019-05-27 11:19:49

标签: java algorithm merge

说我有两个矩形的两个坐标(x,y)数组,例如[(0,0),(0,1),(2,1),(2,0)]和[(1 ,0),(1,2),(3,2),(3,0)]],我如何将这两个坐标数组合并为一个表示结果多边形的数组?

以图形方式看起来像这样:

   _ _
 _|_  |
|_|_|_|

   _ _
 _|   |
|_ _ _|

具有结果数组[[0,0),(0,1),(1,1),(1,2),(3,2),(3,0)]。

我正在尝试设计某种合并算法,但是我不确定从哪里开始。

对于输入,将有两个数组,此方法将返回一个合并的数组。

我完全不知道该从哪里开始。

4 个答案:

答案 0 :(得分:1)

作为指针,请考虑以下内容:

我假设每个数组(r1和r2)的构造都与以下方式相同: [(左下方)(左上方)(右上方)(左上方)]

如果矩形(实体而不仅仅是角)有任何重叠,则结果可能是新数组内的四到十二个不同坐标之间。

我们首先检查哪对是最左边的,如果有一对,我们将其添加到新数组中。将r1的左下角的X坐标与r2的左下角的X坐标进行比较就足够了。如果不是,并且两个矩形的左侧都在同一X坐标上,则将左下角的Y值降低,并将左上角的Y值较大。该逻辑可以应用于所有四个方面。

在这种情况下,例如在最左侧的位置,我们仍然需要检查较小的左侧是否与顶部或底部重叠。我们可以通过从左上角r2的Y值中减去左上角r1的Y来实现。如果存在差异(也就是,左侧越小越高),我们将R2的左上角坐标与(r2 X's,r1 Y's)一起添加到数组中。极端。

因此,一般的流程是

  1. 检查最外面的边缘。可以直接添加这些内容。一个简单的单坐标比较就足够了。如果有外部边缘,请参见(2),否则请参见(3)
  2. 检查NOT最外边缘是否在另一个方向上更长。因此,例如,在进行左检查的情况下,假设r1更靠左。检查r2的左上方是否高于r1的左上方。如果是这种情况,请添加r2的左上角以及一个新坐标(r2的左上角x | r1的左上角Y)。请记住,例如在这种情况下,r2的左边缘可能是这两者:从顶部到顶部和从底部到顶部!
  3. 由于两个边缘都在同一水平上(例如,相同的X值),因此我们需要查看哪个是左下角进一步向下,将其与左上角进一步添加到一起。

A small visualization of single cases.

答案 1 :(得分:0)

(排列顺序永远不会太麻烦(但在这里可能无济于事:按正旋转顺序排列点,例如从左上边缘开始)。

对于合并(a.topx .. a.bottomx)和(b.topx .. b.bottomx)必须重叠,与y相同。

外部矩形是external.topx = min(a.topx,b.topx)等等。

X坐标(可能是偶然的)是external.topx,a.topx,b.topx,external.bottom.x。 现在,您找到了多边形的一个边界。依此类推。

连接的内部边缘微不足道。

请注意,有很多形式,但广义的形式是:

...._____.....
:___|    |___:
|___      ___|
:...|____|...:

问题是您是否希望合并 any 多边形的更通用算法,因为添加第三个矩形将变成完全不同的情况。

答案 2 :(得分:0)

首先,请确保第一个矩形的左下角不在另一个矩形内。如果是,请交换它们。角可以重叠或角可以在另一个矩形的一侧,这很好。

然后,开始沿逆时针方向在左侧矩形旁边并排,然后在底部右侧移至右侧。检查您是否会因为以下原因而结束:

  1. 先到达终点
  2. 先击中另一个矩形的左墙

如果到达终点,请继续在第一个矩形的右边缘上走。如果您碰到另一个矩形,则在另一个矩形的左墙上走下去。

重复直到再次加热第一个矩形的左下角。在每个点上,您都需要记住:走哪条路/走到哪一边(由于您总是逆时针方向行驶,因此可以很容易地计算出另一边),以及您要走的矩形。

如果您在步行中完全没有碰到另一个矩形,则意味着该矩形未触摸,或者第二个矩形位于第一个矩形内。

请确保仔细考虑将要使用的不等式,例如:

 ______
|  |_| |
|      |
|______|

这两个小弯角应该合并为一个,还是直线上合并3条直线的6多边形?还是应该这样:

 _
|_|_
  |_|

是2个不同的矩形,还是1个具有2个相同点的8多边形?

答案 3 :(得分:0)

这里有许多个自由度,用于说明方法和实际实现。只是从我的脑海中考虑一些相关的问题:

  • 坐标总是整数吗?
  • 输入形状是否总是(与轴对齐)矩形?
  • 矩形是否总是重叠?
  • 这些点是否始终位于不同的坐标?
  • 边缘永不平等吗?
  • ...

在某些情况下(如果前三个问题回答为“是”),您可能会采用一种技术上非常简单的方法:将整个输入视为“网格”,其中矩形定义了网格单元,被“填充”,最后返回填充区域的边界。

如果对其中一个的回答可能是“否”,那么您正在打开一罐蠕虫,它具有许多很多微妙之处。

幸运的是,Sun / Oracle的员工已经很好地解决了这个问题,即使对于非常复杂的问题,仍然仍然是一个简单的解决方案:您可以将输入形状,然后使用Area#add方法来计算合并的形状。

在此示例中实现。但是请注意,与可以用于更简单情况的基于网格的方法相比,这不是很有效。而且,对于不重叠的矩形该如何处理仍然存在疑问。但是,至少对于给定的输入,结果是预期的:

import java.awt.Point;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class RectangleMerge {

    public static void main(String[] args) {
        List<Point2D> pointsA = Arrays.asList(new Point(0, 0), new Point(0, 1), new Point(2, 1), new Point(2, 0));
        List<Point2D> pointsB = Arrays.asList(new Point(1, 0), new Point(1, 2), new Point(3, 2), new Point(3, 0));

        System.out.println(merge(pointsA, pointsB));
    }

    private static List<Point2D> merge(List<? extends Point2D> pointsA, List<? extends Point2D> pointsB) {
        Area aa = new Area(toShape(pointsA));
        aa.add(new Area(toShape(pointsB)));
        return toPoints(aa);
    }

    private static Shape toShape(List<? extends Point2D> points) {
        Path2D path = new Path2D.Double();
        for (int i = 0; i < points.size(); i++) {
            Point2D p = points.get(i);
            if (i == 0) {
                path.moveTo(p.getX(), p.getY());
            } else {
                path.lineTo(p.getX(), p.getY());
            }
        }
        path.closePath();
        return path;
    }

    private static List<Point2D> toPoints(Shape shape) {
        List<Point2D> result = new ArrayList<Point2D>();
        PathIterator pi = shape.getPathIterator(null, 0.0);
        double[] coords = new double[6];
        while (!pi.isDone()) {
            int segment = pi.currentSegment(coords);
            switch (segment) {
            case PathIterator.SEG_MOVETO:
            case PathIterator.SEG_LINETO:
                result.add(new Point2D.Double(coords[0], coords[1]));
                break;
            }
            pi.next();
        }
        return result;
    }

}