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
polyblk.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 * File: polyblk.c (Formerly poly_block.c)
3 * Description: Polygonal blocks
4 * Author: Sheelagh Lloyd?
5 * Created:
6 *
7 * (C) Copyright 1993, 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 <ctype.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include "elst.h"
25 #include "polyblk.h"
26
27 // Include automatically generated configuration file if running autoconf.
28 #ifdef HAVE_CONFIG_H
29 #include "config_auto.h"
30 #endif
31
32 #include "hpddef.h" // must be last (handpd.dll)
33
34 #define PBLOCK_LABEL_SIZE 150
35 #define INTERSECTING MAX_INT16
36
37 int lessthan(const void *first, const void *second);
38
39 POLY_BLOCK::POLY_BLOCK(ICOORDELT_LIST *points, PolyBlockType t) {
40 ICOORDELT_IT v = &vertices;
41
42 vertices.clear();
43 v.move_to_first();
44 v.add_list_before(points);
45 compute_bb();
46 type = t;
47 }
48
49 // Initialize from box coordinates.
50 POLY_BLOCK::POLY_BLOCK(const TBOX& box, PolyBlockType t) {
51 vertices.clear();
52 ICOORDELT_IT v = &vertices;
53 v.move_to_first();
54 v.add_to_end(new ICOORDELT(box.left(), box.top()));
55 v.add_to_end(new ICOORDELT(box.left(), box.bottom()));
56 v.add_to_end(new ICOORDELT(box.right(), box.bottom()));
57 v.add_to_end(new ICOORDELT(box.right(), box.top()));
58 compute_bb();
59 type = t;
60 }
61
68 void POLY_BLOCK::compute_bb() { //constructor
69 ICOORD ibl, itr; //integer bb
70 ICOORD botleft; //bounding box
71 ICOORD topright;
72 ICOORD pos; //current pos;
73 ICOORDELT_IT pts = &vertices; //iterator
74
75 botleft = *pts.data ();
76 topright = botleft;
77 do {
78 pos = *pts.data ();
79 if (pos.x () < botleft.x ())
80 //get bounding box
81 botleft = ICOORD (pos.x (), botleft.y ());
82 if (pos.y () < botleft.y ())
83 botleft = ICOORD (botleft.x (), pos.y ());
84 if (pos.x () > topright.x ())
85 topright = ICOORD (pos.x (), topright.y ());
86 if (pos.y () > topright.y ())
87 topright = ICOORD (topright.x (), pos.y ());
88 pts.forward ();
89 }
90 while (!pts.at_first ());
91 ibl = ICOORD (botleft.x (), botleft.y ());
92 itr = ICOORD (topright.x (), topright.y ());
93 box = TBOX (ibl, itr);
94 }
95
96
104 inT16 POLY_BLOCK::winding_number(const ICOORD &point) {
105 inT16 count; //winding count
106 ICOORD pt; //current point
107 ICOORD vec; //point to current point
108 ICOORD vvec; //current point to next point
109 inT32 cross; //cross product
110 ICOORDELT_IT it = &vertices; //iterator
111
112 count = 0;
113 do {
114 pt = *it.data ();
115 vec = pt - point;
116 vvec = *it.data_relative (1) - pt;
117 //crossing the line
118 if (vec.y () <= 0 && vec.y () + vvec.y () > 0) {
119 cross = vec * vvec; //cross product
120 if (cross > 0)
121 count++; //crossing right half
122 else if (cross == 0)
123 return INTERSECTING; //going through point
124 }
125 else if (vec.y () > 0 && vec.y () + vvec.y () <= 0) {
126 cross = vec * vvec;
127 if (cross < 0)
128 count--; //crossing back
129 else if (cross == 0)
130 return INTERSECTING; //illegal
131 }
132 else if (vec.y () == 0 && vec.x () == 0)
133 return INTERSECTING;
134 it.forward ();
135 }
136 while (!it.at_first ());
137 return count; //winding number
138 }
139
140
142 bool POLY_BLOCK::contains(POLY_BLOCK *other) {
143 inT16 count; // winding count
144 ICOORDELT_IT it = &vertices; // iterator
145 ICOORD vertex;
146
147 if (!box.overlap (*(other->bounding_box ())))
148 return false; // can't be contained
149
150 /* check that no vertex of this is inside other */
151
152 do {
153 vertex = *it.data ();
154 // get winding number
155 count = other->winding_number (vertex);
156 if (count != INTERSECTING)
157 if (count != 0)
158 return false;
159 it.forward ();
160 }
161 while (!it.at_first ());
162
163 /* check that all vertices of other are inside this */
164
165 //switch lists
166 it.set_to_list (other->points ());
167 do {
168 vertex = *it.data ();
169 //try other way round
170 count = winding_number (vertex);
171 if (count != INTERSECTING)
172 if (count == 0)
173 return false;
174 it.forward ();
175 }
176 while (!it.at_first ());
177 return true;
178 }
179
180
188 void POLY_BLOCK::rotate(FCOORD rotation) {
189 FCOORD pos; //current pos;
190 ICOORDELT *pt; //current point
191 ICOORDELT_IT pts = &vertices; //iterator
192
193 do {
194 pt = pts.data ();
195 pos.set_x (pt->x ());
196 pos.set_y (pt->y ());
197 pos.rotate (rotation);
198 pt->set_x ((inT16) (floor (pos.x () + 0.5)));
199 pt->set_y ((inT16) (floor (pos.y () + 0.5)));
200 pts.forward ();
201 }
202 while (!pts.at_first ());
203 compute_bb();
204 }
205
212 void POLY_BLOCK::reflect_in_y_axis() {
213 ICOORDELT *pt; // current point
214 ICOORDELT_IT pts = &vertices; // Iterator.
215
216 do {
217 pt = pts.data();
218 pt->set_x(-pt->x());
219 pts.forward();
220 }
221 while (!pts.at_first());
222 compute_bb();
223 }
224
225
233 void POLY_BLOCK::move(ICOORD shift) {
234 ICOORDELT *pt; //current point
235 ICOORDELT_IT pts = &vertices; //iterator
236
237 do {
238 pt = pts.data ();
239 *pt += shift;
240 pts.forward ();
241 }
242 while (!pts.at_first ());
243 compute_bb();
244 }
245
246
247 #ifndef GRAPHICS_DISABLED
248 void POLY_BLOCK::plot(ScrollView* window, inT32 num) {
249 ICOORDELT_IT v = &vertices;
250
251 window->Pen(ColorForPolyBlockType(type));
252
253 v.move_to_first ();
254
255 if (num > 0) {
256 window->TextAttributes("Times", 80, false, false, false);
257 char temp_buff[34];
258 #ifdef __UNIX__
259 sprintf(temp_buff, INT32FORMAT, num);
260 #else
261 ltoa (num, temp_buff, 10);
262 #endif
263 window->Text(v.data ()->x (), v.data ()->y (), temp_buff);
264 }
265
266 window->SetCursor(v.data ()->x (), v.data ()->y ());
267 for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) {
268 window->DrawTo(v.data ()->x (), v.data ()->y ());
269 }
270 v.move_to_first ();
271 window->DrawTo(v.data ()->x (), v.data ()->y ());
272 }
273
274
275 void POLY_BLOCK::fill(ScrollView* window, ScrollView::Color colour) {
276 inT16 y;
277 inT16 width;
278 PB_LINE_IT *lines;
279 ICOORDELT_LIST *segments;
280 ICOORDELT_IT s_it;
281
282 lines = new PB_LINE_IT (this);
283 window->Pen(colour);
284
285 for (y = this->bounding_box ()->bottom ();
286 y <= this->bounding_box ()->top (); y++) {
287 segments = lines->get_line (y);
288 if (!segments->empty ()) {
289 s_it.set_to_list (segments);
290 for (s_it.mark_cycle_pt (); !s_it.cycled_list (); s_it.forward ()) {
291 // Note different use of ICOORDELT, x coord is x coord of pixel
292 // at the start of line segment, y coord is length of line segment
293 // Last pixel is start pixel + length.
294 width = s_it.data ()->y ();
295 window->SetCursor(s_it.data ()->x (), y);
296 window->DrawTo(s_it.data ()->x () + (float) width, y);
297 }
298 }
299 }
300 }
301 #endif
302
303
305 bool POLY_BLOCK::overlap(POLY_BLOCK *other) {
306 inT16 count; // winding count
307 ICOORDELT_IT it = &vertices; // iterator
308 ICOORD vertex;
309
310 if (!box.overlap(*(other->bounding_box())))
311 return false; // can't be any overlap.
312
313 /* see if a vertex of this is inside other */
314
315 do {
316 vertex = *it.data ();
317 // get winding number
318 count = other->winding_number (vertex);
319 if (count != INTERSECTING)
320 if (count != 0)
321 return true;
322 it.forward ();
323 }
324 while (!it.at_first ());
325
326 /* see if a vertex of other is inside this */
327
328 // switch lists
329 it.set_to_list (other->points ());
330 do {
331 vertex = *it.data();
332 // try other way round
333 count = winding_number (vertex);
334 if (count != INTERSECTING)
335 if (count != 0)
336 return true;
337 it.forward ();
338 }
339 while (!it.at_first ());
340 return false;
341 }
342
343
344 ICOORDELT_LIST *PB_LINE_IT::get_line(inT16 y) {
345 ICOORDELT_IT v, r;
346 ICOORDELT_LIST *result;
347 ICOORDELT *x, *current, *previous;
348 float fy, fx;
349
350 fy = (float) (y + 0.5);
351 result = new ICOORDELT_LIST ();
352 r.set_to_list (result);
353 v.set_to_list (block->points ());
354
355 for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) {
356 if (((v.data_relative (-1)->y () > y) && (v.data ()->y () <= y))
357 || ((v.data_relative (-1)->y () <= y) && (v.data ()->y () > y))) {
358 previous = v.data_relative (-1);
359 current = v.data ();
360 fx = (float) (0.5 + previous->x () +
361 (current->x () - previous->x ()) * (fy -
362 previous->y ()) /
363 (current->y () - previous->y ()));
364 x = new ICOORDELT ((inT16) fx, 0);
365 r.add_to_end (x);
366 }
367 }
368
369 if (!r.empty ()) {
370 r.sort (lessthan);
371 for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ())
372 x = r.data ();
373 for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ()) {
374 r.data ()->set_y (r.data_relative (1)->x () - r.data ()->x ());
375 r.forward ();
376 delete (r.extract ());
377 }
378 }
379
380 return result;
381 }
382
383
384 int lessthan(const void *first, const void *second) {
385 ICOORDELT *p1 = (*(ICOORDELT **) first);
386 ICOORDELT *p2 = (*(ICOORDELT **) second);
387
388 if (p1->x () < p2->x ())
389 return (-1);
390 else if (p1->x () > p2->x ())
391 return (1);
392 else
393 return (0);
394 }
395
396 #ifndef GRAPHICS_DISABLED
397
398 ScrollView::Color POLY_BLOCK::ColorForPolyBlockType(PolyBlockType type) {
399 // Keep kPBColors in sync with PolyBlockType.
400 const ScrollView::Color kPBColors[PT_COUNT] = {
401 ScrollView::WHITE, // Type is not yet known. Keep as the 1st element.
402 ScrollView::BLUE, // Text that lives inside a column.
403 ScrollView::CYAN, // Text that spans more than one column.
404 ScrollView::MEDIUM_BLUE, // Text that is in a cross-column pull-out region.
405 ScrollView::AQUAMARINE, // Partition belonging to an equation region.
406 ScrollView::SKY_BLUE, // Partition belonging to an inline equation region.
407 ScrollView::MAGENTA, // Partition belonging to a table region.
408 ScrollView::GREEN, // Text-line runs vertically.
409 ScrollView::LIGHT_BLUE, // Text that belongs to an image.
410 ScrollView::RED, // Image that lives inside a column.
411 ScrollView::YELLOW, // Image that spans more than one column.
412 ScrollView::ORANGE, // Image in a cross-column pull-out region.
413 ScrollView::BROWN, // Horizontal Line.
414 ScrollView::DARK_GREEN, // Vertical Line.
415 ScrollView::GREY // Lies outside of any column.
416 };
417 if (type >= 0 && type < PT_COUNT) {
418 return kPBColors[type];
419 }
420 return ScrollView::WHITE;
421 }
422 #endif // GRAPHICS_DISABLED