Add rotate and transform(QTransform) methods to QgsGeometry

Reimplement translate in terms of transform(QTransform).
Includes new unit test for rotate() and translate() methods.
Includes sip bindings update.
This commit is contained in:
Sandro Santilli 2015-01-09 12:15:47 +01:00
parent 85619dae12
commit e2e47d71c6
4 changed files with 140 additions and 24 deletions

View File

@ -251,6 +251,18 @@ class QgsGeometry
@return 0 in case of success*/
int transform( const QgsCoordinateTransform& ct );
/**Transform this geometry as described by QTransform ct
@note added in 2.8
@return 0 in case of success*/
int transform( const QTransform& ct );
/**Rotate this geometry around the Z axis
@note added in 2.8
@param rotation clockwise rotation in degrees
@param center rotation center
@return 0 in case of success*/
int rotate( double rotation, const QgsPoint& center );
/**Splits this geometry according to a given line. Note that the geometry is only split once. If there are several intersections
between geometry and splitLine, only the first one is considered.
@param splitLine the line that splits the geometry

View File

@ -2706,7 +2706,7 @@ int QgsGeometry::addPart( GEOSGeometry *newPart )
return 0;
}
int QgsGeometry::translate( double dx, double dy )
int QgsGeometry::transform( const QTransform& t )
{
if ( mDirtyWkb )
exportGeosToWkb();
@ -2717,17 +2717,17 @@ int QgsGeometry::translate( double dx, double dy )
return 1;
}
bool hasZValue = false;
QgsWkbPtr wkbPtr( mGeometry + 1 );
QGis::WkbType wkbType;
wkbPtr >> wkbType;
bool hasZValue = false;
switch ( wkbType )
{
case QGis::WKBPoint25D:
case QGis::WKBPoint:
{
translateVertex( wkbPtr, dx, dy, hasZValue );
transformVertex( wkbPtr, t, hasZValue );
}
break;
@ -2738,7 +2738,7 @@ int QgsGeometry::translate( double dx, double dy )
int nPoints;
wkbPtr >> nPoints;
for ( int index = 0; index < nPoints; ++index )
translateVertex( wkbPtr, dx, dy, hasZValue );
transformVertex( wkbPtr, t, hasZValue );
break;
}
@ -2754,7 +2754,7 @@ int QgsGeometry::translate( double dx, double dy )
int nPoints;
wkbPtr >> nPoints;
for ( int index2 = 0; index2 < nPoints; ++index2 )
translateVertex( wkbPtr, dx, dy, hasZValue );
transformVertex( wkbPtr, t, hasZValue );
}
break;
@ -2766,11 +2766,10 @@ int QgsGeometry::translate( double dx, double dy )
{
int nPoints;
wkbPtr >> nPoints;
for ( int index = 0; index < nPoints; ++index )
{
wkbPtr += 1 + sizeof( int );
translateVertex( wkbPtr, dx, dy, hasZValue );
transformVertex( wkbPtr, t, hasZValue );
}
break;
}
@ -2787,7 +2786,8 @@ int QgsGeometry::translate( double dx, double dy )
int nPoints;
wkbPtr >> nPoints;
for ( int index2 = 0; index2 < nPoints; ++index2 )
translateVertex( wkbPtr, dx, dy, hasZValue );
transformVertex( wkbPtr, t, hasZValue );
}
break;
}
@ -2801,19 +2801,17 @@ int QgsGeometry::translate( double dx, double dy )
for ( int index = 0; index < nPolys; ++index )
{
wkbPtr += 1 + sizeof( int ); //skip endian and polygon type
int nRings;
wkbPtr >> nRings;
for ( int index2 = 0; index2 < nRings; ++index2 )
{
int nPoints;
wkbPtr >> nPoints;
for ( int index3 = 0; index3 < nPoints; ++index3 )
translateVertex( wkbPtr, dx, dy, hasZValue );
transformVertex( wkbPtr, t, hasZValue );
}
}
break;
}
default:
@ -2823,6 +2821,19 @@ int QgsGeometry::translate( double dx, double dy )
return 0;
}
int QgsGeometry::translate( double dx, double dy )
{
return transform( QTransform::fromTranslate( dx, dy ) );
}
int QgsGeometry::rotate( double rotation, const QgsPoint& center )
{
QTransform t = QTransform::fromTranslate( center.x(), center.y() );
t.rotate( -rotation );
t.translate( -center.x(), -center.y() );
return transform( t );
}
int QgsGeometry::transform( const QgsCoordinateTransform& ct )
{
if ( mDirtyWkb )
@ -4612,20 +4623,25 @@ bool QgsGeometry::convertToMultiType()
return true;
}
void QgsGeometry::translateVertex( QgsWkbPtr &wkbPtr, double dx, double dy, bool hasZValue )
void QgsGeometry::transformVertex( QgsWkbPtr &wkbPtr, const QTransform& trans, bool hasZValue )
{
double x, y, translated_x, translated_y;
double x, y, rotated_x, rotated_y;
QgsWkbPtr tmp = wkbPtr;
memcpy( &x, tmp, sizeof( double ) );
tmp += sizeof( double );
memcpy( &y, tmp, sizeof( double ) );
tmp += sizeof( double );
trans.map( x, y, &rotated_x, &rotated_y );
//x-coordinate
memcpy( &x, wkbPtr, sizeof( double ) );
translated_x = x + dx;
memcpy( wkbPtr, &translated_x, sizeof( double ) );
memcpy( wkbPtr, &rotated_x, sizeof( double ) );
wkbPtr += sizeof( double );
//y-coordinate
memcpy( &y, wkbPtr, sizeof( double ) );
translated_y = y + dy;
memcpy( wkbPtr, &translated_y, sizeof( double ) );
memcpy( wkbPtr, &rotated_y, sizeof( double ) );
wkbPtr += sizeof( double );
if ( hasZValue )

View File

@ -293,6 +293,18 @@ class CORE_EXPORT QgsGeometry
@return 0 in case of success*/
int transform( const QgsCoordinateTransform& ct );
/**Transform this geometry as described by QTransform ct
@note added in 2.8
@return 0 in case of success*/
int transform( const QTransform& ct );
/**Rotate this geometry around the Z axis
@note added in 2.8
@param rotation clockwise rotation in degrees
@param center rotation center
@return 0 in case of success*/
int rotate( double rotation, const QgsPoint& center );
/**Splits this geometry according to a given line. Note that the geometry is only split once. If there are several intersections
between geometry and splitLine, only the first one is considered.
@param splitLine the line that splits the geometry
@ -565,12 +577,11 @@ class CORE_EXPORT QgsGeometry
const GEOSCoordSequence* old_sequence,
GEOSCoordSequence** new_sequence );
/**Translates a single vertex by dx and dy.
/**Transform a single vertex by QTransform
@param wkbPtr pointer to current position in wkb array. Is increased automatically by the function
@param dx translation of x coordinate
@param dy translation of y coordinate
@param trans transform matrix
@param hasZValue 25D type?*/
void translateVertex( QgsWkbPtr &wkbPtr, double dx, double dy, bool hasZValue );
void transformVertex( QgsWkbPtr &wkbPtr, const QTransform& trans, bool hasZValue );
/**Transforms a single vertex by ct.
@param wkbPtr pointer to current position in wkb. Is increased automatically by the function

View File

@ -60,6 +60,8 @@ class TestQgsGeometry : public QObject
#endif
void intersectionCheck1();
void intersectionCheck2();
void translateCheck1();
void rotateCheck1();
void unionCheck1();
void unionCheck2();
void differenceCheck1();
@ -359,6 +361,81 @@ void TestQgsGeometry::intersectionCheck2()
QVERIFY( !mpPolygonGeometryA->intersects( mpPolygonGeometryC ) );
}
void TestQgsGeometry::translateCheck1()
{
QString wkt = "LINESTRING(0 0, 10 0, 10 10)";
QScopedPointer<QgsGeometry> geom( QgsGeometry::fromWkt( wkt ) );
geom->translate( 10, -5 );
QString obtained = geom->exportToWkt();
QString expected = "LINESTRING(10 -5, 20 -5, 20 5)";
QCOMPARE( obtained, expected );
geom->translate( -10, 5 );
obtained = geom->exportToWkt();
QCOMPARE( obtained, wkt );
wkt = "POLYGON((-2 4,-2 -10,2 3,-2 4),(1 1,-1 1,-1 -1,1 1))";
geom.reset( QgsGeometry::fromWkt( wkt ) );
geom->translate( -2, 10 );
obtained = geom->exportToWkt();
expected = "POLYGON((-4 14,-4 0,0 13,-4 14),(-1 11,-3 11,-3 9,-1 11))";
QCOMPARE( obtained, expected );
geom->translate( 2, -10 );
obtained = geom->exportToWkt();
QCOMPARE( obtained, wkt );
wkt = "POINT(40 50)";
geom.reset( QgsGeometry::fromWkt( wkt ) );
geom->translate( -2, 10 );
obtained = geom->exportToWkt();
expected = "POINT(38 60)";
QCOMPARE( obtained, expected );
geom->translate( 2, -10 );
obtained = geom->exportToWkt();
QCOMPARE( obtained, wkt );
}
void TestQgsGeometry::rotateCheck1()
{
QString wkt = "LINESTRING(0 0, 10 0, 10 10)";
QScopedPointer<QgsGeometry> geom( QgsGeometry::fromWkt( wkt ) );
geom->rotate( 90, QgsPoint( 0, 0 ) );
QString obtained = geom->exportToWkt();
QString expected = "LINESTRING(0 0, 0 -10, 10 -10)";
QCOMPARE( obtained, expected );
geom->rotate( -90, QgsPoint( 0, 0 ) );
obtained = geom->exportToWkt();
QCOMPARE( obtained, wkt );
wkt = "POLYGON((-2 4,-2 -10,2 3,-2 4),(1 1,-1 1,-1 -1,1 1))";
geom.reset( QgsGeometry::fromWkt( wkt ) );
geom->rotate( 90, QgsPoint( 0, 0 ) );
obtained = geom->exportToWkt();
expected = "POLYGON((4 2,-10 2,3 -2,4 2),(1 -1,1 1,-1 1,1 -1))";
QCOMPARE( obtained, expected );
geom->rotate( -90, QgsPoint( 0, 0 ) );
obtained = geom->exportToWkt();
QCOMPARE( obtained, wkt );
wkt = "POINT(40 50)";
geom.reset( QgsGeometry::fromWkt( wkt ) );
geom->rotate( 90, QgsPoint( 0, 0 ) );
obtained = geom->exportToWkt();
expected = "POINT(50 -40)";
QCOMPARE( obtained, expected );
geom->rotate( -90, QgsPoint( 0, 0 ) );
obtained = geom->exportToWkt();
QCOMPARE( obtained, wkt );
geom->rotate( 180, QgsPoint( 40, 0 ) );
expected = "POINT(40 -50)";
obtained = geom->exportToWkt();
QCOMPARE( obtained, expected );
geom->rotate( 180, QgsPoint( 40, 0 ) ); // round-trip
obtained = geom->exportToWkt();
QCOMPARE( obtained, wkt );
}
void TestQgsGeometry::unionCheck1()
{
// should be a multipolygon with 2 parts as A does not intersect C