Skip to content

Commit

Permalink
Tests and fixes for QgsPolygonV2
Browse files Browse the repository at this point in the history
- Setting exterior ring will force all interior rings to match
dimensionality of exterior ring
- add equality operator
- use correct WKB types for rings when creating polygon from WKB
- segmentize curves when setting exterior ring with curved segments
- fix export to GML2/3 (should use LinearRing, not LineString as
ring element tag)
  • Loading branch information
nyalldawson committed Dec 15, 2015
1 parent 2f72b3b commit 4e18d54
Show file tree
Hide file tree
Showing 19 changed files with 565 additions and 30 deletions.
3 changes: 3 additions & 0 deletions python/core/geometry/qgscircularstringv2.sip
Expand Up @@ -8,6 +8,9 @@ class QgsCircularStringV2: public QgsCurveV2
QgsCircularStringV2();
~QgsCircularStringV2();

virtual bool operator==( const QgsCurveV2& other ) const;
virtual bool operator!=( const QgsCurveV2& other ) const;

virtual QString geometryType() const;
virtual int dimension() const;
virtual QgsCircularStringV2* clone() const;
Expand Down
3 changes: 3 additions & 0 deletions python/core/geometry/qgscompoundcurvev2.sip
Expand Up @@ -10,6 +10,9 @@ class QgsCompoundCurveV2: public QgsCurveV2
//QgsCompoundCurveV2 &operator=( const QgsCompoundCurveV2 & curve );
~QgsCompoundCurveV2();

virtual bool operator==( const QgsCurveV2& other ) const;
virtual bool operator!=( const QgsCurveV2& other ) const;

virtual QString geometryType() const;
virtual int dimension() const;
virtual QgsCompoundCurveV2* clone() const;
Expand Down
11 changes: 9 additions & 2 deletions python/core/geometry/qgscurvepolygonv2.sip
Expand Up @@ -39,8 +39,15 @@ class QgsCurvePolygonV2: public QgsSurfaceV2
QgsCurveV2* interiorRing( int i ) const;
virtual QgsPolygonV2* toPolygon() const;

/** Sets exterior ring (takes ownership)*/
void setExteriorRing( QgsCurveV2* ring /Transfer/ );
/** Sets the exterior ring of the polygon. The CurvePolygon type will be updated to match the dimensionality
* of the exterior ring. For instance, setting a 2D exterior ring on a 3D CurvePolygon will drop the z dimension
* from the CurvePolygon and all interior rings.
* @param ring new exterior ring. Ownership is transferred to the CurvePolygon.
* @see setInteriorRings()
* @see exteriorRing()
*/
virtual void setExteriorRing( QgsCurveV2* ring /Transfer/ );

/** Sets interior rings (takes ownership)*/
void setInteriorRings( const QList<QgsCurveV2*>& rings );
virtual void addInteriorRing( QgsCurveV2* ring /Transfer/ );
Expand Down
8 changes: 7 additions & 1 deletion python/core/geometry/qgscurvev2.sip
Expand Up @@ -6,6 +6,12 @@ class QgsCurveV2: public QgsAbstractGeometryV2
public:
QgsCurveV2();
virtual ~QgsCurveV2();

virtual bool operator==( const QgsCurveV2& other ) const = 0;
virtual bool operator!=( const QgsCurveV2& other ) const = 0;

virtual QgsCurveV2* clone() const = 0;

virtual QgsPointV2 startPoint() const = 0;
virtual QgsPointV2 endPoint() const = 0;
virtual bool isClosed() const;
Expand All @@ -29,7 +35,7 @@ class QgsCurveV2: public QgsAbstractGeometryV2
virtual QgsCurveV2* reversed() const = 0 /Factory/;

/** Returns a geometry without curves. Caller takes ownership*/
QgsAbstractGeometryV2* segmentize() const /Factory/;
virtual QgsCurveV2* segmentize() const /Factory/;

virtual int vertexCount(int part = 0, int ring = 0) const;
virtual int ringCount(int part = 0) const;
Expand Down
4 changes: 2 additions & 2 deletions python/core/geometry/qgslinestringv2.sip
Expand Up @@ -14,8 +14,8 @@ class QgsLineStringV2: public QgsCurveV2
QgsLineStringV2();
~QgsLineStringV2();

bool operator==( const QgsLineStringV2& other ) const;
bool operator!=( const QgsLineStringV2& other ) const;
bool operator==( const QgsCurveV2& other ) const;
bool operator!=( const QgsCurveV2& other ) const;

/** Returns the specified point from inside the line string.
* @param i index of point, starting at 0 for the first point
Expand Down
5 changes: 5 additions & 0 deletions python/core/geometry/qgspolygonv2.sip
Expand Up @@ -7,6 +7,9 @@ class QgsPolygonV2: public QgsCurvePolygonV2
public:
QgsPolygonV2();

bool operator==( const QgsPolygonV2& other ) const;
bool operator!=( const QgsPolygonV2& other ) const;

virtual QString geometryType() const;
virtual QgsPolygonV2* clone() const;

Expand All @@ -23,4 +26,6 @@ class QgsPolygonV2: public QgsCurvePolygonV2
QgsPolygonV2* surfaceToPolygon() const;

void addInteriorRing( QgsCurveV2* ring /Transfer/ );
//overridden to handle LineString25D rings
virtual void setExteriorRing( QgsCurveV2* ring /Transfer/ );
};
14 changes: 14 additions & 0 deletions src/core/geometry/qgscircularstringv2.cpp
Expand Up @@ -36,6 +36,20 @@ QgsCircularStringV2::~QgsCircularStringV2()

}

bool QgsCircularStringV2::operator==( const QgsCurveV2& other ) const
{
const QgsCircularStringV2* otherLine = dynamic_cast< const QgsCircularStringV2* >( &other );
if ( !otherLine )
return false;

return *otherLine == *this;
}

bool QgsCircularStringV2::operator!=( const QgsCurveV2& other ) const
{
return !operator==( other );
}

QgsCircularStringV2 *QgsCircularStringV2::clone() const
{
return new QgsCircularStringV2( *this );
Expand Down
3 changes: 3 additions & 0 deletions src/core/geometry/qgscircularstringv2.h
Expand Up @@ -33,6 +33,9 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2
QgsCircularStringV2();
~QgsCircularStringV2();

virtual bool operator==( const QgsCurveV2& other ) const override;
virtual bool operator!=( const QgsCurveV2& other ) const override;

virtual QString geometryType() const override { return "CircularString"; }
virtual int dimension() const override { return 1; }
virtual QgsCircularStringV2* clone() const override;
Expand Down
14 changes: 14 additions & 0 deletions src/core/geometry/qgscompoundcurvev2.cpp
Expand Up @@ -35,6 +35,20 @@ QgsCompoundCurveV2::~QgsCompoundCurveV2()
clear();
}

bool QgsCompoundCurveV2::operator==( const QgsCurveV2& other ) const
{
const QgsCompoundCurveV2* otherCurve = dynamic_cast< const QgsCompoundCurveV2* >( &other );
if ( !otherCurve )
return false;

return *otherCurve == *this;
}

bool QgsCompoundCurveV2::operator!=( const QgsCurveV2& other ) const
{
return !operator==( other );
}

QgsCompoundCurveV2::QgsCompoundCurveV2( const QgsCompoundCurveV2& curve ): QgsCurveV2( curve )
{
Q_FOREACH ( const QgsCurveV2* c, curve.mCurves )
Expand Down
3 changes: 3 additions & 0 deletions src/core/geometry/qgscompoundcurvev2.h
Expand Up @@ -34,6 +34,9 @@ class CORE_EXPORT QgsCompoundCurveV2: public QgsCurveV2
QgsCompoundCurveV2& operator=( const QgsCompoundCurveV2& curve );
~QgsCompoundCurveV2();

virtual bool operator==( const QgsCurveV2& other ) const override;
virtual bool operator!=( const QgsCurveV2& other ) const override;

virtual QString geometryType() const override { return "CompoundCurve"; }
virtual int dimension() const override { return 1; }
virtual QgsCompoundCurveV2* clone() const override;
Expand Down
30 changes: 26 additions & 4 deletions src/core/geometry/qgscurvepolygonv2.cpp
Expand Up @@ -291,14 +291,18 @@ QDomElement QgsCurvePolygonV2::asGML2( QDomDocument& doc, int precision, const Q
QDomElement elemPolygon = doc.createElementNS( ns, "Polygon" );
QDomElement elemOuterBoundaryIs = doc.createElementNS( ns, "outerBoundaryIs" );
QgsLineStringV2* exteriorLineString = exteriorRing()->curveToLine();
elemOuterBoundaryIs.appendChild( exteriorLineString->asGML2( doc, precision, ns ) );
QDomElement outerRing = exteriorLineString->asGML2( doc, precision, ns );
outerRing.toElement().setTagName( "LinearRing" );
elemOuterBoundaryIs.appendChild( outerRing );
delete exteriorLineString;
elemPolygon.appendChild( elemOuterBoundaryIs );
QDomElement elemInnerBoundaryIs = doc.createElementNS( ns, "innerBoundaryIs" );
for ( int i = 0, n = numInteriorRings(); i < n; ++i )
{
QgsLineStringV2* interiorLineString = interiorRing( i )->curveToLine();
elemInnerBoundaryIs.appendChild( interiorLineString->asGML2( doc, precision, ns ) );
QDomElement innerRing = interiorLineString->asGML2( doc, precision, ns );
innerRing.toElement().setTagName( "LinearRing" );
elemInnerBoundaryIs.appendChild( innerRing );
delete interiorLineString;
}
elemPolygon.appendChild( elemInnerBoundaryIs );
Expand All @@ -309,12 +313,16 @@ QDomElement QgsCurvePolygonV2::asGML3( QDomDocument& doc, int precision, const Q
{
QDomElement elemCurvePolygon = doc.createElementNS( ns, "Polygon" );
QDomElement elemExterior = doc.createElementNS( ns, "exterior" );
elemExterior.appendChild( exteriorRing()->asGML2( doc, precision, ns ) );
QDomElement outerRing = exteriorRing()->asGML2( doc, precision, ns );
outerRing.toElement().setTagName( "LinearRing" );
elemExterior.appendChild( outerRing );
elemCurvePolygon.appendChild( elemExterior );
QDomElement elemInterior = doc.createElementNS( ns, "interior" );
for ( int i = 0, n = numInteriorRings(); i < n; ++i )
{
elemInterior.appendChild( interiorRing( i )->asGML2( doc, precision, ns ) );
QDomElement innerRing = interiorRing( i )->asGML2( doc, precision, ns );
innerRing.toElement().setTagName( "LinearRing" );
elemInterior.appendChild( innerRing );
}
elemCurvePolygon.appendChild( elemInterior );
return elemCurvePolygon;
Expand Down Expand Up @@ -468,6 +476,20 @@ void QgsCurvePolygonV2::setExteriorRing( QgsCurveV2* ring )
{
setZMTypeFromSubGeometry( ring, QgsWKBTypes::CurvePolygon );
}

//match dimensionality for rings
Q_FOREACH ( QgsCurveV2* ring, mInteriorRings )
{
if ( is3D() )
ring->addZValue();
else
ring->dropZValue();

if ( isMeasure() )
ring->addMValue();
else
ring->dropMValue();
}
}

void QgsCurvePolygonV2::setInteriorRings( const QList<QgsCurveV2*>& rings )
Expand Down
12 changes: 10 additions & 2 deletions src/core/geometry/qgscurvepolygonv2.h
Expand Up @@ -65,8 +65,15 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2
QgsCurveV2* interiorRing( int i ) const;
virtual QgsPolygonV2* toPolygon() const;

/** Sets exterior ring (takes ownership)*/
void setExteriorRing( QgsCurveV2* ring );
/** Sets the exterior ring of the polygon. The CurvePolygon type will be updated to match the dimensionality
* of the exterior ring. For instance, setting a 2D exterior ring on a 3D CurvePolygon will drop the z dimension
* from the CurvePolygon and all interior rings.
* @param ring new exterior ring. Ownership is transferred to the CurvePolygon.
* @see setInteriorRings()
* @see exteriorRing()
*/
virtual void setExteriorRing( QgsCurveV2* ring );

/** Sets all interior rings (takes ownership)*/
void setInteriorRings( const QList<QgsCurveV2*>& rings );
/** Adds an interior ring to the geometry (takes ownership)*/
Expand Down Expand Up @@ -112,6 +119,7 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2

QgsCurveV2* mExteriorRing;
QList<QgsCurveV2*> mInteriorRings;

};

#endif // QGSCURVEPOLYGONV2_H
2 changes: 1 addition & 1 deletion src/core/geometry/qgscurvev2.cpp
Expand Up @@ -77,7 +77,7 @@ bool QgsCurveV2::nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const
return pointAt( id.vertex, vertex, id.type );
}

QgsAbstractGeometryV2* QgsCurveV2::segmentize() const
QgsCurveV2* QgsCurveV2::segmentize() const
{
return curveToLine();
}
Expand Down
7 changes: 6 additions & 1 deletion src/core/geometry/qgscurvev2.h
Expand Up @@ -35,6 +35,11 @@ class CORE_EXPORT QgsCurveV2: public QgsAbstractGeometryV2
QgsCurveV2();
virtual ~QgsCurveV2();

virtual bool operator==( const QgsCurveV2& other ) const = 0;
virtual bool operator!=( const QgsCurveV2& other ) const = 0;

virtual QgsCurveV2* clone() const override = 0;

/** Returns the starting point of the curve.
* @see endPoint
*/
Expand Down Expand Up @@ -96,7 +101,7 @@ class CORE_EXPORT QgsCurveV2: public QgsAbstractGeometryV2
*/
virtual QgsCurveV2* reversed() const = 0;

QgsAbstractGeometryV2* segmentize() const override;
QgsCurveV2* segmentize() const override;

virtual int vertexCount( int /*part*/ = 0, int /*ring*/ = 0 ) const override { return numPoints(); }
virtual int ringCount( int /*part*/ = 0 ) const override { return numPoints() > 0 ? 1 : 0; }
Expand Down
20 changes: 12 additions & 8 deletions src/core/geometry/qgslinestringv2.cpp
Expand Up @@ -41,31 +41,35 @@ QgsLineStringV2::QgsLineStringV2(): QgsCurveV2()
QgsLineStringV2::~QgsLineStringV2()
{}

bool QgsLineStringV2::operator==( const QgsLineStringV2& other ) const
bool QgsLineStringV2::operator==( const QgsCurveV2& other ) const
{
if ( mWkbType != other.mWkbType )
const QgsLineStringV2* otherLine = dynamic_cast< const QgsLineStringV2* >( &other );
if ( !otherLine )
return false;

if ( mX.count() != other.mX.count() )
if ( mWkbType != otherLine->mWkbType )
return false;

if ( mX.count() != otherLine->mX.count() )
return false;

for ( int i = 0; i < mX.count(); ++i )
{
if ( !qgsDoubleNear( mX.at( i ), other.mX.at( i ) )
|| !qgsDoubleNear( mY.at( i ), other.mY.at( i ) ) )
if ( !qgsDoubleNear( mX.at( i ), otherLine->mX.at( i ) )
|| !qgsDoubleNear( mY.at( i ), otherLine->mY.at( i ) ) )
return false;

if ( is3D() && !qgsDoubleNear( mZ.at( i ), other.mZ.at( i ) ) )
if ( is3D() && !qgsDoubleNear( mZ.at( i ), otherLine->mZ.at( i ) ) )
return false;

if ( isMeasure() && !qgsDoubleNear( mM.at( i ), other.mM.at( i ) ) )
if ( isMeasure() && !qgsDoubleNear( mM.at( i ), otherLine->mM.at( i ) ) )
return false;
}

return true;
}

bool QgsLineStringV2::operator!=( const QgsLineStringV2& other ) const
bool QgsLineStringV2::operator!=( const QgsCurveV2& other ) const
{
return !operator==( other );
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/geometry/qgslinestringv2.h
Expand Up @@ -39,8 +39,8 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2
QgsLineStringV2();
~QgsLineStringV2();

bool operator==( const QgsLineStringV2& other ) const;
bool operator!=( const QgsLineStringV2& other ) const;
bool operator==( const QgsCurveV2& other ) const override;
bool operator!=( const QgsCurveV2& other ) const override;

/** Returns the specified point from inside the line string.
* @param i index of point, starting at 0 for the first point
Expand Down

0 comments on commit 4e18d54

Please sign in to comment.