From 969df016bcdbd1ead8a347b7a5d55c8b36db183a Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Fri, 8 Mar 2013 00:30:21 +0100 Subject: [PATCH] Moved GML import/export to a new class: QgsOgcUtils --- python/core/core.sip | 1 + python/core/qgsgeometry.sip | 12 - python/core/qgsogcutils.sip | 32 + src/core/CMakeLists.txt | 2 + src/core/qgsexpression.cpp | 10 +- src/core/qgsgeometry.cpp | 929 ------------------------- src/core/qgsgeometry.h | 36 - src/core/qgsogcutils.cpp | 969 +++++++++++++++++++++++++++ src/core/qgsogcutils.h | 67 ++ src/core/qgsrectangle.cpp | 26 - src/core/qgsrectangle.h | 3 - src/mapserver/qgsfilter.cpp | 14 +- src/mapserver/qgswfsserver.cpp | 16 +- src/providers/wfs/qgswfsprovider.cpp | 8 +- tests/src/core/CMakeLists.txt | 1 + tests/src/core/testqgsgeometry.cpp | 14 - tests/src/core/testqgsogcutils.cpp | 67 ++ 17 files changed, 1166 insertions(+), 1041 deletions(-) create mode 100644 python/core/qgsogcutils.sip create mode 100644 src/core/qgsogcutils.cpp create mode 100644 src/core/qgsogcutils.h create mode 100644 tests/src/core/testqgsogcutils.cpp diff --git a/python/core/core.sip b/python/core/core.sip index 9cd10b13967..42b66b67730 100644 --- a/python/core/core.sip +++ b/python/core/core.sip @@ -47,6 +47,7 @@ %Include qgsmimedatautils.sip %Include qgsnetworkaccessmanager.sip %Include qgsofflineediting.sip +%Include qgsogcutils.sip %Include qgsoverlayobject.sip %Include qgsowsconnection.sip %Include qgspaintenginehack.sip diff --git a/python/core/qgsgeometry.sip b/python/core/qgsgeometry.sip index ac9e2729e25..c6c962c345c 100644 --- a/python/core/qgsgeometry.sip +++ b/python/core/qgsgeometry.sip @@ -41,18 +41,6 @@ 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 (...) or in "gml" namespace (...) - @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 */ diff --git a/python/core/qgsogcutils.sip b/python/core/qgsogcutils.sip new file mode 100644 index 00000000000..4306e1283b2 --- /dev/null +++ b/python/core/qgsogcutils.sip @@ -0,0 +1,32 @@ + + +class QgsOgcUtils +{ +%TypeHeaderCode +#include +%End + +public: + + /** static method that creates geometry from GML2 + @param XML representation of the geometry. GML elements are expected to be + in default namespace (...) or in "gml" namespace (...) + @note added in 1.9 + */ + static QgsGeometry* geometryFromGML2( const QString& xmlString ) /Factory/; + + /** static method that creates geometry from GML2 + @note added in 1.9 + */ + static QgsGeometry* geometryFromGML2( const QDomNode& geometryNode ) /Factory/; + + /** Exports the geometry to mGML2 + @return true in case of success and false else + */ + static QDomElement geometryToGML2( QgsGeometry* geometry, QDomDocument& doc ); + + /** read rectangle from GML2 Box */ + static QgsRectangle rectangleFromGMLBox( const QDomNode& boxNode ); + +}; + diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5aacc5c520f..4cd2bf45cea 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -86,6 +86,7 @@ SET(QGIS_CORE_SRCS qgsnetworkreplyparser.cpp qgscredentials.cpp qgsofflineediting.cpp + qgsogcutils.cpp qgsoverlayobject.cpp qgsowsconnection.cpp qgspalgeometry.cpp @@ -404,6 +405,7 @@ SET(QGIS_CORE_HDRS qgsnetworkreplyparser.h qgscredentials.h qgsofflineediting.h + qgsogcutils.h qgsoverlayobjectpositionmanager.h qgsowsconnection.h qgspallabeling.h diff --git a/src/core/qgsexpression.cpp b/src/core/qgsexpression.cpp index eebb757b0ef..502de7acf87 100644 --- a/src/core/qgsexpression.cpp +++ b/src/core/qgsexpression.cpp @@ -28,6 +28,7 @@ #include "qgsfeature.h" #include "qgsgeometry.h" #include "qgslogger.h" +#include "qgsogcutils.h" // from parser extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg ); @@ -796,7 +797,7 @@ static QVariant fcnGeomFromWKT( const QVariantList& values, QgsFeature*, QgsExpr static QVariant fcnGeomFromGML2( const QVariantList& values, QgsFeature*, QgsExpression* parent ) { QString gml = getStringValue( values.at( 0 ), parent ); - QgsGeometry* geom = QgsGeometry::fromGML2( gml ); + QgsGeometry* geom = QgsOgcUtils::geometryFromGML2( gml ); if ( geom ) return QVariant::fromValue( *geom ); @@ -2268,11 +2269,10 @@ void QgsExpression::NodeFunction::toOgcFilter( QDomDocument &doc, QDomElement &e { if ( childElem.attribute( "name" ) == "geomFromWKT" ) { - QgsGeometry* geom = 0; - geom = QgsGeometry::fromWkt( childElem.firstChildElement().text() ); + QgsGeometry* geom = QgsGeometry::fromWkt( childElem.firstChildElement().text() ); if ( geom ) - funcElem.appendChild( geom->exportToGML2( doc ) ); - + funcElem.appendChild( QgsOgcUtils::geometryToGML2( geom, doc ) ); + delete geom; } else if ( childElem.attribute( "name" ) == "geomFromGML2" ) { diff --git a/src/core/qgsgeometry.cpp b/src/core/qgsgeometry.cpp index f027d97178c..edfe258ab24 100644 --- a/src/core/qgsgeometry.cpp +++ b/src/core/qgsgeometry.cpp @@ -533,625 +533,6 @@ QgsGeometry* QgsGeometry::fromRect( const QgsRectangle& rect ) return fromPolygon( polygon ); } -static const QString GML_NAMESPACE = "http://www.opengis.net/gml"; -QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode ) -{ - QgsGeometry* g = new QgsGeometry(); - QDomElement geometryTypeElement = geometryNode.toElement(); - QString geomType = geometryTypeElement.tagName(); - - if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) ) - { - QDomNode geometryChild = geometryNode.firstChild(); - if ( geometryChild.isNull() ) - { - return 0; - } - geometryTypeElement = geometryChild.toElement(); - geomType = geometryTypeElement.tagName(); - } - - if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) ) - return 0; - - if ( geomType == "Point" && g->setFromGML2Point( geometryTypeElement ) ) - { - return g; - } - else if ( geomType == "LineString" && g->setFromGML2LineString( geometryTypeElement ) ) - { - return g; - } - else if ( geomType == "Polygon" && g->setFromGML2Polygon( geometryTypeElement ) ) - { - return g; - } - else if ( geomType == "MultiPoint" && g->setFromGML2MultiPoint( geometryTypeElement ) ) - { - return g; - } - else if ( geomType == "MultiLineString" && g->setFromGML2MultiLineString( geometryTypeElement ) ) - { - return g; - } - else if ( geomType == "MultiPolygon" && g->setFromGML2MultiPolygon( geometryTypeElement ) ) - { - 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( "%2").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" ); - if ( coordList.size() < 1 ) - { - return false; - } - QDomElement coordElement = coordList.at( 0 ).toElement(); - std::list pointCoordinate; - if ( readGML2Coordinates( pointCoordinate, coordElement ) != 0 ) - { - return false; - } - - if ( pointCoordinate.size() < 1 ) - { - return false; - } - - std::list::const_iterator point_it = pointCoordinate.begin(); - //char e = QgsApplication::endian(); - char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; - double x = point_it->x(); - double y = point_it->y(); - int size = 1 + sizeof( int ) + 2 * sizeof( double ); - - QGis::WkbType type = QGis::WKBPoint; - unsigned char* wkb = new unsigned char[size]; - - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); - - fromWkb( wkb, size ); - return true; -} - -bool QgsGeometry::setFromGML2LineString( const QDomElement& geometryElement ) -{ - QDomNodeList coordinatesList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( coordinatesList.size() < 1 ) - { - return false; - } - QDomElement coordinatesElement = coordinatesList.at( 0 ).toElement(); - std::list lineCoordinates; - if ( readGML2Coordinates( lineCoordinates, coordinatesElement ) != 0 ) - { - return false; - } - - //char e = QgsApplication::endian(); - char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; - int size = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double ); - - QGis::WkbType type = QGis::WKBLineString; - unsigned char* wkb = new unsigned char[size]; - - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - double x, y; - int nPoints = lineCoordinates.size(); - - //fill the contents into *wkb - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); - wkbPosition += sizeof( int ); - - std::list::const_iterator iter; - for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter ) - { - x = iter->x(); - y = iter->y(); - memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - - fromWkb( wkb, size ); - return true; -} - -bool QgsGeometry::setFromGML2Polygon( const QDomElement& geometryElement ) -{ - //read all the coordinates (as QgsPoint) into memory. Each linear ring has an entry in the vector - std::vector > ringCoordinates; - - //read coordinates for outer boundary - QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); - if ( outerBoundaryList.size() < 1 ) //outer ring is necessary - { - return false; - } - QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement(); - if ( coordinatesElement.isNull() ) - { - return false; - } - std::list exteriorPointList; - if ( readGML2Coordinates( exteriorPointList, coordinatesElement ) != 0 ) - { - return false; - } - ringCoordinates.push_back( exteriorPointList ); - - //read coordinates for inner boundary - QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); - for ( int i = 0; i < innerBoundaryList.size(); ++i ) - { - std::list interiorPointList; - QDomElement coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement(); - if ( coordinatesElement.isNull() ) - { - return false; - } - if ( readGML2Coordinates( interiorPointList, coordinatesElement ) != 0 ) - { - return false; - } - ringCoordinates.push_back( interiorPointList ); - } - - //calculate number of bytes to allocate - int nrings = ringCoordinates.size(); - int npoints = 0;//total number of points - for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) - { - npoints += it->size(); - } - int size = 1 + 2 * sizeof( int ) + nrings * sizeof( int ) + 2 * npoints * sizeof( double ); - - QGis::WkbType type = QGis::WKBPolygon; - unsigned char* wkb = new unsigned char[size]; - - //char e = QgsApplication::endian(); - char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - int nPointsInRing = 0; - double x, y; - - //fill the contents into *wkb - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( wkb )[wkbPosition], &nrings, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) - { - nPointsInRing = it->size(); - memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); - wkbPosition += sizeof( int ); - //iterate through the string list converting the strings to x-/y- doubles - std::list::const_iterator iter; - for ( iter = it->begin(); iter != it->end(); ++iter ) - { - x = iter->x(); - y = iter->y(); - //qWarning("currentCoordinate: " + QString::number(x) + " // " + QString::number(y)); - memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - } - - fromWkb( wkb, size ); - return true; -} - -bool QgsGeometry::setFromGML2MultiPoint( const QDomElement& geometryElement ) -{ - std::list pointList; - std::list currentPoint; - QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "pointMember" ); - if ( pointMemberList.size() < 1 ) - { - return false; - } - QDomNodeList pointNodeList; - QDomNodeList coordinatesList; - for ( int i = 0; i < pointMemberList.size(); ++i ) - { - // element - pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS( GML_NAMESPACE, "Point" ); - if ( pointNodeList.size() < 1 ) - { - continue; - } - // element - coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( coordinatesList.size() < 1 ) - { - continue; - } - currentPoint.clear(); - if ( readGML2Coordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 ) - { - continue; - } - if ( currentPoint.size() < 1 ) - { - continue; - } - pointList.push_back(( *currentPoint.begin() ) ); - } - - //calculate the required wkb size - int size = 1 + 2 * sizeof( int ) + pointList.size() * ( 2 * sizeof( double ) + 1 + sizeof( int ) ); - - QGis::WkbType type = QGis::WKBMultiPoint; - unsigned char* wkb = new unsigned char[size]; - - //fill the wkb content - //char e = QgsApplication::endian(); - char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - int nPoints = pointList.size(); //number of points - double x, y; - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list::const_iterator it = pointList.begin(); it != pointList.end(); ++it ) - { - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - x = it->x(); - memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - y = it->y(); - memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - - fromWkb( wkb, size ); - return true; -} - -bool QgsGeometry::setFromGML2MultiLineString( const QDomElement& geometryElement ) -{ - //geoserver has - // - // - // - - //mapserver has directly - // > lineCoordinates; //first list: lines, second list: points of one line - QDomElement currentLineStringElement; - QDomNodeList currentCoordList; - - QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "lineStringMember" ); - if ( lineStringMemberList.size() > 0 ) //geoserver - { - for ( int i = 0; i < lineStringMemberList.size(); ++i ) - { - QDomNodeList lineStringNodeList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); - if ( lineStringNodeList.size() < 1 ) - { - return false; - } - currentLineStringElement = lineStringNodeList.at( 0 ).toElement(); - currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordList.size() < 1 ) - { - return false; - } - std::list currentPointList; - if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) - { - return false; - } - lineCoordinates.push_back( currentPointList ); - } - } - else - { - QDomNodeList lineStringList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); - if ( lineStringList.size() > 0 ) //mapserver - { - for ( int i = 0; i < lineStringList.size(); ++i ) - { - currentLineStringElement = lineStringList.at( i ).toElement(); - currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordList.size() < 1 ) - { - return false; - } - std::list currentPointList; - if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) - { - return false; - } - lineCoordinates.push_back( currentPointList ); - } - } - else - { - return false; - } - } - - - //calculate the required wkb size - int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 * sizeof( int ) ); - for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) - { - size += it->size() * 2 * sizeof( double ); - } - - QGis::WkbType type = QGis::WKBMultiLineString; - unsigned char* wkb = new unsigned char[size]; - - //fill the wkb content - //char e = QgsApplication::endian(); - char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - int nLines = lineCoordinates.size(); - int nPoints; //number of points in a line - double x, y; - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( wkb )[wkbPosition], &nLines, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) - { - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - nPoints = it->size(); - memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list::const_iterator iter = it->begin(); iter != it->end(); ++iter ) - { - x = iter->x(); - //qWarning("x is: " + QString::number(x)); - y = iter->y(); - //qWarning("y is: " + QString::number(y)); - memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - } - - fromWkb( wkb, size ); - return true; -} - -bool QgsGeometry::setFromGML2MultiPolygon( const QDomElement& geometryElement ) -{ - //first list: different polygons, second list: different rings, third list: different points - std::list > > multiPolygonPoints; - QDomElement currentPolygonMemberElement; - QDomNodeList polygonList; - QDomElement currentPolygonElement; - QDomNodeList outerBoundaryList; - QDomElement currentOuterBoundaryElement; - QDomElement currentInnerBoundaryElement; - QDomNodeList innerBoundaryList; - QDomNodeList linearRingNodeList; - QDomElement currentLinearRingElement; - QDomNodeList currentCoordinateList; - - QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "polygonMember" ); - for ( int i = 0; i < polygonMemberList.size(); ++i ) - { - std::list > currentPolygonList; - currentPolygonMemberElement = polygonMemberList.at( i ).toElement(); - polygonList = currentPolygonMemberElement.elementsByTagNameNS( GML_NAMESPACE, "Polygon" ); - if ( polygonList.size() < 1 ) - { - continue; - } - currentPolygonElement = polygonList.at( 0 ).toElement(); - - //find exterior ring - outerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); - if ( outerBoundaryList.size() < 1 ) - { - continue; - } - - currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement(); - std::list ringCoordinates; - - linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); - if ( linearRingNodeList.size() < 1 ) - { - continue; - } - currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); - currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordinateList.size() < 1 ) - { - continue; - } - if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) - { - continue; - } - currentPolygonList.push_back( ringCoordinates ); - - //find interior rings - QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); - for ( int j = 0; j < innerBoundaryList.size(); ++j ) - { - std::list ringCoordinates; - currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement(); - linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); - if ( linearRingNodeList.size() < 1 ) - { - continue; - } - currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); - currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); - if ( currentCoordinateList.size() < 1 ) - { - continue; - } - if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) - { - continue; - } - currentPolygonList.push_back( ringCoordinates ); - } - multiPolygonPoints.push_back( currentPolygonList ); - } - - int size = 1 + 2 * sizeof( int ); - //calculate the wkb size - for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) - { - size += 1 + 2 * sizeof( int ); - for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) - { - size += sizeof( int ) + 2 * iter->size() * sizeof( double ); - } - } - - QGis::WkbType type = QGis::WKBMultiPolygon; - unsigned char* wkb = new unsigned char[size]; - - int polygonType = QGis::WKBPolygon; - //char e = QgsApplication::endian(); - char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; - int wkbPosition = 0; //current offset from wkb beginning (in bytes) - double x, y; - int nPolygons = multiPolygonPoints.size(); - int nRings; - int nPointsInRing; - - //fill the contents into *wkb - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); - wkbPosition += sizeof( int ); - memcpy( &( wkb )[wkbPosition], &nPolygons, sizeof( int ) ); - wkbPosition += sizeof( int ); - - for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) - { - memcpy( &( wkb )[wkbPosition], &e, 1 ); - wkbPosition += 1; - memcpy( &( wkb )[wkbPosition], &polygonType, sizeof( int ) ); - wkbPosition += sizeof( int ); - nRings = it->size(); - memcpy( &( wkb )[wkbPosition], &nRings, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) - { - nPointsInRing = iter->size(); - memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); - wkbPosition += sizeof( int ); - for ( std::list::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator ) - { - x = iterator->x(); - y = iterator->y(); - memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); - wkbPosition += sizeof( double ); - memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); - wkbPosition += sizeof( double ); - } - } - } - - fromWkb( wkb, size ); - return true; -} - -bool QgsGeometry::readGML2Coordinates( std::list& coords, const QDomElement elem ) const -{ - QString coordSeparator = ","; - QString tupelSeparator = " "; - //"decimal" has to be "." - - coords.clear(); - - if ( elem.hasAttribute( "cs" ) ) - { - coordSeparator = elem.attribute( "cs" ); - } - if ( elem.hasAttribute( "ts" ) ) - { - tupelSeparator = elem.attribute( "ts" ); - } - - QStringList tupels = elem.text().split( tupelSeparator, QString::SkipEmptyParts ); - QStringList tupel_coords; - double x, y; - bool conversionSuccess; - - QStringList::const_iterator it; - for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it ) - { - tupel_coords = ( *it ).split( coordSeparator, QString::SkipEmptyParts ); - if ( tupel_coords.size() < 2 ) - { - continue; - } - x = tupel_coords.at( 0 ).toDouble( &conversionSuccess ); - if ( !conversionSuccess ) - { - return 1; - } - y = tupel_coords.at( 1 ).toDouble( &conversionSuccess ); - if ( !conversionSuccess ) - { - return 1; - } - coords.push_back( QgsPoint( x, y ) ); - } - return 0; -} QgsGeometry & QgsGeometry::operator=( QgsGeometry const & rhs ) { @@ -5145,316 +4526,6 @@ QString QgsGeometry::exportToGeoJSON() } } -QDomElement QgsGeometry::exportToGML2( QDomDocument& doc ) -{ - QgsDebugMsg( "entered." ); - - // TODO: implement with GEOS - if ( mDirtyWkb ) - { - exportGeosToWkb(); - } - - if ( !mGeometry ) - { - QgsDebugMsg( "WKB geometry not available!" ); - return QDomElement(); - } - - QGis::WkbType wkbType; - bool hasZValue = false; - double *x, *y; - - QString mWkt; // TODO: rename - - // Will this really work when mGeometry[0] == 0 ???? I (gavin) think not. - //wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4]; - memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); - - switch ( wkbType ) - { - case QGis::WKBPoint25D: - case QGis::WKBPoint: - { - QDomElement pointElem = doc.createElement( "gml:Point" ); - QDomElement coordElem = doc.createElement( "gml:coordinates" ); - coordElem.setAttribute( "cs", "," ); - coordElem.setAttribute( "ts", " " ); - QString coordString; - x = ( double * )( mGeometry + 5 ); - coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - coordString += ","; - y = ( double * )( mGeometry + 5 + sizeof( double ) ); - coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - QDomText coordText = doc.createTextNode( coordString ); - coordElem.appendChild( coordText ); - pointElem.appendChild( coordElem ); - return pointElem; - } - case QGis::WKBMultiPoint25D: - hasZValue = true; - case QGis::WKBMultiPoint: - { - unsigned char *ptr; - int idx; - int *nPoints; - - QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" ); - nPoints = ( int* )( mGeometry + 5 ); - ptr = mGeometry + 5 + sizeof( int ); - for ( idx = 0; idx < *nPoints; ++idx ) - { - ptr += ( 1 + sizeof( int ) ); - QDomElement pointMemberElem = doc.createElement( "gml:pointMember" ); - QDomElement pointElem = doc.createElement( "gml:Point" ); - QDomElement coordElem = doc.createElement( "gml:coordinates" ); - coordElem.setAttribute( "cs", "," ); - coordElem.setAttribute( "ts", " " ); - QString coordString; - x = ( double * )( ptr ); - coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - coordString += ","; - ptr += sizeof( double ); - y = ( double * )( ptr ); - coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - QDomText coordText = doc.createTextNode( coordString ); - coordElem.appendChild( coordText ); - pointElem.appendChild( coordElem ); - - ptr += sizeof( double ); - if ( hasZValue ) - { - ptr += sizeof( double ); - } - pointMemberElem.appendChild( pointElem ); - multiPointElem.appendChild( pointMemberElem ); - } - return multiPointElem; - } - case QGis::WKBLineString25D: - hasZValue = true; - case QGis::WKBLineString: - { - QgsDebugMsg( "LINESTRING found" ); - unsigned char *ptr; - int *nPoints; - int idx; - - QDomElement lineStringElem = doc.createElement( "gml:LineString" ); - // get number of points in the line - ptr = mGeometry + 5; - nPoints = ( int * ) ptr; - ptr = mGeometry + 1 + 2 * sizeof( int ); - QDomElement coordElem = doc.createElement( "gml:coordinates" ); - coordElem.setAttribute( "cs", "," ); - coordElem.setAttribute( "ts", " " ); - QString coordString; - for ( idx = 0; idx < *nPoints; ++idx ) - { - if ( idx != 0 ) - { - coordString += " "; - } - x = ( double * ) ptr; - coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - coordString += ","; - ptr += sizeof( double ); - y = ( double * ) ptr; - coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - ptr += sizeof( double ); - if ( hasZValue ) - { - ptr += sizeof( double ); - } - } - QDomText coordText = doc.createTextNode( coordString ); - coordElem.appendChild( coordText ); - lineStringElem.appendChild( coordElem ); - return lineStringElem; - } - case QGis::WKBMultiLineString25D: - hasZValue = true; - case QGis::WKBMultiLineString: - { - QgsDebugMsg( "MULTILINESTRING found" ); - unsigned char *ptr; - int idx, jdx, numLineStrings; - int *nPoints; - - QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" ); - numLineStrings = ( int )( mGeometry[5] ); - ptr = mGeometry + 9; - for ( jdx = 0; jdx < numLineStrings; jdx++ ) - { - QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" ); - QDomElement lineStringElem = doc.createElement( "gml:LineString" ); - ptr += 5; // skip type since we know its 2 - nPoints = ( int * ) ptr; - ptr += sizeof( int ); - QDomElement coordElem = doc.createElement( "gml:coordinates" ); - coordElem.setAttribute( "cs", "," ); - coordElem.setAttribute( "ts", " " ); - QString coordString; - for ( idx = 0; idx < *nPoints; idx++ ) - { - if ( idx != 0 ) - { - coordString += " "; - } - x = ( double * ) ptr; - coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - ptr += sizeof( double ); - coordString += ","; - y = ( double * ) ptr; - coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - ptr += sizeof( double ); - if ( hasZValue ) - { - ptr += sizeof( double ); - } - } - QDomText coordText = doc.createTextNode( coordString ); - coordElem.appendChild( coordText ); - lineStringElem.appendChild( coordElem ); - lineStringMemberElem.appendChild( lineStringElem ); - multiLineStringElem.appendChild( lineStringMemberElem ); - } - return multiLineStringElem; - } - case QGis::WKBPolygon25D: - hasZValue = true; - case QGis::WKBPolygon: - { - QgsDebugMsg( "POLYGON found" ); - unsigned char *ptr; - int idx, jdx; - int *numRings, *nPoints; - - QDomElement polygonElem = doc.createElement( "gml:Polygon" ); - // get number of rings in the polygon - numRings = ( int * )( mGeometry + 1 + sizeof( int ) ); - if ( !( *numRings ) ) // sanity check for zero rings in polygon - { - return QDomElement(); - } - int *ringStart; // index of first point for each ring - int *ringNumPoints; // number of points in each ring - ringStart = new int[*numRings]; - ringNumPoints = new int[*numRings]; - ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring - for ( idx = 0; idx < *numRings; idx++ ) - { - QString boundaryName = "gml:outerBoundaryIs"; - if ( idx != 0 ) - { - boundaryName = "gml:innerBoundaryIs"; - } - QDomElement boundaryElem = doc.createElement( boundaryName ); - QDomElement ringElem = doc.createElement( "gml:LinearRing" ); - // get number of points in the ring - nPoints = ( int * ) ptr; - ringNumPoints[idx] = *nPoints; - ptr += 4; - QDomElement coordElem = doc.createElement( "gml:coordinates" ); - coordElem.setAttribute( "cs", "," ); - coordElem.setAttribute( "ts", " " ); - QString coordString; - for ( jdx = 0; jdx < *nPoints; jdx++ ) - { - if ( jdx != 0 ) - { - coordString += " "; - } - x = ( double * ) ptr; - coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - coordString += ","; - ptr += sizeof( double ); - y = ( double * ) ptr; - coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - ptr += sizeof( double ); - if ( hasZValue ) - { - ptr += sizeof( double ); - } - } - QDomText coordText = doc.createTextNode( coordString ); - coordElem.appendChild( coordText ); - ringElem.appendChild( coordElem ); - boundaryElem.appendChild( ringElem ); - polygonElem.appendChild( boundaryElem ); - } - delete [] ringStart; - delete [] ringNumPoints; - return polygonElem; - } - case QGis::WKBMultiPolygon25D: - hasZValue = true; - case QGis::WKBMultiPolygon: - { - QgsDebugMsg( "MULTIPOLYGON found" ); - unsigned char *ptr; - int idx, jdx, kdx; - int *numPolygons, *numRings, *nPoints; - - QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" ); - ptr = mGeometry + 5; - numPolygons = ( int * ) ptr; - ptr = mGeometry + 9; - for ( kdx = 0; kdx < *numPolygons; kdx++ ) - { - QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" ); - QDomElement polygonElem = doc.createElement( "gml:Polygon" ); - ptr += 5; - numRings = ( int * ) ptr; - ptr += 4; - for ( idx = 0; idx < *numRings; idx++ ) - { - QString boundaryName = "gml:outerBoundaryIs"; - if ( idx != 0 ) - { - boundaryName = "gml:innerBoundaryIs"; - } - QDomElement boundaryElem = doc.createElement( boundaryName ); - QDomElement ringElem = doc.createElement( "gml:LinearRing" ); - nPoints = ( int * ) ptr; - ptr += 4; - QDomElement coordElem = doc.createElement( "gml:coordinates" ); - coordElem.setAttribute( "cs", "," ); - coordElem.setAttribute( "ts", " " ); - QString coordString; - for ( jdx = 0; jdx < *nPoints; jdx++ ) - { - if ( jdx != 0 ) - { - coordString += " "; - } - x = ( double * ) ptr; - coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - ptr += sizeof( double ); - coordString += ","; - y = ( double * ) ptr; - coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); - ptr += sizeof( double ); - if ( hasZValue ) - { - ptr += sizeof( double ); - } - } - QDomText coordText = doc.createTextNode( coordString ); - coordElem.appendChild( coordText ); - ringElem.appendChild( coordElem ); - boundaryElem.appendChild( ringElem ); - polygonElem.appendChild( boundaryElem ); - polygonMemberElem.appendChild( polygonElem ); - multiPolygonElem.appendChild( polygonMemberElem ); - } - } - return multiPolygonElem; - } - default: - return QDomElement(); - } -} bool QgsGeometry::exportWkbToGeos() { diff --git a/src/core/qgsgeometry.h b/src/core/qgsgeometry.h index f684cbbb9ec..21e60afb530 100644 --- a/src/core/qgsgeometry.h +++ b/src/core/qgsgeometry.h @@ -89,18 +89,6 @@ 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 (...) or in "gml" namespace (...) - @note added in 1.9 - */ - static QgsGeometry* fromGML2( const QString& xmlString ); - - /** static method that creates geometry from GML2 - @note added in 1.9 - */ - static QgsGeometry* fromGML2( const QDomNode& geometryNode ); - /** construct geometry from a point */ static QgsGeometry* fromPoint( const QgsPoint& point ); /** construct geometry from a multipoint */ @@ -395,12 +383,6 @@ class CORE_EXPORT QgsGeometry */ QString exportToGeoJSON(); - /** Exports the geometry to mGML2 - @return true in case of success and false else - * @note added in 1.9 - */ - QDomElement exportToGML2( QDomDocument& doc ); - /* Accessor functions for getting geometry data */ /** return contents of the geometry as a point @@ -506,24 +488,6 @@ class CORE_EXPORT QgsGeometry // Private functions - /** static method that creates geometry from GML2 Point */ - bool setFromGML2Point( const QDomElement& geometryElement ); - /** static method that creates geometry from GML2 LineString */ - bool setFromGML2LineString( const QDomElement& geometryElement ); - /** static method that creates geometry from GML2 Polygon */ - bool setFromGML2Polygon( const QDomElement& geometryElement ); - /** static method that creates geometry from GML2 MultiPoint */ - bool setFromGML2MultiPoint( const QDomElement& geometryElement ); - /** static method that creates geometry from GML2 MultiLineString */ - bool setFromGML2MultiLineString( const QDomElement& geometryElement ); - /** static method that creates geometry from GML2 MultiPolygon */ - bool setFromGML2MultiPolygon( const QDomElement& geometryElement ); - /**Reads the element and extracts the coordinates as points - @param coords list where the found coordinates are appended - @param elem the element - @return boolean for success*/ - bool readGML2Coordinates( std::list& coords, const QDomElement elem ) const; - /** Converts from the WKB geometry to the GEOS geometry. @return true in case of success and false else */ diff --git a/src/core/qgsogcutils.cpp b/src/core/qgsogcutils.cpp new file mode 100644 index 00000000000..c71053710a7 --- /dev/null +++ b/src/core/qgsogcutils.cpp @@ -0,0 +1,969 @@ +#include "qgsogcutils.h" + +#include "qgsgeometry.h" + +#include + +#ifndef Q_WS_WIN +#include +#else +#include +#endif + + +static const QString GML_NAMESPACE = "http://www.opengis.net/gml"; + +QgsGeometry* QgsOgcUtils::geometryFromGML2( const QDomNode& geometryNode ) +{ + QDomElement geometryTypeElement = geometryNode.toElement(); + QString geomType = geometryTypeElement.tagName(); + + if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) ) + { + QDomNode geometryChild = geometryNode.firstChild(); + if ( geometryChild.isNull() ) + { + return 0; + } + geometryTypeElement = geometryChild.toElement(); + geomType = geometryTypeElement.tagName(); + } + + if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) ) + return 0; + + if ( geomType == "Point" ) + { + return geometryFromGML2Point( geometryTypeElement ); + } + else if ( geomType == "LineString" ) + { + return geometryFromGML2LineString( geometryTypeElement ); + } + else if ( geomType == "Polygon" ) + { + return geometryFromGML2Polygon( geometryTypeElement ); + } + else if ( geomType == "MultiPoint" ) + { + return geometryFromGML2MultiPoint( geometryTypeElement ); + } + else if ( geomType == "MultiLineString" ) + { + return geometryFromGML2MultiLineString( geometryTypeElement ); + } + else if ( geomType == "MultiPolygon" ) + { + return geometryFromGML2MultiPolygon( geometryTypeElement ); + } + else if ( geomType == "Box" ) + { + return QgsGeometry::fromRect( rectangleFromGMLBox( geometryTypeElement ) ); + } + else //unknown type + { + return 0; + } +} + +QgsGeometry* QgsOgcUtils::geometryFromGML2( const QString& xmlString ) +{ + // wrap the string into a root tag to have "gml" namespace (and also as a default namespace) + QString xml = QString( "%2").arg( GML_NAMESPACE ).arg( xmlString ); + QDomDocument doc; + if ( !doc.setContent( xml, true ) ) + return 0; + + return geometryFromGML2( doc.documentElement().firstChildElement() ); +} + + +QgsGeometry* QgsOgcUtils::geometryFromGML2Point( const QDomElement& geometryElement ) +{ + QDomNodeList coordList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( coordList.size() < 1 ) + { + return 0; + } + QDomElement coordElement = coordList.at( 0 ).toElement(); + std::list pointCoordinate; + if ( readGML2Coordinates( pointCoordinate, coordElement ) != 0 ) + { + return 0; + } + + if ( pointCoordinate.size() < 1 ) + { + return 0; + } + + std::list::const_iterator point_it = pointCoordinate.begin(); + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + double x = point_it->x(); + double y = point_it->y(); + int size = 1 + sizeof( int ) + 2 * sizeof( double ); + + QGis::WkbType type = QGis::WKBPoint; + unsigned char* wkb = new unsigned char[size]; + + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + + QgsGeometry* g = new QgsGeometry(); + g->fromWkb( wkb, size ); + return g; +} + +QgsGeometry* QgsOgcUtils::geometryFromGML2LineString( const QDomElement& geometryElement ) +{ + QDomNodeList coordinatesList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( coordinatesList.size() < 1 ) + { + return 0; + } + QDomElement coordinatesElement = coordinatesList.at( 0 ).toElement(); + std::list lineCoordinates; + if ( readGML2Coordinates( lineCoordinates, coordinatesElement ) != 0 ) + { + return 0; + } + + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int size = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double ); + + QGis::WkbType type = QGis::WKBLineString; + unsigned char* wkb = new unsigned char[size]; + + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + double x, y; + int nPoints = lineCoordinates.size(); + + //fill the contents into *wkb + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); + wkbPosition += sizeof( int ); + + std::list::const_iterator iter; + for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter ) + { + x = iter->x(); + y = iter->y(); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + + QgsGeometry* g = new QgsGeometry(); + g->fromWkb( wkb, size ); + return g; +} + +QgsGeometry* QgsOgcUtils::geometryFromGML2Polygon( const QDomElement& geometryElement ) +{ + //read all the coordinates (as QgsPoint) into memory. Each linear ring has an entry in the vector + std::vector > ringCoordinates; + + //read coordinates for outer boundary + QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); + if ( outerBoundaryList.size() < 1 ) //outer ring is necessary + { + return 0; + } + QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement(); + if ( coordinatesElement.isNull() ) + { + return 0; + } + std::list exteriorPointList; + if ( readGML2Coordinates( exteriorPointList, coordinatesElement ) != 0 ) + { + return 0; + } + ringCoordinates.push_back( exteriorPointList ); + + //read coordinates for inner boundary + QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); + for ( int i = 0; i < innerBoundaryList.size(); ++i ) + { + std::list interiorPointList; + QDomElement coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement(); + if ( coordinatesElement.isNull() ) + { + return 0; + } + if ( readGML2Coordinates( interiorPointList, coordinatesElement ) != 0 ) + { + return 0; + } + ringCoordinates.push_back( interiorPointList ); + } + + //calculate number of bytes to allocate + int nrings = ringCoordinates.size(); + int npoints = 0;//total number of points + for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) + { + npoints += it->size(); + } + int size = 1 + 2 * sizeof( int ) + nrings * sizeof( int ) + 2 * npoints * sizeof( double ); + + QGis::WkbType type = QGis::WKBPolygon; + unsigned char* wkb = new unsigned char[size]; + + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + int nPointsInRing = 0; + double x, y; + + //fill the contents into *wkb + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nrings, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::vector >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) + { + nPointsInRing = it->size(); + memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); + wkbPosition += sizeof( int ); + //iterate through the string list converting the strings to x-/y- doubles + std::list::const_iterator iter; + for ( iter = it->begin(); iter != it->end(); ++iter ) + { + x = iter->x(); + y = iter->y(); + //qWarning("currentCoordinate: " + QString::number(x) + " // " + QString::number(y)); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + } + + QgsGeometry* g = new QgsGeometry(); + g->fromWkb( wkb, size ); + return g; +} + +QgsGeometry* QgsOgcUtils::geometryFromGML2MultiPoint( const QDomElement& geometryElement ) +{ + std::list pointList; + std::list currentPoint; + QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "pointMember" ); + if ( pointMemberList.size() < 1 ) + { + return 0; + } + QDomNodeList pointNodeList; + QDomNodeList coordinatesList; + for ( int i = 0; i < pointMemberList.size(); ++i ) + { + // element + pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS( GML_NAMESPACE, "Point" ); + if ( pointNodeList.size() < 1 ) + { + continue; + } + // element + coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( coordinatesList.size() < 1 ) + { + continue; + } + currentPoint.clear(); + if ( readGML2Coordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 ) + { + continue; + } + if ( currentPoint.size() < 1 ) + { + continue; + } + pointList.push_back(( *currentPoint.begin() ) ); + } + + //calculate the required wkb size + int size = 1 + 2 * sizeof( int ) + pointList.size() * ( 2 * sizeof( double ) + 1 + sizeof( int ) ); + + QGis::WkbType type = QGis::WKBMultiPoint; + unsigned char* wkb = new unsigned char[size]; + + //fill the wkb content + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + int nPoints = pointList.size(); //number of points + double x, y; + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list::const_iterator it = pointList.begin(); it != pointList.end(); ++it ) + { + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + x = it->x(); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + y = it->y(); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + + QgsGeometry* g = new QgsGeometry(); + g->fromWkb( wkb, size ); + return g; +} + +QgsGeometry* QgsOgcUtils::geometryFromGML2MultiLineString( const QDomElement& geometryElement ) +{ + //geoserver has + // + // + // + + //mapserver has directly + // > lineCoordinates; //first list: lines, second list: points of one line + QDomElement currentLineStringElement; + QDomNodeList currentCoordList; + + QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "lineStringMember" ); + if ( lineStringMemberList.size() > 0 ) //geoserver + { + for ( int i = 0; i < lineStringMemberList.size(); ++i ) + { + QDomNodeList lineStringNodeList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); + if ( lineStringNodeList.size() < 1 ) + { + return 0; + } + currentLineStringElement = lineStringNodeList.at( 0 ).toElement(); + currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordList.size() < 1 ) + { + return 0; + } + std::list currentPointList; + if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) + { + return 0; + } + lineCoordinates.push_back( currentPointList ); + } + } + else + { + QDomNodeList lineStringList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); + if ( lineStringList.size() > 0 ) //mapserver + { + for ( int i = 0; i < lineStringList.size(); ++i ) + { + currentLineStringElement = lineStringList.at( i ).toElement(); + currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordList.size() < 1 ) + { + return 0; + } + std::list currentPointList; + if ( readGML2Coordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) + { + return 0; + } + lineCoordinates.push_back( currentPointList ); + } + } + else + { + return 0; + } + } + + + //calculate the required wkb size + int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 * sizeof( int ) ); + for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) + { + size += it->size() * 2 * sizeof( double ); + } + + QGis::WkbType type = QGis::WKBMultiLineString; + unsigned char* wkb = new unsigned char[size]; + + //fill the wkb content + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + int nLines = lineCoordinates.size(); + int nPoints; //number of points in a line + double x, y; + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nLines, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) + { + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + nPoints = it->size(); + memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list::const_iterator iter = it->begin(); iter != it->end(); ++iter ) + { + x = iter->x(); + //qWarning("x is: " + QString::number(x)); + y = iter->y(); + //qWarning("y is: " + QString::number(y)); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + } + + QgsGeometry* g = new QgsGeometry(); + g->fromWkb( wkb, size ); + return g; +} + +QgsGeometry* QgsOgcUtils::geometryFromGML2MultiPolygon( const QDomElement& geometryElement ) +{ + //first list: different polygons, second list: different rings, third list: different points + std::list > > multiPolygonPoints; + QDomElement currentPolygonMemberElement; + QDomNodeList polygonList; + QDomElement currentPolygonElement; + QDomNodeList outerBoundaryList; + QDomElement currentOuterBoundaryElement; + QDomElement currentInnerBoundaryElement; + QDomNodeList innerBoundaryList; + QDomNodeList linearRingNodeList; + QDomElement currentLinearRingElement; + QDomNodeList currentCoordinateList; + + QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "polygonMember" ); + for ( int i = 0; i < polygonMemberList.size(); ++i ) + { + std::list > currentPolygonList; + currentPolygonMemberElement = polygonMemberList.at( i ).toElement(); + polygonList = currentPolygonMemberElement.elementsByTagNameNS( GML_NAMESPACE, "Polygon" ); + if ( polygonList.size() < 1 ) + { + continue; + } + currentPolygonElement = polygonList.at( 0 ).toElement(); + + //find exterior ring + outerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); + if ( outerBoundaryList.size() < 1 ) + { + continue; + } + + currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement(); + std::list ringCoordinates; + + linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); + if ( linearRingNodeList.size() < 1 ) + { + continue; + } + currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); + currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordinateList.size() < 1 ) + { + continue; + } + if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) + { + continue; + } + currentPolygonList.push_back( ringCoordinates ); + + //find interior rings + QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); + for ( int j = 0; j < innerBoundaryList.size(); ++j ) + { + std::list ringCoordinates; + currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement(); + linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); + if ( linearRingNodeList.size() < 1 ) + { + continue; + } + currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); + currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); + if ( currentCoordinateList.size() < 1 ) + { + continue; + } + if ( readGML2Coordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) + { + continue; + } + currentPolygonList.push_back( ringCoordinates ); + } + multiPolygonPoints.push_back( currentPolygonList ); + } + + int size = 1 + 2 * sizeof( int ); + //calculate the wkb size + for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) + { + size += 1 + 2 * sizeof( int ); + for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) + { + size += sizeof( int ) + 2 * iter->size() * sizeof( double ); + } + } + + QGis::WkbType type = QGis::WKBMultiPolygon; + unsigned char* wkb = new unsigned char[size]; + + int polygonType = QGis::WKBPolygon; + //char e = QgsApplication::endian(); + char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; + int wkbPosition = 0; //current offset from wkb beginning (in bytes) + double x, y; + int nPolygons = multiPolygonPoints.size(); + int nRings; + int nPointsInRing; + + //fill the contents into *wkb + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); + wkbPosition += sizeof( int ); + memcpy( &( wkb )[wkbPosition], &nPolygons, sizeof( int ) ); + wkbPosition += sizeof( int ); + + for ( std::list > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) + { + memcpy( &( wkb )[wkbPosition], &e, 1 ); + wkbPosition += 1; + memcpy( &( wkb )[wkbPosition], &polygonType, sizeof( int ) ); + wkbPosition += sizeof( int ); + nRings = it->size(); + memcpy( &( wkb )[wkbPosition], &nRings, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) + { + nPointsInRing = iter->size(); + memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); + wkbPosition += sizeof( int ); + for ( std::list::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator ) + { + x = iterator->x(); + y = iterator->y(); + memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); + wkbPosition += sizeof( double ); + memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); + wkbPosition += sizeof( double ); + } + } + } + + QgsGeometry* g = new QgsGeometry(); + g->fromWkb( wkb, size ); + return g; +} + +bool QgsOgcUtils::readGML2Coordinates( std::list& coords, const QDomElement elem ) +{ + QString coordSeparator = ","; + QString tupelSeparator = " "; + //"decimal" has to be "." + + coords.clear(); + + if ( elem.hasAttribute( "cs" ) ) + { + coordSeparator = elem.attribute( "cs" ); + } + if ( elem.hasAttribute( "ts" ) ) + { + tupelSeparator = elem.attribute( "ts" ); + } + + QStringList tupels = elem.text().split( tupelSeparator, QString::SkipEmptyParts ); + QStringList tupel_coords; + double x, y; + bool conversionSuccess; + + QStringList::const_iterator it; + for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it ) + { + tupel_coords = ( *it ).split( coordSeparator, QString::SkipEmptyParts ); + if ( tupel_coords.size() < 2 ) + { + continue; + } + x = tupel_coords.at( 0 ).toDouble( &conversionSuccess ); + if ( !conversionSuccess ) + { + return 1; + } + y = tupel_coords.at( 1 ).toDouble( &conversionSuccess ); + if ( !conversionSuccess ) + { + return 1; + } + coords.push_back( QgsPoint( x, y ) ); + } + return 0; +} + + + + +QDomElement QgsOgcUtils::geometryToGML2( QgsGeometry* geometry, QDomDocument& doc ) +{ + if ( !geometry || !geometry->asWkb() ) + return QDomElement(); + + bool hasZValue = false; + double *x, *y; + unsigned char* wkb = geometry->asWkb(); + + switch ( geometry->wkbType() ) + { + case QGis::WKBPoint25D: + case QGis::WKBPoint: + { + QDomElement pointElem = doc.createElement( "gml:Point" ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + x = ( double * )( wkb + 5 ); + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + coordString += ","; + y = ( double * )( wkb + 5 + sizeof( double ) ); + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + pointElem.appendChild( coordElem ); + return pointElem; + } + case QGis::WKBMultiPoint25D: + hasZValue = true; + case QGis::WKBMultiPoint: + { + unsigned char *ptr; + int idx; + int *nPoints; + + QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" ); + nPoints = ( int* )( wkb + 5 ); + ptr = wkb + 5 + sizeof( int ); + for ( idx = 0; idx < *nPoints; ++idx ) + { + ptr += ( 1 + sizeof( int ) ); + QDomElement pointMemberElem = doc.createElement( "gml:pointMember" ); + QDomElement pointElem = doc.createElement( "gml:Point" ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + x = ( double * )( ptr ); + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + coordString += ","; + ptr += sizeof( double ); + y = ( double * )( ptr ); + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + pointElem.appendChild( coordElem ); + + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + pointMemberElem.appendChild( pointElem ); + multiPointElem.appendChild( pointMemberElem ); + } + return multiPointElem; + } + case QGis::WKBLineString25D: + hasZValue = true; + case QGis::WKBLineString: + { + unsigned char *ptr; + int *nPoints; + int idx; + + QDomElement lineStringElem = doc.createElement( "gml:LineString" ); + // get number of points in the line + ptr = wkb + 5; + nPoints = ( int * ) ptr; + ptr = wkb + 1 + 2 * sizeof( int ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( idx = 0; idx < *nPoints; ++idx ) + { + if ( idx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + coordString += ","; + ptr += sizeof( double ); + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + lineStringElem.appendChild( coordElem ); + return lineStringElem; + } + case QGis::WKBMultiLineString25D: + hasZValue = true; + case QGis::WKBMultiLineString: + { + unsigned char *ptr; + int idx, jdx, numLineStrings; + int *nPoints; + + QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" ); + numLineStrings = ( int )( wkb[5] ); + ptr = wkb + 9; + for ( jdx = 0; jdx < numLineStrings; jdx++ ) + { + QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" ); + QDomElement lineStringElem = doc.createElement( "gml:LineString" ); + ptr += 5; // skip type since we know its 2 + nPoints = ( int * ) ptr; + ptr += sizeof( int ); + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( idx = 0; idx < *nPoints; idx++ ) + { + if ( idx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + ptr += sizeof( double ); + coordString += ","; + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + lineStringElem.appendChild( coordElem ); + lineStringMemberElem.appendChild( lineStringElem ); + multiLineStringElem.appendChild( lineStringMemberElem ); + } + return multiLineStringElem; + } + case QGis::WKBPolygon25D: + hasZValue = true; + case QGis::WKBPolygon: + { + unsigned char *ptr; + int idx, jdx; + int *numRings, *nPoints; + + QDomElement polygonElem = doc.createElement( "gml:Polygon" ); + // get number of rings in the polygon + numRings = ( int * )( wkb + 1 + sizeof( int ) ); + if ( !( *numRings ) ) // sanity check for zero rings in polygon + { + return QDomElement(); + } + int *ringStart; // index of first point for each ring + int *ringNumPoints; // number of points in each ring + ringStart = new int[*numRings]; + ringNumPoints = new int[*numRings]; + ptr = wkb + 1 + 2 * sizeof( int ); // set pointer to the first ring + for ( idx = 0; idx < *numRings; idx++ ) + { + QString boundaryName = "gml:outerBoundaryIs"; + if ( idx != 0 ) + { + boundaryName = "gml:innerBoundaryIs"; + } + QDomElement boundaryElem = doc.createElement( boundaryName ); + QDomElement ringElem = doc.createElement( "gml:LinearRing" ); + // get number of points in the ring + nPoints = ( int * ) ptr; + ringNumPoints[idx] = *nPoints; + ptr += 4; + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( jdx = 0; jdx < *nPoints; jdx++ ) + { + if ( jdx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + coordString += ","; + ptr += sizeof( double ); + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + ringElem.appendChild( coordElem ); + boundaryElem.appendChild( ringElem ); + polygonElem.appendChild( boundaryElem ); + } + delete [] ringStart; + delete [] ringNumPoints; + return polygonElem; + } + case QGis::WKBMultiPolygon25D: + hasZValue = true; + case QGis::WKBMultiPolygon: + { + unsigned char *ptr; + int idx, jdx, kdx; + int *numPolygons, *numRings, *nPoints; + + QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" ); + ptr = wkb + 5; + numPolygons = ( int * ) ptr; + ptr = wkb + 9; + for ( kdx = 0; kdx < *numPolygons; kdx++ ) + { + QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" ); + QDomElement polygonElem = doc.createElement( "gml:Polygon" ); + ptr += 5; + numRings = ( int * ) ptr; + ptr += 4; + for ( idx = 0; idx < *numRings; idx++ ) + { + QString boundaryName = "gml:outerBoundaryIs"; + if ( idx != 0 ) + { + boundaryName = "gml:innerBoundaryIs"; + } + QDomElement boundaryElem = doc.createElement( boundaryName ); + QDomElement ringElem = doc.createElement( "gml:LinearRing" ); + nPoints = ( int * ) ptr; + ptr += 4; + QDomElement coordElem = doc.createElement( "gml:coordinates" ); + coordElem.setAttribute( "cs", "," ); + coordElem.setAttribute( "ts", " " ); + QString coordString; + for ( jdx = 0; jdx < *nPoints; jdx++ ) + { + if ( jdx != 0 ) + { + coordString += " "; + } + x = ( double * ) ptr; + coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + ptr += sizeof( double ); + coordString += ","; + y = ( double * ) ptr; + coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); + ptr += sizeof( double ); + if ( hasZValue ) + { + ptr += sizeof( double ); + } + } + QDomText coordText = doc.createTextNode( coordString ); + coordElem.appendChild( coordText ); + ringElem.appendChild( coordElem ); + boundaryElem.appendChild( ringElem ); + polygonElem.appendChild( boundaryElem ); + polygonMemberElem.appendChild( polygonElem ); + multiPolygonElem.appendChild( polygonMemberElem ); + } + } + return multiPolygonElem; + } + default: + return QDomElement(); + } + +} + + +QgsRectangle QgsOgcUtils::rectangleFromGMLBox( const QDomNode& boxNode ) +{ + QgsRectangle rect; + + QDomElement boxElem = boxNode.toElement(); + if ( boxElem.tagName() != "Box" ) + return rect; + + QDomElement bElem = boxElem.firstChild().toElement(); + QString coordSeparator = ","; + QString tupelSeparator = " "; + if ( bElem.hasAttribute( "cs" ) ) + { + coordSeparator = bElem.attribute( "cs" ); + } + if ( bElem.hasAttribute( "ts" ) ) + { + tupelSeparator = bElem.attribute( "ts" ); + } + + QString bString = bElem.text(); + bool ok1, ok2, ok3, ok4; + double xmin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &ok1 ); + double ymin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &ok2 ); + double xmax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &ok3 ); + double ymax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &ok4 ); + + if ( ok1 && ok2 && ok3 && ok4 ) + { + rect = QgsRectangle( xmin, ymin, xmax, ymax ); + rect.normalize(); + } + + return rect; +} diff --git a/src/core/qgsogcutils.h b/src/core/qgsogcutils.h new file mode 100644 index 00000000000..784d20ab430 --- /dev/null +++ b/src/core/qgsogcutils.h @@ -0,0 +1,67 @@ +#ifndef QGSOGCUTILS_H +#define QGSOGCUTILS_H + +class QDomNode; +class QDomElement; +class QDomDocument; +class QString; + +#include + +class QgsGeometry; +class QgsPoint; +class QgsRectangle; + +/** + * @brief The QgsOgcUtils class provides various utility functions for conversion between + * OGC (Open Geospatial Consortium) standards and QGIS internal representations. + * + * Currently supported standards: + * - GML2 - Geography Markup Language (import, export) + * + * @note added in 2.0 + */ +class CORE_EXPORT QgsOgcUtils +{ +public: + + + /** static method that creates geometry from GML2 + @param XML representation of the geometry. GML elements are expected to be + in default namespace (...) or in "gml" namespace (...) + */ + static QgsGeometry* geometryFromGML2( const QString& xmlString ); + + /** static method that creates geometry from GML2 + */ + static QgsGeometry* geometryFromGML2( const QDomNode& geometryNode ); + + /** Exports the geometry to mGML2 + @return true in case of success and false else + */ + static QDomElement geometryToGML2( QgsGeometry* geometry, QDomDocument& doc ); + + /** read rectangle from GML2 Box */ + static QgsRectangle rectangleFromGMLBox( const QDomNode& boxNode ); + +private: + /** static method that creates geometry from GML2 Point */ + static QgsGeometry* geometryFromGML2Point( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 LineString */ + static QgsGeometry* geometryFromGML2LineString( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 Polygon */ + static QgsGeometry* geometryFromGML2Polygon( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 MultiPoint */ + static QgsGeometry* geometryFromGML2MultiPoint( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 MultiLineString */ + static QgsGeometry* geometryFromGML2MultiLineString( const QDomElement& geometryElement ); + /** static method that creates geometry from GML2 MultiPolygon */ + static QgsGeometry* geometryFromGML2MultiPolygon( const QDomElement& geometryElement ); + /** Reads the element and extracts the coordinates as points + @param coords list where the found coordinates are appended + @param elem the element + @return boolean for success*/ + static bool readGML2Coordinates( std::list& coords, const QDomElement elem ); +}; + +#endif // QGSOGCUTILS_H diff --git a/src/core/qgsrectangle.cpp b/src/core/qgsrectangle.cpp index f1f321d2520..092cf6ed971 100644 --- a/src/core/qgsrectangle.cpp +++ b/src/core/qgsrectangle.cpp @@ -55,32 +55,6 @@ QgsRectangle::QgsRectangle( const QgsRectangle &r ) ymax = r.yMaximum(); } -QgsRectangle::QgsRectangle( const QDomNode& boxNode ) -{ - QDomElement boxElem = boxNode.toElement(); - if ( boxElem.tagName() == "Box" ) - { - QDomElement bElem = boxElem.firstChild().toElement(); - QString coordSeparator = ","; - QString tupelSeparator = " "; - if ( bElem.hasAttribute( "cs" ) ) - { - coordSeparator = bElem.attribute( "cs" ); - } - if ( bElem.hasAttribute( "ts" ) ) - { - tupelSeparator = bElem.attribute( "ts" ); - } - - QString bString = bElem.text(); - bool conversionSuccess; - xmin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &conversionSuccess ); - ymin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &conversionSuccess ); - xmax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &conversionSuccess ); - ymax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &conversionSuccess ); - } - normalize(); -} void QgsRectangle::set( const QgsPoint& p1, const QgsPoint& p2 ) { diff --git a/src/core/qgsrectangle.h b/src/core/qgsrectangle.h index 596f3100c0e..5c05d96a2cd 100644 --- a/src/core/qgsrectangle.h +++ b/src/core/qgsrectangle.h @@ -44,9 +44,6 @@ class CORE_EXPORT QgsRectangle QgsRectangle( const QRectF & qRectF ); //! Copy constructor QgsRectangle( const QgsRectangle &other ); - //! GML2 constructor - //@note added in 1.9 - QgsRectangle( const QDomNode& boxNode ); //! Destructor ~QgsRectangle(); //! Set the rectangle from two QgsPoints. The rectangle is diff --git a/src/mapserver/qgsfilter.cpp b/src/mapserver/qgsfilter.cpp index 9d91b6d1ae4..0193257ad7b 100644 --- a/src/mapserver/qgsfilter.cpp +++ b/src/mapserver/qgsfilter.cpp @@ -21,6 +21,8 @@ #include "qgslogicalfilter.h" #include "qgsspatialfilter.h" #include "qgsvectordataprovider.h" +#include "qgsogcutils.h" + #include #include #include "qgsvectorlayer.h" @@ -129,7 +131,7 @@ QgsFilter* QgsFilter::createFilterFromXml( const QDomElement& filterElem, QgsVec if ( gNodes.size() > 0 ) { QDomElement gElem = gNodes.at( 0 ).toElement(); - geom = QgsGeometry::fromGML2( gElem ); + geom = QgsOgcUtils::geometryFromGML2( gElem ); } } @@ -139,7 +141,7 @@ QgsFilter* QgsFilter::createFilterFromXml( const QDomElement& filterElem, QgsVec if ( gNodes.size() > 0 ) { QDomElement gElem = gNodes.at( 0 ).toElement(); - geom = QgsGeometry::fromGML2( gElem ); + geom = QgsOgcUtils::geometryFromGML2( gElem ); } } @@ -149,7 +151,7 @@ QgsFilter* QgsFilter::createFilterFromXml( const QDomElement& filterElem, QgsVec if ( gNodes.size() > 0 ) { QDomElement gElem = gNodes.at( 0 ).toElement(); - geom = QgsGeometry::fromGML2( gElem ); + geom = QgsOgcUtils::geometryFromGML2( gElem ); } } @@ -159,7 +161,7 @@ QgsFilter* QgsFilter::createFilterFromXml( const QDomElement& filterElem, QgsVec if ( gNodes.size() > 0 ) { QDomElement gElem = gNodes.at( 0 ).toElement(); - geom = QgsGeometry::fromGML2( gElem ); + geom = QgsOgcUtils::geometryFromGML2( gElem ); } } @@ -169,7 +171,7 @@ QgsFilter* QgsFilter::createFilterFromXml( const QDomElement& filterElem, QgsVec if ( gNodes.size() > 0 ) { QDomElement gElem = gNodes.at( 0 ).toElement(); - geom = QgsGeometry::fromGML2( gElem ); + geom = QgsOgcUtils::geometryFromGML2( gElem ); } } @@ -179,7 +181,7 @@ QgsFilter* QgsFilter::createFilterFromXml( const QDomElement& filterElem, QgsVec if ( gNodes.size() > 0 ) { QDomElement gElem = gNodes.at( 0 ).toElement(); - geom = QgsGeometry::fromGML2( gElem ); + geom = QgsOgcUtils::geometryFromGML2( gElem ); } } diff --git a/src/mapserver/qgswfsserver.cpp b/src/mapserver/qgswfsserver.cpp index 548de6cdbb7..c8a93ecb0a7 100644 --- a/src/mapserver/qgswfsserver.cpp +++ b/src/mapserver/qgswfsserver.cpp @@ -41,6 +41,8 @@ #include "qgslegendmodel.h" #include "qgscomposerlegenditem.h" #include "qgsrequesthandler.h" +#include "qgsogcutils.h" + #include #include #include @@ -509,11 +511,11 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format { if ( childElem.tagName() == "Box" ) { - req.setFilterRect( QgsRectangle( childElem ) ); + req.setFilterRect( QgsOgcUtils::rectangleFromGMLBox( childElem ) ); } else if ( childElem.tagName() != "PropertyName" ) { - QgsGeometry *geom = QgsGeometry::fromGML2( childElem ); + QgsGeometry *geom = QgsOgcUtils::geometryFromGML2( childElem ); req.setFilterRect( geom->boundingBox() ); delete geom; } @@ -892,11 +894,11 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format { if ( childElem.tagName() == "Box" ) { - req.setFilterRect( QgsRectangle( childElem ) ); + req.setFilterRect( QgsOgcUtils::rectangleFromGMLBox( childElem ) ); } else if ( childElem.tagName() != "PropertyName" ) { - QgsGeometry* geom = QgsGeometry::fromGML2( childElem ); + QgsGeometry* geom = QgsOgcUtils::geometryFromGML2( childElem ); req.setFilterRect( geom->boundingBox() ); delete geom; } @@ -1335,7 +1337,7 @@ QDomDocument QgsWFSServer::transaction( const QString& requestBody ) if ( !geometryElem.isNull() ) { - if ( !layer->changeGeometry( *fidIt, QgsGeometry::fromGML2( geometryElem ) ) ) + if ( !layer->changeGeometry( *fidIt, QgsOgcUtils::geometryFromGML2( geometryElem ) ) ) throw QgsMapServiceException( "RequestNotWellFormed", "Error in change geometry" ); } } @@ -1451,7 +1453,7 @@ QDomDocument QgsWFSServer::transaction( const QString& requestBody ) } else //a geometry attribute { - f->setGeometry( QgsGeometry::fromGML2( currentAttributeElement ) ); + f->setGeometry( QgsOgcUtils::geometryFromGML2( currentAttributeElement ) ); } } currentAttributeChild = currentAttributeChild.nextSibling(); @@ -1649,7 +1651,7 @@ QDomElement QgsWFSServer::createFeatureGML2( QgsFeature* feat, QDomDocument& doc QgsGeometry* geom = feat->geometry(); QDomElement geomElem = doc.createElement( "qgs:geometry" ); - QDomElement gmlElem = geom->exportToGML2( doc ); + QDomElement gmlElem = QgsOgcUtils::geometryToGML2( geom, doc ); if ( !gmlElem.isNull() ) { QgsRectangle box = geom->boundingBox(); diff --git a/src/providers/wfs/qgswfsprovider.cpp b/src/providers/wfs/qgswfsprovider.cpp index 9e591b6d99c..772e6841e94 100644 --- a/src/providers/wfs/qgswfsprovider.cpp +++ b/src/providers/wfs/qgswfsprovider.cpp @@ -30,6 +30,8 @@ #include "qgsspatialindex.h" #include "qgslogger.h" #include "qgsnetworkaccessmanager.h" +#include "qgsogcutils.h" + #include #include #include @@ -418,7 +420,7 @@ bool QgsWFSProvider::addFeatures( QgsFeatureList &flist ) //add geometry column (as gml) QDomElement geomElem = transactionDoc.createElementNS( mWfsNamespace, mGeometryAttribute ); - QDomElement gmlElem = featureIt->geometry()->exportToGML2( transactionDoc ); + QDomElement gmlElem = QgsOgcUtils::geometryToGML2( featureIt->geometry(), transactionDoc ); if ( !gmlElem.isNull() ) { geomElem.appendChild( gmlElem ); @@ -569,7 +571,7 @@ bool QgsWFSProvider::changeGeometryValues( QgsGeometryMap & geometry_map ) nameElem.appendChild( nameText ); propertyElem.appendChild( nameElem ); QDomElement valueElem = transactionDoc.createElementNS( "http://www.opengis.net/wfs", "Value" ); - QDomElement gmlElem = ( &geomIt.value() )->exportToGML2( transactionDoc ); + QDomElement gmlElem = QgsOgcUtils::geometryToGML2( &geomIt.value(), transactionDoc ); valueElem.appendChild( gmlElem ); propertyElem.appendChild( valueElem ); updateElem.appendChild( propertyElem ); @@ -1287,7 +1289,7 @@ int QgsWFSProvider::getFeaturesFromGML2( const QDomElement& wfsCollectionElement } else //a geometry attribute { - f->setGeometry( QgsGeometry::fromGML2( currentAttributeElement ) ); + f->setGeometry( QgsOgcUtils::geometryFromGML2( currentAttributeElement ) ); } } currentAttributeChild = currentAttributeChild.nextSibling(); diff --git a/tests/src/core/CMakeLists.txt b/tests/src/core/CMakeLists.txt index 93e487e841c..9a9810aa6b8 100644 --- a/tests/src/core/CMakeLists.txt +++ b/tests/src/core/CMakeLists.txt @@ -109,3 +109,4 @@ ADD_QGIS_TEST(stylev2test testqgsstylev2.cpp) ADD_QGIS_TEST(composerhtmltest testqgscomposerhtml.cpp ) ADD_QGIS_TEST(rectangletest testqgsrectangle.cpp) ADD_QGIS_TEST(composerscalebartest testqgscomposerscalebar.cpp ) +ADD_QGIS_TEST(ogcutilstest testqgsogcutils.cpp) diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index d64221426ba..33f58256968 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -56,8 +56,6 @@ class TestQgsGeometry: public QObject 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 = "" ); @@ -372,18 +370,6 @@ void TestQgsGeometry::dumpPolyline( QgsPolyline &thePolyline ) mpPainter->drawPolyline( myPoints ); } -void TestQgsGeometry::gmlTest() -{ - QgsGeometry* geom = QgsGeometry::fromGML2( "123,456" ); - QVERIFY( geom ); - QVERIFY( geom->wkbType() == QGis::WKBPoint ); - QVERIFY( geom->asPoint() == QgsPoint( 123, 456 ) ); - - QgsGeometry* geomBox = QgsGeometry::fromGML2( "135.2239,34.4879 135.8578,34.8471" ); - QVERIFY( geomBox ); - QVERIFY( geomBox->wkbType() == QGis::WKBPolygon ); -} - QTEST_MAIN( TestQgsGeometry ) #include "moc_testqgsgeometry.cxx" diff --git a/tests/src/core/testqgsogcutils.cpp b/tests/src/core/testqgsogcutils.cpp new file mode 100644 index 00000000000..01e82a07830 --- /dev/null +++ b/tests/src/core/testqgsogcutils.cpp @@ -0,0 +1,67 @@ + +/*************************************************************************** + testqgsogcutils.cpp + -------------------------------------- + Date : March 2013 + Copyright : (C) 2013 Martin Dobias + Email : wonder.sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include + +//qgis includes... +#include +#include + + +/** \ingroup UnitTests + * This is a unit test for OGC utilities + */ +class TestQgsOgcUtils : public QObject +{ + Q_OBJECT + private slots: + + void testGeometryFromGML(); + void testGeometryToGML(); +}; + + +void TestQgsOgcUtils::testGeometryFromGML() +{ + QgsGeometry* geom = QgsOgcUtils::geometryFromGML2( "123,456" ); + QVERIFY( geom ); + QVERIFY( geom->wkbType() == QGis::WKBPoint ); + QVERIFY( geom->asPoint() == QgsPoint( 123, 456 ) ); + + QgsGeometry* geomBox = QgsOgcUtils::geometryFromGML2( "135.2239,34.4879 135.8578,34.8471" ); + QVERIFY( geomBox ); + QVERIFY( geomBox->wkbType() == QGis::WKBPolygon ); +} + +void TestQgsOgcUtils::testGeometryToGML() +{ + QDomDocument doc; + + QDomElement elemInvalid = QgsOgcUtils::geometryToGML2( 0, doc ); + QVERIFY( elemInvalid.isNull() ); + + QgsGeometry* geomPoint = QgsGeometry::fromPoint( QgsPoint( 111, 222 ) ); + QDomElement elemPoint = QgsOgcUtils::geometryToGML2( geomPoint, doc ); + delete geomPoint; + QVERIFY( !elemPoint.isNull() ); + + doc.appendChild( elemPoint ); + QCOMPARE( doc.toString( -1 ), QString( "111.0,222.0" ) ); +} + + +QTEST_MAIN( TestQgsOgcUtils ) +#include "moc_testqgsogcutils.cxx"