Skip to content

Commit 6a6fe45

Browse files
committed
Add snap-to-grid to QgsGeos
1 parent 643eb10 commit 6a6fe45

12 files changed

Lines changed: 110 additions & 76 deletions

‎src/core/geometry/qgsgeometry.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ size_t QgsGeometry::wkbSize() const
294294
return d->mWkbSize;
295295
}
296296

297-
const GEOSGeometry* QgsGeometry::asGeos() const
297+
const GEOSGeometry* QgsGeometry::asGeos( double precision ) const
298298
{
299299
if ( !d || !d->geometry )
300300
{
@@ -303,7 +303,7 @@ const GEOSGeometry* QgsGeometry::asGeos() const
303303

304304
if ( !d->mGeos )
305305
{
306-
d->mGeos = QgsGeos::asGeos( d->geometry );
306+
d->mGeos = QgsGeos::asGeos( d->geometry, precision );
307307
}
308308
return d->mGeos;
309309
}

‎src/core/geometry/qgsgeometry.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ class CORE_EXPORT QgsGeometry
161161
@note this method was added in version 1.1
162162
@note not available in python bindings
163163
*/
164-
const GEOSGeometry* asGeos() const;
164+
const GEOSGeometry* asGeos( double precision = 1E-8 ) const;
165165

166166
/** Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
167167
* @see type

‎src/core/geometry/qgsgeos.cpp‎

Lines changed: 79 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ class GEOSGeomScopedPtr
114114
GEOSGeometry* mGeom;
115115
};
116116

117-
QgsGeos::QgsGeos( const QgsAbstractGeometryV2* geometry, int precision ) : QgsGeometryEngine( geometry ), mGeos( 0 ), mGeosPrepared( 0 )
117+
QgsGeos::QgsGeos( const QgsAbstractGeometryV2* geometry, double precision )
118+
: QgsGeometryEngine( geometry ), mGeos( 0 ), mGeosPrepared( 0 ), mPrecision( precision )
118119
{
119120
cacheGeos();
120121
}
@@ -149,7 +150,7 @@ void QgsGeos::cacheGeos() const
149150
return;
150151
}
151152

152-
mGeos = asGeos( mGeometry );
153+
mGeos = asGeos( mGeometry, mPrecision );
153154
}
154155

155156
QgsAbstractGeometryV2* QgsGeos::intersection( const QgsAbstractGeometryV2& geom, QString* errorMsg ) const
@@ -174,7 +175,7 @@ QgsAbstractGeometryV2* QgsGeos::combine( const QList< const QgsAbstractGeometryV
174175
geosGeometries.resize( geomList.size() );
175176
for ( int i = 0; i < geomList.size(); ++i )
176177
{
177-
geosGeometries[i] = asGeos( geomList.at( i ) );
178+
geosGeometries[i] = asGeos( geomList.at( i ), mPrecision );
178179
}
179180

180181
GEOSGeometry* geomUnion = 0;
@@ -204,7 +205,7 @@ double QgsGeos::distance( const QgsAbstractGeometryV2& geom, QString* errorMsg )
204205
return distance;
205206
}
206207

207-
GEOSGeometry* otherGeosGeom = asGeos( &geom );
208+
GEOSGeometry* otherGeosGeom = asGeos( &geom, mPrecision );
208209
if ( !otherGeosGeom )
209210
{
210211
return distance;
@@ -321,12 +322,12 @@ int QgsGeos::splitGeometry( const QgsLineStringV2& splitLine,
321322
{
322323
if ( splitLine.numPoints() > 1 )
323324
{
324-
splitLineGeos = createGeosLinestring( &splitLine );
325+
splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
325326
}
326327
else if ( splitLine.numPoints() == 1 )
327328
{
328329
QgsPointV2 pt = splitLine.pointN( 0 );
329-
splitLineGeos = createGeosPoint( &pt, 2 );
330+
splitLineGeos = createGeosPoint( &pt, 2, mPrecision );
330331
}
331332
else
332333
{
@@ -490,7 +491,7 @@ GEOSGeometry* QgsGeos::linePointDifference( GEOSGeometry* GEOSsplitPoint ) const
490491

491492
delete splitGeom;
492493
delete multiCurve;
493-
return asGeos( &lines );
494+
return asGeos( &lines, mPrecision );
494495
}
495496

496497
int QgsGeos::splitLinearGeometry( GEOSGeometry* splitLine, QList<QgsAbstractGeometryV2*>& newGeometries ) const
@@ -958,7 +959,7 @@ QgsPointV2 QgsGeos::coordSeqPoint( const GEOSCoordSequence* cs, int i, bool hasZ
958959
return QgsPointV2( t, x, y, z, m );
959960
}
960961

961-
GEOSGeometry* QgsGeos::asGeos( const QgsAbstractGeometryV2* geom )
962+
GEOSGeometry* QgsGeos::asGeos( const QgsAbstractGeometryV2* geom, double precision )
962963
{
963964
int coordDims = 2;
964965
if ( geom->is3D() )
@@ -976,16 +977,16 @@ GEOSGeometry* QgsGeos::asGeos( const QgsAbstractGeometryV2* geom )
976977
if ( curve )
977978
{
978979
QScopedPointer< QgsLineStringV2> lineString( curve->curveToLine() );
979-
return createGeosLinestring( lineString.data() );
980+
return createGeosLinestring( lineString.data(), precision );
980981
}
981982
else if ( curvePolygon )
982983
{
983984
QScopedPointer<QgsPolygonV2> polygon( curvePolygon->toPolygon() );
984-
return createGeosPolygon( polygon.data() );
985+
return createGeosPolygon( polygon.data(), precision );
985986
}
986987
else if ( geom->geometryType() == "Point" )
987988
{
988-
return createGeosPoint( geom, coordDims );
989+
return createGeosPoint( geom, coordDims, precision );
989990
}
990991
else if ( QgsWKBTypes::isMultiType( geom->wkbType() ) )
991992
{
@@ -1016,7 +1017,7 @@ GEOSGeometry* QgsGeos::asGeos( const QgsAbstractGeometryV2* geom )
10161017
QVector< GEOSGeometry* > geomVector( c->numGeometries() );
10171018
for ( int i = 0; i < c->numGeometries(); ++i )
10181019
{
1019-
geomVector[i] = asGeos( c->geometryN( i ) );
1020+
geomVector[i] = asGeos( c->geometryN( i ), precision );
10201021
}
10211022
return createGeosCollection( geosType, geomVector );
10221023
}
@@ -1031,7 +1032,7 @@ QgsAbstractGeometryV2* QgsGeos::overlay( const QgsAbstractGeometryV2& geom, Over
10311032
return 0;
10321033
}
10331034

1034-
GEOSGeomScopedPtr geosGeom( asGeos( &geom ) );
1035+
GEOSGeomScopedPtr geosGeom( asGeos( &geom, mPrecision ) );
10351036
if ( !geosGeom )
10361037
{
10371038
return 0;
@@ -1091,7 +1092,7 @@ bool QgsGeos::relation( const QgsAbstractGeometryV2& geom, Relation r, QString*
10911092
return false;
10921093
}
10931094

1094-
GEOSGeomScopedPtr geosGeom( asGeos( &geom ) );
1095+
GEOSGeomScopedPtr geosGeom( asGeos( &geom, mPrecision ) );
10951096
if ( !geosGeom )
10961097
{
10971098
return false;
@@ -1348,7 +1349,7 @@ bool QgsGeos::isEqual( const QgsAbstractGeometryV2& geom, QString* errorMsg ) co
13481349

13491350
try
13501351
{
1351-
GEOSGeomScopedPtr geosGeom( asGeos( &geom ) );
1352+
GEOSGeomScopedPtr geosGeom( asGeos( &geom, mPrecision ) );
13521353
if ( !geosGeom )
13531354
{
13541355
return false;
@@ -1373,7 +1374,7 @@ bool QgsGeos::isEmpty( QString* errorMsg ) const
13731374
CATCH_GEOS_WITH_ERRMSG( false );
13741375
}
13751376

1376-
GEOSCoordSequence* QgsGeos::createCoordinateSequence( const QgsCurveV2* curve )
1377+
GEOSCoordSequence* QgsGeos::createCoordinateSequence( const QgsCurveV2* curve, double precision )
13771378
{
13781379
bool segmentize = false;
13791380
const QgsLineStringV2* line = dynamic_cast<const QgsLineStringV2*>( curve );
@@ -1406,18 +1407,38 @@ GEOSCoordSequence* QgsGeos::createCoordinateSequence( const QgsCurveV2* curve )
14061407
try
14071408
{
14081409
coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, numPoints, coordDims );
1409-
for ( int i = 0; i < numPoints; ++i )
1410+
if ( precision > 0. )
14101411
{
1411-
QgsPointV2 pt = line->pointN( i ); //todo: create method to get const point reference
1412-
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, pt.x() );
1413-
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, pt.y() );
1414-
if ( hasZ )
1412+
for ( int i = 0; i < numPoints; ++i )
14151413
{
1416-
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, pt.z() );
1414+
QgsPointV2 pt = line->pointN( i ); //todo: create method to get const point reference
1415+
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( pt.x() / precision ) * precision );
1416+
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( pt.y() / precision ) * precision );
1417+
if ( hasZ )
1418+
{
1419+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( pt.z() / precision ) * precision );
1420+
}
1421+
if ( hasM )
1422+
{
1423+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, pt.m() );
1424+
}
14171425
}
1418-
if ( hasM )
1426+
}
1427+
else
1428+
{
1429+
for ( int i = 0; i < numPoints; ++i )
14191430
{
1420-
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, pt.m() );
1431+
QgsPointV2 pt = line->pointN( i ); //todo: create method to get const point reference
1432+
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, pt.x() );
1433+
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, pt.y() );
1434+
if ( hasZ )
1435+
{
1436+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, pt.z() );
1437+
}
1438+
if ( hasM )
1439+
{
1440+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, pt.m() );
1441+
}
14211442
}
14221443
}
14231444
}
@@ -1430,7 +1451,7 @@ GEOSCoordSequence* QgsGeos::createCoordinateSequence( const QgsCurveV2* curve )
14301451
return coordSeq;
14311452
}
14321453

1433-
GEOSGeometry* QgsGeos::createGeosPoint( const QgsAbstractGeometryV2* point, int coordDims )
1454+
GEOSGeometry* QgsGeos::createGeosPoint( const QgsAbstractGeometryV2* point, int coordDims, double precision )
14341455
{
14351456
const QgsPointV2* pt = dynamic_cast<const QgsPointV2*>( point );
14361457
if ( !pt )
@@ -1441,11 +1462,23 @@ GEOSGeometry* QgsGeos::createGeosPoint( const QgsAbstractGeometryV2* point, int
14411462
try
14421463
{
14431464
GEOSCoordSequence* coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, 1, coordDims );
1444-
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, pt->x() );
1445-
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, pt->y() );
1446-
if ( pt->is3D() )
1465+
if ( precision > 0. )
14471466
{
1448-
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, pt->z() );
1467+
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, std::round( pt->x() / precision ) * precision );
1468+
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, std::round( pt->y() / precision ) * precision );
1469+
if ( pt->is3D() )
1470+
{
1471+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, std::round( pt->z() / precision ) * precision );
1472+
}
1473+
}
1474+
else
1475+
{
1476+
GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, pt->x() );
1477+
GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, pt->y() );
1478+
if ( pt->is3D() )
1479+
{
1480+
GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, pt->z() );
1481+
}
14491482
}
14501483
if ( 0 /*pt->isMeasure()*/ ) //disabled until geos supports m-coordinates
14511484
{
@@ -1457,13 +1490,13 @@ GEOSGeometry* QgsGeos::createGeosPoint( const QgsAbstractGeometryV2* point, int
14571490
return geosPoint;
14581491
}
14591492

1460-
GEOSGeometry* QgsGeos::createGeosLinestring( const QgsAbstractGeometryV2* curve )
1493+
GEOSGeometry* QgsGeos::createGeosLinestring( const QgsAbstractGeometryV2* curve , double precision )
14611494
{
14621495
const QgsCurveV2* c = dynamic_cast<const QgsCurveV2*>( curve );
14631496
if ( !c )
14641497
return 0;
14651498

1466-
GEOSCoordSequence* coordSeq = createCoordinateSequence( c );
1499+
GEOSCoordSequence* coordSeq = createCoordinateSequence( c, precision );
14671500
if ( !coordSeq )
14681501
return 0;
14691502

@@ -1476,7 +1509,7 @@ GEOSGeometry* QgsGeos::createGeosLinestring( const QgsAbstractGeometryV2* curve
14761509
return geosGeom;
14771510
}
14781511

1479-
GEOSGeometry* QgsGeos::createGeosPolygon( const QgsAbstractGeometryV2* poly )
1512+
GEOSGeometry* QgsGeos::createGeosPolygon( const QgsAbstractGeometryV2* poly , double precision )
14801513
{
14811514
const QgsCurvePolygonV2* polygon = dynamic_cast<const QgsCurvePolygonV2*>( poly );
14821515
if ( !polygon )
@@ -1491,7 +1524,7 @@ GEOSGeometry* QgsGeos::createGeosPolygon( const QgsAbstractGeometryV2* poly )
14911524
GEOSGeometry* geosPolygon = 0;
14921525
try
14931526
{
1494-
GEOSGeometry* exteriorRingGeos = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( exteriorRing ) );
1527+
GEOSGeometry* exteriorRingGeos = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( exteriorRing, precision ) );
14951528

14961529

14971530
int nHoles = polygon->numInteriorRings();
@@ -1504,7 +1537,7 @@ GEOSGeometry* QgsGeos::createGeosPolygon( const QgsAbstractGeometryV2* poly )
15041537
for ( int i = 0; i < nHoles; ++i )
15051538
{
15061539
const QgsCurveV2* interiorRing = polygon->interiorRing( i );
1507-
holes[i] = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( interiorRing ) );
1540+
holes[i] = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( interiorRing, precision ) );
15081541
}
15091542
geosPolygon = GEOSGeom_createPolygon_r( geosinit.ctxt, exteriorRingGeos, holes, nHoles );
15101543
delete[] holes;
@@ -1538,7 +1571,7 @@ QgsAbstractGeometryV2* QgsGeos::reshapeGeometry( const QgsLineStringV2& reshapeW
15381571
return 0;
15391572
}
15401573

1541-
GEOSGeometry* reshapeLineGeos = createGeosLinestring( &reshapeWithLine );
1574+
GEOSGeometry* reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
15421575

15431576
//single or multi?
15441577
int numGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, mGeos );
@@ -1560,11 +1593,11 @@ QgsAbstractGeometryV2* QgsGeos::reshapeGeometry( const QgsLineStringV2& reshapeW
15601593
GEOSGeometry* reshapedGeometry;
15611594
if ( isLine )
15621595
{
1563-
reshapedGeometry = reshapeLine( mGeos, reshapeLineGeos );
1596+
reshapedGeometry = reshapeLine( mGeos, reshapeLineGeos, mPrecision );
15641597
}
15651598
else
15661599
{
1567-
reshapedGeometry = reshapePolygon( mGeos, reshapeLineGeos );
1600+
reshapedGeometry = reshapePolygon( mGeos, reshapeLineGeos, mPrecision );
15681601
}
15691602

15701603
if ( errorCode ) { *errorCode = 0; }
@@ -1585,9 +1618,9 @@ QgsAbstractGeometryV2* QgsGeos::reshapeGeometry( const QgsLineStringV2& reshapeW
15851618
for ( int i = 0; i < numGeoms; ++i )
15861619
{
15871620
if ( isLine )
1588-
currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit.ctxt, mGeos, i ), reshapeLineGeos );
1621+
currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit.ctxt, mGeos, i ), reshapeLineGeos, mPrecision );
15891622
else
1590-
currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit.ctxt, mGeos, i ), reshapeLineGeos );
1623+
currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit.ctxt, mGeos, i ), reshapeLineGeos, mPrecision );
15911624

15921625
if ( currentReshapeGeometry )
15931626
{
@@ -1636,7 +1669,7 @@ QgsAbstractGeometryV2* QgsGeos::reshapeGeometry( const QgsLineStringV2& reshapeW
16361669
}
16371670
}
16381671

1639-
GEOSGeometry* QgsGeos::reshapeLine( const GEOSGeometry* line, const GEOSGeometry* reshapeLineGeos )
1672+
GEOSGeometry* QgsGeos::reshapeLine( const GEOSGeometry* line, const GEOSGeometry* reshapeLineGeos , double precision )
16401673
{
16411674
if ( !line || !reshapeLineGeos )
16421675
return 0;
@@ -1682,9 +1715,9 @@ GEOSGeometry* QgsGeos::reshapeLine( const GEOSGeometry* line, const GEOSGeometry
16821715
GEOSCoordSeq_getX_r( geosinit.ctxt, lineCoordSeq, lineCoordSeqSize - 1, &x2 );
16831716
GEOSCoordSeq_getY_r( geosinit.ctxt, lineCoordSeq, lineCoordSeqSize - 1, &y2 );
16841717
QgsPointV2 beginPoint( x1, y1 );
1685-
GEOSGeometry* beginLineVertex = createGeosPoint( &beginPoint, 2 );
1718+
GEOSGeometry* beginLineVertex = createGeosPoint( &beginPoint, 2, precision );
16861719
QgsPointV2 endPoint( x2, y2 );
1687-
GEOSGeometry* endLineVertex = createGeosPoint( &endPoint, 2 );
1720+
GEOSGeometry* endLineVertex = createGeosPoint( &endPoint, 2, precision );
16881721

16891722
bool isRing = false;
16901723
if ( GEOSGeomTypeId_r( geosinit.ctxt, line ) == GEOS_LINEARRING
@@ -1742,9 +1775,9 @@ GEOSGeometry* QgsGeos::reshapeLine( const GEOSGeometry* line, const GEOSGeometry
17421775
GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
17431776
GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
17441777
QgsPointV2 beginPoint( xBegin, yBegin );
1745-
GEOSGeometry* beginCurrentGeomVertex = createGeosPoint( &beginPoint, 2 );
1778+
GEOSGeometry* beginCurrentGeomVertex = createGeosPoint( &beginPoint, 2, precision );
17461779
QgsPointV2 endPoint( xEnd, yEnd );
1747-
GEOSGeometry* endCurrentGeomVertex = createGeosPoint( &endPoint, 2 );
1780+
GEOSGeometry* endCurrentGeomVertex = createGeosPoint( &endPoint, 2, precision );
17481781

17491782
//check how many endpoints of the line merge result are on the (original) line
17501783
int nEndpointsOnOriginalLine = 0;
@@ -1864,7 +1897,7 @@ GEOSGeometry* QgsGeos::reshapeLine( const GEOSGeometry* line, const GEOSGeometry
18641897
return result;
18651898
}
18661899

1867-
GEOSGeometry* QgsGeos::reshapePolygon( const GEOSGeometry* polygon, const GEOSGeometry* reshapeLineGeos )
1900+
GEOSGeometry* QgsGeos::reshapePolygon( const GEOSGeometry* polygon, const GEOSGeometry* reshapeLineGeos, double precision )
18681901
{
18691902
//go through outer shell and all inner rings and check if there is exactly one intersection of a ring and the reshape line
18701903
int nIntersections = 0;
@@ -1913,7 +1946,7 @@ GEOSGeometry* QgsGeos::reshapePolygon( const GEOSGeometry* polygon, const GEOSGe
19131946
}
19141947

19151948
//we have one intersecting ring, let's try to reshape it
1916-
GEOSGeometry* reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos );
1949+
GEOSGeometry* reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos, precision );
19171950
if ( !reshapeResult )
19181951
{
19191952
delete [] innerRings;

0 commit comments

Comments
 (0)