Skip to content

Commit e2e47d7

Browse files
author
Sandro Santilli
committed
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.
1 parent 85619da commit e2e47d7

File tree

4 files changed

+140
-24
lines changed

4 files changed

+140
-24
lines changed

python/core/qgsgeometry.sip

+12
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,18 @@ class QgsGeometry
251251
@return 0 in case of success*/
252252
int transform( const QgsCoordinateTransform& ct );
253253

254+
/**Transform this geometry as described by QTransform ct
255+
@note added in 2.8
256+
@return 0 in case of success*/
257+
int transform( const QTransform& ct );
258+
259+
/**Rotate this geometry around the Z axis
260+
@note added in 2.8
261+
@param rotation clockwise rotation in degrees
262+
@param center rotation center
263+
@return 0 in case of success*/
264+
int rotate( double rotation, const QgsPoint& center );
265+
254266
/**Splits this geometry according to a given line. Note that the geometry is only split once. If there are several intersections
255267
between geometry and splitLine, only the first one is considered.
256268
@param splitLine the line that splits the geometry

src/core/qgsgeometry.cpp

+36-20
Original file line numberDiff line numberDiff line change
@@ -2706,7 +2706,7 @@ int QgsGeometry::addPart( GEOSGeometry *newPart )
27062706
return 0;
27072707
}
27082708

2709-
int QgsGeometry::translate( double dx, double dy )
2709+
int QgsGeometry::transform( const QTransform& t )
27102710
{
27112711
if ( mDirtyWkb )
27122712
exportGeosToWkb();
@@ -2717,17 +2717,17 @@ int QgsGeometry::translate( double dx, double dy )
27172717
return 1;
27182718
}
27192719

2720+
bool hasZValue = false;
27202721
QgsWkbPtr wkbPtr( mGeometry + 1 );
27212722
QGis::WkbType wkbType;
27222723
wkbPtr >> wkbType;
27232724

2724-
bool hasZValue = false;
27252725
switch ( wkbType )
27262726
{
27272727
case QGis::WKBPoint25D:
27282728
case QGis::WKBPoint:
27292729
{
2730-
translateVertex( wkbPtr, dx, dy, hasZValue );
2730+
transformVertex( wkbPtr, t, hasZValue );
27312731
}
27322732
break;
27332733

@@ -2738,7 +2738,7 @@ int QgsGeometry::translate( double dx, double dy )
27382738
int nPoints;
27392739
wkbPtr >> nPoints;
27402740
for ( int index = 0; index < nPoints; ++index )
2741-
translateVertex( wkbPtr, dx, dy, hasZValue );
2741+
transformVertex( wkbPtr, t, hasZValue );
27422742

27432743
break;
27442744
}
@@ -2754,7 +2754,7 @@ int QgsGeometry::translate( double dx, double dy )
27542754
int nPoints;
27552755
wkbPtr >> nPoints;
27562756
for ( int index2 = 0; index2 < nPoints; ++index2 )
2757-
translateVertex( wkbPtr, dx, dy, hasZValue );
2757+
transformVertex( wkbPtr, t, hasZValue );
27582758

27592759
}
27602760
break;
@@ -2766,11 +2766,10 @@ int QgsGeometry::translate( double dx, double dy )
27662766
{
27672767
int nPoints;
27682768
wkbPtr >> nPoints;
2769-
27702769
for ( int index = 0; index < nPoints; ++index )
27712770
{
27722771
wkbPtr += 1 + sizeof( int );
2773-
translateVertex( wkbPtr, dx, dy, hasZValue );
2772+
transformVertex( wkbPtr, t, hasZValue );
27742773
}
27752774
break;
27762775
}
@@ -2787,7 +2786,8 @@ int QgsGeometry::translate( double dx, double dy )
27872786
int nPoints;
27882787
wkbPtr >> nPoints;
27892788
for ( int index2 = 0; index2 < nPoints; ++index2 )
2790-
translateVertex( wkbPtr, dx, dy, hasZValue );
2789+
transformVertex( wkbPtr, t, hasZValue );
2790+
27912791
}
27922792
break;
27932793
}
@@ -2801,19 +2801,17 @@ int QgsGeometry::translate( double dx, double dy )
28012801
for ( int index = 0; index < nPolys; ++index )
28022802
{
28032803
wkbPtr += 1 + sizeof( int ); //skip endian and polygon type
2804-
28052804
int nRings;
28062805
wkbPtr >> nRings;
2807-
28082806
for ( int index2 = 0; index2 < nRings; ++index2 )
28092807
{
28102808
int nPoints;
28112809
wkbPtr >> nPoints;
28122810
for ( int index3 = 0; index3 < nPoints; ++index3 )
2813-
translateVertex( wkbPtr, dx, dy, hasZValue );
2811+
transformVertex( wkbPtr, t, hasZValue );
2812+
28142813
}
28152814
}
2816-
break;
28172815
}
28182816

28192817
default:
@@ -2823,6 +2821,19 @@ int QgsGeometry::translate( double dx, double dy )
28232821
return 0;
28242822
}
28252823

2824+
int QgsGeometry::translate( double dx, double dy )
2825+
{
2826+
return transform( QTransform::fromTranslate( dx, dy ) );
2827+
}
2828+
2829+
int QgsGeometry::rotate( double rotation, const QgsPoint& center )
2830+
{
2831+
QTransform t = QTransform::fromTranslate( center.x(), center.y() );
2832+
t.rotate( -rotation );
2833+
t.translate( -center.x(), -center.y() );
2834+
return transform( t );
2835+
}
2836+
28262837
int QgsGeometry::transform( const QgsCoordinateTransform& ct )
28272838
{
28282839
if ( mDirtyWkb )
@@ -4612,20 +4623,25 @@ bool QgsGeometry::convertToMultiType()
46124623
return true;
46134624
}
46144625

4615-
void QgsGeometry::translateVertex( QgsWkbPtr &wkbPtr, double dx, double dy, bool hasZValue )
4626+
void QgsGeometry::transformVertex( QgsWkbPtr &wkbPtr, const QTransform& trans, bool hasZValue )
46164627
{
4617-
double x, y, translated_x, translated_y;
4628+
double x, y, rotated_x, rotated_y;
4629+
4630+
QgsWkbPtr tmp = wkbPtr;
4631+
4632+
memcpy( &x, tmp, sizeof( double ) );
4633+
tmp += sizeof( double );
4634+
memcpy( &y, tmp, sizeof( double ) );
4635+
tmp += sizeof( double );
4636+
4637+
trans.map( x, y, &rotated_x, &rotated_y );
46184638

46194639
//x-coordinate
4620-
memcpy( &x, wkbPtr, sizeof( double ) );
4621-
translated_x = x + dx;
4622-
memcpy( wkbPtr, &translated_x, sizeof( double ) );
4640+
memcpy( wkbPtr, &rotated_x, sizeof( double ) );
46234641
wkbPtr += sizeof( double );
46244642

46254643
//y-coordinate
4626-
memcpy( &y, wkbPtr, sizeof( double ) );
4627-
translated_y = y + dy;
4628-
memcpy( wkbPtr, &translated_y, sizeof( double ) );
4644+
memcpy( wkbPtr, &rotated_y, sizeof( double ) );
46294645
wkbPtr += sizeof( double );
46304646

46314647
if ( hasZValue )

src/core/qgsgeometry.h

+15-4
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,18 @@ class CORE_EXPORT QgsGeometry
293293
@return 0 in case of success*/
294294
int transform( const QgsCoordinateTransform& ct );
295295

296+
/**Transform this geometry as described by QTransform ct
297+
@note added in 2.8
298+
@return 0 in case of success*/
299+
int transform( const QTransform& ct );
300+
301+
/**Rotate this geometry around the Z axis
302+
@note added in 2.8
303+
@param rotation clockwise rotation in degrees
304+
@param center rotation center
305+
@return 0 in case of success*/
306+
int rotate( double rotation, const QgsPoint& center );
307+
296308
/**Splits this geometry according to a given line. Note that the geometry is only split once. If there are several intersections
297309
between geometry and splitLine, only the first one is considered.
298310
@param splitLine the line that splits the geometry
@@ -565,12 +577,11 @@ class CORE_EXPORT QgsGeometry
565577
const GEOSCoordSequence* old_sequence,
566578
GEOSCoordSequence** new_sequence );
567579

568-
/**Translates a single vertex by dx and dy.
580+
/**Transform a single vertex by QTransform
569581
@param wkbPtr pointer to current position in wkb array. Is increased automatically by the function
570-
@param dx translation of x coordinate
571-
@param dy translation of y coordinate
582+
@param trans transform matrix
572583
@param hasZValue 25D type?*/
573-
void translateVertex( QgsWkbPtr &wkbPtr, double dx, double dy, bool hasZValue );
584+
void transformVertex( QgsWkbPtr &wkbPtr, const QTransform& trans, bool hasZValue );
574585

575586
/**Transforms a single vertex by ct.
576587
@param wkbPtr pointer to current position in wkb. Is increased automatically by the function

tests/src/core/testqgsgeometry.cpp

+77
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class TestQgsGeometry : public QObject
6060
#endif
6161
void intersectionCheck1();
6262
void intersectionCheck2();
63+
void translateCheck1();
64+
void rotateCheck1();
6365
void unionCheck1();
6466
void unionCheck2();
6567
void differenceCheck1();
@@ -359,6 +361,81 @@ void TestQgsGeometry::intersectionCheck2()
359361
QVERIFY( !mpPolygonGeometryA->intersects( mpPolygonGeometryC ) );
360362
}
361363

364+
void TestQgsGeometry::translateCheck1()
365+
{
366+
QString wkt = "LINESTRING(0 0, 10 0, 10 10)";
367+
QScopedPointer<QgsGeometry> geom( QgsGeometry::fromWkt( wkt ) );
368+
geom->translate( 10, -5 );
369+
QString obtained = geom->exportToWkt();
370+
QString expected = "LINESTRING(10 -5, 20 -5, 20 5)";
371+
QCOMPARE( obtained, expected );
372+
geom->translate( -10, 5 );
373+
obtained = geom->exportToWkt();
374+
QCOMPARE( obtained, wkt );
375+
376+
wkt = "POLYGON((-2 4,-2 -10,2 3,-2 4),(1 1,-1 1,-1 -1,1 1))";
377+
geom.reset( QgsGeometry::fromWkt( wkt ) );
378+
geom->translate( -2, 10 );
379+
obtained = geom->exportToWkt();
380+
expected = "POLYGON((-4 14,-4 0,0 13,-4 14),(-1 11,-3 11,-3 9,-1 11))";
381+
QCOMPARE( obtained, expected );
382+
geom->translate( 2, -10 );
383+
obtained = geom->exportToWkt();
384+
QCOMPARE( obtained, wkt );
385+
386+
wkt = "POINT(40 50)";
387+
geom.reset( QgsGeometry::fromWkt( wkt ) );
388+
geom->translate( -2, 10 );
389+
obtained = geom->exportToWkt();
390+
expected = "POINT(38 60)";
391+
QCOMPARE( obtained, expected );
392+
geom->translate( 2, -10 );
393+
obtained = geom->exportToWkt();
394+
QCOMPARE( obtained, wkt );
395+
396+
}
397+
398+
void TestQgsGeometry::rotateCheck1()
399+
{
400+
QString wkt = "LINESTRING(0 0, 10 0, 10 10)";
401+
QScopedPointer<QgsGeometry> geom( QgsGeometry::fromWkt( wkt ) );
402+
geom->rotate( 90, QgsPoint( 0, 0 ) );
403+
QString obtained = geom->exportToWkt();
404+
QString expected = "LINESTRING(0 0, 0 -10, 10 -10)";
405+
QCOMPARE( obtained, expected );
406+
geom->rotate( -90, QgsPoint( 0, 0 ) );
407+
obtained = geom->exportToWkt();
408+
QCOMPARE( obtained, wkt );
409+
410+
wkt = "POLYGON((-2 4,-2 -10,2 3,-2 4),(1 1,-1 1,-1 -1,1 1))";
411+
geom.reset( QgsGeometry::fromWkt( wkt ) );
412+
geom->rotate( 90, QgsPoint( 0, 0 ) );
413+
obtained = geom->exportToWkt();
414+
expected = "POLYGON((4 2,-10 2,3 -2,4 2),(1 -1,1 1,-1 1,1 -1))";
415+
QCOMPARE( obtained, expected );
416+
geom->rotate( -90, QgsPoint( 0, 0 ) );
417+
obtained = geom->exportToWkt();
418+
QCOMPARE( obtained, wkt );
419+
420+
wkt = "POINT(40 50)";
421+
geom.reset( QgsGeometry::fromWkt( wkt ) );
422+
geom->rotate( 90, QgsPoint( 0, 0 ) );
423+
obtained = geom->exportToWkt();
424+
expected = "POINT(50 -40)";
425+
QCOMPARE( obtained, expected );
426+
geom->rotate( -90, QgsPoint( 0, 0 ) );
427+
obtained = geom->exportToWkt();
428+
QCOMPARE( obtained, wkt );
429+
geom->rotate( 180, QgsPoint( 40, 0 ) );
430+
expected = "POINT(40 -50)";
431+
obtained = geom->exportToWkt();
432+
QCOMPARE( obtained, expected );
433+
geom->rotate( 180, QgsPoint( 40, 0 ) ); // round-trip
434+
obtained = geom->exportToWkt();
435+
QCOMPARE( obtained, wkt );
436+
437+
}
438+
362439
void TestQgsGeometry::unionCheck1()
363440
{
364441
// should be a multipolygon with 2 parts as A does not intersect C

0 commit comments

Comments
 (0)