235 {
236 int ext_start_y, ext_end_y;
237 BLOBNBOX_CLIST good_points;
238
239 TBOX box = bbox->bounding_box();
241 int pt_count = AlignTabs(align_params, false, bbox, &good_points, &ext_end_y);
242 pt_count += AlignTabs(align_params, true, bbox, &good_points, &ext_start_y);
243 BLOBNBOX_C_IT it(&good_points);
244 it.move_to_last();
245 box = it.data()->bounding_box();
246 int end_y = box.top();
247 int end_x = align_params.right_tab ? box.right() : box.left();
248 it.move_to_first();
249 box = it.data()->bounding_box();
250 int start_x = align_params.right_tab ? box.right() : box.left();
251 int start_y = box.bottom();
252
253
254
255
256
257 bool at_least_2_crossings = AtLeast2LineCrossings(&good_points);
258 if ((pt_count >= align_params.min_points && end_y - start_y >= align_params.min_length &&
259 (align_params.ragged || end_y - start_y >= abs(end_x - start_x) *
kMinTabGradient)) ||
260 at_least_2_crossings) {
261 int confirmed_points = 0;
262
263 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
264 bbox = it.data();
265 if (align_params.right_tab) {
266 if (bbox->right_tab_type() == align_params.confirmed_type) {
267 ++confirmed_points;
268 }
269 } else {
270 if (bbox->left_tab_type() == align_params.confirmed_type) {
271 ++confirmed_points;
272 }
273 }
274 }
275
276 if (!align_params.ragged || confirmed_points + confirmed_points < pt_count) {
277 const TBOX &box = bbox->bounding_box();
278 if (debug) {
279 tprintf(
"Confirming tab vector of %d pts starting at %d,%d\n", pt_count, box.left(),
280 box.bottom());
281 }
282
283 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
284 bbox = it.data();
285 if (align_params.right_tab) {
286 bbox->set_right_tab_type(align_params.confirmed_type);
287 } else {
288 bbox->set_left_tab_type(align_params.confirmed_type);
289 }
290 if (debug) {
291 bbox->bounding_box().print();
292 }
293 }
294
295 TabVector *result =
297 ext_end_y, &good_points, vertical_x, vertical_y);
298 result->set_intersects_other_lines(at_least_2_crossings);
299 if (debug) {
300 tprintf(
"Box was %d, %d\n", box.left(), box.bottom());
301 result->Print("After fitting");
302 }
303 return result;
304 } else if (debug) {
305 tprintf(
"Ragged tab used too many used points: %d out of %d\n", confirmed_points, pt_count);
306 }
307 } else if (debug) {
309 "Tab vector failed basic tests: pt count %d vs min %d, "
310 "length %d vs min %d, min grad %g\n",
311 pt_count, align_params.min_points, end_y - start_y, align_params.min_length,
313 }
314 return nullptr;
315}
void tprintf(const char *format,...)
const double kMinTabGradient
static bool WithinTestRegion(int detail_level, int x, int y)
static TabVector * FitVector(TabAlignment alignment, ICOORD vertical, int extended_start_y, int extended_end_y, BLOBNBOX_CLIST *good_points, int *vertical_x, int *vertical_y)