| /********************************************************************** |
| * 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 anticlockwise about the origin. |
| **********************************************************************/ |
| |
| void PBLOB::rotate() { // Rotate 90 deg anti |
| rotate(FCOORD(0.0f, 1.0f)); |
| } |
| |
| /********************************************************************** |
| * PBLOB::rotate |
| * |
| * Rotate PBLOB by the given rotation about the origin. |
| * The rotation is defined to be (cos a, sin a) where a is the anticlockwise |
| * rotation angle (in units appropriate for cos, sin). |
| * Alternatively think of multiplication by the complex number |
| * rotation = z = (x + iy), with |z| = 1. |
| **********************************************************************/ |
| void PBLOB::rotate(const FCOORD& rotation) { // Rotate by given rotation. |
| OUTLINE_IT it(&outlines); |
| |
| for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { |
| it.data()->rotate(rotation); // 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 |