25 #include "config_auto.h"
67 TPOINT b0a1, b0a0, a1b1, b0b1, a1a0;
80 int b0a1xb0b1 = b0a1.
cross(b0b1);
81 int b0b1xb0a0 = b0b1.
cross(b0a0);
82 int a1b1xa1a0 = a1b1.
cross(a1a0);
85 int a1a0xa1b0 = -a1a0.
cross(b0a1);
87 return ((b0a1xb0b1 > 0 && b0b1xb0a0 > 0) ||
88 (b0a1xb0b1 < 0 && b0b1xb0a0 < 0)) &&
89 ((a1b1xa1a0 > 0 && a1a0xa1b0 > 0) || (a1b1xa1a0 < 0 && a1a0xa1b0 < 0));
95 result->loop = outline;
107 }
while (pt != outline);
109 result->SetupFromPos();
120 if (src.
loop !=
nullptr) {
125 newpt =
new EDGEPT(*srcpt);
126 if (prevpt ==
nullptr) {
129 newpt->
prev = prevpt;
130 prevpt->
next = newpt;
134 }
while (srcpt != src.
loop);
142 if (
loop ==
nullptr)
return;
148 this_edge = next_edge;
149 }
while (this_edge !=
loop);
159 }
while (pt !=
loop);
167 int tmp = static_cast<int>(
168 floor(pt->
pos.
x * rot.
x() - pt->
pos.
y * rot.
y() + 0.5));
169 pt->
pos.
y = static_cast<int>(
170 floor(pt->
pos.
y * rot.
x() + pt->
pos.
x * rot.
y() + 0.5));
173 }
while (pt !=
loop);
181 pt->
pos.
x += vec.
x();
182 pt->
pos.
y += vec.
y();
184 }
while (pt !=
loop);
192 pt->
pos.
x = static_cast<int>(floor(pt->
pos.
x * factor + 0.5));
193 pt->
pos.
y = static_cast<int>(floor(pt->
pos.
y * factor + 0.5));
195 }
while (pt !=
loop);
206 }
while (pt !=
loop);
213 int minx = INT32_MAX;
214 int miny = INT32_MAX;
215 int maxx = -INT32_MAX;
216 int maxy = -INT32_MAX;
223 if (this_edge->
pos.
x < minx) minx = this_edge->
pos.
x;
224 if (this_edge->
pos.
y < miny) miny = this_edge->
pos.
y;
225 if (this_edge->
pos.
x > maxx) maxx = this_edge->
pos.
x;
226 if (this_edge->
pos.
y > maxy) maxy = this_edge->
pos.
y;
228 this_edge = this_edge->
next;
229 }
while (this_edge !=
loop);
249 int product = this_edge->
pos.
cross(vec);
252 this_edge = this_edge->
next;
253 }
while (this_edge !=
loop);
260 #ifndef GRAPHICS_DISABLED
264 window->
Pen(child_color);
276 }
while (pt !=
loop);
278 #endif // GRAPHICS_DISABLED
302 static TESSLINE** ApproximateOutlineList(
bool allow_detailed_fx,
303 C_OUTLINE_LIST* outlines,
305 C_OUTLINE_IT ol_it(outlines);
306 for (ol_it.mark_cycle_pt(); !ol_it.cycled_list(); ol_it.forward()) {
312 tail = &tessline->
next;
314 if (!outline->
child()->empty()) {
315 tail = ApproximateOutlineList(allow_detailed_fx, outline->
child(),
true,
327 auto* tblob =
new TBLOB;
328 ApproximateOutlineList(allow_detailed_fx, src->
out_list(),
false,
335 auto* blob =
new TBLOB;
336 blob->denorm_ = src.denorm_;
346 TBLOB* rotated_blob =
nullptr;
349 if (denorm_.
block() !=
nullptr &&
352 int x_middle = (box.
left() + box.
right()) / 2;
353 int y_middle = (box.
top() + box.
bottom()) / 2;
354 rotated_blob =
new TBLOB(*
this);
360 (rotation.
y() > 0 ? x_middle - box.
left() : box.
right() - x_middle);
361 rotated_blob->
Normalize(
nullptr, &rotation, &denorm_, x_middle, y_middle,
362 1.0f, 1.0f, 0.0f, target_y, denorm_.
inverse(),
373 srcline = srcline->
next) {
374 auto* new_outline =
new TESSLINE(*srcline);
378 prev_outline->
next = new_outline;
379 prev_outline = new_outline;
381 denorm_ = src.denorm_;
397 const DENORM* predecessor,
float x_origin,
float y_origin,
398 float x_scale,
float y_scale,
float final_xshift,
399 float final_yshift,
bool inverse, Pix* pix) {
401 x_scale, y_scale, final_xshift, final_yshift);
412 for (
TESSLINE* outline =
outlines; outline !=
nullptr; outline = outline->next) {
413 outline->Normalize(denorm_);
423 outline = outline->next) {
424 outline->Rotate(rotation);
431 outline = outline->next) {
439 outline = outline->next) {
440 outline->Scale(factor);
447 outline = outline->next) {
448 outline->ComputeBoundingBox();
456 outline = outline->next)
471 for (outline = outline->
next; outline !=
nullptr; outline = outline->
next) {
481 outline = outline->next) {
483 for (
TESSLINE* other_outline = outline->next; other_outline !=
nullptr;
484 last_outline = other_outline, other_outline = other_outline->
next) {
485 if (outline->SameBox(*other_outline)) {
486 last_outline->
next = other_outline->
next;
488 other_outline->
loop =
nullptr;
489 delete other_outline;
490 other_outline = last_outline;
492 outline->is_hole =
false;
508 #ifndef GRAPHICS_DISABLED
512 outline = outline->next)
513 outline->
plot(window, color, child_color);
515 #endif // GRAPHICS_DISABLED
526 CollectEdges(box,
nullptr, &accumulator,
nullptr,
nullptr);
531 if (x2nd < 1.0) x2nd = 1.0;
532 if (y2nd < 1.0) y2nd = 1.0;
533 second_moments->
set_x(x2nd);
534 second_moments->
set_y(y2nd);
535 return accumulator.
count();
542 *precise_box =
TBOX();
543 CollectEdges(box, precise_box,
nullptr,
nullptr,
nullptr);
561 y_coords->init_to_size(box.
width(), empty);
562 CollectEdges(box,
nullptr,
nullptr, x_coords, y_coords);
564 for (
int i = 0; i < x_coords->size(); ++i) (*x_coords)[i].sort();
565 for (
int i = 0; i < y_coords->size(); ++i) (*y_coords)[i].sort();
570 static void SegmentLLSQ(
const FCOORD& pt1,
const FCOORD& pt2,
578 if (xstart == xend && ystart == yend)
return;
579 double weight = step.length() / (xend - xstart + yend - ystart);
581 for (
int x = xstart; x < xend; ++x) {
582 double y = pt1.
y() + step.y() * (x + 0.5 - pt1.
x()) / step.x();
583 accumulator->
add(x + 0.5, y, weight);
586 for (
int y = ystart; y < yend; ++y) {
587 double x = pt1.
x() + step.x() * (y + 0.5 - pt1.
y()) / step.y();
588 accumulator->
add(x, y + 0.5, weight);
597 static void SegmentCoords(
const FCOORD& pt1,
const FCOORD& pt2,
int x_limit,
606 for (
int x = start; x < end; ++x) {
607 int y =
IntCastRounded(pt1.
y() + step.y() * (x + 0.5 - pt1.
x()) / step.x());
608 (*y_coords)[x].push_back(y);
612 for (
int y = start; y < end; ++y) {
613 int x =
IntCastRounded(pt1.
x() + step.x() * (y + 0.5 - pt1.
y()) / step.y());
614 (*x_coords)[y].push_back(x);
631 TBOX point(x1, std::min(y1, y2), x2, std::max(y1, y2));
641 TBOX point(std::min(x1, x2), y1, std::max(x1, x2), y2);
656 static void CollectEdgesOfRun(
const EDGEPT* startpt,
const EDGEPT* lastpt,
658 TBOX* bounding_box,
LLSQ* accumulator,
662 int x_limit = box.
width() - 1;
663 int y_limit = box.
height() - 1;
664 if (outline !=
nullptr) {
679 if (end_index <= start_index) end_index += step_length;
691 prev_normed -= origin;
692 for (
int index = start_index; index < end_index; ++index) {
693 ICOORD step = outline->
step(index % step_length);
706 pos_normed -= origin;
708 if (bounding_box !=
nullptr) {
709 SegmentBBox(pos_normed, prev_normed, bounding_box);
711 if (accumulator !=
nullptr) {
712 SegmentLLSQ(pos_normed, prev_normed, accumulator);
714 if (x_coords !=
nullptr && y_coords !=
nullptr) {
715 SegmentCoords(pos_normed, prev_normed, x_limit, y_limit, x_coords,
718 prev_normed = pos_normed;
725 const EDGEPT* pt = startpt;
730 if (bounding_box !=
nullptr) {
731 SegmentBBox(next_pos, pos, bounding_box);
733 if (accumulator !=
nullptr) {
734 SegmentLLSQ(next_pos, pos, accumulator);
736 if (x_coords !=
nullptr && y_coords !=
nullptr) {
737 SegmentCoords(next_pos, pos, x_limit, y_limit, x_coords, y_coords);
739 }
while ((pt = pt->
next) != endpt);
748 void TBLOB::CollectEdges(
const TBOX& box,
TBOX* bounding_box,
LLSQ* llsq,
754 EDGEPT* loop_pt = ol->FindBestStartPt();
756 if (pt ==
nullptr)
continue;
762 last_pt = last_pt->
next;
763 }
while (last_pt != loop_pt && !last_pt->
IsHidden() &&
765 last_pt = last_pt->
prev;
766 CollectEdgesOfRun(pt, last_pt, denorm_, box,
bounding_box, llsq, x_coords,
769 }
while ((pt = pt->
next) != loop_pt);
776 auto* tessword =
new TWERD;
779 for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
780 C_BLOB* blob = b_it.data();
782 tessword->blobs.push_back(tblob);
790 bool inverse,
float x_height,
float baseline_shift,
794 if (norm_box !=
nullptr) word_box = *norm_box;
795 float word_middle = (word_box.
left() + word_box.
right()) / 2.0f;
796 float input_y_offset = 0.0f;
799 if (row ==
nullptr) {
800 word_middle = word_box.
left();
801 input_y_offset = word_box.
bottom();
802 final_y_offset = 0.0f;
804 input_y_offset = row->
base_line(word_middle) + baseline_shift;
809 float mid_x = (blob_box.
left() + blob_box.
right()) / 2.0f;
811 float blob_scale = scale;
815 scale, scale * 1.5f);
816 }
else if (row !=
nullptr) {
826 blob_scale, 0.0f, final_y_offset, inverse, pix);
828 if (word_denorm !=
nullptr) {
830 input_y_offset, scale, scale, 0.0f,
841 for (
int b = 0; b < src.
blobs.
size(); ++b) {
856 blobs[b]->ComputeBoundingBoxes();
874 for (
int i = start + 1; i < end && i <
blobs.
size(); ++i) {
877 if (outline ==
nullptr) {
879 outline =
blobs[start]->outlines;
881 while (outline->
next !=
nullptr) outline = outline->
next;
890 for (
int i = start + 1; i < end && start + 1 <
blobs.
size(); ++i) {
895 #ifndef GRAPHICS_DISABLED
903 #endif // GRAPHICS_DISABLED
919 outline1 = outline1->
next) {
920 if (outline1->is_hole)
continue;
922 static_cast<int16_t>((outline1->topleft.x + outline1->botright.x) / 2),
923 static_cast<int16_t>((outline1->topleft.y + outline1->botright.y) / 2));
924 int mid_prod1 = mid_pt1.
cross(vertical);
925 int min_prod1, max_prod1;
926 outline1->MinMaxCrossProduct(vertical, &min_prod1, &max_prod1);
927 for (
TESSLINE* outline2 = outline1->
next; outline2 !=
nullptr;
928 outline2 = outline2->
next) {
929 if (outline2->is_hole)
continue;
930 TPOINT mid_pt2(static_cast<int16_t>(
931 (outline2->topleft.x + outline2->botright.x) / 2),
932 static_cast<int16_t>(
933 (outline2->topleft.y + outline2->botright.y) / 2));
934 int mid_prod2 = mid_pt2.
cross(vertical);
935 int min_prod2, max_prod2;
936 outline2->MinMaxCrossProduct(vertical, &min_prod2, &max_prod2);
937 int mid_gap = abs(mid_prod2 - mid_prod1);
939 std::min(max_prod1, max_prod2) - std::max(min_prod1, min_prod2);
940 if (mid_gap - overlap / 4 > max_gap) {
941 max_gap = mid_gap - overlap / 4;
943 *location += mid_pt2;
950 return max_gap > vertical.
y;
970 int location_prod = location.
cross(vertical);
972 while (outline !=
nullptr) {
976 int mid_prod = mid_pt.
cross(vertical);
977 if (mid_prod < location_prod) {
980 outline1->
next = outline;
987 outline2->
next = outline;
992 outline = outline->
next;
995 if (outline1) outline1->
next =
nullptr;
996 if (outline2) outline2->
next =
nullptr;