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