Skip to content

Commit

Permalink
Improved support for parsing of GML2, added some autotests
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Mar 6, 2013
1 parent ed48ffb commit d628c2c
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 16 deletions.
12 changes: 12 additions & 0 deletions python/core/qgsgeometry.sip
Expand Up @@ -41,6 +41,18 @@ class QgsGeometry
/** static method that creates geometry from Wkt */
static QgsGeometry* fromWkt( QString wkt ) /Factory/;

/** static method that creates geometry from GML2
@param XML representation of the geometry. GML elements are expected to be
in default namespace (<Point>...</Point>) or in "gml" namespace (<gml:Point>...</gml:Point>)
@note added in 1.9
*/
static QgsGeometry* fromGML2( const QString& xmlString ) /Factory/;

/** static method that creates geometry from GML2
@note added in 1.9
*/
static QgsGeometry* fromGML2( const QDomNode& geometryNode ) /Factory/;

/** construct geometry from a point */
static QgsGeometry* fromPoint( const QgsPoint& point ) /Factory/;
/** construct geometry from a multipoint */
Expand Down
15 changes: 1 addition & 14 deletions src/core/qgsexpression.cpp
Expand Up @@ -795,21 +795,8 @@ static QVariant fcnGeomFromWKT( const QVariantList& values, QgsFeature*, QgsExpr
}
static QVariant fcnGeomFromGML2( const QVariantList& values, QgsFeature*, QgsExpression* parent )
{
QDomDocument doc;
QString errorMsg;
QString gml = getStringValue( values.at( 0 ), parent );
if ( !doc.setContent( gml, true, &errorMsg ) )
return QVariant();

QgsGeometry* geom = 0;
QDomElement elem = doc.documentElement();
if ( elem.tagName() == "Box" )
{
QgsRectangle* rect = new QgsRectangle( elem );
geom = QgsGeometry::fromRect( *rect );
}
else
geom = QgsGeometry::fromGML2( doc.documentElement() );
QgsGeometry* geom = QgsGeometry::fromGML2( gml );

if ( geom )
return QVariant::fromValue( *geom );
Expand Down
20 changes: 18 additions & 2 deletions src/core/qgsgeometry.cpp
Expand Up @@ -540,7 +540,7 @@ QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode )
QDomElement geometryTypeElement = geometryNode.toElement();
QString geomType = geometryTypeElement.tagName();

if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" ) )
if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) )
{
QDomNode geometryChild = geometryNode.firstChild();
if ( geometryChild.isNull() )
Expand All @@ -551,7 +551,7 @@ QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode )
geomType = geometryTypeElement.tagName();
}

if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" ) )
if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) )
return 0;

if ( geomType == "Point" && g->setFromGML2Point( geometryTypeElement ) )
Expand All @@ -578,12 +578,28 @@ QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode )
{
return g;
}
else if ( geomType == "Box" )
{
return QgsGeometry::fromRect( QgsRectangle( geometryTypeElement ) );
}
else //unknown type
{
return 0;
}
}

QgsGeometry* QgsGeometry::fromGML2( const QString& xmlString )
{
// wrap the string into a root tag to have "gml" namespace (and also as a default namespace)
QString xml = QString( "<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>").arg( GML_NAMESPACE ).arg( xmlString );
QDomDocument doc;
if ( !doc.setContent( xml, true ) )
return 0;

return fromGML2( doc.documentElement().firstChildElement() );
}


bool QgsGeometry::setFromGML2Point( const QDomElement& geometryElement )
{
QDomNodeList coordList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" );
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgsgeometry.h
Expand Up @@ -89,6 +89,13 @@ class CORE_EXPORT QgsGeometry
/** static method that creates geometry from Wkt */
static QgsGeometry* fromWkt( QString wkt );

/** static method that creates geometry from GML2
@param XML representation of the geometry. GML elements are expected to be
in default namespace (<Point>...</Point>) or in "gml" namespace (<gml:Point>...</gml:Point>)
@note added in 1.9
*/
static QgsGeometry* fromGML2( const QString& xmlString );

/** static method that creates geometry from GML2
@note added in 1.9
*/
Expand Down
121 changes: 121 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -569,6 +569,20 @@ class TestQgsExpression: public QObject
QTest::newRow( "geomFromWKT Line" ) << "geomFromWKT('" + QgsGeometry::fromPolyline( line )->exportToWkt() + "')" << ( void* ) QgsGeometry::fromPolyline( line ) << false;
QTest::newRow( "geomFromWKT Polyline" ) << "geomFromWKT('" + QgsGeometry::fromPolyline( polyline )->exportToWkt() + "')" << ( void* ) QgsGeometry::fromPolyline( polyline ) << false;
QTest::newRow( "geomFromWKT Polygon" ) << "geomFromWKT('" + QgsGeometry::fromPolygon( polygon )->exportToWkt() + "')" << ( void* ) QgsGeometry::fromPolygon( polygon ) << false;

// GML Point
QTest::newRow( "GML Point (coordinates)" ) << "geomFromGML2('<gml:Point><gml:coordinates>123,456</gml:coordinates></gml:Point>')" << ( void * ) QgsGeometry::fromPoint( point ) << false;
// gml:pos if from GML3
//QTest::newRow( "GML Point (pos)" ) << "geomFromGML2('<gml:Point srsName=\"foo\"><gml:pos srsDimension=\"2\">123 456</gml:pos></gml:Point>')" << ( void * ) QgsGeometry::fromPoint( point ) << false;

// GML Box
QgsRectangle rect( 135.2239, 34.4879, 135.8578, 34.8471 );
QTest::newRow( "GML Box" ) << "geomFromGML2('<gml:Box srsName=\"foo\"><gml:coordinates>135.2239,34.4879 135.8578,34.8471</gml:coordinates></gml:Box>')" << ( void * ) QgsGeometry::fromRect( rect ) << false;
// Envelope is from GML3 ?
//QTest::newRow( "GML Envelope" ) << "geomFromGML2('<gml:Envelope>"
// "<gml:lowerCorner>135.2239 34.4879</gml:lowerCorner>"
// "<gml:upperCorner>135.8578 34.8471</gml:upperCorner>"
// "</gml:Envelope>')" << ( void * ) QgsGeometry::fromRect( rect ) << false;
}

void eval_geometry_constructor()
Expand Down Expand Up @@ -744,6 +758,113 @@ class TestQgsExpression: public QObject
QgsExpression::unsetSpecialColumn( "$var1" );
}


void test_from_ogc_filter_data()
{
QTest::addColumn<QString>( "xmlText" );
QTest::addColumn<QString>( "dumpText" );

QTest::newRow( "=" ) << QString(
"<Filter><PropertyIsEqualTo>"
"<PropertyName>NAME</PropertyName>"
"<Literal>New York</Literal>"
"</PropertyIsEqualTo></Filter>" )
<< QString( "NAME = 'New York'" );

QTest::newRow( ">" ) << QString(
"<Filter><PropertyIsGreaterThan>"
"<PropertyName>COUNT</PropertyName>"
"<Literal>3</Literal>"
"</PropertyIsGreaterThan></Filter>" )
<< QString( "COUNT > 3" );

QTest::newRow( "AND" ) << QString(
"<ogc:Filter>"
"<ogc:And>"
"<ogc:PropertyIsGreaterThanOrEqualTo>"
"<ogc:PropertyName>pop</ogc:PropertyName>"
"<ogc:Literal>50000</ogc:Literal>"
"</ogc:PropertyIsGreaterThanOrEqualTo>"
"<ogc:PropertyIsLessThan>"
"<ogc:PropertyName>pop</ogc:PropertyName>"
"<ogc:Literal>100000</ogc:Literal>"
"</ogc:PropertyIsLessThan>"
"</ogc:And>"
"</ogc:Filter>" )
<< QString( "pop >= 50000 AND pop < 100000" );

// TODO: should work also without <Literal> tags in Lower/Upper-Boundary tags?
QTest::newRow( "between" ) << QString(
"<Filter>"
"<PropertyIsBetween><PropertyName>POPULATION</PropertyName>"
"<LowerBoundary><Literal>100</Literal></LowerBoundary>"
"<UpperBoundary><Literal>200</Literal></UpperBoundary></PropertyIsBetween>"
"</Filter>" )
<< QString( "POPULATION >= 100 AND POPULATION <= 200" );

// TODO: needs to handle different wildcards, single chars, escape chars
QTest::newRow( "like" ) << QString(
"<Filter>"
"<PropertyIsLike wildcard='*' singleChar='.' escape='!'>"
"<PropertyName>NAME</PropertyName><Literal>*QGIS*</Literal></PropertyIsLike>"
"</Filter>" )
<< QString( "NAME LIKE '*QGIS*'" );

QTest::newRow( "is null" ) << QString(
"<Filter>"
"<ogc:PropertyIsNull>"
"<ogc:PropertyName>FIRST_NAME</ogc:PropertyName>"
"</ogc:PropertyIsNull>"
"</Filter>" )
<< QString( "FIRST_NAME IS NULL" );

QTest::newRow( "bbox" ) << QString(
"<Filter>"
"<BBOX><PropertyName>Name>NAME</PropertyName><gml:Box srsName='foo'>"
"<gml:coordinates>135.2239,34.4879 135.8578,34.8471</gml:coordinates></gml:Box></BBOX>"
"</Filter>" )
<< QString( "bbox($geometry, geomFromGML2('<Box srsName=\"foo\"><coordinates>135.2239,34.4879 135.8578,34.8471</coordinates></Box>'))" );

QTest::newRow( "Intersects" ) << QString(
"<Filter>"
"<Intersects>"
"<PropertyName>GEOMETRY</PropertyName>"
"<gml:Point>"
"<gml:coordinates>123,456</gml:coordinates>"
"</gml:Point>"
"</Intersects>"
"</Filter>" )
<< QString( "intersects($geometry, geomFromGML2('<Point><coordinates>123,456</coordinates></Point>'))" );
}

void test_from_ogc_filter()
{
QFETCH( QString, xmlText );
QFETCH( QString, dumpText );

QDomDocument doc;
QVERIFY(doc.setContent(xmlText, true));
QDomElement rootElem = doc.documentElement();

QgsExpression* expr = QgsExpression::createFromOgcFilter( rootElem );
QVERIFY( expr );

qDebug("OGC XML : %s", xmlText.toAscii().data() );
qDebug("EXPR-DUMP: %s", expr->dump().toAscii().data() );

if ( expr->hasParserError() )
qDebug( "ERROR: %s ", expr->parserErrorString().toAscii().data() );
QVERIFY( !expr->hasParserError() );

QCOMPARE( dumpText, expr->dump() );

delete expr;
}

void test_to_ogc_filter()
{
// TODO
}
};

QTEST_MAIN( TestQgsExpression )
Expand Down
16 changes: 16 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -55,6 +55,9 @@ class TestQgsGeometry: public QObject
void differenceCheck1();
void differenceCheck2();
void bufferCheck();

void gmlTest();

private:
/** A helper method to do a render check to see if the geometry op is as expected */
bool renderCheck( QString theTestName, QString theComment = "" );
Expand Down Expand Up @@ -369,6 +372,19 @@ void TestQgsGeometry::dumpPolyline( QgsPolyline &thePolyline )
mpPainter->drawPolyline( myPoints );
}

void TestQgsGeometry::gmlTest()
{
QgsGeometry* geom = QgsGeometry::fromGML2( "<Point><coordinates>123,456</coordinates></Point>" );
QVERIFY( geom );
QVERIFY( geom->wkbType() == QGis::WKBPoint );
QVERIFY( geom->asPoint() == QgsPoint( 123, 456 ) );

QgsGeometry* geomBox = QgsGeometry::fromGML2( "<gml:Box srsName=\"foo\"><gml:coordinates>135.2239,34.4879 135.8578,34.8471</gml:coordinates></gml:Box>" );
QVERIFY( geomBox );
QVERIFY( geomBox->wkbType() == QGis::WKBPolygon );
}


QTEST_MAIN( TestQgsGeometry )
#include "moc_testqgsgeometry.cxx"

0 comments on commit d628c2c

Please sign in to comment.