Skip to content

Commit d5d89d0

Browse files
authored
Fix crash in ConvexHull::preSort (#1358)
* Add test for GH-1072 Resolves #1072 * ConvexHull: improve robustness of polarCompare
1 parent 3f3a3e9 commit d5d89d0

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

src/algorithm/ConvexHull.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,21 @@ class RadiallyLessThen {
6363
polarCompare(const Coordinate* o, const Coordinate* p,
6464
const Coordinate* q)
6565
{
66-
int orient = Orientation::index(*o, *p, *q);
66+
// To use this comparator in std::sort it must provide a stable ordering, such that
67+
// if cmp(a, b) is true then cmp(b, a) is false. Unfortunately Orientation::index may
68+
// not provide this guarantee when the inputs differ by many orders of magnitude. To
69+
// guard against this, we normalize the order of P and Q before calling OrientationIndex
70+
// and flip the result if the inputs were flipped.
71+
const bool swap = geom::CoordinateLessThan()(p, q);
72+
73+
const int orient = swap ? Orientation::index(*o, *q, *p) : Orientation::index(*o, *p, *q);
6774

6875
if(orient == Orientation::COUNTERCLOCKWISE) {
69-
return 1;
76+
return swap ? -1 : 1;
7077
}
78+
7179
if(orient == Orientation::CLOCKWISE) {
72-
return -1;
80+
return swap ? 1 : -1;
7381
}
7482

7583
/**
@@ -102,7 +110,7 @@ class RadiallyLessThen {
102110
RadiallyLessThen(const Coordinate* c): origin(c) {}
103111

104112
bool
105-
operator()(const Coordinate* p1, const Coordinate* p2)
113+
operator()(const Coordinate* p1, const Coordinate* p2) const
106114
{
107115
return (polarCompare(origin, p1, p2) == -1);
108116
}

tests/unit/capi/GEOSMinimumBoundingCircleTest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,5 +129,20 @@ void object::test<5>
129129
ensure("curved geometry not supported", result_ == nullptr);
130130
}
131131

132+
template<>
133+
template<>
134+
void object::test<6>
135+
()
136+
{
137+
set_test_name("https://github.com/libgeos/geos/issues/1072");
138+
139+
geom1_ = fromWKT("LINESTRING(7777777777777777770 7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777770 1, 1 7 1,-2 1 2)");
140+
geom2_ = GEOSSingleSidedBuffer(geom1_, 1.0, 64, 1, 1.0, 1);
141+
result_ = GEOSMinimumBoundingCircle(geom2_, NULL, NULL);
142+
143+
// no segfault
144+
}
145+
146+
132147
} // namespace tut
133148

0 commit comments

Comments
 (0)