/* -*-C-*-
 ********************************************************************************
 *
 * File:        blobs.c  (Formerly blobs.c)
 * Description:  Blob definition
 * Author:       Mark Seaman, OCR Technology
 * Created:      Fri Oct 27 15:39:52 1989
 * Modified:     Thu Mar 28 15:33:26 1991 (Mark Seaman) marks@hpgrlt
 * Language:     C
 * Package:      N/A
 * Status:       Experimental (Do Not Distribute)
 *
 * (c) Copyright 1989, Hewlett-Packard Company.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 *
 *********************************************************************************/

/*----------------------------------------------------------------------
              I n c l u d e s
----------------------------------------------------------------------*/
#include "mfcpch.h"
#include "blobs.h"
#include "cutil.h"
#include "emalloc.h"
#include "structures.h"

/*----------------------------------------------------------------------
              F u n c t i o n s
----------------------------------------------------------------------*/
/**********************************************************************
 * blob_origin
 *
 * Compute the origin of a compound blob, define to be the centre
 * of the bounding box.
 **********************************************************************/
void blob_origin(TBLOB *blob,       /*blob to compute on */
                 TPOINT *origin) {  /*return value */
  TPOINT topleft;                /*bounding box */
  TPOINT botright;

                                 /*find bounding box */
  blob_bounding_box(blob, &topleft, &botright); 
                                 /*centre of box */
  origin->x = (topleft.x + botright.x) / 2;
  origin->y = (topleft.y + botright.y) / 2;
}


/**********************************************************************
 * blob_bounding_box
 *
 * Compute the bounding_box of a compound blob, define to be the
 * max coordinate value of the bounding boxes of all the top-level
 * outlines in the box.
 **********************************************************************/
void blob_bounding_box(TBLOB *blob,               /*blob to compute on */
                       register TPOINT *topleft,  /*bounding box */
                       register TPOINT *botright) {
  register TESSLINE *outline;    /*current outline */

  if (blob == NULL || blob->outlines == NULL) {
    topleft->x = topleft->y = 0;
    *botright = *topleft;        /*default value */
  }
  else {
    outline = blob->outlines;
    *topleft = outline->topleft;
    *botright = outline->botright;
    for (outline = outline->next; outline != NULL; outline = outline->next) {
      if (outline->topleft.x < topleft->x)
                                 /*find extremes */
        topleft->x = outline->topleft.x;
      if (outline->botright.x > botright->x)
                                 /*find extremes */
        botright->x = outline->botright.x;
      if (outline->topleft.y > topleft->y)
                                 /*find extremes */
        topleft->y = outline->topleft.y;
      if (outline->botright.y < botright->y)
                                 /*find extremes */
        botright->y = outline->botright.y;
    }
  }
}


/**********************************************************************
 * blobs_bounding_box
 *
 * Return the smallest extreme point that contain this word.
 **********************************************************************/
void blobs_bounding_box(TBLOB *blobs, TPOINT *topleft, TPOINT *botright) { 
  TPOINT tl;
  TPOINT br;
  TBLOB *blob;
  /* Start with first blob */
  blob_bounding_box(blobs, topleft, botright); 

  iterate_blobs(blob, blobs) { 
    blob_bounding_box(blob, &tl, &br); 

    if (tl.x < topleft->x)
      topleft->x = tl.x;
    if (tl.y > topleft->y)
      topleft->y = tl.y;
    if (br.x > botright->x)
      botright->x = br.x;
    if (br.y < botright->y)
      botright->y = br.y;
  }
}


/**********************************************************************
 * blobs_origin
 *
 * Compute the origin of a compound blob, define to be the centre
 * of the bounding box.
 **********************************************************************/
void blobs_origin(TBLOB *blobs,      /*blob to compute on */
                  TPOINT *origin) {  /*return value */
  TPOINT topleft;                /*bounding box */
  TPOINT botright;

                                 /*find bounding box */
  blobs_bounding_box(blobs, &topleft, &botright); 
                                 /*center of box */
  origin->x = (topleft.x + botright.x) / 2;
  origin->y = (topleft.y + botright.y) / 2;
}


/**********************************************************************
 * blobs_widths
 *
 * Compute the widths of a list of blobs. Return an array of the widths
 * and gaps.
 **********************************************************************/
WIDTH_RECORD *blobs_widths(TBLOB *blobs) {  /*blob to compute on */
  WIDTH_RECORD *width_record;
  TPOINT topleft;                /*bounding box */
  TPOINT botright;
  TBLOB *blob;                   /*blob to compute on */
  int i = 0;
  int blob_end;
  int num_blobs = count_blobs (blobs);

  /* Get memory */
  width_record = (WIDTH_RECORD *) memalloc (sizeof (int) * num_blobs * 2);
  width_record->num_chars = num_blobs;

  blob_bounding_box(blobs, &topleft, &botright); 
  width_record->widths[i++] = botright.x - topleft.x;
  /* First width */
  blob_end = botright.x;

  iterate_blobs (blob, blobs->next) {
    blob_bounding_box(blob, &topleft, &botright); 
    width_record->widths[i++] = topleft.x - blob_end;
    width_record->widths[i++] = botright.x - topleft.x;
    blob_end = botright.x;
  }
  return (width_record);
}


/**********************************************************************
 * count_blobs
 *
 * Return a count of the number of blobs attached to this one.
 **********************************************************************/
int count_blobs(TBLOB *blobs) { 
  TBLOB *b;
  int x = 0;

  iterate_blobs (b, blobs) x++;
  return (x);
}


/**********************************************************************
 * delete_word
 *
 * Reclaim the memory taken by this word structure and all of its
 * lower level structures.
 **********************************************************************/
void delete_word(TWERD *word) { 
  TBLOB *blob;
  TBLOB *nextblob;
  TESSLINE *outline;
  TESSLINE *nextoutline;
  TESSLINE *child;
  TESSLINE *nextchild;

  for (blob = word->blobs; blob; blob = nextblob) {
    nextblob = blob->next;

    for (outline = blob->outlines; outline; outline = nextoutline) {
      nextoutline = outline->next;

      delete_edgepts (outline->loop);

      for (child = outline->child; child; child = nextchild) {
        nextchild = child->next;

        delete_edgepts (child->loop);

        oldoutline(child); 
      }
      oldoutline(outline); 
    }
    oldblob(blob); 
  }
  if (word->correct != NULL)
    strfree (word->correct);     /* Reclaim memory */
  oldword(word); 
}


/**********************************************************************
 * delete_edgepts
 *
 * Delete a list of EDGEPT structures.
 **********************************************************************/
void delete_edgepts(register EDGEPT *edgepts) { 
  register EDGEPT *this_edge;
  register EDGEPT *next_edge;

  if (edgepts == NULL)
    return;

  this_edge = edgepts;
  do {
    next_edge = this_edge->next;
    oldedgept(this_edge); 
    this_edge = next_edge;
  }
  while (this_edge != edgepts);
}