tesseract 4.1.1
Loading...
Searching...
No Matches
werd.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * File: werd.cpp (Formerly word.c)
3 * Description: Code for the WERD class.
4 * Author: Ray Smith
5 *
6 * (C) Copyright 1991, Hewlett-Packard Ltd.
7 ** Licensed under the Apache License, Version 2.0 (the "License");
8 ** you may not use this file except in compliance with the License.
9 ** You may obtain a copy of the License at
10 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 *
17 **********************************************************************/
18
19#include "werd.h"
20#include "helpers.h"
21#include "linlsq.h"
22
23// Include automatically generated configuration file if running autoconf.
24#ifdef HAVE_CONFIG_H
25# include "config_auto.h"
26#endif
27
28#define FIRST_COLOUR ScrollView::RED
29#define LAST_COLOUR ScrollView::AQUAMARINE
30#define CHILD_COLOUR ScrollView::BROWN
31
33
34
43WERD::WERD(C_BLOB_LIST* blob_list, uint8_t blank_count, const char* text)
44 : blanks(blank_count), flags(0), script_id_(0), correct(text) {
45 C_BLOB_IT start_it = &cblobs;
46 C_BLOB_IT rej_cblob_it = &rej_cblobs;
47 C_OUTLINE_IT c_outline_it;
48 int16_t inverted_vote = 0;
49 int16_t non_inverted_vote = 0;
50
51 // Move blob_list's elements into cblobs.
52 start_it.add_list_after(blob_list);
53
54 /*
55 Set white on black flag for the WERD, moving any duff blobs onto the
56 rej_cblobs list.
57 First, walk the cblobs checking the inverse flag for each outline of each
58 cblob. If a cblob has inconsistent flag settings for its different
59 outlines, move the blob to the reject list. Otherwise, increment the
60 appropriate w-on-b or b-on-w vote for the word.
61
62 Now set the inversion flag for the WERD by maximum vote.
63
64 Walk the blobs again, moving any blob whose inversion flag does not agree
65 with the concencus onto the reject list.
66 */
67 start_it.set_to_list(&cblobs);
68 if (start_it.empty()) return;
69 for (start_it.mark_cycle_pt(); !start_it.cycled_list(); start_it.forward()) {
70 bool reject_blob = false;
71 bool blob_inverted;
72
73 c_outline_it.set_to_list(start_it.data()->out_list());
74 blob_inverted = c_outline_it.data()->flag(COUT_INVERSE);
75 for (c_outline_it.mark_cycle_pt();
76 !c_outline_it.cycled_list() && !reject_blob; c_outline_it.forward()) {
77 reject_blob = c_outline_it.data()->flag(COUT_INVERSE) != blob_inverted;
78 }
79 if (reject_blob) {
80 rej_cblob_it.add_after_then_move(start_it.extract());
81 } else {
82 if (blob_inverted)
83 inverted_vote++;
84 else
85 non_inverted_vote++;
86 }
87 }
88
89 flags.set_bit(W_INVERSE, (inverted_vote > non_inverted_vote));
90
91 start_it.set_to_list(&cblobs);
92 if (start_it.empty()) return;
93 for (start_it.mark_cycle_pt(); !start_it.cycled_list(); start_it.forward()) {
94 c_outline_it.set_to_list(start_it.data()->out_list());
95 if (c_outline_it.data()->flag(COUT_INVERSE) != flags.bit(W_INVERSE))
96 rej_cblob_it.add_after_then_move(start_it.extract());
97 }
98}
99
107WERD::WERD(C_BLOB_LIST* blob_list,
108 WERD* clone)
109 : flags(clone->flags),
110 script_id_(clone->script_id_),
111 correct(clone->correct) {
112 C_BLOB_IT start_it = blob_list; // iterator
113 C_BLOB_IT end_it = blob_list; // another
114
115 while (!end_it.at_last()) end_it.forward(); // move to last
116 (reinterpret_cast<C_BLOB_LIST*>(&cblobs))
117 ->assign_to_sublist(&start_it, &end_it);
118 // move to our list
119 blanks = clone->blanks;
120 // fprintf(stderr,"Wrong constructor!!!!\n");
121}
122
123// Construct a WERD from a single_blob and clone the flags from this.
124// W_BOL and W_EOL flags are set according to the given values.
125WERD* WERD::ConstructFromSingleBlob(bool bol, bool eol, C_BLOB* blob) {
126 C_BLOB_LIST temp_blobs;
127 C_BLOB_IT temp_it(&temp_blobs);
128 temp_it.add_after_then_move(blob);
129 WERD* blob_word = new WERD(&temp_blobs, this);
130 blob_word->set_flag(W_BOL, bol);
131 blob_word->set_flag(W_EOL, eol);
132 return blob_word;
133}
134
148TBOX WERD::bounding_box() const { return restricted_bounding_box(true, true); }
149
150// Returns the bounding box including the desired combination of upper and
151// lower noise/diacritic elements.
152TBOX WERD::restricted_bounding_box(bool upper_dots, bool lower_dots) const {
153 TBOX box = true_bounding_box();
154 int bottom = box.bottom();
155 int top = box.top();
156 // This is a read-only iteration of the rejected blobs.
157 C_BLOB_IT it(const_cast<C_BLOB_LIST*>(&rej_cblobs));
158 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
159 TBOX dot_box = it.data()->bounding_box();
160 if ((upper_dots || dot_box.bottom() <= top) &&
161 (lower_dots || dot_box.top() >= bottom)) {
162 box += dot_box;
163 }
164 }
165 return box;
166}
167
168// Returns the bounding box of only the good blobs.
170 TBOX box; // box being built
171 // This is a read-only iteration of the good blobs.
172 C_BLOB_IT it(const_cast<C_BLOB_LIST*>(&cblobs));
173 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
174 box += it.data()->bounding_box();
175 }
176 return box;
177}
178
186void WERD::move(const ICOORD vec) {
187 C_BLOB_IT cblob_it(&cblobs); // cblob iterator
188
189 for (cblob_it.mark_cycle_pt(); !cblob_it.cycled_list(); cblob_it.forward())
190 cblob_it.data()->move(vec);
191}
192
199void WERD::join_on(WERD* other) {
200 C_BLOB_IT blob_it(&cblobs);
201 C_BLOB_IT src_it(&other->cblobs);
202 C_BLOB_IT rej_cblob_it(&rej_cblobs);
203 C_BLOB_IT src_rej_it(&other->rej_cblobs);
204
205 while (!src_it.empty()) {
206 blob_it.add_to_end(src_it.extract());
207 src_it.forward();
208 }
209 while (!src_rej_it.empty()) {
210 rej_cblob_it.add_to_end(src_rej_it.extract());
211 src_rej_it.forward();
212 }
213}
214
221void WERD::copy_on(WERD* other) {
222 bool reversed = other->bounding_box().left() < bounding_box().left();
223 C_BLOB_IT c_blob_it(&cblobs);
224 C_BLOB_LIST c_blobs;
225
226 c_blobs.deep_copy(&other->cblobs, &C_BLOB::deep_copy);
227 if (reversed) {
228 c_blob_it.add_list_before(&c_blobs);
229 } else {
230 c_blob_it.move_to_last();
231 c_blob_it.add_list_after(&c_blobs);
232 }
233 if (!other->rej_cblobs.empty()) {
234 C_BLOB_IT rej_c_blob_it(&rej_cblobs);
235 C_BLOB_LIST new_rej_c_blobs;
236
237 new_rej_c_blobs.deep_copy(&other->rej_cblobs, &C_BLOB::deep_copy);
238 if (reversed) {
239 rej_c_blob_it.add_list_before(&new_rej_c_blobs);
240 } else {
241 rej_c_blob_it.move_to_last();
242 rej_c_blob_it.add_list_after(&new_rej_c_blobs);
243 }
244 }
245}
246
254 tprintf("Blanks= %d\n", blanks);
256 tprintf("Flags = %d = 0%o\n", flags.val, flags.val);
257 tprintf(" W_SEGMENTED = %s\n", flags.bit(W_SEGMENTED) ? "TRUE" : "FALSE");
258 tprintf(" W_ITALIC = %s\n", flags.bit(W_ITALIC) ? "TRUE" : "FALSE");
259 tprintf(" W_BOL = %s\n", flags.bit(W_BOL) ? "TRUE" : "FALSE");
260 tprintf(" W_EOL = %s\n", flags.bit(W_EOL) ? "TRUE" : "FALSE");
261 tprintf(" W_NORMALIZED = %s\n",
262 flags.bit(W_NORMALIZED) ? "TRUE" : "FALSE");
263 tprintf(" W_SCRIPT_HAS_XHEIGHT = %s\n",
264 flags.bit(W_SCRIPT_HAS_XHEIGHT) ? "TRUE" : "FALSE");
265 tprintf(" W_SCRIPT_IS_LATIN = %s\n",
266 flags.bit(W_SCRIPT_IS_LATIN) ? "TRUE" : "FALSE");
267 tprintf(" W_DONT_CHOP = %s\n", flags.bit(W_DONT_CHOP) ? "TRUE" : "FALSE");
268 tprintf(" W_REP_CHAR = %s\n", flags.bit(W_REP_CHAR) ? "TRUE" : "FALSE");
269 tprintf(" W_FUZZY_SP = %s\n", flags.bit(W_FUZZY_SP) ? "TRUE" : "FALSE");
270 tprintf(" W_FUZZY_NON = %s\n", flags.bit(W_FUZZY_NON) ? "TRUE" : "FALSE");
271 tprintf("Correct= %s\n", correct.string());
272 tprintf("Rejected cblob count = %d\n", rej_cblobs.length());
273 tprintf("Script = %d\n", script_id_);
274}
275
282#ifndef GRAPHICS_DISABLED
284 C_BLOB_IT it = &cblobs;
285 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
286 it.data()->plot(window, colour, colour);
287 }
288 plot_rej_blobs(window);
289}
290
291// Get the next color in the (looping) rainbow.
293 auto next = static_cast<ScrollView::Color>(colour + 1);
294 if (next >= LAST_COLOUR || next < FIRST_COLOUR) next = FIRST_COLOUR;
295 return next;
296}
297
304void WERD::plot(ScrollView* window) {
306 C_BLOB_IT it = &cblobs;
307 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
308 it.data()->plot(window, colour, CHILD_COLOUR);
309 colour = NextColor(colour);
310 }
311 plot_rej_blobs(window);
312}
313
321 C_BLOB_IT it = &rej_cblobs;
322 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
323 it.data()->plot(window, ScrollView::GREY, ScrollView::GREY);
324 }
325}
326#endif // GRAPHICS_DISABLED
327
335 WERD* new_word = new WERD;
336
337 new_word->blanks = blanks;
338 new_word->flags = flags;
339 new_word->correct = correct;
340 return new_word;
341}
342
349WERD& WERD::operator=(const WERD& source) {
350 this->ELIST2_LINK::operator=(source);
351 blanks = source.blanks;
352 flags = source.flags;
353 script_id_ = source.script_id_;
354 correct = source.correct;
355 if (!cblobs.empty()) cblobs.clear();
356 cblobs.deep_copy(&source.cblobs, &C_BLOB::deep_copy);
357
358 if (!rej_cblobs.empty()) rej_cblobs.clear();
359 rej_cblobs.deep_copy(&source.rej_cblobs, &C_BLOB::deep_copy);
360 return *this;
361}
362
370int word_comparator(const void* word1p, const void* word2p) {
371 const WERD* word1 = *reinterpret_cast<const WERD* const*>(word1p);
372 const WERD* word2 = *reinterpret_cast<const WERD* const*>(word2p);
373 return word1->bounding_box().left() - word2->bounding_box().left();
374}
375
388WERD* WERD::ConstructWerdWithNewBlobs(C_BLOB_LIST* all_blobs,
389 C_BLOB_LIST* orphan_blobs) {
390 C_BLOB_LIST current_blob_list;
391 C_BLOB_IT werd_blobs_it(&current_blob_list);
392 // Add the word's c_blobs.
393 werd_blobs_it.add_list_after(cblob_list());
394
395 // New blob list. These contain the blobs which will form the new word.
396 C_BLOB_LIST new_werd_blobs;
397 C_BLOB_IT new_blobs_it(&new_werd_blobs);
398
399 // not_found_blobs contains the list of current word's blobs for which a
400 // corresponding blob wasn't found in the input all_blobs list.
401 C_BLOB_LIST not_found_blobs;
402 C_BLOB_IT not_found_it(&not_found_blobs);
403 not_found_it.move_to_last();
404
405 werd_blobs_it.move_to_first();
406 for (werd_blobs_it.mark_cycle_pt(); !werd_blobs_it.cycled_list();
407 werd_blobs_it.forward()) {
408 C_BLOB* werd_blob = werd_blobs_it.extract();
409 TBOX werd_blob_box = werd_blob->bounding_box();
410 bool found = false;
411 // Now find the corresponding blob for this blob in the all_blobs
412 // list. For now, follow the inefficient method of pairwise
413 // comparisons. Ideally, one can pre-bucket the blobs by row.
414 C_BLOB_IT all_blobs_it(all_blobs);
415 for (all_blobs_it.mark_cycle_pt(); !all_blobs_it.cycled_list();
416 all_blobs_it.forward()) {
417 C_BLOB* a_blob = all_blobs_it.data();
418 // Compute the overlap of the two blobs. If major, a_blob should
419 // be added to the new blobs list.
420 TBOX a_blob_box = a_blob->bounding_box();
421 if (a_blob_box.null_box()) {
422 tprintf("Bounding box couldn't be ascertained\n");
423 }
424 if (werd_blob_box.contains(a_blob_box) ||
425 werd_blob_box.major_overlap(a_blob_box)) {
426 // Old blobs are from minimal splits, therefore are expected to be
427 // bigger. The new small blobs should cover a significant portion.
428 // This is it.
429 all_blobs_it.extract();
430 new_blobs_it.add_after_then_move(a_blob);
431 found = true;
432 }
433 }
434 if (!found) {
435 not_found_it.add_after_then_move(werd_blob);
436 } else {
437 delete werd_blob;
438 }
439 }
440 // Iterate over all not found blobs. Some of them may be due to
441 // under-segmentation (which is OK, since the corresponding blob is already
442 // in the list in that case.
443 not_found_it.move_to_first();
444 for (not_found_it.mark_cycle_pt(); !not_found_it.cycled_list();
445 not_found_it.forward()) {
446 C_BLOB* not_found = not_found_it.data();
447 TBOX not_found_box = not_found->bounding_box();
448 C_BLOB_IT existing_blobs_it(new_blobs_it);
449 for (existing_blobs_it.mark_cycle_pt(); !existing_blobs_it.cycled_list();
450 existing_blobs_it.forward()) {
451 C_BLOB* a_blob = existing_blobs_it.data();
452 TBOX a_blob_box = a_blob->bounding_box();
453 if ((not_found_box.major_overlap(a_blob_box) ||
454 a_blob_box.major_overlap(not_found_box)) &&
455 not_found_box.y_overlap_fraction(a_blob_box) > 0.8) {
456 // Already taken care of.
457 delete not_found_it.extract();
458 break;
459 }
460 }
461 }
462 if (orphan_blobs) {
463 C_BLOB_IT orphan_blobs_it(orphan_blobs);
464 orphan_blobs_it.move_to_last();
465 orphan_blobs_it.add_list_after(&not_found_blobs);
466 }
467
468 // New blobs are ready. Create a new werd object with these.
469 WERD* new_werd = nullptr;
470 if (!new_werd_blobs.empty()) {
471 new_werd = new WERD(&new_werd_blobs, this);
472 } else {
473 // Add the blobs back to this word so that it can be reused.
474 C_BLOB_IT this_list_it(cblob_list());
475 this_list_it.add_list_after(&not_found_blobs);
476 }
477 return new_werd;
478}
479
480// Removes noise from the word by moving small outlines to the rej_cblobs
481// list, based on the size_threshold.
482void WERD::CleanNoise(float size_threshold) {
483 C_BLOB_IT blob_it(&cblobs);
484 C_BLOB_IT rej_it(&rej_cblobs);
485 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
486 C_BLOB* blob = blob_it.data();
487 C_OUTLINE_IT ol_it(blob->out_list());
488 for (ol_it.mark_cycle_pt(); !ol_it.cycled_list(); ol_it.forward()) {
489 C_OUTLINE* outline = ol_it.data();
490 TBOX ol_box = outline->bounding_box();
491 int ol_size =
492 ol_box.width() > ol_box.height() ? ol_box.width() : ol_box.height();
493 if (ol_size < size_threshold) {
494 // This outline is too small. Move it to a separate blob in the
495 // reject blobs list.
496 auto* rej_blob = new C_BLOB(ol_it.extract());
497 rej_it.add_after_then_move(rej_blob);
498 }
499 }
500 if (blob->out_list()->empty()) delete blob_it.extract();
501 }
502}
503
504// Extracts all the noise outlines and stuffs the pointers into the given
505// vector of outlines. Afterwards, the outlines vector owns the pointers.
507 C_BLOB_IT rej_it(&rej_cblobs);
508 for (rej_it.mark_cycle_pt(); !rej_it.empty(); rej_it.forward()) {
509 C_BLOB* blob = rej_it.extract();
510 C_OUTLINE_IT ol_it(blob->out_list());
511 outlines->push_back(ol_it.extract());
512 delete blob;
513 }
514}
515
516// Adds the selected outlines to the indcated real blobs, and puts the rest
517// back in rej_cblobs where they came from. Where the target_blobs entry is
518// nullptr, a run of wanted outlines is put into a single new blob.
519// Ownership of the outlines is transferred back to the word. (Hence
520// GenericVector and not PointerVector.)
521// Returns true if any new blob was added to the start of the word, which
522// suggests that it might need joining to the word before it, and likewise
523// sets make_next_word_fuzzy true if any new blob was added to the end.
525 const GenericVector<C_BLOB*>& target_blobs,
526 const GenericVector<C_OUTLINE*>& outlines,
527 bool* make_next_word_fuzzy) {
528 bool outline_added_to_start = false;
529 if (make_next_word_fuzzy != nullptr) *make_next_word_fuzzy = false;
530 C_BLOB_IT rej_it(&rej_cblobs);
531 for (int i = 0; i < outlines.size(); ++i) {
532 C_OUTLINE* outline = outlines[i];
533 if (outline == nullptr) continue; // Already used it.
534 if (wanted[i]) {
535 C_BLOB* target_blob = target_blobs[i];
536 TBOX noise_box = outline->bounding_box();
537 if (target_blob == nullptr) {
538 target_blob = new C_BLOB(outline);
539 // Need to find the insertion point.
540 C_BLOB_IT blob_it(&cblobs);
541 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();
542 blob_it.forward()) {
543 C_BLOB* blob = blob_it.data();
544 TBOX blob_box = blob->bounding_box();
545 if (blob_box.left() > noise_box.left()) {
546 if (blob_it.at_first() && !flag(W_FUZZY_SP) && !flag(W_FUZZY_NON)) {
547 // We might want to join this word to its predecessor.
548 outline_added_to_start = true;
549 }
550 blob_it.add_before_stay_put(target_blob);
551 break;
552 }
553 }
554 if (blob_it.cycled_list()) {
555 blob_it.add_to_end(target_blob);
556 if (make_next_word_fuzzy != nullptr) *make_next_word_fuzzy = true;
557 }
558 // Add all consecutive wanted, but null-blob outlines to same blob.
559 C_OUTLINE_IT ol_it(target_blob->out_list());
560 while (i + 1 < outlines.size() && wanted[i + 1] &&
561 target_blobs[i + 1] == nullptr) {
562 ++i;
563 ol_it.add_to_end(outlines[i]);
564 }
565 } else {
566 // Insert outline into this blob.
567 C_OUTLINE_IT ol_it(target_blob->out_list());
568 ol_it.add_to_end(outline);
569 }
570 } else {
571 // Put back on noise list.
572 rej_it.add_to_end(new C_BLOB(outline));
573 }
574 }
575 return outline_added_to_start;
576}
@ COUT_INVERSE
Definition: coutln.h:42
#define FIRST_COLOUR
first rainbow colour
Definition: werd.cpp:28
#define CHILD_COLOUR
colour of children
Definition: werd.cpp:30
int word_comparator(const void *word1p, const void *word2p)
Definition: werd.cpp:370
#define LAST_COLOUR
last rainbow colour
Definition: werd.cpp:29
@ W_FUZZY_SP
fuzzy space
Definition: werd.h:39
@ W_SCRIPT_HAS_XHEIGHT
x-height concept makes sense.
Definition: werd.h:35
@ W_EOL
end of line
Definition: werd.h:33
@ W_FUZZY_NON
fuzzy nonspace
Definition: werd.h:40
@ W_NORMALIZED
flags
Definition: werd.h:34
@ W_SEGMENTED
correctly segmented
Definition: werd.h:29
@ W_SCRIPT_IS_LATIN
Special case latin for y. splitting.
Definition: werd.h:36
@ W_REP_CHAR
repeated character
Definition: werd.h:38
@ W_DONT_CHOP
fixed pitch chopped
Definition: werd.h:37
@ W_INVERSE
white on black
Definition: werd.h:41
@ W_ITALIC
italic text
Definition: werd.h:30
@ W_BOL
start of line
Definition: werd.h:32
#define ELIST2IZE(CLASSNAME)
Definition: elst2.h:939
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
int push_back(T object)
int size() const
Definition: genericvector.h:72
const TBOX & bounding_box() const
Definition: coutln.h:113
integer coordinate
Definition: points.h:32
Definition: rect.h:34
double y_overlap_fraction(const TBOX &box) const
Definition: rect.h:479
int16_t top() const
Definition: rect.h:58
void print() const
Definition: rect.h:278
int16_t width() const
Definition: rect.h:115
int16_t height() const
Definition: rect.h:108
bool major_overlap(const TBOX &box) const
Definition: rect.h:368
int16_t left() const
Definition: rect.h:72
int16_t bottom() const
Definition: rect.h:65
bool contains(const FCOORD pt) const
Definition: rect.h:333
bool null_box() const
Definition: rect.h:50
static C_BLOB * deep_copy(const C_BLOB *src)
Definition: stepblob.h:119
TBOX bounding_box() const
Definition: stepblob.cpp:253
C_OUTLINE_LIST * out_list()
Definition: stepblob.h:70
Definition: werd.h:56
WERD * ConstructWerdWithNewBlobs(C_BLOB_LIST *all_blobs, C_BLOB_LIST *orphan_blobs)
Definition: werd.cpp:388
static ScrollView::Color NextColor(ScrollView::Color colour)
Definition: werd.cpp:292
C_BLOB_LIST * cblob_list()
Definition: werd.h:95
WERD * ConstructFromSingleBlob(bool bol, bool eol, C_BLOB *blob)
Definition: werd.cpp:125
WERD * shallow_copy()
Definition: werd.cpp:334
bool AddSelectedOutlines(const GenericVector< bool > &wanted, const GenericVector< C_BLOB * > &target_blobs, const GenericVector< C_OUTLINE * > &outlines, bool *make_next_word_fuzzy)
Definition: werd.cpp:524
TBOX restricted_bounding_box(bool upper_dots, bool lower_dots) const
Definition: werd.cpp:152
void print()
Definition: werd.cpp:253
WERD()=default
WERD & operator=(const WERD &source)
Definition: werd.cpp:349
void CleanNoise(float size_threshold)
Definition: werd.cpp:482
void set_flag(WERD_FLAGS mask, bool value)
Definition: werd.h:118
void copy_on(WERD *other)
Definition: werd.cpp:221
TBOX bounding_box() const
Definition: werd.cpp:148
void join_on(WERD *other)
Definition: werd.cpp:199
TBOX true_bounding_box() const
Definition: werd.cpp:169
void plot_rej_blobs(ScrollView *window)
Definition: werd.cpp:320
void plot(ScrollView *window, ScrollView::Color colour)
Definition: werd.cpp:283
bool flag(WERD_FLAGS mask) const
Definition: werd.h:117
void move(const ICOORD vec)
Definition: werd.cpp:186
void GetNoiseOutlines(GenericVector< C_OUTLINE * > *outlines)
Definition: werd.cpp:506
uint16_t val
Definition: bits16.h:27
bool bit(uint8_t bit_num) const
Definition: bits16.h:51
void operator=(const ELIST2_LINK &)
Definition: elst2.h:74
const char * string() const
Definition: strngs.cpp:194