Return true if this vector is the same side, overlaps, and close enough to the other to be merged.
| 392 | // Return true if this vector is the same side, overlaps, and close |
| 393 | // enough to the other to be merged. |
| 394 | bool TabVector::SimilarTo(const ICOORD& vertical, |
| 395 | const TabVector& other, BlobGrid* grid) const { |
| 396 | if ((IsRightTab() && other.IsRightTab()) || |
| 397 | (IsLeftTab() && other.IsLeftTab())) { |
| 398 | // If they don't overlap, at least in extensions, then there is no chance. |
| 399 | if (ExtendedOverlap(other.extended_ymax_, other.extended_ymin_) < 0) |
| 400 | return false; |
| 401 | // A fast approximation to the scale factor of the sort_key_. |
| 402 | int v_scale = abs(vertical.y()); |
| 403 | if (v_scale == 0) |
| 404 | v_scale = 1; |
| 405 | // If they are close enough, then OK. |
| 406 | if (sort_key_ + kSimilarVectorDist * v_scale >= other.sort_key_ && |
| 407 | sort_key_ - kSimilarVectorDist * v_scale <= other.sort_key_) |
| 408 | return true; |
| 409 | // Ragged tabs get a bigger threshold. |
| 410 | if (!IsRagged() || !other.IsRagged() || |
| 411 | sort_key_ + kSimilarRaggedDist * v_scale < other.sort_key_ || |
| 412 | sort_key_ - kSimilarRaggedDist * v_scale > other.sort_key_) |
| 413 | return false; |
| 414 | if (grid == NULL) { |
| 415 | // There is nothing else to test! |
| 416 | return true; |
| 417 | } |
| 418 | // If there is nothing in the rectangle between the vector that is going to |
| 419 | // move, and the place it is moving to, then they can be merged. |
| 420 | // Setup a vertical search for any blob. |
| 421 | const TabVector* mover = (IsRightTab() && |
| 422 | sort_key_ < other.sort_key_) ? this : &other; |
| 423 | int top_y = mover->endpt_.y(); |
| 424 | int bottom_y = mover->startpt_.y(); |
| 425 | int left = MIN(mover->XAtY(top_y), mover->XAtY(bottom_y)); |
| 426 | int right = MAX(mover->XAtY(top_y), mover->XAtY(bottom_y)); |
| 427 | int shift = abs(sort_key_ - other.sort_key_) / v_scale; |
| 428 | if (IsRightTab()) { |
| 429 | right += shift; |
| 430 | } else { |
| 431 | left -= shift; |
| 432 | } |
| 433 | |
| 434 | GridSearch<BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT> vsearch(grid); |
| 435 | vsearch.StartVerticalSearch(left, right, top_y); |
| 436 | BLOBNBOX* blob; |
| 437 | while ((blob = vsearch.NextVerticalSearch(true)) != NULL) { |
| 438 | const TBOX& box = blob->bounding_box(); |
| 439 | if (box.top() > bottom_y) |
| 440 | return true; // Nothing found. |
| 441 | if (box.bottom() < top_y) |
| 442 | continue; // Doesn't overlap. |
| 443 | int left_at_box = XAtY(box.bottom()); |
| 444 | int right_at_box = left_at_box; |
| 445 | if (IsRightTab()) |
| 446 | right_at_box += shift; |
| 447 | else |
| 448 | left_at_box -= shift; |
| 449 | if (MIN(right_at_box, box.right()) > MAX(left_at_box, box.left())) |
| 450 | return false; |
| 451 | } |
no test coverage detected