/********************************************************************** * File: polyblob.cpp (Formerly blob.c) * Description: Code for PBLOB class. * Author: Ray Smith * Created: Wed Oct 23 15:17:41 BST 1991 * * (C) Copyright 1991, Hewlett-Packard Ltd. ** 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. * **********************************************************************/ #include "mfcpch.h" #include "varable.h" #include "ocrrow.h" #include "polyblob.h" //#include "lapoly.h" #include "polyaprx.h" #define EXTERN EXTERN BOOL_VAR (polygon_tess_approximation, TRUE, "Do tess poly instead of greyscale"); ELISTIZE_S (PBLOB) /********************************************************************** * position_outline * * Position the outline in the given list at the relevant place * according to its nesting. **********************************************************************/ static void position_outline( //put in place OUTLINE *outline, //thing to place OUTLINE_LIST *destlist //desstination list ) { OUTLINE *dest_outline; //outline from dest list OUTLINE_IT it = destlist; //iterator //iterator on children OUTLINE_IT child_it = outline->child (); if (!it.empty ()) { do { dest_outline = it.data (); //get destination //encloses dest if (*dest_outline < *outline) { //take off list dest_outline = it.extract (); //put this in place it.add_after_then_move (outline); //make it a child child_it.add_to_end (dest_outline); while (!it.at_last ()) { it.forward (); //do rest of list //check for other children dest_outline = it.data (); if (*dest_outline < *outline) { //take off list dest_outline = it.extract (); child_it.add_to_end (dest_outline); //make it a child if (it.empty ()) break; } } return; //finished } //enclosed by dest else if (*outline < *dest_outline) { position_outline (outline, dest_outline->child ()); //place in child list return; //finished } it.forward (); } while (!it.at_first ()); } it.add_to_end (outline); //at outer level } /********************************************************************** * plot_outline_list * * Draw a list of outlines in the given colour and their children * in the child colour. **********************************************************************/ #ifndef GRAPHICS_DISABLED static void plot_outline_list( //draw outlines OUTLINE_LIST *list, //outline to draw ScrollView* window, //window to draw in ScrollView::Color colour, //colour to use ScrollView::Color child_colour //colour of children ) { OUTLINE *outline; //current outline OUTLINE_IT it = list; //iterator for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { outline = it.data (); //draw it outline->plot (window, colour); if (!outline->child ()->empty ()) plot_outline_list (outline->child (), window, child_colour, child_colour); } } #endif /********************************************************************** * PBLOB::PBLOB * * Constructor to build a PBLOB from a list of OUTLINEs. * The OUTLINEs are not copied so the source list is emptied. * The OUTLINEs are nested correctly in the blob. **********************************************************************/ PBLOB::PBLOB( //constructor OUTLINE_LIST *outline_list //in random order ) { OUTLINE *outline; //current outline OUTLINE_IT it = outline_list; //iterator while (!it.empty ()) { //grab the list outline = it.extract (); //get off the list //put it in place position_outline(outline, &outlines); if (!it.empty ()) it.forward (); } } /********************************************************************** * approximate_outline_list * * Convert a list of outlines to polygonal form. **********************************************************************/ static void approximate_outline_list( //do list of outlines C_OUTLINE_LIST *srclist, //list to convert OUTLINE_LIST *destlist, //desstination list float xheight //height of line ) { C_OUTLINE *src_outline; //outline from src list OUTLINE *dest_outline; //result C_OUTLINE_IT src_it = srclist; //source iterator OUTLINE_IT dest_it = destlist; //iterator do { src_outline = src_it.data (); // if (polygon_tess_approximation) dest_outline = tesspoly_outline (src_outline, xheight); // else // dest_outline=greypoly_outline(src_outline,xheight); if (dest_outline != NULL) { dest_it.add_after_then_move (dest_outline); if (!src_outline->child ()->empty ()) //do child list approximate_outline_list (src_outline->child (), dest_outline->child (), xheight); } src_it.forward (); } while (!src_it.at_first ()); } /********************************************************************** * PBLOB::PBLOB * * Constructor to build a PBLOB from a C_BLOB by polygonal approximation. **********************************************************************/ PBLOB::PBLOB( //constructor C_BLOB *cblob, //compact blob float xheight //height of line ) { TBOX bbox; //bounding box if (!cblob->out_list ()->empty ()) { //get bounding box bbox = cblob->bounding_box (); if (bbox.height () > xheight) xheight = bbox.height (); //max of line and blob //copy it approximate_outline_list (cblob->out_list (), &outlines, xheight); } } /********************************************************************** * PBLOB::bounding_box * * Return the bounding box of the blob. **********************************************************************/ TBOX PBLOB::bounding_box() { //bounding box OUTLINE *outline; //current outline OUTLINE_IT it = &outlines; //outlines of blob TBOX box; //bounding box for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { outline = it.data (); box += outline->bounding_box (); } return box; } /********************************************************************** * PBLOB::area * * Return the area of the blob. **********************************************************************/ float PBLOB::area() { //area OUTLINE *outline; //current outline OUTLINE_IT it = &outlines; //outlines of blob float total; //total area total = 0.0f; for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { outline = it.data (); total += outline->area (); } return total; } /********************************************************************** * PBLOB::baseline_normalise * * Baseline normalize a blob **********************************************************************/ PBLOB *PBLOB::baseline_normalise( //normalize blob ROW *row, //row it came from DENORM *denorm //inverse mapping ) { TBOX blob_box = bounding_box (); float x_centre = (blob_box.left () + blob_box.right ()) / 2.0; PBLOB *bn_blob; //copied blob *denorm = DENORM (x_centre, bln_x_height / row->x_height (), row); bn_blob = new PBLOB; //get one *bn_blob = *this; //deep copy bn_blob->move (FCOORD (-denorm->origin (), -row->base_line (x_centre))); bn_blob->scale (denorm->scale ()); bn_blob->move (FCOORD (0.0, bln_baseline_offset)); return bn_blob; } /********************************************************************** * PBLOB::baseline_denormalise * * DeBaseline Normalise the blob properly with the given denorm. **********************************************************************/ void PBLOB::baseline_denormalise( // Tess style BL Norm const DENORM *denorm //antidote ) { float blob_x_left; // Left edge of blob. TBOX blob_box; //blob bounding box move(FCOORD (0.0f, 0.0f - bln_baseline_offset)); blob_box = bounding_box (); blob_x_left = blob_box.left (); scale (1.0 / denorm->scale_at_x (blob_x_left)); move (FCOORD (denorm->origin (), denorm->yshift_at_x (blob_x_left))); } /********************************************************************** * PBLOB::move * * Move PBLOB by vector **********************************************************************/ void PBLOB::move( // reposition blob const FCOORD vec // by vector ) { OUTLINE_IT it(&outlines); // iterator for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) it.data ()->move (vec); // move each outline } /********************************************************************** * PBLOB::scale * * Scale PBLOB by float multiplier **********************************************************************/ void PBLOB::scale( // scale blob const float f // by multiplier ) { OUTLINE_IT it(&outlines); // iterator for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) it.data ()->scale (f); // scale each outline } /********************************************************************** * PBLOB::scale * * Scale PBLOB by float multiplier **********************************************************************/ void PBLOB::scale( // scale blob const FCOORD vec // by multiplier ) { OUTLINE_IT it(&outlines); // iterator for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) it.data ()->scale (vec); // scale each outline } /********************************************************************** * PBLOB::rotate * * Rotate PBLOB 90 deg anti **********************************************************************/ void PBLOB::rotate() { // Rotate 90 deg anti OUTLINE_IT it(&outlines); // iterator for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { it.data ()->rotate (FCOORD(0.0f, 1.0f)); // rotate each outline } } /********************************************************************** * PBLOB::plot * * Draw the PBLOB in the given colour. **********************************************************************/ #ifndef GRAPHICS_DISABLED void PBLOB::plot( //draw it ScrollView* window, //window to draw in ScrollView::Color blob_colour, //main colour ScrollView::Color child_colour //for holes ) { plot_outline_list(&outlines, window, blob_colour, child_colour); } #endif