25 #include "allheaders.h" 26 #include "arrayaccess.h" 37 #include "config_auto.h" 41 ICOORD C_OUTLINE::step_coords[4] = {
57 : box(bot_left, top_right), start(startpt->pos), offsets(nullptr) {
67 steps = (uint8_t *)calloc(step_mem(), 1);
70 for (stepindex = 0; stepindex < length; stepindex++) {
73 edgept = edgept->
next;
87 ):start (startpt), offsets(nullptr) {
100 steps =
static_cast<uint8_t*
>(calloc(step_mem(), 1));
102 lastdir = new_steps[length - 1];
104 for (stepindex = 0, srcindex = 0; srcindex < length;
105 stepindex++, srcindex++) {
106 new_box =
TBOX (pos, pos);
109 dir = new_steps[srcindex];
111 dirdiff = dir - prevdir;
112 pos +=
step (stepindex);
113 if ((dirdiff == 64 || dirdiff == -64) && stepindex > 0) {
115 prevdir = stepindex >= 0 ?
step_dir (stepindex) : lastdir;
123 if (dirdiff == 64 || dirdiff == -64) {
126 for (
int i = 0; i < stepindex; ++i)
130 while (stepindex > 1 && (dirdiff == 64 || dirdiff == -64));
131 stepcount = stepindex;
151 int16_t destindex = INT16_MAX;
155 stepcount = srcline->stepcount * 2;
156 if (stepcount == 0) {
163 steps = (uint8_t *)calloc(step_mem(), 1);
165 for (
int iteration = 0; iteration < 2; ++iteration) {
166 DIR128 round1 = iteration == 0 ? 32 : 0;
167 DIR128 round2 = iteration != 0 ? 32 : 0;
168 pos = srcline->start;
170 prevpos.
rotate (rotation);
172 box =
TBOX (start, start);
174 for (stepindex = 0; stepindex < srcline->stepcount; stepindex++) {
175 pos += srcline->
step (stepindex);
177 destpos.
rotate (rotation);
179 while (destpos.
x () != prevpos.
x () || destpos.
y () != prevpos.
y ()) {
185 set_step(destindex++, dir + round1);
186 prevpos +=
step(destindex - 1);
190 -64 && dirdiff != 64)) {
191 set_step(destindex++, dir + round2);
192 prevpos +=
step(destindex - 1);
194 prevpos -=
step(destindex - 1);
196 prevpos -=
step(destindex - 1);
197 set_step(destindex - 1, dir + round2);
198 prevpos +=
step(destindex - 1);
203 prevpos +=
step(destindex - 1);
205 while (destindex >= 2 &&
209 prevpos -=
step(destindex - 1);
210 prevpos -=
step(destindex - 2);
214 new_box =
TBOX (destpos, destpos);
218 ASSERT_HOST (destpos.
x () == start.
x () && destpos.
y () == start.
y ());
220 while ((dirdiff == 64 || dirdiff == -64) && destindex > 1) {
223 for (
int i = 0; i < destindex; ++i)
231 stepcount = destindex;
233 for (stepindex = 0; stepindex < stepcount; stepindex++) {
234 destpos +=
step (stepindex);
236 ASSERT_HOST (destpos.
x () == start.
x () && destpos.
y () == start.
y ());
241 C_OUTLINE_IT ol_it(outlines);
247 ol_it.add_to_end(outline);
264 C_OUTLINE_IT it(const_cast<C_OUTLINE_LIST*>(&children));
269 for (stepindex = 0; stepindex < total_steps; stepindex++) {
271 next_step =
step (stepindex);
272 if (next_step.
x () < 0)
274 else if (next_step.
x () > 0)
278 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
279 total += it.data ()->area ();
294 C_OUTLINE_IT it(const_cast<C_OUTLINE_LIST*>(&children));
297 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward())
298 total_steps += it.data()->pathlength();
318 if (total_steps == 0)
321 for (stepindex = 0; stepindex < total_steps; stepindex++) {
323 next_step =
step (stepindex);
324 if (next_step.
x () < 0)
326 else if (next_step.
x () > 0)
342 bool first_was_max_x;
343 bool first_was_max_y;
344 bool looking_for_max_x;
345 bool looking_for_min_x;
346 bool looking_for_max_y;
347 bool looking_for_min_y;
351 int32_t max_x, min_x, max_y, min_y;
352 int32_t initial_x, initial_y;
360 max_x = min_x = pos.
x();
361 max_y = min_y = pos.
y();
362 looking_for_max_x =
true;
363 looking_for_min_x =
true;
364 looking_for_max_y =
true;
365 looking_for_min_y =
true;
366 first_was_max_x =
false;
367 first_was_max_y =
false;
370 for (stepindex = 0; stepindex < total_steps; stepindex++) {
372 next_step =
step(stepindex);
374 if (next_step.
x() < 0) {
375 if (looking_for_max_x && pos.
x() < min_x)
377 if (looking_for_min_x && max_x - pos.
x() > threshold) {
378 if (looking_for_max_x) {
380 first_was_max_x =
false;
383 looking_for_max_x =
true;
384 looking_for_min_x =
false;
388 else if (next_step.
x() > 0) {
389 if (looking_for_min_x && pos.
x() > max_x)
391 if (looking_for_max_x && pos.
x() - min_x > threshold) {
392 if (looking_for_min_x) {
394 first_was_max_x =
true;
397 looking_for_max_x =
false;
398 looking_for_min_x =
true;
402 else if (next_step.
y() < 0) {
403 if (looking_for_max_y && pos.
y() < min_y)
405 if (looking_for_min_y && max_y - pos.
y() > threshold) {
406 if (looking_for_max_y) {
408 first_was_max_y =
false;
411 looking_for_max_y =
true;
412 looking_for_min_y =
false;
417 if (looking_for_min_y && pos.
y() > max_y)
419 if (looking_for_max_y && pos.
y() - min_y > threshold) {
420 if (looking_for_min_y) {
422 first_was_max_y =
true;
425 looking_for_max_y =
false;
426 looking_for_min_y =
true;
432 if (first_was_max_x && looking_for_min_x) {
433 if (max_x - initial_x > threshold)
438 else if (!first_was_max_x && looking_for_max_x) {
439 if (initial_x - min_x > threshold)
444 if (first_was_max_y && looking_for_min_y) {
445 if (max_y - initial_y > threshold)
450 else if (!first_was_max_y && looking_for_max_y) {
451 if (initial_y - min_y > threshold)
476 return other.box.
contains(this->box);
479 for (stepindex = 0; stepindex < stepcount
481 pos +=
step (stepindex);
485 for (stepindex = 0; stepindex < other.stepcount
488 pos += other.
step (stepindex);
510 for (stepindex = 0; stepindex < stepcount; stepindex++) {
511 stepvec =
step (stepindex);
513 if (vec.
y () <= 0 && vec.
y () + stepvec.
y () > 0) {
514 cross = vec * stepvec;
520 else if (vec.
y () > 0 && vec.
y () + stepvec.
y () <= 0) {
521 cross = vec * stepvec;
549 for (stepindex = 0; stepindex < stepcount; stepindex++) {
551 dirdiff = dir - prevdir;
552 ASSERT_HOST (dirdiff == 0 || dirdiff == 32 || dirdiff == -32);
573 halfsteps = (stepcount + 1) / 2;
574 for (stepindex = 0; stepindex < halfsteps; stepindex++) {
575 farindex = stepcount - stepindex - 1;
578 set_step (farindex, stepdir + halfturn);
590 C_OUTLINE_IT it(&children);
595 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
596 it.data ()->move (vec);
606 if (stepcount == 0)
return true;
610 C_OUTLINE_IT child_it(const_cast<C_OUTLINE_LIST*>(&children));
611 for (child_it.mark_cycle_pt(); !child_it.cycled_list(); child_it.forward()) {
613 if (
child->outer_area() * parent_area > 0 || !
child->IsLegallyNested())
629 if (box.
width() < min_size || box.
height() < min_size) {
631 delete it->extract();
632 }
else if (!children.empty()) {
634 C_OUTLINE_IT child_it(&children);
635 for (child_it.mark_cycle_pt(); !child_it.cycled_list();
636 child_it.forward()) {
638 child->RemoveSmallRecursive(min_size, &child_it);
652 static void ComputeGradient(
const l_uint32* data,
int wpl,
653 int x,
int y,
int width,
int height,
655 const l_uint32* line = data + y * wpl;
656 int pix_x_y = x < width && y < height ? GET_DATA_BYTE(line, x) : 255;
657 int pix_x_prevy = x < width && y > 0 ? GET_DATA_BYTE(line - wpl, x) : 255;
658 int pix_prevx_prevy = x > 0 && y > 0 ? GET_DATA_BYTE(line - wpl, x - 1) : 255;
659 int pix_prevx_y = x > 0 && y < height ? GET_DATA_BYTE(line, x - 1) : 255;
660 gradient->
set_x(pix_x_y + pix_x_prevy - (pix_prevx_y + pix_prevx_prevy));
661 gradient->
set_y(pix_x_prevy + pix_prevx_prevy - (pix_x_y + pix_prevx_y));
669 static bool EvaluateVerticalDiff(
const l_uint32* data,
int wpl,
int diff_sign,
670 int x,
int y,
int height,
671 int* best_diff,
int* best_sum,
int* best_y) {
672 if (y <= 0 || y >= height)
674 const l_uint32* line = data + y * wpl;
675 int pixel1 = GET_DATA_BYTE(line - wpl, x);
676 int pixel2 = GET_DATA_BYTE(line, x);
677 int diff = (pixel2 - pixel1) * diff_sign;
678 if (diff > *best_diff) {
680 *best_sum = pixel1 + pixel2;
691 static bool EvaluateHorizontalDiff(
const l_uint32* line,
int diff_sign,
693 int* best_diff,
int* best_sum,
int* best_x) {
694 if (x <= 0 || x >= width)
696 int pixel1 = GET_DATA_BYTE(line, x - 1);
697 int pixel2 = GET_DATA_BYTE(line, x);
698 int diff = (pixel2 - pixel1) * diff_sign;
699 if (diff > *best_diff) {
701 *best_sum = pixel1 + pixel2;
723 if (pixGetDepth(pix) != 8)
return;
724 const l_uint32* data = pixGetData(pix);
725 int wpl = pixGetWpl(pix);
726 int width = pixGetWidth(pix);
727 int height = pixGetHeight(pix);
733 ComputeGradient(data, wpl, pos.
x(), height - pos.
y(), width, height,
735 for (
int s = 0; s < stepcount; ++s) {
741 ComputeGradient(data, wpl, pos.
x(), height - pos.
y(), width, height,
744 ICOORD gradient = prev_gradient + next_gradient;
751 if (pt1.
y == pt2.
y && abs(gradient.y()) * 2 >= abs(gradient.x())) {
753 int diff_sign = (pt1.
x > pt2.
x) == negative ? 1 : -1;
754 int x = std::min(pt1.
x, pt2.
x);
755 int y = height - pt1.
y;
758 EvaluateVerticalDiff(data, wpl, diff_sign, x, y, height,
759 &best_diff, &best_sum, &best_y);
764 }
while (EvaluateVerticalDiff(data, wpl, diff_sign, x, test_y, height,
765 &best_diff, &best_sum, &best_y));
769 }
while (EvaluateVerticalDiff(data, wpl, diff_sign, x, test_y, height,
770 &best_diff, &best_sum, &best_y));
771 offset = diff_sign * (best_sum / 2 - threshold) +
772 (y - best_y) * best_diff;
773 }
else if (pt1.
x == pt2.
x && abs(gradient.x()) * 2 >= abs(gradient.y())) {
775 int diff_sign = (pt1.
y > pt2.
y) == negative ? 1 : -1;
777 int y = height - std::max(pt1.
y, pt2.
y);
778 const l_uint32* line = pixGetData(pix) + y * wpl;
781 EvaluateHorizontalDiff(line, diff_sign, x, width,
782 &best_diff, &best_sum, &best_x);
787 }
while (EvaluateHorizontalDiff(line, diff_sign, test_x, width,
788 &best_diff, &best_sum, &best_x));
792 }
while (EvaluateHorizontalDiff(line, diff_sign, test_x, width,
793 &best_diff, &best_sum, &best_x));
794 offset = diff_sign * (threshold - best_sum / 2) +
795 (best_x - x) * best_diff;
798 ClipToRange<int>(offset, -INT8_MAX, INT8_MAX);
799 offsets[s].
pixel_diff = ClipToRange<int>(best_diff, 0, UINT8_MAX);
800 if (negative) gradient = -gradient;
805 prev_gradient = next_gradient;
846 memset(dir_counts, 0,
sizeof(dir_counts));
847 memset(pos_totals, 0,
sizeof(pos_totals));
852 tail_pos -=
step(stepcount - 1);
853 tail_pos -=
step(stepcount - 2);
856 ICOORD head_pos = tail_pos;
858 for (
int s = -2; s < 2; ++s) {
859 increment_step(s, 1, &head_pos, dir_counts, pos_totals);
861 for (
int s = 0; s < stepcount; pos +=
step(s++)) {
863 increment_step(s + 2, 1, &head_pos, dir_counts, pos_totals);
870 if (dir_counts[dir_index] >= 2 || (dir_counts[dir_index] == 1 &&
871 dir_counts[
Modulo(dir_index - 1, 4)] == 2 &&
872 dir_counts[
Modulo(dir_index + 1, 4)] == 2)) {
874 best_diff = dir_counts[dir_index];
875 int edge_pos = step_vec.
x() == 0 ? pos.
x() : pos.
y();
879 offset = pos_totals[dir_index] - best_diff * edge_pos;
882 ClipToRange<int>(offset, -INT8_MAX, INT8_MAX);
883 offsets[s].
pixel_diff = ClipToRange<int>(best_diff, 0, UINT8_MAX);
887 increment_step(s - 2, -1, &tail_pos, dir_counts, pos_totals);
897 for (
int stepindex = 0; stepindex < stepcount; ++stepindex) {
899 if (next_step.
y() < 0) {
900 pixRasterop(pix, 0, top - pos.
y(), pos.
x() - left, 1,
901 PIX_NOT(PIX_DST),
nullptr, 0, 0);
902 }
else if (next_step.
y() > 0) {
903 pixRasterop(pix, 0, top - pos.
y() - 1, pos.
x() - left, 1,
904 PIX_NOT(PIX_DST),
nullptr, 0, 0);
919 for (
int stepindex = 0; stepindex < stepcount; ++stepindex) {
921 if (next_step.
y() < 0) {
922 pixSetPixel(pix, pos.
x() - left, top - pos.
y(), 1);
923 }
else if (next_step.
y() > 0) {
924 pixSetPixel(pix, pos.
x() - left - 1, top - pos.
y() - 1, 1);
925 }
else if (next_step.
x() < 0) {
926 pixSetPixel(pix, pos.
x() - left - 1, top - pos.
y(), 1);
927 }
else if (next_step.
x() > 0) {
928 pixSetPixel(pix, pos.
x() - left, top - pos.
y() - 1, 1);
942 #ifndef GRAPHICS_DISABLED 950 if (stepcount == 0) {
957 while (stepindex < stepcount) {
958 pos +=
step(stepindex);
962 while (stepindex < stepcount &&
964 pos +=
step(stepindex);
978 if (stepcount == 0) {
989 for (
int s = 0; s < stepcount; pos +=
step(s++)) {
991 if (edge_weight == 0) {
1013 start = source.start;
1015 stepcount = source.stepcount;
1016 steps = (uint8_t *)malloc(step_mem());
1017 memmove (steps, source.steps, step_mem());
1018 if (!children.empty ())
1020 children.deep_copy(&source.children, &
deep_copy);
1022 if (source.offsets !=
nullptr) {
1024 memcpy(offsets, source.offsets, stepcount *
sizeof(*offsets));
1037 void C_OUTLINE::increment_step(
int s,
int increment,
ICOORD* pos,
1038 int* dir_counts,
int* pos_totals)
const {
1039 int step_index =
Modulo(s, stepcount);
1041 dir_counts[dir_index] += increment;
1043 if (step_vec.
x() == 0)
1044 pos_totals[dir_index] += pos->
x() * increment;
1046 pos_totals[dir_index] += pos->
y() * increment;
1051 return step_coords[chaindir % 4];
void ComputeBinaryOffsets()
void NormTransform(const DENORM *first_norm, const TPOINT &pt, TPOINT *transformed) const
int16_t winding_number(ICOORD testpt) const
void DrawTo(int x, int y)
const DENORM * RootDenorm() const
void rotate(const FCOORD &vec)
FCOORD sub_pixel_pos_at_index(const ICOORD &pos, int index) const
void set_x(int16_t xin)
rewrite function
void ComputeEdgeOffsets(int threshold, Pix *pix)
int16_t y() const
access_function
int32_t perimeter() const
const ICOORD & start_pos() const
void set_step(int16_t stepindex, int8_t stepdir)
int direction(EDGEPT *point)
bool flag(C_OUTLINE_FLAGS mask) const
void SetCursor(int x, int y)
void move(const ICOORD vec)
static ICOORD chain_step(int chaindir)
int16_t turn_direction() const
static uint8_t binary_angle_plus_pi(double angle)
void render_outline(int left, int top, Pix *pix) const
int16_t x() const
access function
int edge_strength_at_index(int index) const
int IntCastRounded(double x)
void render(int left, int top, Pix *pix) const
#define ELISTIZE(CLASSNAME)
C_OUTLINE & operator=(const C_OUTLINE &source)
int32_t pathlength() const
void plot(ScrollView *window, ScrollView::Color colour) const
static C_OUTLINE * deep_copy(const C_OUTLINE *src)
void rotate(const FCOORD &vec)
void plot_normed(const DENORM &denorm, ScrollView::Color colour, ScrollView *window) const
bool operator<(const C_OUTLINE &other) const
void move(const ICOORD vec)
bool overlap(const TBOX &box) const
int32_t count_transitions(int32_t threshold)
bool contains(const FCOORD pt) const
void RemoveSmallRecursive(int min_size, C_OUTLINE_IT *it)
bool IsLegallyNested() const
DIR128 step_dir(int index) const
void Rectangle(int x1, int y1, int x2, int y2)
int chain_code(int index) const
static void FakeOutline(const TBOX &box, C_OUTLINE_LIST *outlines)
void set_y(int16_t yin)
rewrite function
int32_t outer_area() const
ICOORD step(int index) const