Skip to content
Permalink
Browse files

Ensure that QgsGeometry::offsetCurve does not reverse curve orientation

(cherry picked from commit 329d6a6)
  • Loading branch information
nyalldawson committed Dec 2, 2018
1 parent 6d8a479 commit 34a821ecf1f3dd663b42658f81e425a066720817
Showing with 30 additions and 2 deletions.
  1. +14 −2 src/core/geometry/qgsgeometry.cpp
  2. +16 −0 tests/src/python/test_qgsgeometry.py
@@ -1793,14 +1793,26 @@ QgsGeometry QgsGeometry::offsetCurve( double distance, int segments, JoinStyle j
{
QgsGeos geos( d->geometry.get() );
mLastError.clear();
QgsAbstractGeometry *offsetGeom = geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError );

// GEOS can flip the curve orientation in some circumstances. So record previous orientation and correct if required
const QgsCurve::Orientation prevOrientation = qgsgeometry_cast< const QgsCurve * >( d->geometry.get() )->orientation();

std::unique_ptr< QgsAbstractGeometry > offsetGeom( geos.offsetCurve( distance, segments, joinStyle, miterLimit, &mLastError ) );
if ( !offsetGeom )
{
QgsGeometry result;
result.mLastError = mLastError;
return result;
}
return QgsGeometry( offsetGeom );

const QgsCurve::Orientation newOrientation = qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() )->orientation();
if ( newOrientation != prevOrientation )
{
// GEOS has flipped line orientation, flip it back
std::unique_ptr< QgsAbstractGeometry > flipped( qgsgeometry_cast< const QgsCurve * >( offsetGeom.get() )->reversed() );
offsetGeom = std::move( flipped );
}
return QgsGeometry( std::move( offsetGeom ) );
}
}

@@ -4595,6 +4595,22 @@ def testBoundingBoxIntersectsRectangle(self):
res = g1.boundingBoxIntersects(t[1])
self.assertEqual(res, t[2], "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(g1.asWkt(), t[1].toString(), t[2], res))

def testOffsetCurve(self):
tests = [
["LINESTRING (0 0, 0 100, 100 100)", 1, "LineString (-1 0, -1 101, 100 101)"],
["LINESTRING (0 0, 0 100, 100 100)", -1, "LineString (1 0, 1 99, 100 99)"],
["LINESTRING (100 100, 0 100, 0 0)", 1, "LineString (100 99, 1 99, 1 0)"],
["LINESTRING (100 100, 0 100, 0 0)", -1, "LineString (100 101, -1 101, -1 0)"],
["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))"]
]
for t in tests:
g1 = QgsGeometry.fromWkt(t[0])
res = g1.offsetCurve(t[1], 2, QgsGeometry.JoinStyleMiter, 5)

self.assertEqual(res.asWkt(1), t[2],
"mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[1],
t[2], res.asWkt(1)))

def renderGeometry(self, geom, use_pen, as_polygon=False, as_painter_path=False):
image = QImage(200, 200, QImage.Format_RGB32)
image.fill(QColor(0, 0, 0))

0 comments on commit 34a821e

Please sign in to comment.
You can’t perform that action at this time.