Skip to content

Commit e5946c5

Browse files
committedNov 9, 2018
Ensure that QgsGeometry::offsetCurve does not reverse curve orientation
1 parent d1e09a2 commit e5946c5

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed
 

‎src/core/geometry/qgsgeometry.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,14 +1746,26 @@ QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, JoinStyle j
17461746
{
17471747
QgsGeos geos( d->geometry.get() );
17481748
mLastError.clear();
1749-
QgsAbstractGeometry *offsetGeom = geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError );
1749+
1750+
// GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
1751+
const QgsCurve::Orientation prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();
1752+
1753+
std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
17501754
if ( !offsetGeom )
17511755
{
17521756
QgsGeometry result;
17531757
result.mLastError = mLastError;
17541758
return result;
17551759
}
1756-
return QgsGeometry( offsetGeom );
1760+
1761+
const QgsCurve::Orientation newOrientation = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() )->orientation();
1762+
if ( newOrientation != prevOrientation )
1763+
{
1764+
// GEOS has flipped line orientation, flip it back
1765+
std::unique_ptr< QgsAbstractGeometry > flipped( qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() )->reversed() );
1766+
offsetGeom = std::move( flipped );
1767+
}
1768+
return QgsGeometry( std::move( offsetGeom ) );
17571769
}
17581770
}
17591771

‎tests/src/python/test_qgsgeometry.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4483,6 +4483,22 @@ def testBoundingBoxIntersectsRectangle(self):
44834483
res = g1.boundingBoxIntersects(t[1])
44844484
self.assertEqual(res, t[2], "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(g1.asWkt(), t[1].toString(), t[2], res))
44854485

4486+
def testOffsetCurve(self):
4487+
tests = [
4488+
["LINESTRING (0 0, 0 100, 100 100)", 1, "LineString (-1 0, -1 101, 100 101)"],
4489+
["LINESTRING (0 0, 0 100, 100 100)", -1, "LineString (1 0, 1 99, 100 99)"],
4490+
["LINESTRING (100 100, 0 100, 0 0)", 1, "LineString (100 99, 1 99, 1 0)"],
4491+
["LINESTRING (100 100, 0 100, 0 0)", -1, "LineString (100 101, -1 101, -1 0)"],
4492+
["MULTILINESTRING ((0 0, 0 100, 100 100),(100 100, 0 100, 0 0))", 1, "MultiLineString ((-1 0, -1 101, 100 101),(100 99, 1 99, 1 0))"]
4493+
]
4494+
for t in tests:
4495+
g1 = QgsGeometry.fromWkt(t[0])
4496+
res = g1.offsetCurve(t[1], 2, QgsGeometry.JoinStyleMiter, 5)
4497+
4498+
self.assertEqual(res.asWkt(1), t[2],
4499+
"mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[1],
4500+
t[2], res.asWkt(1)))
4501+
44864502
def renderGeometry(self, geom, use_pen, as_polygon=False, as_painter_path=False):
44874503
image = QImage(200, 200, QImage.Format_RGB32)
44884504
image.fill(QColor(0, 0, 0))

0 commit comments

Comments
 (0)
Please sign in to comment.