Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Move forceRHR to QgsGeometry, avoid duplicate code
(cherry picked from commit c0cd6e6)
  • Loading branch information
nyalldawson committed Dec 2, 2018
1 parent 320adf4 commit ad3338c
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
9 changes: 9 additions & 0 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -1562,6 +1562,15 @@ by calling `error()` on the returned geometry.


.. versionadded:: 3.0
%End

QgsGeometry forceRHR() const;
%Docstring
Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon
is to the right of the boundary. In particular, the exterior ring is oriented in a clockwise direction
and the interior rings in a counter-clockwise direction.

.. versionadded:: 3.6
%End

class Error
Expand Down
41 changes: 41 additions & 0 deletions src/core/geometry/qgsgeometry.cpp
Expand Up @@ -2412,6 +2412,47 @@ QgsGeometry QgsGeometry::makeValid() const
return result;
}

QgsGeometry QgsGeometry::forceRHR() const
{
if ( !d->geometry )
return QgsGeometry();

if ( isMultipart() )
{
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( d->geometry.get() );
std::unique_ptr< QgsGeometryCollection > newCollection( collection->createEmptyWithSameType() );
for ( int i = 0; i < collection->numGeometries(); ++i )
{
const QgsAbstractGeometry *g = collection->geometryN( i );
if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( g ) )
{
std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
corrected->forceRHR();
newCollection->addGeometry( corrected.release() );
}
else
{
newCollection->addGeometry( g->clone() );
}
}
return QgsGeometry( std::move( newCollection ) );
}
else
{
if ( const QgsCurvePolygon *cp = qgsgeometry_cast< const QgsCurvePolygon * >( d->geometry.get() ) )
{
std::unique_ptr< QgsCurvePolygon > corrected( cp->clone() );
corrected->forceRHR();
return QgsGeometry( std::move( corrected ) );
}
else
{
// not a curve polygon, so return unchanged
return *this;
}
}
}


void QgsGeometry::validateGeometry( QVector<QgsGeometry::Error> &errors, ValidationMethod method ) const
{
Expand Down
9 changes: 9 additions & 0 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -1550,6 +1550,15 @@ class CORE_EXPORT QgsGeometry
*/
QgsGeometry makeValid() const;

/**
* Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon
* is to the right of the boundary. In particular, the exterior ring is oriented in a clockwise direction
* and the interior rings in a counter-clockwise direction.
*
* \since QGIS 3.6
*/
QgsGeometry forceRHR() const;

/**
* \ingroup core
*/
Expand Down
18 changes: 18 additions & 0 deletions tests/src/python/test_qgsgeometry.py
Expand Up @@ -4611,6 +4611,24 @@ def testOffsetCurve(self):
"mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[1],
t[2], res.asWkt(1)))

def testForceRHR(self):
tests = [
["", ""],
["Point (100 100)", "Point (100 100)"],
["LINESTRING (0 0, 0 100, 100 100)", "LineString (0 0, 0 100, 100 100)"],
["LINESTRING (100 100, 0 100, 0 0)", "LineString (100 100, 0 100, 0 0)"],
["POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", "Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1))"],
["MULTIPOLYGON(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", "MultiPolygon (((-1 -1, 0 2, 4 2, 4 0, -1 -1)),((100 100, 100 200, 200 200, 200 100, 100 100)))"],
[
"GeometryCollection(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))",
"GeometryCollection (Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1)),Polygon ((100 100, 100 200, 200 200, 200 100, 100 100)))"]
]
for t in tests:
g1 = QgsGeometry.fromWkt(t[0])
res = g1.forceRHR()
self.assertEqual(res.asWkt(1), t[1],
"mismatch for {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[1], 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))
Expand Down

0 comments on commit ad3338c

Please sign in to comment.