tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/ccstruct/normalis.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        normalis.cpp  (Formerly denorm.c)
00003  * Description: Code for the DENORM class.
00004  * Author:      Ray Smith
00005  * Created:     Thu Apr 23 09:22:43 BST 1992
00006  *
00007  * (C) Copyright 1992, Hewlett-Packard Ltd.
00008  ** Licensed under the Apache License, Version 2.0 (the "License");
00009  ** you may not use this file except in compliance with the License.
00010  ** You may obtain a copy of the License at
00011  ** http://www.apache.org/licenses/LICENSE-2.0
00012  ** Unless required by applicable law or agreed to in writing, software
00013  ** distributed under the License is distributed on an "AS IS" BASIS,
00014  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  ** See the License for the specific language governing permissions and
00016  ** limitations under the License.
00017  *
00018  **********************************************************************/
00019 
00020 #include "normalis.h"
00021 
00022 #include <stdlib.h>
00023 
00024 #include "allheaders.h"
00025 #include "blobs.h"
00026 #include "helpers.h"
00027 #include "matrix.h"
00028 #include "ocrblock.h"
00029 #include "unicharset.h"
00030 #include "werd.h"
00031 
00032 // Tolerance in pixels used for baseline and xheight on non-upper/lower scripts.
00033 const int kSloppyTolerance = 4;
00034 // Final tolerance in pixels added to the computed xheight range.
00035 const float kFinalPixelTolerance = 0.125f;
00036 
00037 DENORM::DENORM() {
00038   Init();
00039 }
00040 
00041 DENORM::DENORM(const DENORM &src) {
00042   rotation_ = NULL;
00043   *this = src;
00044 }
00045 
00046 
00047 DENORM & DENORM::operator=(const DENORM & src) {
00048   Clear();
00049   inverse_ = src.inverse_;
00050   predecessor_ = src.predecessor_;
00051   pix_ = src.pix_;
00052   block_ = src.block_;
00053   if (src.rotation_ == NULL)
00054     rotation_ = NULL;
00055   else
00056     rotation_ = new FCOORD(*src.rotation_);
00057   x_origin_ = src.x_origin_;
00058   y_origin_ = src.y_origin_;
00059   x_scale_ = src.x_scale_;
00060   y_scale_ = src.y_scale_;
00061   final_xshift_ = src.final_xshift_;
00062   final_yshift_ = src.final_yshift_;
00063   return *this;
00064 }
00065 
00066 DENORM::~DENORM() {
00067   Clear();
00068 }
00069 
00070 // Initializes the denorm for a transformation. For details see the large
00071 // comment in normalis.h.
00072 // Arguments:
00073 // block: if not NULL, then this is the first transformation, and
00074 //        block->re_rotation() needs to be used after the Denorm
00075 //        transformation to get back to the image coords.
00076 // rotation: if not NULL, apply this rotation after translation to the
00077 //           origin and scaling. (Usually a classify rotation.)
00078 // predecessor: if not NULL, then predecessor has been applied to the
00079 //              input space and needs to be undone to complete the inverse.
00080 // The above pointers are not owned by this DENORM and are assumed to live
00081 // longer than this denorm, except rotation, which is deep copied on input.
00082 //
00083 // x_origin: The x origin which will be mapped to final_xshift in the result.
00084 // y_origin: The y origin which will be mapped to final_yshift in the result.
00085 //           Added to result of row->baseline(x) if not NULL.
00086 //
00087 // x_scale: scale factor for the x-coordinate.
00088 // y_scale: scale factor for the y-coordinate. Ignored if segs is given.
00089 // Note that these scale factors apply to the same x and y system as the
00090 // x-origin and y-origin apply, ie after any block rotation, but before
00091 // the rotation argument is applied.
00092 //
00093 // final_xshift: The x component of the final translation.
00094 // final_yshift: The y component of the final translation.
00095 void DENORM::SetupNormalization(const BLOCK* block,
00096                                 const FCOORD* rotation,
00097                                 const DENORM* predecessor,
00098                                 float x_origin, float y_origin,
00099                                 float x_scale, float y_scale,
00100                                 float final_xshift, float final_yshift) {
00101   Clear();
00102   block_ = block;
00103   if (rotation == NULL)
00104     rotation_ = NULL;
00105   else
00106     rotation_ = new FCOORD(*rotation);
00107   predecessor_ = predecessor;
00108   x_origin_ = x_origin;
00109   y_origin_ = y_origin;
00110   x_scale_ = x_scale;
00111   y_scale_ = y_scale;
00112   final_xshift_ = final_xshift;
00113   final_yshift_ = final_yshift;
00114 }
00115 
00116 // Helper for SetupNonLinear computes an image of shortest run-lengths from
00117 // the x/y edges provided.
00118 // Based on "A nonlinear normalization method for handprinted Kanji character
00119 // recognition -- line density equalization" by Hiromitsu Yamada et al.
00120 // Eg below is an O in a 1-pixel margin-ed bounding box and the corresponding
00121 //  ______________     input x_coords and y_coords.
00122 // |  _________  |     <empty>
00123 // | |    _    | |     1, 6
00124 // | |   | |   | |     1, 3, 4, 6
00125 // | |   | |   | |     1, 3, 4, 6
00126 // | |   | |   | |     1, 3, 4, 6
00127 // | |   |_|   | |     1, 3, 4, 6
00128 // | |_________| |     1, 6
00129 // |_____________|     <empty>
00130 //  E 1 1 1 1 1 E
00131 //  m 7 7 2 7 7 m
00132 //  p     6     p
00133 //  t     7     t
00134 //  y           y
00135 // The output image contains the min of the x and y run-length (distance
00136 // between edges) at each coordinate in the image thus:
00137 //  ______________
00138 // |7 1_1_1_1_1 7|
00139 // |1|5 5 1 5 5|1|
00140 // |1|2 2|1|2 2|1|
00141 // |1|2 2|1|2 2|1|
00142 // |1|2 2|1|2 2|1|
00143 // |1|2 2|1|2 2|1|
00144 // |1|5_5_1_5_5|1|
00145 // |7_1_1_1_1_1_7|
00146 // Note that the input coords are all integer, so all partial pixels are dealt
00147 // with elsewhere. Although it is nice for outlines to be properly connected
00148 // and continuous, there is no requirement that they be as such, so they could
00149 // have been derived from a flaky source, such as greyscale.
00150 // This function works only within the provided box, and it is assumed that the
00151 // input x_coords and y_coords have already been translated to have the bottom-
00152 // left of box as the origin. Although an output, the minruns should have been
00153 // pre-initialized to be the same size as box. Each element will contain the
00154 // minimum of x and y run-length as shown above.
00155 static void ComputeRunlengthImage(
00156     const TBOX& box,
00157     const GenericVector<GenericVector<int> >& x_coords,
00158     const GenericVector<GenericVector<int> >& y_coords,
00159     GENERIC_2D_ARRAY<int>* minruns) {
00160   int width = box.width();
00161   int height = box.height();
00162   ASSERT_HOST(minruns->dim1() == width);
00163   ASSERT_HOST(minruns->dim2() == height);
00164   // Set a 2-d image array to the run lengths at each pixel.
00165   for (int ix = 0; ix < width; ++ix) {
00166     int y = 0;
00167     for (int i = 0; i < y_coords[ix].size(); ++i) {
00168       int y_edge = ClipToRange(y_coords[ix][i], 0, height);
00169       int gap = y_edge - y;
00170       // Every pixel between the last and current edge get set to the gap.
00171       while (y < y_edge) {
00172         (*minruns)(ix, y) = gap;
00173         ++y;
00174       }
00175     }
00176     // Pretend there is a bounding box of edges all around the image.
00177     int gap = height - y;
00178     while (y < height) {
00179       (*minruns)(ix, y) = gap;
00180       ++y;
00181     }
00182   }
00183   // Now set the image pixels the the MIN of the x and y runlengths.
00184   for (int iy = 0; iy < height; ++iy) {
00185     int x = 0;
00186     for (int i = 0; i < x_coords[iy].size(); ++i) {
00187       int x_edge = ClipToRange(x_coords[iy][i], 0, width);
00188       int gap = x_edge - x;
00189       while (x < x_edge) {
00190         if (gap < (*minruns)(x, iy))
00191           (*minruns)(x, iy) = gap;
00192         ++x;
00193       }
00194     }
00195     int gap = width - x;
00196     while (x < width) {
00197       if (gap < (*minruns)(x, iy))
00198         (*minruns)(x, iy) = gap;
00199       ++x;
00200     }
00201   }
00202 }
00203 // Converts the run-length image (see above to the edge density profiles used
00204 // for scaling, thus:
00205 //  ______________
00206 // |7 1_1_1_1_1 7|  = 5.28
00207 // |1|5 5 1 5 5|1|  = 3.8
00208 // |1|2 2|1|2 2|1|  = 5
00209 // |1|2 2|1|2 2|1|  = 5
00210 // |1|2 2|1|2 2|1|  = 5
00211 // |1|2 2|1|2 2|1|  = 5
00212 // |1|5_5_1_5_5|1|  = 3.8
00213 // |7_1_1_1_1_1_7|  = 5.28
00214 //  6 4 4 8 4 4 6
00215 //  . . . . . . .
00216 //  2 4 4 0 4 4 2
00217 //  8           8
00218 // Each profile is the sum of the reciprocals of the pixels in the image in
00219 // the appropriate row or column, and these are then normalized to sum to 1.
00220 // On output hx, hy contain an extra element, which will eventually be used
00221 // to guarantee that the top/right edge of the box (and anything beyond) always
00222 // gets mapped to the maximum target coordinate.
00223 static void ComputeEdgeDensityProfiles(const TBOX& box,
00224                                        const GENERIC_2D_ARRAY<int>& minruns,
00225                                        GenericVector<float>* hx,
00226                                        GenericVector<float>* hy) {
00227   int width = box.width();
00228   int height = box.height();
00229   hx->init_to_size(width + 1, 0.0);
00230   hy->init_to_size(height + 1, 0.0);
00231   double total = 0.0;
00232   for (int iy = 0; iy < height; ++iy) {
00233     for (int ix = 0; ix < width; ++ix) {
00234       int run = minruns(ix, iy);
00235       if (run == 0) run = 1;
00236       float density = 1.0f / run;
00237       (*hx)[ix] += density;
00238       (*hy)[iy] += density;
00239     }
00240     total += (*hy)[iy];
00241   }
00242   // Normalize each profile to sum to 1.
00243   if (total > 0.0) {
00244     for (int ix = 0; ix < width; ++ix) {
00245       (*hx)[ix] /= total;
00246     }
00247     for (int iy = 0; iy < height; ++iy) {
00248       (*hy)[iy] /= total;
00249     }
00250   }
00251   // There is an extra element in each array, so initialize to 1.
00252   (*hx)[width] = 1.0f;
00253   (*hy)[height] = 1.0f;
00254 }
00255 
00256 // Sets up the DENORM to execute a non-linear transformation based on
00257 // preserving an even distribution of stroke edges. The transformation
00258 // operates only within the given box.
00259 // x_coords is a collection of the x-coords of vertical edges for each
00260 // y-coord starting at box.bottom().
00261 // y_coords is a collection of the y-coords of horizontal edges for each
00262 // x-coord starting at box.left().
00263 // Eg x_coords[0] is a collection of the x-coords of edges at y=bottom.
00264 // Eg x_coords[1] is a collection of the x-coords of edges at y=bottom + 1.
00265 // The second-level vectors must all be sorted in ascending order.
00266 // See comments on the helper functions above for more details.
00267 void DENORM::SetupNonLinear(
00268     const DENORM* predecessor, const TBOX& box, float target_width,
00269     float target_height, float final_xshift, float final_yshift,
00270     const GenericVector<GenericVector<int> >& x_coords,
00271     const GenericVector<GenericVector<int> >& y_coords) {
00272   Clear();
00273   predecessor_ = predecessor;
00274   // x_map_ and y_map_ store a mapping from input x and y coordinate to output
00275   // x and y coordinate, based on scaling to the supplied target_width and
00276   // target_height.
00277   x_map_ = new GenericVector<float>;
00278   y_map_ = new GenericVector<float>;
00279   // Set a 2-d image array to the run lengths at each pixel.
00280   int width = box.width();
00281   int height = box.height();
00282   GENERIC_2D_ARRAY<int> minruns(width, height, 0);
00283   ComputeRunlengthImage(box, x_coords, y_coords, &minruns);
00284   // Edge density is the sum of the inverses of the run lengths. Compute
00285   // edge density projection profiles.
00286   ComputeEdgeDensityProfiles(box, minruns, x_map_, y_map_);
00287   // Convert the edge density profiles to the coordinates by multiplying by
00288   // the desired size and accumulating.
00289   (*x_map_)[width] = target_width;
00290   for (int x = width - 1; x >= 0; --x) {
00291     (*x_map_)[x] = (*x_map_)[x + 1] - (*x_map_)[x] * target_width;
00292   }
00293   (*y_map_)[height] = target_height;
00294   for (int y = height - 1; y >= 0; --y) {
00295     (*y_map_)[y] = (*y_map_)[y + 1] - (*y_map_)[y] * target_height;
00296   }
00297   x_origin_ = box.left();
00298   y_origin_ = box.bottom();
00299   final_xshift_ = final_xshift;
00300   final_yshift_ = final_yshift;
00301 }
00302 
00303 // Transforms the given coords one step forward to normalized space, without
00304 // using any block rotation or predecessor.
00305 void DENORM::LocalNormTransform(const TPOINT& pt, TPOINT* transformed) const {
00306   FCOORD src_pt(pt.x, pt.y);
00307   FCOORD float_result;
00308   LocalNormTransform(src_pt, &float_result);
00309   transformed->x = IntCastRounded(float_result.x());
00310   transformed->y = IntCastRounded(float_result.y());
00311 }
00312 void DENORM::LocalNormTransform(const FCOORD& pt, FCOORD* transformed) const {
00313   FCOORD translated(pt.x() - x_origin_, pt.y() - y_origin_);
00314   if (x_map_ != NULL && y_map_ != NULL) {
00315     int x = ClipToRange(IntCastRounded(translated.x()), 0, x_map_->size()-1);
00316     translated.set_x((*x_map_)[x]);
00317     int y = ClipToRange(IntCastRounded(translated.y()), 0, y_map_->size()-1);
00318     translated.set_y((*y_map_)[y]);
00319   } else {
00320     translated.set_x(translated.x() * x_scale_);
00321     translated.set_y(translated.y() * y_scale_);
00322     if (rotation_ != NULL)
00323       translated.rotate(*rotation_);
00324   }
00325   transformed->set_x(translated.x() + final_xshift_);
00326   transformed->set_y(translated.y() + final_yshift_);
00327 }
00328 
00329 // Transforms the given coords forward to normalized space using the
00330 // full transformation sequence defined by the block rotation, the
00331 // predecessors, deepest first, and finally this. If first_norm is not NULL,
00332 // then the first and deepest transformation used is first_norm, ending
00333 // with this, and the block rotation will not be applied.
00334 void DENORM::NormTransform(const DENORM* first_norm, const TPOINT& pt,
00335                            TPOINT* transformed) const {
00336   FCOORD src_pt(pt.x, pt.y);
00337   FCOORD float_result;
00338   NormTransform(first_norm, src_pt, &float_result);
00339   transformed->x = IntCastRounded(float_result.x());
00340   transformed->y = IntCastRounded(float_result.y());
00341 }
00342 void DENORM::NormTransform(const DENORM* first_norm, const FCOORD& pt,
00343                            FCOORD* transformed) const {
00344   FCOORD src_pt(pt);
00345   if (first_norm != this) {
00346     if (predecessor_ != NULL) {
00347       predecessor_->NormTransform(first_norm, pt, &src_pt);
00348     } else if (block_ != NULL) {
00349       FCOORD fwd_rotation(block_->re_rotation().x(),
00350                           -block_->re_rotation().y());
00351       src_pt.rotate(fwd_rotation);
00352     }
00353   }
00354   LocalNormTransform(src_pt, transformed);
00355 }
00356 
00357 // Transforms the given coords one step back to source space, without
00358 // using to any block rotation or predecessor.
00359 void DENORM::LocalDenormTransform(const TPOINT& pt, TPOINT* original) const {
00360   FCOORD src_pt(pt.x, pt.y);
00361   FCOORD float_result;
00362   LocalDenormTransform(src_pt, &float_result);
00363   original->x = IntCastRounded(float_result.x());
00364   original->y = IntCastRounded(float_result.y());
00365 }
00366 void DENORM::LocalDenormTransform(const FCOORD& pt, FCOORD* original) const {
00367   FCOORD rotated(pt.x() - final_xshift_, pt.y() - final_yshift_);
00368   if (x_map_ != NULL && y_map_ != NULL) {
00369     int x = x_map_->binary_search(rotated.x());
00370     original->set_x(x + x_origin_);
00371     int y = y_map_->binary_search(rotated.y());
00372     original->set_y(y + y_origin_);
00373   } else {
00374     if (rotation_ != NULL) {
00375       FCOORD inverse_rotation(rotation_->x(), -rotation_->y());
00376       rotated.rotate(inverse_rotation);
00377     }
00378     original->set_x(rotated.x() / x_scale_ + x_origin_);
00379     float y_scale = y_scale_;
00380     original->set_y(rotated.y() / y_scale + y_origin_);
00381   }
00382 }
00383 
00384 // Transforms the given coords all the way back to source image space using
00385 // the full transformation sequence defined by this and its predecesors
00386 // recursively, shallowest first, and finally any block re_rotation.
00387 // If last_denorm is not NULL, then the last transformation used will
00388 // be last_denorm, and the block re_rotation will never be executed.
00389 void DENORM::DenormTransform(const DENORM* last_denorm, const TPOINT& pt,
00390                              TPOINT* original) const {
00391   FCOORD src_pt(pt.x, pt.y);
00392   FCOORD float_result;
00393   DenormTransform(last_denorm, src_pt, &float_result);
00394   original->x = IntCastRounded(float_result.x());
00395   original->y = IntCastRounded(float_result.y());
00396 }
00397 void DENORM::DenormTransform(const DENORM* last_denorm, const FCOORD& pt,
00398                              FCOORD* original) const {
00399   LocalDenormTransform(pt, original);
00400   if (last_denorm != this) {
00401     if (predecessor_ != NULL) {
00402       predecessor_->DenormTransform(last_denorm, *original, original);
00403     } else if (block_ != NULL) {
00404       original->rotate(block_->re_rotation());
00405     }
00406   }
00407 }
00408 
00409 // Normalize a blob using blob transformations. Less accurate, but
00410 // more accurately copies the old way.
00411 void DENORM::LocalNormBlob(TBLOB* blob) const {
00412   TBOX blob_box = blob->bounding_box();
00413   ICOORD translation(-IntCastRounded(x_origin_), -IntCastRounded(y_origin_));
00414   blob->Move(translation);
00415   if (y_scale_ != 1.0f)
00416     blob->Scale(y_scale_);
00417   if (rotation_ != NULL)
00418     blob->Rotate(*rotation_);
00419   translation.set_x(IntCastRounded(final_xshift_));
00420   translation.set_y(IntCastRounded(final_yshift_));
00421   blob->Move(translation);
00422 }
00423 
00424 // Fills in the x-height range accepted by the given unichar_id, given its
00425 // bounding box in the usual baseline-normalized coordinates, with some
00426 // initial crude x-height estimate (such as word size) and this denoting the
00427 // transformation that was used.
00428 void DENORM::XHeightRange(int unichar_id, const UNICHARSET& unicharset,
00429                           const TBOX& bbox,
00430                           float* min_xht, float* max_xht, float* yshift) const {
00431   // Default return -- accept anything.
00432   *yshift = 0.0f;
00433   *min_xht = 0.0f;
00434   *max_xht = MAX_FLOAT32;
00435 
00436   if (!unicharset.top_bottom_useful())
00437     return;
00438 
00439   // Clip the top and bottom to the limit of normalized feature space.
00440   int top = ClipToRange<int>(bbox.top(), 0, kBlnCellHeight - 1);
00441   int bottom = ClipToRange<int>(bbox.bottom(), 0, kBlnCellHeight - 1);
00442   // A tolerance of yscale corresponds to 1 pixel in the image.
00443   double tolerance = y_scale();
00444   // If the script doesn't have upper and lower-case characters, widen the
00445   // tolerance to allow sloppy baseline/x-height estimates.
00446   if (!unicharset.script_has_upper_lower())
00447     tolerance = y_scale() * kSloppyTolerance;
00448 
00449   int min_bottom, max_bottom, min_top, max_top;
00450   unicharset.get_top_bottom(unichar_id, &min_bottom, &max_bottom,
00451                             &min_top, &max_top);
00452 
00453   // Calculate the scale factor we'll use to get to image y-pixels
00454   double midx = (bbox.left() + bbox.right()) / 2;
00455   double ydiff = (bbox.top() - bbox.bottom()) + 2;
00456   FCOORD mid_bot(midx, bbox.bottom()), tmid_bot;
00457   FCOORD mid_high(midx, bbox.bottom() + ydiff), tmid_high;
00458   DenormTransform(NULL, mid_bot, &tmid_bot);
00459   DenormTransform(NULL, mid_high, &tmid_high);
00460 
00461   // bln_y_measure * yscale = image_y_measure
00462   double yscale = tmid_high.pt_to_pt_dist(tmid_bot) / ydiff;
00463 
00464   // Calculate y-shift
00465   int bln_yshift = 0, bottom_shift = 0, top_shift = 0;
00466   if (bottom < min_bottom - tolerance) {
00467     bottom_shift = bottom - min_bottom;
00468   } else if (bottom > max_bottom + tolerance) {
00469     bottom_shift = bottom - max_bottom;
00470   }
00471   if (top < min_top - tolerance) {
00472     top_shift = top - min_top;
00473   } else if (top > max_top + tolerance) {
00474     top_shift = top - max_top;
00475   }
00476   if ((top_shift >= 0 && bottom_shift > 0) ||
00477       (top_shift < 0 && bottom_shift < 0)) {
00478     bln_yshift = (top_shift + bottom_shift) / 2;
00479   }
00480   *yshift = bln_yshift * yscale;
00481 
00482   // To help very high cap/xheight ratio fonts accept the correct x-height,
00483   // and to allow the large caps in small caps to accept the xheight of the
00484   // small caps, add kBlnBaselineOffset to chars with a maximum max, and have
00485   // a top already at a significantly high position.
00486   if (max_top == kBlnCellHeight - 1 &&
00487       top > kBlnCellHeight - kBlnBaselineOffset / 2)
00488     max_top += kBlnBaselineOffset;
00489   top -= bln_yshift;
00490   int height = top - kBlnBaselineOffset - bottom_shift;
00491   double min_height = min_top - kBlnBaselineOffset - tolerance;
00492   double max_height = max_top - kBlnBaselineOffset + tolerance;
00493 
00494   // We shouldn't try calculations if the characters are very short (for example
00495   // for punctuation).
00496   if (min_height > kBlnXHeight / 8 && height > 0) {
00497     float result = height * kBlnXHeight * yscale / min_height;
00498     *max_xht = result + kFinalPixelTolerance;
00499     result = height * kBlnXHeight * yscale / max_height;
00500     *min_xht = result - kFinalPixelTolerance;
00501   }
00502 }
00503 
00504 // Prints the content of the DENORM for debug purposes.
00505 void DENORM::Print() const {
00506   if (pix_ != NULL) {
00507     tprintf("Pix dimensions %d x %d x %d\n",
00508             pixGetWidth(pix_), pixGetHeight(pix_), pixGetDepth(pix_));
00509   }
00510   if (inverse_)
00511     tprintf("Inverse\n");
00512   if (block_ && block_->re_rotation().x() != 1.0f) {
00513     tprintf("Block rotation %g, %g\n",
00514             block_->re_rotation().x(), block_->re_rotation().y());
00515   }
00516   tprintf("Input Origin = (%g, %g)\n", x_origin_, y_origin_);
00517   if (x_map_ != NULL && y_map_ != NULL) {
00518     tprintf("x map:\n");
00519     for (int x = 0; x < x_map_->size(); ++x) {
00520       tprintf("%g ", (*x_map_)[x]);
00521     }
00522     tprintf("\ny map:\n");
00523     for (int y = 0; y < y_map_->size(); ++y) {
00524       tprintf("%g ", (*y_map_)[y]);
00525     }
00526     tprintf("\n");
00527   } else {
00528     tprintf("Scale = (%g, %g)\n", x_scale_, y_scale_);
00529     if (rotation_ != NULL)
00530       tprintf("Rotation = (%g, %g)\n", rotation_->x(), rotation_->y());
00531   }
00532   tprintf("Final Origin = (%g, %g)\n", final_xshift_, final_xshift_);
00533   if (predecessor_ != NULL) {
00534     tprintf("Predecessor:\n");
00535     predecessor_->Print();
00536   }
00537 }
00538 
00539 
00540 // ============== Private Code ======================
00541 
00542 // Free allocated memory and clear pointers.
00543 void DENORM::Clear() {
00544   if (x_map_ != NULL) {
00545     delete x_map_;
00546     x_map_ = NULL;
00547   }
00548   if (y_map_ != NULL) {
00549     delete y_map_;
00550     y_map_ = NULL;
00551   }
00552   if (rotation_ != NULL) {
00553     delete rotation_;
00554     rotation_ = NULL;
00555   }
00556 }
00557 
00558 // Setup default values.
00559 void DENORM::Init() {
00560   inverse_ = false;
00561   pix_ = NULL;
00562   block_ = NULL;
00563   rotation_ = NULL;
00564   predecessor_ = NULL;
00565   x_map_ = NULL;
00566   y_map_ = NULL;
00567   x_origin_ = 0.0f;
00568   y_origin_ = 0.0f;
00569   x_scale_ = 1.0f;
00570   y_scale_ = 1.0f;
00571   final_xshift_ = 0.0f;
00572   final_yshift_ = static_cast<float>(kBlnBaselineOffset);
00573 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines