+ char changed;
+ do {
+ head_t*h1 = context->heads;
+ changed = 0;
+ while(h1) {
+ head_t*next = h1->next;
+ head_t*h2 = context->heads;
+ while(h2) {
+ if(h1!=h2) {
+ if(ibbox_does_overlap(&h1->bbox, &h2->bbox)) {
+ merge(context, h1->pos, h2->pos);
+ changed = 1;
+ break;
+ }
+ }
+ h2 = h2->next;
+ }
+ h1 = next;
+ }
+ } while(changed);
+}
+
+static head_t* search_vicinity(context_t*context, head_t*h, int max_radius, double*cos, double*sin)
+{
+ int t;
+ void**data = context->group;
+ /* FIXME: this function isn't very efficient. We need a better way to iterate
+ through all points, sorted by distance, in the neighborhood of a coordinate */
+ for(t=3;t<max_radius*2;t++) {
+ int s;
+ for(s=0;s<256;s++) {
+ int x=h->x+cos[s]*t/4.0+0.5;
+ int y=h->y+sin[s]*t/4.0+0.5;
+ if(x>=0 && y>=0 && x<context->width && y<context->height) {
+ int pos = y*context->width+x;
+ if(data[pos]) {
+ while(!POINTS_TO_HEAD(data[pos])) {
+ pos=(void**)data[pos]-(void**)data;
+ }
+ head_t*new_head = (head_t*)data[pos];
+ if(new_head != h) {
+ return new_head;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static void fix_small_boxes(context_t*context)
+{
+ double sintab[256];
+ double costab[256];
+ int t;
+ for(t=0;t<256;t++) {
+ sintab[t] = sin(t*M_PI/128);
+ costab[t] = cos(t*M_PI/128);
+ }
+
+ head_t*h = context->heads;
+ while(h) {
+ h->seen = 0;
+ h = h->next;
+ }
+
+ char changed;
+ do {
+ changed = 0;
+ head_t*h = context->heads;
+ while(h) {
+ head_t*next = h->next;
+ if(!h->seen) {
+ if(h->bbox.xmax - h->bbox.ymin < 16
+ && h->bbox.ymax - h->bbox.ymin < 16) {
+ head_t*other = search_vicinity(context, h, 64, costab, sintab);
+ if(other) {
+ merge(context, h->pos, other->pos);
+ changed = 1;
+ break;
+ } else {
+ h->seen = 1;
+ }
+ }
+ }
+ h = next;
+ }
+ } while(changed);
+}
+
+static void display(context_t*context)
+{
+ int width = context->width;
+ int height = context->height;
+ void**group = context->group;