blob: 86b09b3220fa5c97f3520da2f7f140f03a594b03 [file] [log] [blame]
// Copyright 2006 Google Inc.
// All Rights Reserved.
// Author: <renn@google.com> (Marius Renn)
#include "helium_cluster.h"
#include "clusterer.h"
#include "clustervalidator.h"
#include "debugging.h"
#include "helium_image.h"
#include "shape.h"
using namespace helium;
const int kMaxInt = ~(0x01 << (sizeof(int)*8 - 1));
Clusterer::Clusterer() : clusters_(4) {
}
Clusterer::~Clusterer() {
ClearClusters();
}
void Clusterer::ClearClusters() {
for (unsigned i = 0; i < clusters_.size(); i++) delete clusters_.ValueAt(i);
clusters_.DeleteValues();
}
void Clusterer::ClusterShapes(const Array<Shape*>& shapes,
ClusterValidator& validator){
SetNeighbors(shapes, validator);
AddClusters(shapes, validator);
}
void Clusterer::SetNeighbors(const Array<Shape*>& shapes,
ClusterValidator& validator) {
for (unsigned i = 0; i < shapes.size(); i++) {
Shape* left = shapes.ValueAt(i);
if (!validator.ValidateShape(*left)) continue;
Box left_box = left->bounds();
// Find best neighbor
unsigned best_distance = kMaxInt;
Shape* best_neighbor = NULL;
for (unsigned j = 0; j < shapes.size(); j++) {
if (j == i) continue;
Shape* right = shapes.ValueAt(j);
if (!validator.ValidateShape(*right)) continue;
Box right_box = right->bounds();
if (right_box.center().x <= left_box.center().x) continue;
bool qualifies = validator.ValidatePair(*left, *right);
if (qualifies) {
Point left_rb(left_box.right(), left_box.bottom());
Point right_lb(right_box.left(), right_box.bottom());
unsigned distance = Distance(left_rb, right_lb);
if (distance < best_distance) {
best_distance = distance;
best_neighbor = right;
}
}
}
// Did we find a neighbor?
if (best_neighbor) {
if (best_neighbor->left_neighbor()) // Remove old link, if there
best_neighbor->left_neighbor()->set_right_neighbor(NULL);
left->set_right_neighbor(best_neighbor);
best_neighbor->set_left_neighbor(left);
left->set_needs_clustering(true);
best_neighbor->set_needs_clustering(true);
}
}
}
void Clusterer::AddClusters(const Array<Shape*>& shapes,
ClusterValidator& validator) {
for (unsigned i = 0; i < shapes.size(); i++) {
Shape* cur_shape = shapes.ValueAt(i);
if (!cur_shape->needs_clustering()) continue;
while (cur_shape->left_neighbor())
cur_shape = cur_shape->left_neighbor();
Shape *first_shape = validator.ValidateClusterStartingAt(*cur_shape);
if (first_shape) {
Cluster* cluster = new Cluster(first_shape);
clusters_.Add(cluster);
}
}
}
void Clusterer::DrawClusterBounds(Image& image) const {
Color white = MakeColor(255, 0, 0);
for (unsigned i = 0; i < clusters_.size(); ++i) {
Cluster* cur_cluster = clusters_.ValueAt(i);
const Box& bounds = cur_cluster->CalculateBounds();
image.DrawBox(bounds, white);
}
}