26#include "config_auto.h"
68 TPOINT b0a1, b0a0, a1b1, b0b1, a1a0;
81 int b0a1xb0b1 = b0a1.
cross(b0b1);
82 int b0b1xb0a0 = b0b1.
cross(b0a0);
83 int a1b1xa1a0 = a1b1.
cross(a1a0);
86 int a1a0xa1b0 = -a1a0.
cross(b0a1);
88 return ((b0a1xb0b1 > 0 && b0b1xb0a0 > 0) ||
89 (b0a1xb0b1 < 0 && b0b1xb0a0 < 0)) &&
90 ((a1b1xa1a0 > 0 && a1a0xa1b0 > 0) || (a1b1xa1a0 < 0 && a1a0xa1b0 < 0));
96 result->loop = outline;
108 }
while (pt != outline);
110 result->SetupFromPos();
121 if (src.
loop !=
nullptr) {
126 newpt =
new EDGEPT(*srcpt);
127 if (prevpt ==
nullptr) {
130 newpt->
prev = prevpt;
131 prevpt->
next = newpt;
135 }
while (srcpt != src.
loop);
143 if (
loop ==
nullptr)
return;
149 this_edge = next_edge;
150 }
while (this_edge !=
loop);
160 }
while (pt !=
loop);
168 int tmp =
static_cast<int>(
169 floor(pt->
pos.
x * rot.
x() - pt->
pos.
y * rot.
y() + 0.5));
170 pt->
pos.
y =
static_cast<int>(
171 floor(pt->
pos.
y * rot.
x() + pt->
pos.
x * rot.
y() + 0.5));
174 }
while (pt !=
loop);
182 pt->
pos.
x += vec.
x();
183 pt->
pos.
y += vec.
y();
185 }
while (pt !=
loop);
193 pt->
pos.
x =
static_cast<int>(floor(pt->
pos.
x * factor + 0.5));
194 pt->
pos.
y =
static_cast<int>(floor(pt->
pos.
y * factor + 0.5));
196 }
while (pt !=
loop);
207 }
while (pt !=
loop);
214 int minx = INT32_MAX;
215 int miny = INT32_MAX;
216 int maxx = -INT32_MAX;
217 int maxy = -INT32_MAX;
224 if (this_edge->
pos.
x < minx) minx = this_edge->
pos.
x;
225 if (this_edge->
pos.
y < miny) miny = this_edge->
pos.
y;
226 if (this_edge->
pos.
x > maxx) maxx = this_edge->
pos.
x;
227 if (this_edge->
pos.
y > maxy) maxy = this_edge->
pos.
y;
229 this_edge = this_edge->
next;
230 }
while (this_edge !=
loop);
250 int product = this_edge->
pos.
cross(vec);
253 this_edge = this_edge->
next;
254 }
while (this_edge !=
loop);
261#ifndef GRAPHICS_DISABLED
265 window->
Pen(child_color);
277 }
while (pt !=
loop);
303static TESSLINE** ApproximateOutlineList(
bool allow_detailed_fx,
304 C_OUTLINE_LIST* outlines,
306 C_OUTLINE_IT ol_it(outlines);
307 for (ol_it.mark_cycle_pt(); !ol_it.cycled_list(); ol_it.forward()) {
313 tail = &tessline->
next;
315 if (!outline->
child()->empty()) {
316 tail = ApproximateOutlineList(allow_detailed_fx, outline->
child(),
true,
328 auto* tblob =
new TBLOB;
329 ApproximateOutlineList(allow_detailed_fx, src->
out_list(),
false,
336 auto* blob =
new TBLOB;
337 blob->denorm_ = src.denorm_;
347 TBLOB* rotated_blob =
nullptr;
350 if (denorm_.
block() !=
nullptr &&
353 int x_middle = (box.
left() + box.
right()) / 2;
354 int y_middle = (box.
top() + box.
bottom()) / 2;
355 rotated_blob =
new TBLOB(*
this);
361 (rotation.
y() > 0 ? x_middle - box.
left() : box.
right() - x_middle);
362 rotated_blob->
Normalize(
nullptr, &rotation, &denorm_, x_middle, y_middle,
363 1.0f, 1.0f, 0.0f, target_y, denorm_.
inverse(),
374 srcline = srcline->
next) {
375 auto* new_outline =
new TESSLINE(*srcline);
379 prev_outline->
next = new_outline;
380 prev_outline = new_outline;
382 denorm_ = src.denorm_;
398 const DENORM* predecessor,
float x_origin,
float y_origin,
399 float x_scale,
float y_scale,
float final_xshift,
400 float final_yshift,
bool inverse, Pix* pix) {
402 x_scale, y_scale, final_xshift, final_yshift);
413 for (
TESSLINE* outline =
outlines; outline !=
nullptr; outline = outline->next) {
414 outline->Normalize(denorm_);
424 outline = outline->next) {
425 outline->Rotate(rotation);
432 outline = outline->next) {
440 outline = outline->next) {
441 outline->Scale(factor);
448 outline = outline->next) {
449 outline->ComputeBoundingBox();
457 outline = outline->next)
472 for (outline = outline->
next; outline !=
nullptr; outline = outline->
next) {
482 outline = outline->next) {
484 for (
TESSLINE* other_outline = outline->next; other_outline !=
nullptr;
485 last_outline = other_outline, other_outline = other_outline->
next) {
486 if (outline->SameBox(*other_outline)) {
487 last_outline->
next = other_outline->
next;
489 other_outline->
loop =
nullptr;
490 delete other_outline;
491 other_outline = last_outline;
493 outline->is_hole =
false;
509#ifndef GRAPHICS_DISABLED
513 outline = outline->next)
514 outline->
plot(window, color, child_color);
527 CollectEdges(box,
nullptr, &accumulator,
nullptr,
nullptr);
532 if (x2nd < 1.0) x2nd = 1.0;
533 if (y2nd < 1.0) y2nd = 1.0;
534 second_moments->
set_x(x2nd);
535 second_moments->
set_y(y2nd);
536 return accumulator.
count();
543 *precise_box =
TBOX();
544 CollectEdges(box, precise_box,
nullptr,
nullptr,
nullptr);
562 y_coords->init_to_size(box.
width(), empty);
563 CollectEdges(box,
nullptr,
nullptr, x_coords, y_coords);
565 for (
int i = 0; i < x_coords->size(); ++i) (*x_coords)[i].sort();
566 for (
int i = 0; i < y_coords->size(); ++i) (*y_coords)[i].sort();
571static void SegmentLLSQ(
const FCOORD& pt1,
const FCOORD& pt2,
579 if (xstart == xend && ystart == yend)
return;
580 double weight = step.length() / (xend - xstart + yend - ystart);
582 for (
int x = xstart; x < xend; ++x) {
583 double y = pt1.
y() + step.y() * (x + 0.5 - pt1.
x()) / step.x();
584 accumulator->
add(x + 0.5, y, weight);
587 for (
int y = ystart; y < yend; ++y) {
588 double x = pt1.
x() + step.x() * (y + 0.5 - pt1.
y()) / step.y();
589 accumulator->
add(x, y + 0.5, weight);
598static void SegmentCoords(
const FCOORD& pt1,
const FCOORD& pt2,
int x_limit,
607 for (
int x = start; x < end; ++x) {
608 int y =
IntCastRounded(pt1.
y() + step.y() * (x + 0.5 - pt1.
x()) / step.x());
609 (*y_coords)[x].push_back(y);
613 for (
int y = start; y < end; ++y) {
614 int x =
IntCastRounded(pt1.
x() + step.x() * (y + 0.5 - pt1.
y()) / step.y());
615 (*x_coords)[y].push_back(x);
632 TBOX point(x1, std::min(y1, y2), x2, std::max(y1, y2));
642 TBOX point(std::min(x1, x2), y1, std::max(x1, x2), y2);
657static void CollectEdgesOfRun(
const EDGEPT* startpt,
const EDGEPT* lastpt,
659 TBOX* bounding_box,
LLSQ* accumulator,
663 int x_limit = box.
width() - 1;
664 int y_limit = box.
height() - 1;
665 if (outline !=
nullptr) {
680 if (end_index <= start_index) end_index += step_length;
692 prev_normed -= origin;
693 for (
int index = start_index; index < end_index; ++index) {
694 ICOORD step = outline->
step(index % step_length);
707 pos_normed -= origin;
709 if (bounding_box !=
nullptr) {
710 SegmentBBox(pos_normed, prev_normed, bounding_box);
712 if (accumulator !=
nullptr) {
713 SegmentLLSQ(pos_normed, prev_normed, accumulator);
715 if (x_coords !=
nullptr && y_coords !=
nullptr) {
716 SegmentCoords(pos_normed, prev_normed, x_limit, y_limit, x_coords,
719 prev_normed = pos_normed;
726 const EDGEPT* pt = startpt;
731 if (bounding_box !=
nullptr) {
732 SegmentBBox(next_pos, pos, bounding_box);
734 if (accumulator !=
nullptr) {
735 SegmentLLSQ(next_pos, pos, accumulator);
737 if (x_coords !=
nullptr && y_coords !=
nullptr) {
738 SegmentCoords(next_pos, pos, x_limit, y_limit, x_coords, y_coords);
740 }
while ((pt = pt->
next) != endpt);
749void TBLOB::CollectEdges(
const TBOX& box,
TBOX* bounding_box,
LLSQ* llsq,
755 EDGEPT* loop_pt = ol->FindBestStartPt();
757 if (pt ==
nullptr)
continue;
763 last_pt = last_pt->
next;
764 }
while (last_pt != loop_pt && !last_pt->
IsHidden() &&
766 last_pt = last_pt->
prev;
767 CollectEdgesOfRun(pt, last_pt, denorm_, box,
bounding_box, llsq, x_coords,
770 }
while ((pt = pt->
next) != loop_pt);
777 auto* tessword =
new TWERD;
780 for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
781 C_BLOB* blob = b_it.data();
783 tessword->blobs.push_back(tblob);
791 bool inverse,
float x_height,
float baseline_shift,
795 if (norm_box !=
nullptr) word_box = *norm_box;
796 float word_middle = (word_box.
left() + word_box.
right()) / 2.0f;
797 float input_y_offset = 0.0f;
800 if (row ==
nullptr) {
801 word_middle = word_box.
left();
802 input_y_offset = word_box.
bottom();
803 final_y_offset = 0.0f;
805 input_y_offset = row->
base_line(word_middle) + baseline_shift;
810 float mid_x = (blob_box.
left() + blob_box.
right()) / 2.0f;
812 float blob_scale = scale;
816 scale, scale * 1.5f);
817 }
else if (row !=
nullptr) {
827 blob_scale, 0.0f, final_y_offset, inverse, pix);
829 if (word_denorm !=
nullptr) {
831 input_y_offset, scale, scale, 0.0f,
842 for (
int b = 0; b < src.
blobs.
size(); ++b) {
857 blobs[b]->ComputeBoundingBoxes();
875 for (
int i = start + 1; i < end && i <
blobs.
size(); ++i) {
878 if (outline ==
nullptr) {
880 outline =
blobs[start]->outlines;
882 while (outline->
next !=
nullptr) outline = outline->
next;
891 for (
int i = start + 1; i < end && start + 1 <
blobs.
size(); ++i) {
896#ifndef GRAPHICS_DISABLED
920 outline1 = outline1->
next) {
921 if (outline1->is_hole)
continue;
923 static_cast<int16_t
>((outline1->topleft.x + outline1->botright.x) / 2),
924 static_cast<int16_t
>((outline1->topleft.y + outline1->botright.y) / 2));
925 int mid_prod1 = mid_pt1.
cross(vertical);
926 int min_prod1, max_prod1;
927 outline1->MinMaxCrossProduct(vertical, &min_prod1, &max_prod1);
928 for (
TESSLINE* outline2 = outline1->
next; outline2 !=
nullptr;
929 outline2 = outline2->
next) {
930 if (outline2->is_hole)
continue;
931 TPOINT mid_pt2(
static_cast<int16_t
>(
932 (outline2->topleft.x + outline2->botright.x) / 2),
933 static_cast<int16_t
>(
934 (outline2->topleft.y + outline2->botright.y) / 2));
935 int mid_prod2 = mid_pt2.
cross(vertical);
936 int min_prod2, max_prod2;
937 outline2->MinMaxCrossProduct(vertical, &min_prod2, &max_prod2);
938 int mid_gap = abs(mid_prod2 - mid_prod1);
940 std::min(max_prod1, max_prod2) - std::max(min_prod1, min_prod2);
941 if (mid_gap - overlap / 4 > max_gap) {
942 max_gap = mid_gap - overlap / 4;
944 *location += mid_pt2;
951 return max_gap > vertical.
y;
971 int location_prod = location.
cross(vertical);
973 while (outline !=
nullptr) {
977 int mid_prod = mid_pt.
cross(vertical);
978 if (mid_prod < location_prod) {
981 outline1->
next = outline;
988 outline2->
next = outline;
993 outline = outline->
next;
996 if (outline1) outline1->
next =
nullptr;
997 if (outline2) outline2->
next =
nullptr;
const TPOINT kDivisibleVerticalUpright(0, 1)
const TPOINT kDivisibleVerticalItalic(1, 5)
void divide_blobs(TBLOB *blob, TBLOB *other_blob, bool italic_blob, const TPOINT &location)
bool divisible_blob(TBLOB *blob, bool italic_blob, TPOINT *location)
const int kBlnBaselineOffset
TESSLINE * ApproximateOutline(bool allow_detailed_fx, C_OUTLINE *c_outline)
@ W_SCRIPT_IS_LATIN
Special case latin for y. splitting.
#define CLISTIZE(CLASSNAME)
void UpdateRange(const T1 &x, T2 *lower_bound, T2 *upper_bound)
int IntCastRounded(double x)
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
void init_to_size(int size, const T &t)
void delete_data_pointers()
int cross(const TPOINT &other) const
void Move(const ICOORD vec)
EDGEPT * FindBestStartPt() const
void Rotate(const FCOORD rotation)
void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color)
static TESSLINE * BuildFromOutlineList(EDGEPT *outline)
void MinMaxCrossProduct(const TPOINT vec, int *min_xp, int *max_xp) const
void ComputeBoundingBox()
void CopyFrom(const TESSLINE &src)
TBOX bounding_box() const
void Normalize(const DENORM &denorm)
void CorrectBlobOrder(TBLOB *next)
void Move(const ICOORD vec)
TBOX bounding_box() const
void GetEdgeCoords(const TBOX &box, GenericVector< GenericVector< int > > *x_coords, GenericVector< GenericVector< int > > *y_coords) const
int ComputeMoments(FCOORD *center, FCOORD *second_moments) const
void Rotate(const FCOORD rotation)
void Normalize(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, float final_yshift, bool inverse, Pix *pix)
void EliminateDuplicateOutlines()
void ComputeBoundingBoxes()
void CopyFrom(const TBLOB &src)
static TBLOB * PolygonalCopy(bool allow_detailed_fx, C_BLOB *src)
void GetPreciseBoundingBox(TBOX *precise_box) const
TBLOB * ClassifyNormalizeIfNeeded() const
static TBLOB * ShallowCopy(const TBLOB &src)
void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color)
void MergeBlobs(int start, int end)
void BLNormalize(const BLOCK *block, const ROW *row, Pix *pix, bool inverse, float x_height, float baseline_shift, bool numeric_mode, tesseract::OcrEngineMode hint, const TBOX *norm_box, DENORM *word_denorm)
GenericVector< TBLOB * > blobs
void CopyFrom(const TWERD &src)
void ComputeBoundingBoxes()
TBOX bounding_box() const
static TWERD * PolygonalCopy(bool allow_detailed_fx, WERD *src)
void plot(ScrollView *window)
ICOORD step(int index) const
void plot(ScrollView *window, ScrollView::Color colour) const
int edge_strength_at_index(int index) const
ICOORD position_at_index(int index) const
FCOORD sub_pixel_pos_at_index(const ICOORD &pos, int index) const
int32_t pathlength() const
double y_variance() const
double x_variance() const
void add(double x, double y)
FCOORD mean_point() const
void LocalNormBlob(TBLOB *blob) const
void set_inverse(bool value)
const DENORM * RootDenorm() const
void NormTransform(const DENORM *first_norm, const TPOINT &pt, TPOINT *transformed) const
void LocalNormTransform(const TPOINT &pt, TPOINT *transformed) const
void SetupNormalization(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, float final_yshift)
const BLOCK * block() const
FCOORD classify_rotation() const
float base_line(float xpos) const
int16_t y() const
access_function
int16_t x() const
access function
void set_y(float yin)
rewrite function
void set_x(float xin)
rewrite function
const ICOORD & botleft() const
void move(const ICOORD vec)
C_OUTLINE_LIST * out_list()
static ScrollView::Color NextColor(ScrollView::Color colour)
C_BLOB_LIST * cblob_list()
bool flag(WERD_FLAGS mask) const
void DrawTo(int x, int y)
void SetCursor(int x, int y)