Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
coutln.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 * File: coutln.c (Formerly coutline.c)
3 * Description: Code for the C_OUTLINE class.
4 * Author: Ray Smith
5 * Created: Mon Oct 07 16:01:57 BST 1991
6 *
7 * (C) Copyright 1991, Hewlett-Packard Ltd.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #include "mfcpch.h"
21 #include <string.h>
22 #ifdef __UNIX__
23 #include <assert.h>
24 #endif
25 #include "coutln.h"
26 #include "allheaders.h"
27
28 // Include automatically generated configuration file if running autoconf.
29 #ifdef HAVE_CONFIG_H
30 #include "config_auto.h"
31 #endif
32
33 ELISTIZE (C_OUTLINE)
34 ICOORD C_OUTLINE::step_coords[4] = {
35 ICOORD (-1, 0), ICOORD (0, -1), ICOORD (1, 0), ICOORD (0, 1)
36 };
37
38 /**********************************************************************
39 * C_OUTLINE::C_OUTLINE
40 *
41 * Constructor to build a C_OUTLINE from a CRACKEDGE LOOP.
42 **********************************************************************/
43
44 C_OUTLINE::C_OUTLINE (
45 //constructor
46 CRACKEDGE * startpt, //outline to convert
47 ICOORD bot_left, //bounding box
48 ICOORD top_right, inT16 length //length of loop
49 ):box (bot_left, top_right), start (startpt->pos) {
50 inT16 stepindex; //index to step
51 CRACKEDGE *edgept; //current point
52
53 stepcount = length; //no of steps
54 if (length == 0) {
55 steps = NULL;
56 return;
57 }
58 //get memory
59 steps = (uinT8 *) alloc_mem (step_mem());
60 memset(steps, 0, step_mem());
61 edgept = startpt;
62
63 for (stepindex = 0; stepindex < length; stepindex++) {
64 //set compact step
65 set_step (stepindex, edgept->stepdir);
66 edgept = edgept->next;
67 }
68 }
69
70
71 /**********************************************************************
72 * C_OUTLINE::C_OUTLINE
73 *
74 * Constructor to build a C_OUTLINE from a C_OUTLINE_FRAG.
75 **********************************************************************/
76 C_OUTLINE::C_OUTLINE (
77 //constructor
78 //steps to copy
79 ICOORD startpt, DIR128 * new_steps,
80 inT16 length //length of loop
81 ):start (startpt) {
82 inT8 dirdiff; //direction difference
83 DIR128 prevdir; //previous direction
84 DIR128 dir; //current direction
85 DIR128 lastdir; //dir of last step
86 TBOX new_box; //easy bounding
87 inT16 stepindex; //index to step
88 inT16 srcindex; //source steps
89 ICOORD pos; //current position
90
91 pos = startpt;
92 stepcount = length; //no of steps
93 //get memory
94 steps = (uinT8 *) alloc_mem (step_mem());
95 memset(steps, 0, step_mem());
96
97 lastdir = new_steps[length - 1];
98 prevdir = lastdir;
99 for (stepindex = 0, srcindex = 0; srcindex < length;
100 stepindex++, srcindex++) {
101 new_box = TBOX (pos, pos);
102 box += new_box;
103 //copy steps
104 dir = new_steps[srcindex];
105 set_step(stepindex, dir);
106 dirdiff = dir - prevdir;
107 pos += step (stepindex);
108 if ((dirdiff == 64 || dirdiff == -64) && stepindex > 0) {
109 stepindex -= 2; //cancel there-and-back
110 prevdir = stepindex >= 0 ? step_dir (stepindex) : lastdir;
111 }
112 else
113 prevdir = dir;
114 }
115 ASSERT_HOST (pos.x () == startpt.x () && pos.y () == startpt.y ());
116 do {
117 dirdiff = step_dir (stepindex - 1) - step_dir (0);
118 if (dirdiff == 64 || dirdiff == -64) {
119 start += step (0);
120 stepindex -= 2; //cancel there-and-back
121 for (int i = 0; i < stepindex; ++i)
122 set_step(i, step_dir(i + 1));
123 }
124 }
125 while (stepindex > 1 && (dirdiff == 64 || dirdiff == -64));
126 stepcount = stepindex;
127 ASSERT_HOST (stepcount >= 4);
128 }
129
130 /**********************************************************************
131 * C_OUTLINE::C_OUTLINE
132 *
133 * Constructor to build a C_OUTLINE from a rotation of a C_OUTLINE.
134 **********************************************************************/
135
136 C_OUTLINE::C_OUTLINE( //constructor
137 C_OUTLINE *srcline, //outline to
138 FCOORD rotation //rotate
139 ) {
140 TBOX new_box; //easy bounding
141 inT16 stepindex; //index to step
142 inT16 dirdiff; //direction change
143 ICOORD pos; //current position
144 ICOORD prevpos; //previous dest point
145
146 ICOORD destpos; //destination point
147 inT16 destindex; //index to step
148 DIR128 dir; //coded direction
149 uinT8 new_step;
150
151 stepcount = srcline->stepcount * 2;
152 if (stepcount == 0) {
153 steps = NULL;
154 box = srcline->box;
155 box.rotate(rotation);
156 return;
157 }
158 //get memory
159 steps = (uinT8 *) alloc_mem (step_mem());
160 memset(steps, 0, step_mem());
161
162 for (int iteration = 0; iteration < 2; ++iteration) {
163 DIR128 round1 = iteration == 0 ? 32 : 0;
164 DIR128 round2 = iteration != 0 ? 32 : 0;
165 pos = srcline->start;
166 prevpos = pos;
167 prevpos.rotate (rotation);
168 start = prevpos;
169 box = TBOX (start, start);
170 destindex = 0;
171 for (stepindex = 0; stepindex < srcline->stepcount; stepindex++) {
172 pos += srcline->step (stepindex);
173 destpos = pos;
174 destpos.rotate (rotation);
175 // printf("%i %i %i %i ", destpos.x(), destpos.y(), pos.x(), pos.y());
176 while (destpos.x () != prevpos.x () || destpos.y () != prevpos.y ()) {
177 dir = DIR128 (FCOORD (destpos - prevpos));
178 dir += 64; //turn to step style
179 new_step = dir.get_dir ();
180 // printf(" %i\n", new_step);
181 if (new_step & 31) {
182 set_step(destindex++, dir + round1);
183 prevpos += step(destindex - 1);
184 if (destindex < 2
185 || ((dirdiff =
186 step_dir (destindex - 1) - step_dir (destindex - 2)) !=
187 -64 && dirdiff != 64)) {
188 set_step(destindex++, dir + round2);
189 prevpos += step(destindex - 1);
190 } else {
191 prevpos -= step(destindex - 1);
192 destindex--;
193 prevpos -= step(destindex - 1);
194 set_step(destindex - 1, dir + round2);
195 prevpos += step(destindex - 1);
196 }
197 }
198 else {
199 set_step(destindex++, dir);
200 prevpos += step(destindex - 1);
201 }
202 while (destindex >= 2 &&
203 ((dirdiff =
204 step_dir (destindex - 1) - step_dir (destindex - 2)) == -64 ||
205 dirdiff == 64)) {
206 prevpos -= step(destindex - 1);
207 prevpos -= step(destindex - 2);
208 destindex -= 2; // Forget u turn
209 }
210 //ASSERT_HOST(prevpos.x() == destpos.x() && prevpos.y() == destpos.y());
211 new_box = TBOX (destpos, destpos);
212 box += new_box;
213 }
214 }
215 ASSERT_HOST (destpos.x () == start.x () && destpos.y () == start.y ());
216 dirdiff = step_dir (destindex - 1) - step_dir (0);
217 while ((dirdiff == 64 || dirdiff == -64) && destindex > 1) {
218 start += step (0);
219 destindex -= 2;
220 for (int i = 0; i < destindex; ++i)
221 set_step(i, step_dir(i + 1));
222 dirdiff = step_dir (destindex - 1) - step_dir (0);
223 }
224 if (destindex >= 4)
225 break;
226 }
227 ASSERT_HOST(destindex <= stepcount);
228 stepcount = destindex;
229 destpos = start;
230 for (stepindex = 0; stepindex < stepcount; stepindex++) {
231 destpos += step (stepindex);
232 }
233 ASSERT_HOST (destpos.x () == start.x () && destpos.y () == start.y ());
234 }
235
236 // Build a fake outline, given just a bounding box and append to the list.
237 void C_OUTLINE::FakeOutline(const TBOX& box, C_OUTLINE_LIST* outlines) {
238 C_OUTLINE_IT ol_it(outlines);
239 // Make a C_OUTLINE from the bounds. This is a bit of a hack,
240 // as there is no outline, just a bounding box, but it works nicely.
241 CRACKEDGE start;
242 start.pos = box.topleft();
243 C_OUTLINE* outline = new C_OUTLINE(&start, box.topleft(), box.botright(), 0);
244 ol_it.add_to_end(outline);
245 }
246
247 /**********************************************************************
248 * C_OUTLINE::area
249 *
250 * Compute the area of the outline.
251 **********************************************************************/
252
253 inT32 C_OUTLINE::area() { //winding number
254 int stepindex; //current step
255 inT32 total_steps; //steps to do
256 inT32 total; //total area
257 ICOORD pos; //position of point
258 ICOORD next_step; //step to next pix
259 C_OUTLINE_IT it = child ();
260
261 pos = start_pos ();
262 total_steps = pathlength ();
263 total = 0;
264 for (stepindex = 0; stepindex < total_steps; stepindex++) {
265 //all intersected
266 next_step = step (stepindex);
267 if (next_step.x () < 0)
268 total += pos.y ();
269 else if (next_step.x () > 0)
270 total -= pos.y ();
271 pos += next_step;
272 }
273 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
274 total += it.data ()->area ();//add areas of children
275
276 return total;
277 }
278
279 /**********************************************************************
280 * C_OUTLINE::perimeter
281 *
282 * Compute the perimeter of the outline and its first level children.
283 **********************************************************************/
284
285 inT32 C_OUTLINE::perimeter() {
286 inT32 total_steps; // Return value.
287 C_OUTLINE_IT it = child();
288
289 total_steps = pathlength();
290 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward())
291 total_steps += it.data()->pathlength(); // Add perimeters of children.
292
293 return total_steps;
294 }
295
296
297 /**********************************************************************
298 * C_OUTLINE::outer_area
299 *
300 * Compute the area of the outline.
301 **********************************************************************/
302
303 inT32 C_OUTLINE::outer_area() { //winding number
304 int stepindex; //current step
305 inT32 total_steps; //steps to do
306 inT32 total; //total area
307 ICOORD pos; //position of point
308 ICOORD next_step; //step to next pix
309
310 pos = start_pos ();
311 total_steps = pathlength ();
312 if (total_steps == 0)
313 return box.area();
314 total = 0;
315 for (stepindex = 0; stepindex < total_steps; stepindex++) {
316 //all intersected
317 next_step = step (stepindex);
318 if (next_step.x () < 0)
319 total += pos.y ();
320 else if (next_step.x () > 0)
321 total -= pos.y ();
322 pos += next_step;
323 }
324
325 return total;
326 }
327
328
329 /**********************************************************************
330 * C_OUTLINE::count_transitions
331 *
332 * Compute the number of x and y maxes and mins in the outline.
333 **********************************************************************/
334
335 inT32 C_OUTLINE::count_transitions( //winding number
336 inT32 threshold //on size
337 ) {
338 BOOL8 first_was_max_x; //what was first
339 BOOL8 first_was_max_y;
340 BOOL8 looking_for_max_x; //what is next
341 BOOL8 looking_for_min_x;
342 BOOL8 looking_for_max_y; //what is next
343 BOOL8 looking_for_min_y;
344 int stepindex; //current step
345 inT32 total_steps; //steps to do
346 //current limits
347 inT32 max_x, min_x, max_y, min_y;
348 inT32 initial_x, initial_y; //initial limits
349 inT32 total; //total changes
350 ICOORD pos; //position of point
351 ICOORD next_step; //step to next pix
352
353 pos = start_pos ();
354 total_steps = pathlength ();
355 total = 0;
356 max_x = min_x = pos.x ();
357 max_y = min_y = pos.y ();
358 looking_for_max_x = TRUE;
359 looking_for_min_x = TRUE;
360 looking_for_max_y = TRUE;
361 looking_for_min_y = TRUE;
362 first_was_max_x = FALSE;
363 first_was_max_y = FALSE;
364 initial_x = pos.x ();
365 initial_y = pos.y (); //stop uninit warning
366 for (stepindex = 0; stepindex < total_steps; stepindex++) {
367 //all intersected
368 next_step = step (stepindex);
369 pos += next_step;
370 if (next_step.x () < 0) {
371 if (looking_for_max_x && pos.x () < min_x)
372 min_x = pos.x ();
373 if (looking_for_min_x && max_x - pos.x () > threshold) {
374 if (looking_for_max_x) {
375 initial_x = max_x;
376 first_was_max_x = FALSE;
377 }
378 total++;
379 looking_for_max_x = TRUE;
380 looking_for_min_x = FALSE;
381 min_x = pos.x (); //reset min
382 }
383 }
384 else if (next_step.x () > 0) {
385 if (looking_for_min_x && pos.x () > max_x)
386 max_x = pos.x ();
387 if (looking_for_max_x && pos.x () - min_x > threshold) {
388 if (looking_for_min_x) {
389 initial_x = min_x; //remember first min
390 first_was_max_x = TRUE;
391 }
392 total++;
393 looking_for_max_x = FALSE;
394 looking_for_min_x = TRUE;
395 max_x = pos.x ();
396 }
397 }
398 else if (next_step.y () < 0) {
399 if (looking_for_max_y && pos.y () < min_y)
400 min_y = pos.y ();
401 if (looking_for_min_y && max_y - pos.y () > threshold) {
402 if (looking_for_max_y) {
403 initial_y = max_y; //remember first max
404 first_was_max_y = FALSE;
405 }
406 total++;
407 looking_for_max_y = TRUE;
408 looking_for_min_y = FALSE;
409 min_y = pos.y (); //reset min
410 }
411 }
412 else {
413 if (looking_for_min_y && pos.y () > max_y)
414 max_y = pos.y ();
415 if (looking_for_max_y && pos.y () - min_y > threshold) {
416 if (looking_for_min_y) {
417 initial_y = min_y; //remember first min
418 first_was_max_y = TRUE;
419 }
420 total++;
421 looking_for_max_y = FALSE;
422 looking_for_min_y = TRUE;
423 max_y = pos.y ();
424 }
425 }
426
427 }
428 if (first_was_max_x && looking_for_min_x) {
429 if (max_x - initial_x > threshold)
430 total++;
431 else
432 total--;
433 }
434 else if (!first_was_max_x && looking_for_max_x) {
435 if (initial_x - min_x > threshold)
436 total++;
437 else
438 total--;
439 }
440 if (first_was_max_y && looking_for_min_y) {
441 if (max_y - initial_y > threshold)
442 total++;
443 else
444 total--;
445 }
446 else if (!first_was_max_y && looking_for_max_y) {
447 if (initial_y - min_y > threshold)
448 total++;
449 else
450 total--;
451 }
452
453 return total;
454 }
455
456
457 /**********************************************************************
458 * C_OUTLINE::operator<
459 *
460 * Return TRUE if the left operand is inside the right one.
461 **********************************************************************/
462
463 BOOL8
464 C_OUTLINE::operator< ( //winding number
465 const C_OUTLINE & other //other outline
466 ) const
467 {
468 inT16 count = 0; //winding count
469 ICOORD pos; //position of point
470 inT32 stepindex; //index to cstep
471
472 if (!box.overlap (other.box))
473 return FALSE; //can't be contained
474 if (stepcount == 0)
475 return other.box.contains(this->box);
476
477 pos = start;
478 for (stepindex = 0; stepindex < stepcount
479 && (count = other.winding_number (pos)) == INTERSECTING; stepindex++)
480 pos += step (stepindex); //try all points
481 if (count == INTERSECTING) {
482 //all intersected
483 pos = other.start;
484 for (stepindex = 0; stepindex < other.stepcount
485 && (count = winding_number (pos)) == INTERSECTING; stepindex++)
486 //try other way round
487 pos += other.step (stepindex);
488 return count == INTERSECTING || count == 0;
489 }
490 return count != 0;
491 }
492
493
494 /**********************************************************************
495 * C_OUTLINE::winding_number
496 *
497 * Return the winding number of the outline around the given point.
498 **********************************************************************/
499
500 inT16 C_OUTLINE::winding_number( //winding number
501 ICOORD point //point to wind around
502 ) const {
503 inT16 stepindex; //index to cstep
504 inT16 count; //winding count
505 ICOORD vec; //to current point
506 ICOORD stepvec; //step vector
507 inT32 cross; //cross product
508
509 vec = start - point; //vector to it
510 count = 0;
511 for (stepindex = 0; stepindex < stepcount; stepindex++) {
512 stepvec = step (stepindex); //get the step
513 //crossing the line
514 if (vec.y () <= 0 && vec.y () + stepvec.y () > 0) {
515 cross = vec * stepvec; //cross product
516 if (cross > 0)
517 count++; //crossing right half
518 else if (cross == 0)
519 return INTERSECTING; //going through point
520 }
521 else if (vec.y () > 0 && vec.y () + stepvec.y () <= 0) {
522 cross = vec * stepvec;
523 if (cross < 0)
524 count--; //crossing back
525 else if (cross == 0)
526 return INTERSECTING; //illegal
527 }
528 vec += stepvec; //sum vectors
529 }
530 return count; //winding number
531 }
532
533
534 /**********************************************************************
535 * C_OUTLINE::turn_direction
536 *
537 * Return the sum direction delta of the outline.
538 **********************************************************************/
539
540 inT16 C_OUTLINE::turn_direction() const { //winding number
541 DIR128 prevdir; //previous direction
542 DIR128 dir; //current direction
543 inT16 stepindex; //index to cstep
544 inT8 dirdiff; //direction difference
545 inT16 count; //winding count
546
547 if (stepcount == 0)
548 return 128;
549 count = 0;
550 prevdir = step_dir (stepcount - 1);
551 for (stepindex = 0; stepindex < stepcount; stepindex++) {
552 dir = step_dir (stepindex);
553 dirdiff = dir - prevdir;
554 ASSERT_HOST (dirdiff == 0 || dirdiff == 32 || dirdiff == -32);
555 count += dirdiff;
556 prevdir = dir;
557 }
558 ASSERT_HOST (count == 128 || count == -128);
559 return count; //winding number
560 }
561
562
563 /**********************************************************************
564 * C_OUTLINE::reverse
565 *
566 * Reverse the direction of an outline.
567 **********************************************************************/
568
569 void C_OUTLINE::reverse() { //reverse drection
570 DIR128 halfturn = MODULUS / 2; //amount to shift
571 DIR128 stepdir; //direction of step
572 inT16 stepindex; //index to cstep
573 inT16 farindex; //index to other side
574 inT16 halfsteps; //half of stepcount
575
576 halfsteps = (stepcount + 1) / 2;
577 for (stepindex = 0; stepindex < halfsteps; stepindex++) {
578 farindex = stepcount - stepindex - 1;
579 stepdir = step_dir (stepindex);
580 set_step (stepindex, step_dir (farindex) + halfturn);
581 set_step (farindex, stepdir + halfturn);
582 }
583 }
584
585
586 /**********************************************************************
587 * C_OUTLINE::move
588 *
589 * Move C_OUTLINE by vector
590 **********************************************************************/
591
592 void C_OUTLINE::move( // reposition OUTLINE
593 const ICOORD vec // by vector
594 ) {
595 C_OUTLINE_IT it(&children); // iterator
596
597 box.move (vec);
598 start += vec;
599
600 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
601 it.data ()->move (vec); // move child outlines
602 }
603
604 // If this outline is smaller than the given min_size, delete this and
605 // remove from its list, via *it, after checking that *it points to this.
606 // Otherwise, if any children of this are too small, delete them.
607 // On entry, *it must be an iterator pointing to this. If this gets deleted
608 // then this is extracted from *it, so an iteration can continue.
609 void C_OUTLINE::RemoveSmallRecursive(int min_size, C_OUTLINE_IT* it) {
610 if (box.width() < min_size || box.height() < min_size) {
611 ASSERT_HOST(this == it->data());
612 delete it->extract(); // Too small so get rid of it and any children.
613 } else if (!children.empty()) {
614 // Search the children of this, deleting any that are too small.
615 C_OUTLINE_IT child_it(&children);
616 for (child_it.mark_cycle_pt(); !child_it.cycled_list();
617 child_it.forward()) {
618 C_OUTLINE* child = child_it.data();
619 child->RemoveSmallRecursive(min_size, &child_it);
620 }
621 }
622 }
623
624 // Renders the outline to the given pix, with left and top being
625 // the coords of the upper-left corner of the pix.
626 void C_OUTLINE::render(int left, int top, Pix* pix) const {
627 ICOORD pos = start;
628 for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
629 ICOORD next_step = step(stepindex);
630 if (next_step.y() < 0) {
631 pixRasterop(pix, 0, top - pos.y(), pos.x() - left, 1,
632 PIX_NOT(PIX_DST), NULL, 0, 0);
633 } else if (next_step.y() > 0) {
634 pixRasterop(pix, 0, top - pos.y() - 1, pos.x() - left, 1,
635 PIX_NOT(PIX_DST), NULL, 0, 0);
636 }
637 pos += next_step;
638 }
639 }
640
641 // Renders just the outline to the given pix (no fill), with left and top
642 // being the coords of the upper-left corner of the pix.
643 void C_OUTLINE::render_outline(int left, int top, Pix* pix) const {
644 ICOORD pos = start;
645 for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
646 ICOORD next_step = step(stepindex);
647 if (next_step.y() < 0) {
648 pixSetPixel(pix, pos.x() - left, top - pos.y(), 1);
649 } else if (next_step.y() > 0) {
650 pixSetPixel(pix, pos.x() - left - 1, top - pos.y() - 1, 1);
651 } else if (next_step.x() < 0) {
652 pixSetPixel(pix, pos.x() - left - 1, top - pos.y(), 1);
653 } else if (next_step.x() > 0) {
654 pixSetPixel(pix, pos.x() - left, top - pos.y() - 1, 1);
655 }
656 pos += next_step;
657 }
658 }
659
660 /**********************************************************************
661 * C_OUTLINE::plot
662 *
663 * Draw the outline in the given colour.
664 **********************************************************************/
665
666 #ifndef GRAPHICS_DISABLED
667 void C_OUTLINE::plot( //draw it
668 ScrollView* window, // window to draw in
669 ScrollView::Color colour // colour to draw in
670 ) const {
671 inT16 stepindex; // index to cstep
672 ICOORD pos; // current position
673 DIR128 stepdir; // direction of step
674
675 pos = start; // current position
676 window->Pen(colour);
677 if (stepcount == 0) {
678 window->Rectangle(box.left(), box.top(), box.right(), box.bottom());
679 return;
680 }
681 window->SetCursor(pos.x(), pos.y());
682
683 stepindex = 0;
684 while (stepindex < stepcount) {
685 pos += step(stepindex); // step to next
686 stepdir = step_dir(stepindex);
687 stepindex++; // count steps
688 // merge straight lines
689 while (stepindex < stepcount &&
690 stepdir.get_dir() == step_dir(stepindex).get_dir()) {
691 pos += step(stepindex);
692 stepindex++;
693 }
694 window->DrawTo(pos.x(), pos.y());
695 }
696 }
697 #endif
698
699
700 /**********************************************************************
701 * C_OUTLINE::operator=
702 *
703 * Assignment - deep copy data
704 **********************************************************************/
705
706 //assignment
707 C_OUTLINE & C_OUTLINE::operator= (
708 const C_OUTLINE & source //from this
709 ) {
710 box = source.box;
711 start = source.start;
712 if (steps != NULL)
713 free_mem(steps);
714 stepcount = source.stepcount;
715 steps = (uinT8 *) alloc_mem (step_mem());
716 memmove (steps, source.steps, step_mem());
717 if (!children.empty ())
718 children.clear ();
719 children.deep_copy(&source.children, &deep_copy);
720 return *this;
721 }
722
723 ICOORD C_OUTLINE::chain_step(int chaindir) {
724 return step_coords[chaindir % 4];
725 }