I'm not very pleased with this code, but it seems to work...
(I'm not pleased because of the maxloop variable I had to add to prevent a hang, for reasons I do not really understand ... yet)
Code:
ArrayList rectangles = new ArrayList();
Rectangle draggedRectangle = null;
ArrayList intersectionList = new ArrayList();
class Rectangle
{
int x;
int y;
int width;
int height;
color colour;
//The set of parents of this rectangle
ArrayList parents = new ArrayList();
public Rectangle(int x, int y, int width, int height, color colour)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.colour = colour;
}
public Rectangle(int x, int y, int width, int height)
{
this(x, y, width, height, randomColor());
}
void drawBorder()
{
stroke(255);
noFill();
rect(x, y, width, height);
}
void addParents(Rectangle parent)
{
if(parent.parents.size() == 0)
{
parents.add(parent);
}
else
{
for(int i = 0; i < parent.parents.size(); i++)
{
Object o = parent.parents.get(i);
if(!parents.contains(o))
{
parents.add(o);
}
}
}
}
int right()
{
return x + width;
}
int bottom()
{
return y + height;
}
Rectangle createRectangle(int left, int top, int right, int bottom, color colour)
{
if(right < left || bottom < top) return null;
return new Rectangle(left, top, right-left, bottom-top, colour);
}
Rectangle getIntersection(Rectangle other)
{
Rectangle intersection = createRectangle(max(x, other.x),
max(y, other.y),
min(right(), other.right()),
min(bottom(), other.bottom()),
averageColor(colour, other.colour));
if(intersection != null)
{
intersection.addParents(this);
intersection.addParents(other);
}
return intersection;
}
boolean hasSameParents(Rectangle other)
{
if(other.parents.size() == 0 || parents.size() == 0) return false;
if(other.parents.size() != parents.size()) return false;
boolean sameParents = true;
Iterator it = parents.iterator();
while(it.hasNext() && sameParents)
{
sameParents &= other.parents.contains(it.next());
}
return sameParents;
}
void draw()
{
fill(colour);
noStroke();
rect(x, y, width, height);
}
float distance(int x, int y)
{
int x1 = x-this.x-width/2;
int y1 = y-this.y-height/2;
return sqrt(x1*x1 + y1*y1);
}
void move(int dx, int dy)
{
x += dx;
y += dy;
}
void print()
{
println("Time: " + millis() + " X: " + x + " Y: " + y + " Width: " + width + " Height: " + height + " # Parents: " + parents.size());
}
}
void setup()
{
size(500, 500);
frameRate(30);
rectangles.add(new Rectangle(50, 50, 100, 200));
rectangles.add(new Rectangle(99, 100, 200, 50));
rectangles.add(new Rectangle(200, 99, 100, 100));
rectangles.add(new Rectangle(60, 200, 80, 70));
rectangles.add(new Rectangle(200, 300, 100, 100));
updateIntersections();
}
void draw()
{
background(0);
//Draw all rectangles
for(int i = 0; i < rectangles.size(); i++)
{
Rectangle rect = (Rectangle)rectangles.get(i);
rect.draw();
}
//Draw intersections
drawIntersections();
if(draggedRectangle != null)
{
draggedRectangle.drawBorder();
}
}
void drawRectangles()
{
}
void drawIntersections()
{
for(int i = 0; i < intersectionList.size(); i++)
{
ArrayList intersections = (ArrayList)intersectionList.get(i);
for(int j = 0; j < intersections.size(); j++)
{
Rectangle intersection = (Rectangle)intersections.get(j);
intersection.draw();
}
}
}
//Draw intersections of rectangles, and return these intersections
ArrayList calculateIntersections(ArrayList rectangles)
{
//Draw all intersection of rectangles
ArrayList intersections = new ArrayList();
for(int i = 0; i < rectangles.size(); i++)
{
Rectangle recti = (Rectangle)rectangles.get(i);
for(int j = 0; j < i; j++)
{
Rectangle rectj = (Rectangle)rectangles.get(j);
//We don't want to add an intersection of 2 rectangles with the same parents
if(!rectj.hasSameParents(recti))
{
Rectangle intersection = rectj.getIntersection(recti);
if(intersection != null)
{
intersections.add(intersection);
//intersection.print();
}
}
}
}
return intersections;
}
void mousePressed()
{
selectClosestRectangle();
}
void mouseReleased()
{
draggedRectangle = null;
}
void mouseDragged()
{
if(draggedRectangle != null)
{
draggedRectangle.move(mouseX - pmouseX, mouseY - pmouseY);
updateIntersections();
}
}
void updateIntersections()
{
ArrayList newIntersectionList = new ArrayList();
ArrayList intersections = rectangles;
int maxloop = 3;
int c = 0;
while(intersections.size() != 0 && c++ < maxloop)
{
intersections = calculateIntersections(intersections);
newIntersectionList.add(intersections);
}
intersectionList = newIntersectionList;
}
//Select the closest rectangle to drag
void selectClosestRectangle()
{
float dist = Float.MAX_VALUE;
Rectangle rectangle = null;
for(int i = 0; i < rectangles.size(); i++)
{
Rectangle rect = (Rectangle)rectangles.get(i);
if(rect.distance(mouseX, mouseY) < dist)
{
rectangle = rect;
dist = rect.distance(mouseX, mouseY);
}
}
draggedRectangle = rectangle;
}
//Get a random color
color randomColor()
{
return color(random(0, 255), random(0, 255), random(0, 255));
}
//Average two colors
color averageColor(color color1, color color2)
{
return (color1+color2)/2;
}