/* -*-C-*-
 ********************************************************************************
 *
 * File:        gradechop.c  (Formerly gradechop.c)
 * Description:
 * Author:       Mark Seaman, OCR Technology
 * Created:      Fri Oct 16 14:37:00 1987
 * Modified:     Tue Jul 30 16:06:27 1991 (Mark Seaman) marks@hpgrlt
 * Language:     C
 * Package:      N/A
 * Status:       Reusable Software Component
 *
 * (c) Copyright 1987, 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 "gradechop.h"
#include "debug.h"
#include "olutil.h"
#include "chop.h"
#include <math.h>

/*----------------------------------------------------------------------
              T y p e s
----------------------------------------------------------------------*/
#define CENTER_GRADE_CAP 25.0

/*----------------------------------------------------------------------
              M a c r o s
----------------------------------------------------------------------*/
/**********************************************************************
 * find_bounds_loop
 *
 * This is a macro to be used by set_outline_bounds.
 **********************************************************************/

#define find_bounds_loop(point1,point2,x_min,x_max)     \
	x_min = point2->pos.x;                               \
	x_max = point2->pos.x;                               \
																		\
	this_point = point1;                                 \
	do {                                                 \
		x_min = min (this_point->pos.x, x_min);           \
		x_max = max (this_point->pos.x, x_max);           \
		this_point = this_point->next;                    \
	}                                                    \
	while (this_point != point2 && this_point != point1) \


/*----------------------------------------------------------------------
              F u n c t i o n s
----------------------------------------------------------------------*/
/**********************************************************************
 * full_split_priority
 *
 * Assign a priority to this split based on the features that it has.
 * Part of the priority has already been calculated so just return the
 * additional amount for the bounding box type information.
 **********************************************************************/
PRIORITY full_split_priority(SPLIT *split, INT16 xmin, INT16 xmax) { 
  BOUNDS_RECT rect;

  set_outline_bounds (split->point1, split->point2, rect);

  if (xmin < min (rect[0], rect[2]) && xmax > max (rect[1], rect[3]))
    return (999.0);

  return (grade_overlap (rect) +
    grade_center_of_blob (rect) + grade_width_change (rect));
}


/**********************************************************************
 * grade_center_of_blob
 *
 * Return a grade for the a split.  Rank it on closeness to the center
 * of the original blob
 *   0    =  "perfect"
 *   100  =  "no way jay"
 **********************************************************************/
PRIORITY grade_center_of_blob(register BOUNDS_RECT rect) { 
  register PRIORITY grade;

  grade = (rect[1] - rect[0]) - (rect[3] - rect[2]);
  if (grade < 0)
    grade = -grade;

  grade *= center_knob;
  grade = min (CENTER_GRADE_CAP, grade);
  return (max (0.0, grade));
}


/**********************************************************************
 * grade_overlap
 *
 * Return a grade for this split for the overlap of the resultant blobs.
 *   0    =  "perfect"
 *   100  =  "no way jay"
 **********************************************************************/
PRIORITY grade_overlap(register BOUNDS_RECT rect) { 
  register PRIORITY grade;
  register INT16 width1;
  register INT16 width2;
  register INT16 overlap;

  width1 = rect[3] - rect[2];
  width2 = rect[1] - rect[0];

  overlap = min (rect[1], rect[3]) - max (rect[0], rect[2]);
  width1 = min (width1, width2);
  if (overlap == width1)
    return (100.0);              /* Total overlap */

  width1 = 2 * overlap - width1; /* Extra penalty for too */
  overlap += max (0, width1);    /* much overlap */

  grade = overlap * overlap_knob;

  return (max (0.0, grade));
}


/**********************************************************************
 * grade_split_length
 *
 * Return a grade for the length of this split.
 *   0    =  "perfect"
 *   100  =  "no way jay"
 **********************************************************************/
PRIORITY grade_split_length(register SPLIT *split) { 
  register PRIORITY grade;
  register float split_length;

  split_length = weighted_edgept_dist (split->point1, split->point2,
    x_y_weight);

  if (split_length <= 0)
    grade = 0;
  else
    grade = sqrt (split_length) * split_dist_knob;

  return (max (0.0, grade));
}


/**********************************************************************
 * grade_sharpness
 *
 * Return a grade for the sharpness of this split.
 *   0    =  "perfect"
 *   100  =  "no way jay"
 **********************************************************************/
PRIORITY grade_sharpness(register SPLIT *split) { 
  register PRIORITY grade;

  grade = point_priority (split->point1) + point_priority (split->point2);

  if (grade < -360.0)
    grade = 0;
  else
    grade += 360.0;

  grade *= sharpness_knob;       /* Values 0 to -360 */

  return (grade);
}


/**********************************************************************
 * grade_width_change
 *
 * Return a grade for the change in width of the resultant blobs.
 *   0    =  "perfect"
 *   100  =  "no way jay"
 **********************************************************************/
PRIORITY grade_width_change(register BOUNDS_RECT rect) { 
  register PRIORITY grade;
  register INT32 width1;
  register INT32 width2;

  width1 = rect[3] - rect[2];
  width2 = rect[1] - rect[0];

  grade = 20 - (max (rect[1], rect[3])
    - min (rect[0], rect[2]) - max (width1, width2));

  grade *= width_change_knob;

  return (max (0.0, grade));
}


/**********************************************************************
 * set_outline_bounds
 *
 * Set up the limits for the x coordinate of the outline.
 **********************************************************************/
void set_outline_bounds(register EDGEPT *point1,
                        register EDGEPT *point2,
                        BOUNDS_RECT rect) {
  register EDGEPT *this_point;
  register INT16 x_min;
  register INT16 x_max;

  find_bounds_loop(point1, point2, x_min, x_max); 

  rect[0] = x_min;
  rect[1] = x_max;

  find_bounds_loop(point2, point1, x_min, x_max); 

  rect[2] = x_min;
  rect[3] = x_max;
}
