blob: 648c1bfbd7a57c0a500d2b727e7b1fb6815dc60b [file] [log] [blame]
// Copyright 2006 Google Inc.
// All Rights Reserved.
// Author: <renn@google.com> (Marius Renn)
#include "box.h"
namespace helium {
Box ScaleBox(const Box& box, float scale) {
float x = box.left();
float y = box.top();
float w = box.width();
float h = box.height();
return Box(static_cast<int>(x * scale),
static_cast<int>(y * scale),
static_cast<unsigned>(w * scale),
static_cast<unsigned>(h * scale));
}
bool Encloses(const Box& outer, const Box& inner) {
return (outer.left() <= inner.left())
&& (outer.top() <= inner.top())
&& (outer.right() >= inner.right())
&& (outer.bottom() >= inner.bottom());
}
bool Surrounds(const Box& outer, const Box& inner) {
return (outer.left() < inner.left())
&& (outer.top() < inner.top())
&& (outer.right() > inner.right())
&& (outer.bottom() > inner.bottom());
}
bool Intersect(const Box& a, const Box& b) {
return (Max(a.left(), b.left()) < Min(a.right(), b.right()))
&& (Max(a.top(), b.top()) < Min(a.bottom(), b.bottom()));
}
Box MinEnclosingBox(const Box& a, const Box& b) {
Box out = Box(Min(a.left(), b.left()),
Min(a.top(), b.top()),
0, 0);
out.set_right(Max(a.right(), b.right()));
out.set_bottom(Max(a.bottom(), b.bottom()));
return out;
}
Box Intersection(const Box& a, const Box& b) {
Box out = Box(Max(a.left(), b.left()),
Max(a.top(), b.top()),
0, 0);
unsigned right = Min(a.right(), b.right());
unsigned bottom = Min(a.bottom(), b.bottom());
if ((right > out.left()) && (bottom > out.top())) {
out.set_right(right);
out.set_bottom(bottom);
}
return out;
}
Box MinEnclosingBox(const Array<Box>& boxes) {
ASSERT(boxes.size() > 0);
Box bounds = boxes.ValueAt(0);
for (unsigned i = 1; i < boxes.size(); i++)
bounds = MinEnclosingBox(bounds, boxes.ValueAt(i));
return bounds;
}
void BoxSetsIntersection(const Array<Box>& boxes_a,
const Array<Box>& boxes_b,
Array<Box>& result) {
for (unsigned i = 0; i < boxes_a.size(); i++) {
for (unsigned j = 0; j < boxes_b.size(); j++) {
Box intersect = Intersection(boxes_a.ValueAt(i), boxes_b.ValueAt(j));
if (intersect.Area() > 0) result.Add(intersect);
}
}
}
void BoxesInvert(const Array<Box>& boxes,
Array<Box>& inversion) {
if (boxes.size() == 0) return;
Array<Box> frame_boxes(4);
frame_boxes.Add(MinEnclosingBox(boxes));
unsigned cur_index = 0;
unsigned max_index = 0;
// Find inverse of area of boxes
for (unsigned i = 0; i < boxes.size(); i++) {
for (unsigned j = cur_index; j <= max_index; j++) {
Box cur_area = frame_boxes.ValueAt(j);
CutBox(cur_area, boxes.ValueAt(i), frame_boxes);
}
cur_index = max_index + 1;
max_index = frame_boxes.size() - 1;
}
// Add to output
for (unsigned i = cur_index; i <= max_index; i++)
inversion.Add(frame_boxes.ValueAt(i));
}
unsigned Area(const Array<Box>& boxes) {
if (boxes.size() == 0) return 0;
Array<Box> frame_boxes(4);
frame_boxes.Add(MinEnclosingBox(boxes));
unsigned frame_area = frame_boxes.ValueAt(0).Area();
unsigned cur_index = 0;
unsigned max_index = 0;
// Find inverse of area of boxes
for (unsigned i = 0; i < boxes.size(); i++) {
for (unsigned j = cur_index; j <= max_index; j++) {
Box cur_area = frame_boxes.ValueAt(j);
CutBox(cur_area, boxes.ValueAt(i), frame_boxes);
}
cur_index = max_index + 1;
max_index = frame_boxes.size() - 1;
}
// Subtract inverse from Max area
for (unsigned i = cur_index; i <= max_index; i++)
frame_area -= frame_boxes.ValueAt(i).Area();
return frame_area;
}
void CutBox(const Box& area, const Box& cut, Array<Box>& result) {
if (!Intersect(cut, area)) {
result.Add(area);
return;
}
// First rectangle: Left
int left = area.left();
int top = area.top();
int right = cut.left();
int bottom = area.bottom();
if ((left < right) && (top < bottom))
result.Add(Box(left, top, right - left, bottom - top));
// Second rectangle: Top
left = Max(cut.left(), area.left());
top = area.top();
right = Min(cut.right(), area.right());
bottom = cut.top();
if ((left < right) && (top < bottom))
result.Add(Box(left, top, right - left, bottom - top));
// Third rectangle: Right
left = cut.right();
top = area.top();
right = area.right();
bottom = area.bottom();
if ((left < right) && (top < bottom))
result.Add(Box(left, top, right - left, bottom - top));
// Fourth rectangle: Bottom
left = Max(cut.left(), area.left());
top = cut.bottom();
right = Min(cut.right(), area.right());
bottom = area.bottom();
if ((left < right) && (top < bottom))
result.Add(Box(left, top, right - left, bottom - top));
}
}