1

I have a list of AWT rectangles. I want to compute the union of the rectangles in an elegant way. Here is my code which works but does not look very elegant.

  Rectangle union(List<Rectangle> rects) {
    if (rects.isEmpty()) {
      return new Rectangle();
    }
    assert !rects.isEmpty();
    final Iterator<Rectangle> iterator = rects.iterator();
    Rectangle rect = iterator.next();
    while (iterator.hasNext()) {
      rect = rect.union( iterator.next() );
    }
    return rect;
  }

I also tried the following which does not work:

  Rectangle union(List<Rectangle> rects) {
    Rectangle result = new Rectangle();
    for (Rectangle rect : rects) {
      result.add( rect );
    }
    return result;
  }

The rectangle result is initialized to (0,0,0,0) so the union will allways contain the origin.

Is there a more elegant way to do this in Java?

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
Daniel
  • 13
  • 1
  • 3
  • Why are you using `union()` in the first code and `add()` in the second? My guess is that that difference is why it does not work ... – Joey May 04 '11 at 08:37

3 Answers3

1

In your second example, you need to initialize result like this:

Rectangle result = new Rectangle(-1, -1);

Be aware that this only works since Java SE 6. In previous versions the behaviour with regards to negative widths and heights is undefined. See the Javadoc entry for Rectangle for a similar example with a set of points.

Christoph Seibert
  • 1,451
  • 10
  • 5
1

I think your solution is not bad. Here is how I would do it:

public static void main(String[] args) {
    List<Rectangle> rects = new ArrayList<Rectangle>();
    rects.add(new Rectangle(new Point(1, 1), new Dimension(3, 4)));
    rects.add(new Rectangle(new Point(2, 2), new Dimension(5, 7)));
    Rectangle u = union(rects);
    Rectangle a = add(rects);
    System.out.println(u);
    System.out.println(a);
}

public static Rectangle union(List<Rectangle> rects) {
    if (rects.isEmpty())
        throw new IllegalArgumentException();
    Rectangle unionRectangle = new Rectangle(rects.get(0));
    for (int i = 1; i < rects.size(); i++)
        unionRectangle = unionRectangle.union(rects.get(i));
    return unionRectangle;
}

public static Rectangle add(List<Rectangle> rects) {
    if (rects.isEmpty())
        throw new IllegalArgumentException();
    Rectangle unionRectangle = new Rectangle(rects.get(0));
    for (int i = 1; i < rects.size(); i++)
        unionRectangle.add(rects.get(i));
    return unionRectangle;
}

Output is

java.awt.Rectangle[x=1,y=1,width=6,height=8]
java.awt.Rectangle[x=1,y=1,width=6,height=8]

Some notes:

  • If the list rects is empty, I would throw an exception rather than returning a Rectangle

  • both Rectangle.union and Rectangle.add give the same results (see output)

  • I would start with a new Rectangle equal to the first element of rects and then use it to compute the union with the following ones (or, equivalently, add the following ones).

I hope this helps.

MarcoS
  • 13,386
  • 7
  • 42
  • 63
0

According the accompanying javadoc, your add based should work. It says:

Adds a Rectangle to this Rectangle. The resulting Rectangle is the union of the two rectangles.

But it only works, you initialize the rectangle with a dimension less than zero. Here's a working solution for method 2:

Rectangle union(List<Rectangle> rects) {
  Rectangle result = new Rectangle(-1,-1);  // dimension less than 0
  for (Rectangle rect : rects) {
    result.add( rect );
  }
  return result;
}

Alternative: create the initial result based on the first list item:

Rectangle union(List<Rectangle> rects) {
  if (rects == null || rects.isEmpty()) return null;

  Rectangle result = new Rectangle(rects.get(0));  
  for (Rectangle rect : rects) {
    result.add( rect );
  }
  return result;
}
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268