Tesseract  3.02
tesseract-ocr/ccstruct/coutln.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        coutln.c  (Formerly coutline.c)
00003  * Description: Code for the C_OUTLINE class.
00004  * Author:                  Ray Smith
00005  * Created:                 Mon Oct 07 16:01:57 BST 1991
00006  *
00007  * (C) Copyright 1991, 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 "mfcpch.h"
00021 #include <string.h>
00022 #ifdef __UNIX__
00023 #include <assert.h>
00024 #endif
00025 #include "coutln.h"
00026 #include "allheaders.h"
00027 
00028 // Include automatically generated configuration file if running autoconf.
00029 #ifdef HAVE_CONFIG_H
00030 #include "config_auto.h"
00031 #endif
00032 
00033 ELISTIZE (C_OUTLINE)
00034 ICOORD C_OUTLINE::step_coords[4] = {
00035   ICOORD (-1, 0), ICOORD (0, -1), ICOORD (1, 0), ICOORD (0, 1)
00036 };
00037 
00038 /**********************************************************************
00039  * C_OUTLINE::C_OUTLINE
00040  *
00041  * Constructor to build a C_OUTLINE from a CRACKEDGE LOOP.
00042  **********************************************************************/
00043 
00044 C_OUTLINE::C_OUTLINE (
00045 //constructor
00046 CRACKEDGE * startpt,             //outline to convert
00047 ICOORD bot_left,                 //bounding box
00048 ICOORD top_right, inT16 length   //length of loop
00049 ):box (bot_left, top_right), start (startpt->pos) {
00050   inT16 stepindex;               //index to step
00051   CRACKEDGE *edgept;             //current point
00052 
00053   stepcount = length;            //no of steps
00054   if (length == 0) {
00055     steps = NULL;
00056     return;
00057   }
00058                                  //get memory
00059   steps = (uinT8 *) alloc_mem (step_mem());
00060   memset(steps, 0, step_mem());
00061   edgept = startpt;
00062 
00063   for (stepindex = 0; stepindex < length; stepindex++) {
00064                                  //set compact step
00065     set_step (stepindex, edgept->stepdir);
00066     edgept = edgept->next;
00067   }
00068 }
00069 
00070 
00071 /**********************************************************************
00072  * C_OUTLINE::C_OUTLINE
00073  *
00074  * Constructor to build a C_OUTLINE from a C_OUTLINE_FRAG.
00075  **********************************************************************/
00076 C_OUTLINE::C_OUTLINE (
00077 //constructor
00078                                  //steps to copy
00079 ICOORD startpt, DIR128 * new_steps,
00080 inT16 length                     //length of loop
00081 ):start (startpt) {
00082   inT8 dirdiff;                  //direction difference
00083   DIR128 prevdir;                //previous direction
00084   DIR128 dir;                    //current direction
00085   DIR128 lastdir;                //dir of last step
00086   TBOX new_box;                   //easy bounding
00087   inT16 stepindex;               //index to step
00088   inT16 srcindex;                //source steps
00089   ICOORD pos;                    //current position
00090 
00091   pos = startpt;
00092   stepcount = length;            //no of steps
00093                                  //get memory
00094   steps = (uinT8 *) alloc_mem (step_mem());
00095   memset(steps, 0, step_mem());
00096 
00097   lastdir = new_steps[length - 1];
00098   prevdir = lastdir;
00099   for (stepindex = 0, srcindex = 0; srcindex < length;
00100   stepindex++, srcindex++) {
00101     new_box = TBOX (pos, pos);
00102     box += new_box;
00103                                  //copy steps
00104     dir = new_steps[srcindex];
00105     set_step(stepindex, dir);
00106     dirdiff = dir - prevdir;
00107     pos += step (stepindex);
00108     if ((dirdiff == 64 || dirdiff == -64) && stepindex > 0) {
00109       stepindex -= 2;            //cancel there-and-back
00110       prevdir = stepindex >= 0 ? step_dir (stepindex) : lastdir;
00111     }
00112     else
00113       prevdir = dir;
00114   }
00115   ASSERT_HOST (pos.x () == startpt.x () && pos.y () == startpt.y ());
00116   do {
00117     dirdiff = step_dir (stepindex - 1) - step_dir (0);
00118     if (dirdiff == 64 || dirdiff == -64) {
00119       start += step (0);
00120       stepindex -= 2;            //cancel there-and-back
00121       for (int i = 0; i < stepindex; ++i)
00122         set_step(i, step_dir(i + 1));
00123     }
00124   }
00125   while (stepindex > 1 && (dirdiff == 64 || dirdiff == -64));
00126   stepcount = stepindex;
00127   ASSERT_HOST (stepcount >= 4);
00128 }
00129 
00130 /**********************************************************************
00131  * C_OUTLINE::C_OUTLINE
00132  *
00133  * Constructor to build a C_OUTLINE from a rotation of a C_OUTLINE.
00134  **********************************************************************/
00135 
00136 C_OUTLINE::C_OUTLINE(                     //constructor
00137                      C_OUTLINE *srcline,  //outline to
00138                      FCOORD rotation      //rotate
00139                     ) {
00140   TBOX new_box;                   //easy bounding
00141   inT16 stepindex;               //index to step
00142   inT16 dirdiff;                 //direction change
00143   ICOORD pos;                    //current position
00144   ICOORD prevpos;                //previous dest point
00145 
00146   ICOORD destpos;                //destination point
00147   inT16 destindex;               //index to step
00148   DIR128 dir;                    //coded direction
00149   uinT8 new_step;
00150 
00151   stepcount = srcline->stepcount * 2;
00152   if (stepcount == 0) {
00153     steps = NULL;
00154     box = srcline->box;
00155     box.rotate(rotation);
00156     return;
00157   }
00158                                  //get memory
00159   steps = (uinT8 *) alloc_mem (step_mem());
00160   memset(steps, 0, step_mem());
00161 
00162   for (int iteration = 0; iteration < 2; ++iteration) {
00163     DIR128 round1 = iteration == 0 ? 32 : 0;
00164     DIR128 round2 = iteration != 0 ? 32 : 0;
00165     pos = srcline->start;
00166     prevpos = pos;
00167     prevpos.rotate (rotation);
00168     start = prevpos;
00169     box = TBOX (start, start);
00170     destindex = 0;
00171     for (stepindex = 0; stepindex < srcline->stepcount; stepindex++) {
00172       pos += srcline->step (stepindex);
00173       destpos = pos;
00174       destpos.rotate (rotation);
00175       //  printf("%i %i %i %i ", destpos.x(), destpos.y(), pos.x(), pos.y());
00176       while (destpos.x () != prevpos.x () || destpos.y () != prevpos.y ()) {
00177         dir = DIR128 (FCOORD (destpos - prevpos));
00178         dir += 64;                 //turn to step style
00179         new_step = dir.get_dir ();
00180         //  printf(" %i\n", new_step);
00181         if (new_step & 31) {
00182           set_step(destindex++, dir + round1);
00183           prevpos += step(destindex - 1);
00184           if (destindex < 2
00185             || ((dirdiff =
00186             step_dir (destindex - 1) - step_dir (destindex - 2)) !=
00187             -64 && dirdiff != 64)) {
00188             set_step(destindex++, dir + round2);
00189             prevpos += step(destindex - 1);
00190           } else {
00191             prevpos -= step(destindex - 1);
00192             destindex--;
00193             prevpos -= step(destindex - 1);
00194             set_step(destindex - 1, dir + round2);
00195             prevpos += step(destindex - 1);
00196           }
00197         }
00198         else {
00199           set_step(destindex++, dir);
00200           prevpos += step(destindex - 1);
00201         }
00202         while (destindex >= 2 &&
00203                ((dirdiff =
00204                  step_dir (destindex - 1) - step_dir (destindex - 2)) == -64 ||
00205                 dirdiff == 64)) {
00206           prevpos -= step(destindex - 1);
00207           prevpos -= step(destindex - 2);
00208           destindex -= 2;        // Forget u turn
00209         }
00210         //ASSERT_HOST(prevpos.x() == destpos.x() && prevpos.y() == destpos.y());
00211         new_box = TBOX (destpos, destpos);
00212         box += new_box;
00213       }
00214     }
00215     ASSERT_HOST (destpos.x () == start.x () && destpos.y () == start.y ());
00216     dirdiff = step_dir (destindex - 1) - step_dir (0);
00217     while ((dirdiff == 64 || dirdiff == -64) && destindex > 1) {
00218       start += step (0);
00219       destindex -= 2;
00220       for (int i = 0; i < destindex; ++i)
00221         set_step(i, step_dir(i + 1));
00222       dirdiff = step_dir (destindex - 1) - step_dir (0);
00223     }
00224     if (destindex >= 4)
00225       break;
00226   }
00227   ASSERT_HOST(destindex <= stepcount);
00228   stepcount = destindex;
00229   destpos = start;
00230   for (stepindex = 0; stepindex < stepcount; stepindex++) {
00231     destpos += step (stepindex);
00232   }
00233   ASSERT_HOST (destpos.x () == start.x () && destpos.y () == start.y ());
00234 }
00235 
00236 // Build a fake outline, given just a bounding box and append to the list.
00237 void C_OUTLINE::FakeOutline(const TBOX& box, C_OUTLINE_LIST* outlines) {
00238   C_OUTLINE_IT ol_it(outlines);
00239   // Make a C_OUTLINE from the bounds. This is a bit of a hack,
00240   // as there is no outline, just a bounding box, but it works nicely.
00241   CRACKEDGE start;
00242   start.pos = box.topleft();
00243   C_OUTLINE* outline = new C_OUTLINE(&start, box.topleft(), box.botright(), 0);
00244   ol_it.add_to_end(outline);
00245 }
00246 
00247 /**********************************************************************
00248  * C_OUTLINE::area
00249  *
00250  * Compute the area of the outline.
00251  **********************************************************************/
00252 
00253 inT32 C_OUTLINE::area() {  //winding number
00254   int stepindex;                 //current step
00255   inT32 total_steps;             //steps to do
00256   inT32 total;                   //total area
00257   ICOORD pos;                    //position of point
00258   ICOORD next_step;              //step to next pix
00259   C_OUTLINE_IT it = child ();
00260 
00261   pos = start_pos ();
00262   total_steps = pathlength ();
00263   total = 0;
00264   for (stepindex = 0; stepindex < total_steps; stepindex++) {
00265                                  //all intersected
00266     next_step = step (stepindex);
00267     if (next_step.x () < 0)
00268       total += pos.y ();
00269     else if (next_step.x () > 0)
00270       total -= pos.y ();
00271     pos += next_step;
00272   }
00273   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
00274     total += it.data ()->area ();//add areas of children
00275 
00276   return total;
00277 }
00278 
00279 /**********************************************************************
00280  * C_OUTLINE::perimeter
00281  *
00282  * Compute the perimeter of the outline and its first level children.
00283  **********************************************************************/
00284 
00285 inT32 C_OUTLINE::perimeter() {
00286   inT32 total_steps;             // Return value.
00287   C_OUTLINE_IT it = child();
00288 
00289   total_steps = pathlength();
00290   for (it.mark_cycle_pt(); !it.cycled_list(); it.forward())
00291     total_steps += it.data()->pathlength();  // Add perimeters of children.
00292 
00293   return total_steps;
00294 }
00295 
00296 
00297 /**********************************************************************
00298  * C_OUTLINE::outer_area
00299  *
00300  * Compute the area of the outline.
00301  **********************************************************************/
00302 
00303 inT32 C_OUTLINE::outer_area() {  //winding number
00304   int stepindex;                 //current step
00305   inT32 total_steps;             //steps to do
00306   inT32 total;                   //total area
00307   ICOORD pos;                    //position of point
00308   ICOORD next_step;              //step to next pix
00309 
00310   pos = start_pos ();
00311   total_steps = pathlength ();
00312   if (total_steps == 0)
00313     return box.area();
00314   total = 0;
00315   for (stepindex = 0; stepindex < total_steps; stepindex++) {
00316                                  //all intersected
00317     next_step = step (stepindex);
00318     if (next_step.x () < 0)
00319       total += pos.y ();
00320     else if (next_step.x () > 0)
00321       total -= pos.y ();
00322     pos += next_step;
00323   }
00324 
00325   return total;
00326 }
00327 
00328 
00329 /**********************************************************************
00330  * C_OUTLINE::count_transitions
00331  *
00332  * Compute the number of x and y maxes and mins in the outline.
00333  **********************************************************************/
00334 
00335 inT32 C_OUTLINE::count_transitions(                 //winding number
00336                                    inT32 threshold  //on size
00337                                   ) {
00338   BOOL8 first_was_max_x;         //what was first
00339   BOOL8 first_was_max_y;
00340   BOOL8 looking_for_max_x;       //what is next
00341   BOOL8 looking_for_min_x;
00342   BOOL8 looking_for_max_y;       //what is next
00343   BOOL8 looking_for_min_y;
00344   int stepindex;                 //current step
00345   inT32 total_steps;             //steps to do
00346                                  //current limits
00347   inT32 max_x, min_x, max_y, min_y;
00348   inT32 initial_x, initial_y;    //initial limits
00349   inT32 total;                   //total changes
00350   ICOORD pos;                    //position of point
00351   ICOORD next_step;              //step to next pix
00352 
00353   pos = start_pos ();
00354   total_steps = pathlength ();
00355   total = 0;
00356   max_x = min_x = pos.x ();
00357   max_y = min_y = pos.y ();
00358   looking_for_max_x = TRUE;
00359   looking_for_min_x = TRUE;
00360   looking_for_max_y = TRUE;
00361   looking_for_min_y = TRUE;
00362   first_was_max_x = FALSE;
00363   first_was_max_y = FALSE;
00364   initial_x = pos.x ();
00365   initial_y = pos.y ();          //stop uninit warning
00366   for (stepindex = 0; stepindex < total_steps; stepindex++) {
00367                                  //all intersected
00368     next_step = step (stepindex);
00369     pos += next_step;
00370     if (next_step.x () < 0) {
00371       if (looking_for_max_x && pos.x () < min_x)
00372         min_x = pos.x ();
00373       if (looking_for_min_x && max_x - pos.x () > threshold) {
00374         if (looking_for_max_x) {
00375           initial_x = max_x;
00376           first_was_max_x = FALSE;
00377         }
00378         total++;
00379         looking_for_max_x = TRUE;
00380         looking_for_min_x = FALSE;
00381         min_x = pos.x ();        //reset min
00382       }
00383     }
00384     else if (next_step.x () > 0) {
00385       if (looking_for_min_x && pos.x () > max_x)
00386         max_x = pos.x ();
00387       if (looking_for_max_x && pos.x () - min_x > threshold) {
00388         if (looking_for_min_x) {
00389           initial_x = min_x;     //remember first min
00390           first_was_max_x = TRUE;
00391         }
00392         total++;
00393         looking_for_max_x = FALSE;
00394         looking_for_min_x = TRUE;
00395         max_x = pos.x ();
00396       }
00397     }
00398     else if (next_step.y () < 0) {
00399       if (looking_for_max_y && pos.y () < min_y)
00400         min_y = pos.y ();
00401       if (looking_for_min_y && max_y - pos.y () > threshold) {
00402         if (looking_for_max_y) {
00403           initial_y = max_y;     //remember first max
00404           first_was_max_y = FALSE;
00405         }
00406         total++;
00407         looking_for_max_y = TRUE;
00408         looking_for_min_y = FALSE;
00409         min_y = pos.y ();        //reset min
00410       }
00411     }
00412     else {
00413       if (looking_for_min_y && pos.y () > max_y)
00414         max_y = pos.y ();
00415       if (looking_for_max_y && pos.y () - min_y > threshold) {
00416         if (looking_for_min_y) {
00417           initial_y = min_y;     //remember first min
00418           first_was_max_y = TRUE;
00419         }
00420         total++;
00421         looking_for_max_y = FALSE;
00422         looking_for_min_y = TRUE;
00423         max_y = pos.y ();
00424       }
00425     }
00426 
00427   }
00428   if (first_was_max_x && looking_for_min_x) {
00429     if (max_x - initial_x > threshold)
00430       total++;
00431     else
00432       total--;
00433   }
00434   else if (!first_was_max_x && looking_for_max_x) {
00435     if (initial_x - min_x > threshold)
00436       total++;
00437     else
00438       total--;
00439   }
00440   if (first_was_max_y && looking_for_min_y) {
00441     if (max_y - initial_y > threshold)
00442       total++;
00443     else
00444       total--;
00445   }
00446   else if (!first_was_max_y && looking_for_max_y) {
00447     if (initial_y - min_y > threshold)
00448       total++;
00449     else
00450       total--;
00451   }
00452 
00453   return total;
00454 }
00455 
00456 
00457 /**********************************************************************
00458  * C_OUTLINE::operator<
00459  *
00460  * Return TRUE if the left operand is inside the right one.
00461  **********************************************************************/
00462 
00463 BOOL8
00464 C_OUTLINE::operator< (           //winding number
00465 const C_OUTLINE & other          //other outline
00466 ) const
00467 {
00468   inT16 count = 0;               //winding count
00469   ICOORD pos;                    //position of point
00470   inT32 stepindex;               //index to cstep
00471 
00472   if (!box.overlap (other.box))
00473     return FALSE;                //can't be contained
00474   if (stepcount == 0)
00475     return other.box.contains(this->box);
00476 
00477   pos = start;
00478   for (stepindex = 0; stepindex < stepcount
00479     && (count = other.winding_number (pos)) == INTERSECTING; stepindex++)
00480     pos += step (stepindex);     //try all points
00481   if (count == INTERSECTING) {
00482                                  //all intersected
00483     pos = other.start;
00484     for (stepindex = 0; stepindex < other.stepcount
00485       && (count = winding_number (pos)) == INTERSECTING; stepindex++)
00486                                  //try other way round
00487       pos += other.step (stepindex);
00488     return count == INTERSECTING || count == 0;
00489   }
00490   return count != 0;
00491 }
00492 
00493 
00494 /**********************************************************************
00495  * C_OUTLINE::winding_number
00496  *
00497  * Return the winding number of the outline around the given point.
00498  **********************************************************************/
00499 
00500 inT16 C_OUTLINE::winding_number(              //winding number
00501                                 ICOORD point  //point to wind around
00502                                ) const {
00503   inT16 stepindex;               //index to cstep
00504   inT16 count;                   //winding count
00505   ICOORD vec;                    //to current point
00506   ICOORD stepvec;                //step vector
00507   inT32 cross;                   //cross product
00508 
00509   vec = start - point;           //vector to it
00510   count = 0;
00511   for (stepindex = 0; stepindex < stepcount; stepindex++) {
00512     stepvec = step (stepindex);  //get the step
00513                                  //crossing the line
00514     if (vec.y () <= 0 && vec.y () + stepvec.y () > 0) {
00515       cross = vec * stepvec;     //cross product
00516       if (cross > 0)
00517         count++;                 //crossing right half
00518       else if (cross == 0)
00519         return INTERSECTING;     //going through point
00520     }
00521     else if (vec.y () > 0 && vec.y () + stepvec.y () <= 0) {
00522       cross = vec * stepvec;
00523       if (cross < 0)
00524         count--;                 //crossing back
00525       else if (cross == 0)
00526         return INTERSECTING;     //illegal
00527     }
00528     vec += stepvec;              //sum vectors
00529   }
00530   return count;                  //winding number
00531 }
00532 
00533 
00534 /**********************************************************************
00535  * C_OUTLINE::turn_direction
00536  *
00537  * Return the sum direction delta of the outline.
00538  **********************************************************************/
00539 
00540 inT16 C_OUTLINE::turn_direction() const {  //winding number
00541   DIR128 prevdir;                //previous direction
00542   DIR128 dir;                    //current direction
00543   inT16 stepindex;               //index to cstep
00544   inT8 dirdiff;                  //direction difference
00545   inT16 count;                   //winding count
00546 
00547   if (stepcount == 0)
00548     return 128;
00549   count = 0;
00550   prevdir = step_dir (stepcount - 1);
00551   for (stepindex = 0; stepindex < stepcount; stepindex++) {
00552     dir = step_dir (stepindex);
00553     dirdiff = dir - prevdir;
00554     ASSERT_HOST (dirdiff == 0 || dirdiff == 32 || dirdiff == -32);
00555     count += dirdiff;
00556     prevdir = dir;
00557   }
00558   ASSERT_HOST (count == 128 || count == -128);
00559   return count;                  //winding number
00560 }
00561 
00562 
00563 /**********************************************************************
00564  * C_OUTLINE::reverse
00565  *
00566  * Reverse the direction of an outline.
00567  **********************************************************************/
00568 
00569 void C_OUTLINE::reverse() {  //reverse drection
00570   DIR128 halfturn = MODULUS / 2; //amount to shift
00571   DIR128 stepdir;                //direction of step
00572   inT16 stepindex;               //index to cstep
00573   inT16 farindex;                //index to other side
00574   inT16 halfsteps;               //half of stepcount
00575 
00576   halfsteps = (stepcount + 1) / 2;
00577   for (stepindex = 0; stepindex < halfsteps; stepindex++) {
00578     farindex = stepcount - stepindex - 1;
00579     stepdir = step_dir (stepindex);
00580     set_step (stepindex, step_dir (farindex) + halfturn);
00581     set_step (farindex, stepdir + halfturn);
00582   }
00583 }
00584 
00585 
00586 /**********************************************************************
00587  * C_OUTLINE::move
00588  *
00589  * Move C_OUTLINE by vector
00590  **********************************************************************/
00591 
00592 void C_OUTLINE::move(                  // reposition OUTLINE
00593                      const ICOORD vec  // by vector
00594                     ) {
00595   C_OUTLINE_IT it(&children);  // iterator
00596 
00597   box.move (vec);
00598   start += vec;
00599 
00600   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
00601     it.data ()->move (vec);      // move child outlines
00602 }
00603 
00604 // If this outline is smaller than the given min_size, delete this and
00605 // remove from its list, via *it, after checking that *it points to this.
00606 // Otherwise, if any children of this are too small, delete them.
00607 // On entry, *it must be an iterator pointing to this. If this gets deleted
00608 // then this is extracted from *it, so an iteration can continue.
00609 void C_OUTLINE::RemoveSmallRecursive(int min_size, C_OUTLINE_IT* it) {
00610   if (box.width() < min_size || box.height() < min_size) {
00611     ASSERT_HOST(this == it->data());
00612     delete it->extract();  // Too small so get rid of it and any children.
00613   } else if (!children.empty()) {
00614     // Search the children of this, deleting any that are too small.
00615     C_OUTLINE_IT child_it(&children);
00616     for (child_it.mark_cycle_pt(); !child_it.cycled_list();
00617          child_it.forward()) {
00618       C_OUTLINE* child = child_it.data();
00619       child->RemoveSmallRecursive(min_size, &child_it);
00620     }
00621   }
00622 }
00623 
00624 // Renders the outline to the given pix, with left and top being
00625 // the coords of the upper-left corner of the pix.
00626 void C_OUTLINE::render(int left, int top, Pix* pix) const {
00627   ICOORD pos = start;
00628   for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
00629     ICOORD next_step = step(stepindex);
00630     if (next_step.y() < 0) {
00631       pixRasterop(pix, 0, top - pos.y(), pos.x() - left, 1,
00632                   PIX_NOT(PIX_DST), NULL, 0, 0);
00633     } else if (next_step.y() > 0) {
00634       pixRasterop(pix, 0, top - pos.y() - 1, pos.x() - left, 1,
00635                   PIX_NOT(PIX_DST), NULL, 0, 0);
00636     }
00637     pos += next_step;
00638   }
00639 }
00640 
00641 // Renders just the outline to the given pix (no fill), with left and top
00642 // being the coords of the upper-left corner of the pix.
00643 void C_OUTLINE::render_outline(int left, int top, Pix* pix) const {
00644   ICOORD pos = start;
00645   for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
00646     ICOORD next_step = step(stepindex);
00647     if (next_step.y() < 0) {
00648       pixSetPixel(pix, pos.x() - left, top - pos.y(), 1);
00649     } else if (next_step.y() > 0) {
00650       pixSetPixel(pix, pos.x() - left - 1, top - pos.y() - 1, 1);
00651     } else if (next_step.x() < 0) {
00652       pixSetPixel(pix, pos.x() - left - 1, top - pos.y(), 1);
00653     } else if (next_step.x() > 0) {
00654       pixSetPixel(pix, pos.x() - left, top - pos.y() - 1, 1);
00655     }
00656     pos += next_step;
00657   }
00658 }
00659 
00660 /**********************************************************************
00661  * C_OUTLINE::plot
00662  *
00663  * Draw the outline in the given colour.
00664  **********************************************************************/
00665 
00666 #ifndef GRAPHICS_DISABLED
00667 void C_OUTLINE::plot(                //draw it
00668                      ScrollView* window,       // window to draw in
00669                      ScrollView::Color colour  // colour to draw in
00670                     ) const {
00671   inT16 stepindex;               // index to cstep
00672   ICOORD pos;                    // current position
00673   DIR128 stepdir;                // direction of step
00674 
00675   pos = start;                   // current position
00676   window->Pen(colour);
00677   if (stepcount == 0) {
00678     window->Rectangle(box.left(), box.top(), box.right(), box.bottom());
00679     return;
00680   }
00681   window->SetCursor(pos.x(), pos.y());
00682 
00683   stepindex = 0;
00684   while (stepindex < stepcount) {
00685     pos += step(stepindex);    // step to next
00686     stepdir = step_dir(stepindex);
00687     stepindex++;               // count steps
00688     // merge straight lines
00689     while (stepindex < stepcount &&
00690            stepdir.get_dir() == step_dir(stepindex).get_dir()) {
00691       pos += step(stepindex);
00692       stepindex++;
00693     }
00694     window->DrawTo(pos.x(), pos.y());
00695   }
00696 }
00697 #endif
00698 
00699 
00700 /**********************************************************************
00701  * C_OUTLINE::operator=
00702  *
00703  * Assignment - deep copy data
00704  **********************************************************************/
00705 
00706                                  //assignment
00707 C_OUTLINE & C_OUTLINE::operator= (
00708 const C_OUTLINE & source         //from this
00709 ) {
00710   box = source.box;
00711   start = source.start;
00712   if (steps != NULL)
00713     free_mem(steps);
00714   stepcount = source.stepcount;
00715   steps = (uinT8 *) alloc_mem (step_mem());
00716   memmove (steps, source.steps, step_mem());
00717   if (!children.empty ())
00718     children.clear ();
00719   children.deep_copy(&source.children, &deep_copy);
00720   return *this;
00721 }
00722 
00723 ICOORD C_OUTLINE::chain_step(int chaindir) {
00724   return step_coords[chaindir % 4];
00725 }