Monday 12 January 2009

DirtyRectSet - Dirty Rectangle Set class

DirtyRectSet is the class that collects all the bits of the image that
have been changed and therefore need replacement. It saves processing
time on image update.

Rectangles are added in ascending sequence of x coordinate, and there is
a collapse() method that enables rectangles which are rather close to
each other to be amalgamated. "Close enough" is defined by GLUE - i.e
within GLUE pixels, the rectangles overlap.

The drawImage method is immensely subtle - so subtle that it always
takes me some time to figure out exactly what it's doing. Importantly,
though, it seems to work.

 
/** * * DirtyRectSet.java * Mark Tacchi Mar 15/1996
* * * Slightly modified by Gil Williamson 2003 */

import java.util.Vector;
import java.awt.Rectangle;


public class DirtyRectSet extends java.lang.Object
{
private Vector rects;
public DirtyRectSet()
{
rects = new Vector();
}
public void addRect (Rectangle r)
{
int size = rects.size ();
for (int index = 0; index < size; index++)
{
Rectangle curr = (Rectangle)rects.elementAt (index);

if (r.x > curr.x)
{
rects.insertElementAt (r, index);
return;
}
}
rects.addElement (r);
}

final int GLUE = 64;

final private boolean closeEnough (Rectangle r1, Rectangle r2)
{
boolean result;
r1.width += GLUE;
r1.height += GLUE;
r2.width += GLUE;
r2.height += GLUE;
result = r1.intersects (r2);
r1.width -= GLUE;
r1.height -= GLUE;
r2.width -= GLUE;
r2.height -= GLUE;
return result;
}

public int getSize()
{
return(rects.size());
}

public Rectangle getRect(int index)
{
return ((Rectangle)rects.elementAt(index));
}

public void empty()
{
if (rects.size()>0)
{
rects.removeAllElements();
}
}

public void collapse ()
{
int index = 0;
if (rects.size () < 2)
return;
Rectangle r1 = (Rectangle)rects.elementAt (index);
Rectangle r2 = (Rectangle)rects.elementAt (index+1);
while (true)
{
// collapse R1 and R2
if (closeEnough (r1, r2))
{
r1 = r1.union (r2);
rects.setElementAt (r1, index);
rects.removeElementAt (index+1);
if (index+1 < rects.size ())
r2 = (Rectangle)rects.elementAt(index+1);
else
return;
}
// go to next pair
else if (index+2 < rects.size ())
{
r1 = r2;
r2 = (Rectangle)rects.elementAt (index+2);
index += 1;
}

// done
else
{
return;
}
}
}

public void drawImage (java.awt.Graphics g, java.awt.Image img,
Bridge owner)
{
collapse ();

for (int i= 0; i< rects.size (); i++) {
Rectangle r = (Rectangle)rects.elementAt(i);
java.awt.Graphics g2 = g.create (r.x, r.y, r.width,
r.height);
g2.drawImage(img, -r.x, -r.y, owner);
g2.dispose ();

}
}

}

No comments: