Skip to content

Commit 74e4381

Browse files
authored
Fix FP exception in Wordrec::angle_change (issue #4242) (#4243)
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 <sw@weilnetz.de>
1 parent bcfdd5e commit 74e4381

File tree

3 files changed

+27
-20
lines changed

3 files changed

+27
-20
lines changed

src/ccstruct/blobs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ struct TPOINT {
8181
return x * other.x + y * other.y;
8282
}
8383

84-
// Calculate length of vector.
85-
int length() const {
84+
// Calculate square of vector length.
85+
int length2() const {
8686
return x * x + y * y;
8787
}
8888

src/ccstruct/polyaprx.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static void cutline( // recursive refine
108108
edge = edge->next;
109109
} while (edge != last); // test all line
110110

111-
perp = vecsum.length();
111+
perp = vecsum.length2();
112112
ASSERT_HOST(perp != 0);
113113

114114
if (maxperp < 256 * INT16_MAX) {
@@ -389,17 +389,17 @@ static void fix2( // polygonal approx
389389
break; // already too few
390390
}
391391
d12vec.diff(edgefix1->pos, edgefix2->pos);
392-
d12 = d12vec.length();
392+
d12 = d12vec.length2();
393393
// TODO(rays) investigate this change:
394394
// Only unfix a point if it is part of a low-curvature section
395395
// of outline and the total angle change of the outlines is
396396
// less than 90 degrees, ie the scalar product is positive.
397397
// if (d12 <= gapmin && edgefix0->vec.dot(edgefix2->vec) > 0) {
398398
if (d12 <= gapmin) {
399399
d01vec.diff(edgefix0->pos, edgefix1->pos);
400-
d01 = d01vec.length();
400+
d01 = d01vec.length2();
401401
d23vec.diff(edgefix2->pos, edgefix3->pos);
402-
d23 = d23vec.length();
402+
d23 = d23vec.length2();
403403
if (d01 > d23) {
404404
edgefix2->fixed = false;
405405
fixed_count--;

src/wordrec/chop.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,24 +107,31 @@ int Wordrec::angle_change(EDGEPT *point1, EDGEPT *point2, EDGEPT *point3) {
107107
vector2.x = point3->pos.x - point2->pos.x;
108108
vector2.y = point3->pos.y - point2->pos.y;
109109
/* Use cross product */
110-
float length = std::sqrt(static_cast<float>(vector1.length()) * vector2.length());
110+
float length = std::sqrt(static_cast<float>(vector1.length2()) * vector2.length2());
111111
if (static_cast<int>(length) == 0) {
112112
return (0);
113113
}
114-
angle = static_cast<int>(floor(std::asin(vector1.cross(vector2) / length) / M_PI * 180.0 + 0.5));
115-
116-
/* Use dot product */
117-
if (vector1.dot(vector2) < 0) {
118-
angle = 180 - angle;
119-
}
120-
/* Adjust angle */
121-
if (angle > 180) {
122-
angle -= 360;
123-
}
124-
if (angle <= -180) {
125-
angle += 360;
114+
auto f = vector1.cross(vector2) / length;
115+
// Avoid FP exception in std::asin caused by illegal values of f
116+
// (caused by rounding errors).
117+
if (f <= -1.0f) {
118+
angle = -90;
119+
} else if (f >= 1.0f) {
120+
angle = 90;
121+
} else {
122+
angle = static_cast<int>(floor(std::asin(f) / M_PI * 180.0 + 0.5));
123+
// Use dot product.
124+
if (vector1.dot(vector2) < 0) {
125+
angle = 180 - angle;
126+
}
127+
// Adjust angle.
128+
if (angle > 180) {
129+
angle -= 360;
130+
} else if (angle <= -180) {
131+
angle += 360;
132+
}
126133
}
127-
return (angle);
134+
return angle;
128135
}
129136

130137
/**

0 commit comments

Comments
 (0)