1 /**********************************************************************
2 * File: drawtord.cpp (Formerly drawto.c)
3 * Description: Draw things to do with textord.
4 * Author: Ray Smith
5 *
6 * (C) Copyright 1992, 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 #ifdef HAVE_CONFIG_H
20 # include "config_auto.h"
21 #endif
22
23 #include "drawtord.h"
24
25 #include "pithsync.h"
26 #include "topitch.h"
27
28 namespace tesseract {
29
30 #define TO_WIN_XPOS 0 // default window pos
31 #define TO_WIN_YPOS 0
32 #define TO_WIN_NAME "Textord"
33 // title of window
34
35 BOOL_VAR(textord_show_fixed_cuts, false, "Draw fixed pitch cell boundaries");
36
37 ScrollView *to_win = nullptr;
38
39 #ifndef GRAPHICS_DISABLED
40
41 /**********************************************************************
42 * create_to_win
43 *
44 * Create the to window used to show the fit.
45 **********************************************************************/
46
create_to_win(ICOORD page_tr)47 ScrollView *create_to_win(ICOORD page_tr) {
48 if (to_win != nullptr) {
49 return to_win;
50 }
51 to_win = new ScrollView(TO_WIN_NAME, TO_WIN_XPOS, TO_WIN_YPOS, page_tr.x() + 1, page_tr.y() + 1,
52 page_tr.x(), page_tr.y(), true);
53 return to_win;
54 }
55
close_to_win()56 void close_to_win() {
57 // to_win is leaked, but this enables the user to view the contents.
58 if (to_win != nullptr) {
59 to_win->Update();
60 }
61 }
62
63 /**********************************************************************
64 * plot_box_list
65 *
66 * Draw a list of blobs.
67 **********************************************************************/
68
plot_box_list(ScrollView * win,BLOBNBOX_LIST * list,ScrollView::Color body_colour)69 void plot_box_list( // make gradients win
70 ScrollView *win, // window to draw in
71 BLOBNBOX_LIST *list, // blob list
72 ScrollView::Color body_colour // colour to draw
73 ) {
74 BLOBNBOX_IT it = list; // iterator
75
76 win->Pen(body_colour);
77 win->Brush(ScrollView::NONE);
78 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
79 it.data()->bounding_box().plot(win);
80 }
81 }
82
83 /**********************************************************************
84 * plot_to_row
85 *
86 * Draw the blobs of a row in a given colour and draw the line fit.
87 **********************************************************************/
88
plot_to_row(TO_ROW * row,ScrollView::Color colour,FCOORD rotation)89 void plot_to_row( // draw a row
90 TO_ROW *row, // row to draw
91 ScrollView::Color colour, // colour to draw in
92 FCOORD rotation // rotation for line
93 ) {
94 FCOORD plot_pt; // point to plot
95 // blobs
96 BLOBNBOX_IT it = row->blob_list();
97 float left, right; // end of row
98
99 if (it.empty()) {
100 tprintf("No blobs in row at %g\n", row->parallel_c());
101 return;
102 }
103 left = it.data()->bounding_box().left();
104 it.move_to_last();
105 right = it.data()->bounding_box().right();
106 plot_blob_list(to_win, row->blob_list(), colour, ScrollView::BROWN);
107 to_win->Pen(colour);
108 plot_pt = FCOORD(left, row->line_m() * left + row->line_c());
109 plot_pt.rotate(rotation);
110 to_win->SetCursor(plot_pt.x(), plot_pt.y());
111 plot_pt = FCOORD(right, row->line_m() * right + row->line_c());
112 plot_pt.rotate(rotation);
113 to_win->DrawTo(plot_pt.x(), plot_pt.y());
114 }
115
116 /**********************************************************************
117 * plot_parallel_row
118 *
119 * Draw the blobs of a row in a given colour and draw the line fit.
120 **********************************************************************/
121
plot_parallel_row(TO_ROW * row,float gradient,int32_t left,ScrollView::Color colour,FCOORD rotation)122 void plot_parallel_row( // draw a row
123 TO_ROW *row, // row to draw
124 float gradient, // gradients of lines
125 int32_t left, // edge of block
126 ScrollView::Color colour, // colour to draw in
127 FCOORD rotation // rotation for line
128 ) {
129 FCOORD plot_pt; // point to plot
130 // blobs
131 BLOBNBOX_IT it = row->blob_list();
132 auto fleft = static_cast<float>(left); // floating version
133 float right; // end of row
134
135 // left=it.data()->bounding_box().left();
136 it.move_to_last();
137 right = it.data()->bounding_box().right();
138 plot_blob_list(to_win, row->blob_list(), colour, ScrollView::BROWN);
139 to_win->Pen(colour);
140 plot_pt = FCOORD(fleft, gradient * left + row->max_y());
141 plot_pt.rotate(rotation);
142 to_win->SetCursor(plot_pt.x(), plot_pt.y());
143 plot_pt = FCOORD(fleft, gradient * left + row->min_y());
144 plot_pt.rotate(rotation);
145 to_win->DrawTo(plot_pt.x(), plot_pt.y());
146 plot_pt = FCOORD(fleft, gradient * left + row->parallel_c());
147 plot_pt.rotate(rotation);
148 to_win->SetCursor(plot_pt.x(), plot_pt.y());
149 plot_pt = FCOORD(right, gradient * right + row->parallel_c());
150 plot_pt.rotate(rotation);
151 to_win->DrawTo(plot_pt.x(), plot_pt.y());
152 }
153
154 /**********************************************************************
155 * draw_occupation
156 *
157 * Draw the row occupation with points above the threshold in white
158 * and points below the threshold in black.
159 **********************************************************************/
160
draw_occupation(int32_t xleft,int32_t ybottom,int32_t min_y,int32_t max_y,int32_t occupation[],int32_t thresholds[])161 void draw_occupation( // draw projection
162 int32_t xleft, // edge of block
163 int32_t ybottom, // bottom of block
164 int32_t min_y, // coordinate limits
165 int32_t max_y, int32_t occupation[], // projection counts
166 int32_t thresholds[] // for drop out
167 ) {
168 int32_t line_index; // pixel coord
169 ScrollView::Color colour; // of histogram
170 auto fleft = static_cast<float>(xleft); // float version
171
172 colour = ScrollView::WHITE;
173 to_win->Pen(colour);
174 to_win->SetCursor(fleft, static_cast<float>(ybottom));
175 for (line_index = min_y; line_index <= max_y; line_index++) {
176 if (occupation[line_index - min_y] < thresholds[line_index - min_y]) {
177 if (colour != ScrollView::BLUE) {
178 colour = ScrollView::BLUE;
179 to_win->Pen(colour);
180 }
181 } else {
182 if (colour != ScrollView::WHITE) {
183 colour = ScrollView::WHITE;
184 to_win->Pen(colour);
185 }
186 }
187 to_win->DrawTo(fleft + occupation[line_index - min_y] / 10.0, static_cast<float>(line_index));
188 }
189 colour = ScrollView::STEEL_BLUE;
190 to_win->Pen(colour);
191 to_win->SetCursor(fleft, static_cast<float>(ybottom));
192 for (line_index = min_y; line_index <= max_y; line_index++) {
193 to_win->DrawTo(fleft + thresholds[line_index - min_y] / 10.0, static_cast<float>(line_index));
194 }
195 }
196
197 /**********************************************************************
198 * draw_meanlines
199 *
200 * Draw the meanlines of the given block in the given colour.
201 **********************************************************************/
202
draw_meanlines(TO_BLOCK * block,float gradient,int32_t left,ScrollView::Color colour,FCOORD rotation)203 void draw_meanlines( // draw a block
204 TO_BLOCK *block, // block to draw
205 float gradient, // gradients of lines
206 int32_t left, // edge of block
207 ScrollView::Color colour, // colour to draw in
208 FCOORD rotation // rotation for line
209 ) {
210 FCOORD plot_pt; // point to plot
211 // rows
212 TO_ROW_IT row_it = block->get_rows();
213 TO_ROW *row; // current row
214 BLOBNBOX_IT blob_it; // blobs
215 float right; // end of row
216 to_win->Pen(colour);
217 for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {
218 row = row_it.data();
219 blob_it.set_to_list(row->blob_list());
220 blob_it.move_to_last();
221 right = blob_it.data()->bounding_box().right();
222 plot_pt = FCOORD(static_cast<float>(left), gradient * left + row->parallel_c() + row->xheight);
223 plot_pt.rotate(rotation);
224 to_win->SetCursor(plot_pt.x(), plot_pt.y());
225 plot_pt = FCOORD(right, gradient * right + row->parallel_c() + row->xheight);
226 plot_pt.rotate(rotation);
227 to_win->DrawTo(plot_pt.x(), plot_pt.y());
228 }
229 }
230
231 /**********************************************************************
232 * plot_word_decisions
233 *
234 * Plot a row with words in different colours and fuzzy spaces
235 * highlighted.
236 **********************************************************************/
237
plot_word_decisions(ScrollView * win,int16_t pitch,TO_ROW * row)238 void plot_word_decisions( // draw words
239 ScrollView *win, // window tro draw in
240 int16_t pitch, // of block
241 TO_ROW *row // row to draw
242 ) {
243 ScrollView::Color colour = ScrollView::MAGENTA; // current colour
244 ScrollView::Color rect_colour; // fuzzy colour
245 int32_t prev_x; // end of prev blob
246 int16_t blob_count; // blobs in word
247 BLOBNBOX *blob; // current blob
248 TBOX blob_box; // bounding box
249 // iterator
250 BLOBNBOX_IT blob_it = row->blob_list();
251 BLOBNBOX_IT start_it = blob_it; // word start
252
253 rect_colour = ScrollView::BLACK;
254 prev_x = -INT16_MAX;
255 blob_count = 0;
256 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
257 blob = blob_it.data();
258 blob_box = blob->bounding_box();
259 if (!blob->joined_to_prev() && blob_box.left() - prev_x > row->max_nonspace) {
260 if ((blob_box.left() - prev_x >= row->min_space ||
261 blob_box.left() - prev_x > row->space_threshold) &&
262 blob_count > 0) {
263 if (pitch > 0 && textord_show_fixed_cuts) {
264 plot_fp_cells(win, colour, &start_it, pitch, blob_count, &row->projection,
265 row->projection_left, row->projection_right,
266 row->xheight * textord_projection_scale);
267 }
268 blob_count = 0;
269 start_it = blob_it;
270 }
271 if (colour == ScrollView::MAGENTA) {
272 colour = ScrollView::RED;
273 } else {
274 colour = static_cast<ScrollView::Color>(colour + 1);
275 }
276 if (blob_box.left() - prev_x < row->min_space) {
277 if (blob_box.left() - prev_x > row->space_threshold) {
278 rect_colour = ScrollView::GOLDENROD;
279 } else {
280 rect_colour = ScrollView::CORAL;
281 }
282 // fill_color_index(win, rect_colour);
283 win->Brush(rect_colour);
284 win->Rectangle(prev_x, blob_box.bottom(), blob_box.left(), blob_box.top());
285 }
286 }
287 if (!blob->joined_to_prev()) {
288 prev_x = blob_box.right();
289 }
290 if (blob->cblob() != nullptr) {
291 blob->cblob()->plot(win, colour, colour);
292 }
293 if (!blob->joined_to_prev() && blob->cblob() != nullptr) {
294 blob_count++;
295 }
296 }
297 if (pitch > 0 && textord_show_fixed_cuts && blob_count > 0) {
298 plot_fp_cells(win, colour, &start_it, pitch, blob_count, &row->projection, row->projection_left,
299 row->projection_right, row->xheight * textord_projection_scale);
300 }
301 }
302
303 /**********************************************************************
304 * plot_fp_cells
305 *
306 * Make a list of fixed pitch cuts and draw them.
307 **********************************************************************/
308
plot_fp_cells(ScrollView * win,ScrollView::Color colour,BLOBNBOX_IT * blob_it,int16_t pitch,int16_t blob_count,STATS * projection,int16_t projection_left,int16_t projection_right,float projection_scale)309 void plot_fp_cells( // draw words
310 ScrollView *win, // window tro draw in
311 ScrollView::Color colour, // colour of lines
312 BLOBNBOX_IT *blob_it, // blobs
313 int16_t pitch, // of block
314 int16_t blob_count, // no of real blobs
315 STATS *projection, // vertical
316 int16_t projection_left, // edges //scale factor
317 int16_t projection_right, float projection_scale) {
318 int16_t occupation; // occupied cells
319 TBOX word_box; // bounding box
320 FPSEGPT_LIST seg_list; // list of cuts
321 FPSEGPT_IT seg_it;
322 FPSEGPT *segpt; // current point
323
324 if (pitsync_linear_version) {
325 check_pitch_sync2(blob_it, blob_count, pitch, 2, projection, projection_left, projection_right,
326 projection_scale, occupation, &seg_list, 0, 0);
327 } else {
328 check_pitch_sync(blob_it, blob_count, pitch, 2, projection, &seg_list);
329 }
330 word_box = blob_it->data()->bounding_box();
331 for (; blob_count > 0; blob_count--) {
332 word_box += box_next(blob_it);
333 }
334 seg_it.set_to_list(&seg_list);
335 for (seg_it.mark_cycle_pt(); !seg_it.cycled_list(); seg_it.forward()) {
336 segpt = seg_it.data();
337 if (segpt->faked) {
338 colour = ScrollView::WHITE;
339 win->Pen(colour);
340 } else {
341 win->Pen(colour);
342 }
343 win->Line(segpt->position(), word_box.bottom(), segpt->position(), word_box.top());
344 }
345 }
346
347 /**********************************************************************
348 * plot_fp_cells2
349 *
350 * Make a list of fixed pitch cuts and draw them.
351 **********************************************************************/
352
plot_fp_cells2(ScrollView * win,ScrollView::Color colour,TO_ROW * row,FPSEGPT_LIST * seg_list)353 void plot_fp_cells2( // draw words
354 ScrollView *win, // window tro draw in
355 ScrollView::Color colour, // colour of lines
356 TO_ROW *row, // for location
357 FPSEGPT_LIST *seg_list // segments to plot
358 ) {
359 TBOX word_box; // bounding box
360 FPSEGPT_IT seg_it = seg_list;
361 // blobs in row
362 BLOBNBOX_IT blob_it = row->blob_list();
363 FPSEGPT *segpt; // current point
364
365 word_box = blob_it.data()->bounding_box();
366 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();) {
367 word_box += box_next(&blob_it);
368 }
369 for (seg_it.mark_cycle_pt(); !seg_it.cycled_list(); seg_it.forward()) {
370 segpt = seg_it.data();
371 if (segpt->faked) {
372 colour = ScrollView::WHITE;
373 win->Pen(colour);
374 } else {
375 win->Pen(colour);
376 }
377 win->Line(segpt->position(), word_box.bottom(), segpt->position(), word_box.top());
378 }
379 }
380
381 /**********************************************************************
382 * plot_row_cells
383 *
384 * Make a list of fixed pitch cuts and draw them.
385 **********************************************************************/
386
plot_row_cells(ScrollView * win,ScrollView::Color colour,TO_ROW * row,float xshift,ICOORDELT_LIST * cells)387 void plot_row_cells( // draw words
388 ScrollView *win, // window tro draw in
389 ScrollView::Color colour, // colour of lines
390 TO_ROW *row, // for location
391 float xshift, // amount of shift
392 ICOORDELT_LIST *cells // cells to draw
393 ) {
394 TBOX word_box; // bounding box
395 ICOORDELT_IT cell_it = cells;
396 // blobs in row
397 BLOBNBOX_IT blob_it = row->blob_list();
398 ICOORDELT *cell; // current cell
399
400 word_box = blob_it.data()->bounding_box();
401 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();) {
402 word_box += box_next(&blob_it);
403 }
404 win->Pen(colour);
405 for (cell_it.mark_cycle_pt(); !cell_it.cycled_list(); cell_it.forward()) {
406 cell = cell_it.data();
407 win->Line(cell->x() + xshift, word_box.bottom(), cell->x() + xshift, word_box.top());
408 }
409 }
410
411 #endif // !GRAPHICS_DISABLED
412
413 } // namespace tesseract
414