Skip to content

Commit

Permalink
Fix FP exception in Wordrec::angle_change (issue #4242) (#4243)
Browse files Browse the repository at this point in the history
std::asin only allows arguments in [-1, 1], but rounding errors can
produce values which are slightly outside of this range and which
would cause a FP exception (or wrong calculation results).

Rename also the internally used function `TPOINT::length` to `TPOINT::length2`
because it calculates the square of the length.

Signed-off-by: Stefan Weil <[email protected]>
  • Loading branch information
stweil authored May 17, 2024
1 parent bcfdd5e commit 74e4381
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/ccstruct/blobs.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ struct TPOINT {
return x * other.x + y * other.y;
}

// Calculate length of vector.
int length() const {
// Calculate square of vector length.
int length2() const {
return x * x + y * y;
}

Expand Down
8 changes: 4 additions & 4 deletions src/ccstruct/polyaprx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static void cutline( // recursive refine
edge = edge->next;
} while (edge != last); // test all line

perp = vecsum.length();
perp = vecsum.length2();
ASSERT_HOST(perp != 0);

if (maxperp < 256 * INT16_MAX) {
Expand Down Expand Up @@ -389,17 +389,17 @@ static void fix2( // polygonal approx
break; // already too few
}
d12vec.diff(edgefix1->pos, edgefix2->pos);
d12 = d12vec.length();
d12 = d12vec.length2();
// TODO(rays) investigate this change:
// Only unfix a point if it is part of a low-curvature section
// of outline and the total angle change of the outlines is
// less than 90 degrees, ie the scalar product is positive.
// if (d12 <= gapmin && edgefix0->vec.dot(edgefix2->vec) > 0) {
if (d12 <= gapmin) {
d01vec.diff(edgefix0->pos, edgefix1->pos);
d01 = d01vec.length();
d01 = d01vec.length2();
d23vec.diff(edgefix2->pos, edgefix3->pos);
d23 = d23vec.length();
d23 = d23vec.length2();
if (d01 > d23) {
edgefix2->fixed = false;
fixed_count--;
Expand Down
35 changes: 21 additions & 14 deletions src/wordrec/chop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,31 @@ int Wordrec::angle_change(EDGEPT *point1, EDGEPT *point2, EDGEPT *point3) {
vector2.x = point3->pos.x - point2->pos.x;
vector2.y = point3->pos.y - point2->pos.y;
/* Use cross product */
float length = std::sqrt(static_cast<float>(vector1.length()) * vector2.length());
float length = std::sqrt(static_cast<float>(vector1.length2()) * vector2.length2());
if (static_cast<int>(length) == 0) {
return (0);
}
angle = static_cast<int>(floor(std::asin(vector1.cross(vector2) / length) / M_PI * 180.0 + 0.5));

/* Use dot product */
if (vector1.dot(vector2) < 0) {
angle = 180 - angle;
}
/* Adjust angle */
if (angle > 180) {
angle -= 360;
}
if (angle <= -180) {
angle += 360;
auto f = vector1.cross(vector2) / length;
// Avoid FP exception in std::asin caused by illegal values of f
// (caused by rounding errors).
if (f <= -1.0f) {
angle = -90;
} else if (f >= 1.0f) {
angle = 90;
} else {
angle = static_cast<int>(floor(std::asin(f) / M_PI * 180.0 + 0.5));
// Use dot product.
if (vector1.dot(vector2) < 0) {
angle = 180 - angle;
}
// Adjust angle.
if (angle > 180) {
angle -= 360;
} else if (angle <= -180) {
angle += 360;
}
}
return (angle);
return angle;
}

/**
Expand Down

0 comments on commit 74e4381

Please sign in to comment.