|
QGIS API Documentation
master-6227475
|
00001 #include "qgsogcutils.h" 00002 00003 #include "qgsexpression.h" 00004 #include "qgsgeometry.h" 00005 00006 #include <QStringList> 00007 #include <QTextStream> 00008 00009 #ifndef Q_WS_WIN 00010 #include <netinet/in.h> 00011 #else 00012 #include <winsock.h> 00013 #endif 00014 00015 00016 static const QString GML_NAMESPACE = "http://www.opengis.net/gml"; 00017 00018 QgsGeometry* QgsOgcUtils::geometryFromGML( const QDomNode& geometryNode ) 00019 { 00020 QDomElement geometryTypeElement = geometryNode.toElement(); 00021 QString geomType = geometryTypeElement.tagName(); 00022 00023 if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" || geomType == "Envelope" ) ) 00024 { 00025 QDomNode geometryChild = geometryNode.firstChild(); 00026 if ( geometryChild.isNull() ) 00027 { 00028 return 0; 00029 } 00030 geometryTypeElement = geometryChild.toElement(); 00031 geomType = geometryTypeElement.tagName(); 00032 } 00033 00034 if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" || geomType == "Envelope" ) ) 00035 return 0; 00036 00037 if ( geomType == "Point" ) 00038 { 00039 return geometryFromGMLPoint( geometryTypeElement ); 00040 } 00041 else if ( geomType == "LineString" ) 00042 { 00043 return geometryFromGMLLineString( geometryTypeElement ); 00044 } 00045 else if ( geomType == "Polygon" ) 00046 { 00047 return geometryFromGMLPolygon( geometryTypeElement ); 00048 } 00049 else if ( geomType == "MultiPoint" ) 00050 { 00051 return geometryFromGMLMultiPoint( geometryTypeElement ); 00052 } 00053 else if ( geomType == "MultiLineString" ) 00054 { 00055 return geometryFromGMLMultiLineString( geometryTypeElement ); 00056 } 00057 else if ( geomType == "MultiPolygon" ) 00058 { 00059 return geometryFromGMLMultiPolygon( geometryTypeElement ); 00060 } 00061 else if ( geomType == "Box" ) 00062 { 00063 return QgsGeometry::fromRect( rectangleFromGMLBox( geometryTypeElement ) ); 00064 } 00065 else if ( geomType == "Envelope" ) 00066 { 00067 return QgsGeometry::fromRect( rectangleFromGMLEnvelope( geometryTypeElement ) ); 00068 } 00069 else //unknown type 00070 { 00071 return 0; 00072 } 00073 } 00074 00075 QgsGeometry* QgsOgcUtils::geometryFromGML( const QString& xmlString ) 00076 { 00077 // wrap the string into a root tag to have "gml" namespace (and also as a default namespace) 00078 QString xml = QString( "<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>" ).arg( GML_NAMESPACE ).arg( xmlString ); 00079 QDomDocument doc; 00080 if ( !doc.setContent( xml, true ) ) 00081 return 0; 00082 00083 return geometryFromGML( doc.documentElement().firstChildElement() ); 00084 } 00085 00086 00087 QgsGeometry* QgsOgcUtils::geometryFromGMLPoint( const QDomElement& geometryElement ) 00088 { 00089 std::list<QgsPoint> pointCoordinate; 00090 00091 QDomNodeList coordList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); 00092 if ( coordList.size() > 0 ) 00093 { 00094 QDomElement coordElement = coordList.at( 0 ).toElement(); 00095 if ( readGMLCoordinates( pointCoordinate, coordElement ) != 0 ) 00096 { 00097 return 0; 00098 } 00099 } 00100 else 00101 { 00102 QDomNodeList posList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "pos" ); 00103 if ( posList.size() < 1 ) 00104 { 00105 return 0; 00106 } 00107 QDomElement posElement = posList.at( 0 ).toElement(); 00108 if ( readGMLPositions( pointCoordinate, posElement ) != 0 ) 00109 { 00110 return 0; 00111 } 00112 } 00113 00114 if ( pointCoordinate.size() < 1 ) 00115 { 00116 return 0; 00117 } 00118 00119 std::list<QgsPoint>::const_iterator point_it = pointCoordinate.begin(); 00120 //char e = QgsApplication::endian(); 00121 char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; 00122 double x = point_it->x(); 00123 double y = point_it->y(); 00124 int size = 1 + sizeof( int ) + 2 * sizeof( double ); 00125 00126 QGis::WkbType type = QGis::WKBPoint; 00127 unsigned char* wkb = new unsigned char[size]; 00128 00129 int wkbPosition = 0; //current offset from wkb beginning (in bytes) 00130 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00131 wkbPosition += 1; 00132 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00133 wkbPosition += sizeof( int ); 00134 memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); 00135 wkbPosition += sizeof( double ); 00136 memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); 00137 00138 QgsGeometry* g = new QgsGeometry(); 00139 g->fromWkb( wkb, size ); 00140 return g; 00141 } 00142 00143 QgsGeometry* QgsOgcUtils::geometryFromGMLLineString( const QDomElement& geometryElement ) 00144 { 00145 std::list<QgsPoint> lineCoordinates; 00146 00147 QDomNodeList coordList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); 00148 if ( coordList.size() > 0 ) 00149 { 00150 QDomElement coordElement = coordList.at( 0 ).toElement(); 00151 if ( readGMLCoordinates( lineCoordinates, coordElement ) != 0 ) 00152 { 00153 return 0; 00154 } 00155 } 00156 else 00157 { 00158 QDomNodeList posList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "posList" ); 00159 if ( posList.size() < 1 ) 00160 { 00161 return 0; 00162 } 00163 QDomElement posElement = posList.at( 0 ).toElement(); 00164 if ( readGMLPositions( lineCoordinates, posElement ) != 0 ) 00165 { 00166 return 0; 00167 } 00168 } 00169 00170 //char e = QgsApplication::endian(); 00171 char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; 00172 int size = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double ); 00173 00174 QGis::WkbType type = QGis::WKBLineString; 00175 unsigned char* wkb = new unsigned char[size]; 00176 00177 int wkbPosition = 0; //current offset from wkb beginning (in bytes) 00178 double x, y; 00179 int nPoints = lineCoordinates.size(); 00180 00181 //fill the contents into *wkb 00182 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00183 wkbPosition += 1; 00184 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00185 wkbPosition += sizeof( int ); 00186 memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); 00187 wkbPosition += sizeof( int ); 00188 00189 std::list<QgsPoint>::const_iterator iter; 00190 for ( iter = lineCoordinates.begin(); iter != lineCoordinates.end(); ++iter ) 00191 { 00192 x = iter->x(); 00193 y = iter->y(); 00194 memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); 00195 wkbPosition += sizeof( double ); 00196 memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); 00197 wkbPosition += sizeof( double ); 00198 } 00199 00200 QgsGeometry* g = new QgsGeometry(); 00201 g->fromWkb( wkb, size ); 00202 return g; 00203 } 00204 00205 QgsGeometry* QgsOgcUtils::geometryFromGMLPolygon( const QDomElement& geometryElement ) 00206 { 00207 //read all the coordinates (as QgsPoint) into memory. Each linear ring has an entry in the vector 00208 std::vector<std::list<QgsPoint> > ringCoordinates; 00209 00210 //read coordinates for outer boundary 00211 std::list<QgsPoint> exteriorPointList; 00212 QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); 00213 if ( outerBoundaryList.size() > 0 ) //outer ring is necessary 00214 { 00215 QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement(); 00216 if ( coordinatesElement.isNull() ) 00217 { 00218 return 0; 00219 } 00220 if ( readGMLCoordinates( exteriorPointList, coordinatesElement ) != 0 ) 00221 { 00222 return 0; 00223 } 00224 ringCoordinates.push_back( exteriorPointList ); 00225 00226 //read coordinates for inner boundary 00227 QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); 00228 for ( int i = 0; i < innerBoundaryList.size(); ++i ) 00229 { 00230 std::list<QgsPoint> interiorPointList; 00231 coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement(); 00232 if ( coordinatesElement.isNull() ) 00233 { 00234 return 0; 00235 } 00236 if ( readGMLCoordinates( interiorPointList, coordinatesElement ) != 0 ) 00237 { 00238 return 0; 00239 } 00240 ringCoordinates.push_back( interiorPointList ); 00241 } 00242 } 00243 else 00244 { 00245 //read coordinates for exterior 00246 QDomNodeList exteriorList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "exterior" ); 00247 if ( exteriorList.size() < 1 ) //outer ring is necessary 00248 { 00249 return 0; 00250 } 00251 QDomElement posElement = exteriorList.at( 0 ).firstChild().firstChild().toElement(); 00252 if ( posElement.isNull() ) 00253 { 00254 return 0; 00255 } 00256 if ( readGMLPositions( exteriorPointList, posElement ) != 0 ) 00257 { 00258 return 0; 00259 } 00260 ringCoordinates.push_back( exteriorPointList ); 00261 00262 //read coordinates for inner boundary 00263 QDomNodeList interiorList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "interior" ); 00264 for ( int i = 0; i < interiorList.size(); ++i ) 00265 { 00266 std::list<QgsPoint> interiorPointList; 00267 QDomElement posElement = interiorList.at( i ).firstChild().firstChild().toElement(); 00268 if ( posElement.isNull() ) 00269 { 00270 return 0; 00271 } 00272 if ( readGMLPositions( interiorPointList, posElement ) != 0 ) 00273 { 00274 return 0; 00275 } 00276 ringCoordinates.push_back( interiorPointList ); 00277 } 00278 } 00279 00280 //calculate number of bytes to allocate 00281 int nrings = ringCoordinates.size(); 00282 if ( nrings < 1 ) 00283 return 0; 00284 00285 int npoints = 0;//total number of points 00286 for ( std::vector<std::list<QgsPoint> >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) 00287 { 00288 npoints += it->size(); 00289 } 00290 int size = 1 + 2 * sizeof( int ) + nrings * sizeof( int ) + 2 * npoints * sizeof( double ); 00291 00292 QGis::WkbType type = QGis::WKBPolygon; 00293 unsigned char* wkb = new unsigned char[size]; 00294 00295 //char e = QgsApplication::endian(); 00296 char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; 00297 int wkbPosition = 0; //current offset from wkb beginning (in bytes) 00298 int nPointsInRing = 0; 00299 double x, y; 00300 00301 //fill the contents into *wkb 00302 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00303 wkbPosition += 1; 00304 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00305 wkbPosition += sizeof( int ); 00306 memcpy( &( wkb )[wkbPosition], &nrings, sizeof( int ) ); 00307 wkbPosition += sizeof( int ); 00308 for ( std::vector<std::list<QgsPoint> >::const_iterator it = ringCoordinates.begin(); it != ringCoordinates.end(); ++it ) 00309 { 00310 nPointsInRing = it->size(); 00311 memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); 00312 wkbPosition += sizeof( int ); 00313 //iterate through the string list converting the strings to x-/y- doubles 00314 std::list<QgsPoint>::const_iterator iter; 00315 for ( iter = it->begin(); iter != it->end(); ++iter ) 00316 { 00317 x = iter->x(); 00318 y = iter->y(); 00319 //qWarning("currentCoordinate: " + QString::number(x) + " // " + QString::number(y)); 00320 memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); 00321 wkbPosition += sizeof( double ); 00322 memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); 00323 wkbPosition += sizeof( double ); 00324 } 00325 } 00326 00327 QgsGeometry* g = new QgsGeometry(); 00328 g->fromWkb( wkb, size ); 00329 return g; 00330 } 00331 00332 QgsGeometry* QgsOgcUtils::geometryFromGMLMultiPoint( const QDomElement& geometryElement ) 00333 { 00334 std::list<QgsPoint> pointList; 00335 std::list<QgsPoint> currentPoint; 00336 QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "pointMember" ); 00337 if ( pointMemberList.size() < 1 ) 00338 { 00339 return 0; 00340 } 00341 QDomNodeList pointNodeList; 00342 // coordinates or pos element 00343 QDomNodeList coordinatesList; 00344 QDomNodeList posList; 00345 for ( int i = 0; i < pointMemberList.size(); ++i ) 00346 { 00347 //<Point> element 00348 pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS( GML_NAMESPACE, "Point" ); 00349 if ( pointNodeList.size() < 1 ) 00350 { 00351 continue; 00352 } 00353 //<coordinates> element 00354 coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); 00355 if ( coordinatesList.size() > 0 ) 00356 { 00357 currentPoint.clear(); 00358 if ( readGMLCoordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 ) 00359 { 00360 continue; 00361 } 00362 if ( currentPoint.size() < 1 ) 00363 { 00364 continue; 00365 } 00366 pointList.push_back(( *currentPoint.begin() ) ); 00367 continue; 00368 } 00369 else 00370 { 00371 //<pos> element 00372 posList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( GML_NAMESPACE, "pos" ); 00373 if ( posList.size() < 1 ) 00374 { 00375 continue; 00376 } 00377 currentPoint.clear(); 00378 if ( readGMLPositions( currentPoint, posList.at( 0 ).toElement() ) != 0 ) 00379 { 00380 continue; 00381 } 00382 if ( currentPoint.size() < 1 ) 00383 { 00384 continue; 00385 } 00386 pointList.push_back(( *currentPoint.begin() ) ); 00387 } 00388 } 00389 00390 int nPoints = pointList.size(); //number of points 00391 if ( nPoints < 1 ) 00392 return 0; 00393 00394 //calculate the required wkb size 00395 int size = 1 + 2 * sizeof( int ) + pointList.size() * ( 2 * sizeof( double ) + 1 + sizeof( int ) ); 00396 00397 QGis::WkbType type = QGis::WKBMultiPoint; 00398 unsigned char* wkb = new unsigned char[size]; 00399 00400 //fill the wkb content 00401 //char e = QgsApplication::endian(); 00402 char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; 00403 int wkbPosition = 0; //current offset from wkb beginning (in bytes) 00404 double x, y; 00405 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00406 wkbPosition += 1; 00407 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00408 wkbPosition += sizeof( int ); 00409 memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); 00410 wkbPosition += sizeof( int ); 00411 for ( std::list<QgsPoint>::const_iterator it = pointList.begin(); it != pointList.end(); ++it ) 00412 { 00413 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00414 wkbPosition += 1; 00415 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00416 wkbPosition += sizeof( int ); 00417 x = it->x(); 00418 memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); 00419 wkbPosition += sizeof( double ); 00420 y = it->y(); 00421 memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); 00422 wkbPosition += sizeof( double ); 00423 } 00424 00425 QgsGeometry* g = new QgsGeometry(); 00426 g->fromWkb( wkb, size ); 00427 return g; 00428 } 00429 00430 QgsGeometry* QgsOgcUtils::geometryFromGMLMultiLineString( const QDomElement& geometryElement ) 00431 { 00432 //geoserver has 00433 //<gml:MultiLineString> 00434 //<gml:lineStringMember> 00435 //<gml:LineString> 00436 00437 //mapserver has directly 00438 //<gml:MultiLineString 00439 //<gml:LineString 00440 00441 std::list<std::list<QgsPoint> > lineCoordinates; //first list: lines, second list: points of one line 00442 QDomElement currentLineStringElement; 00443 QDomNodeList currentCoordList; 00444 QDomNodeList currentPosList; 00445 00446 QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "lineStringMember" ); 00447 if ( lineStringMemberList.size() > 0 ) //geoserver 00448 { 00449 for ( int i = 0; i < lineStringMemberList.size(); ++i ) 00450 { 00451 QDomNodeList lineStringNodeList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); 00452 if ( lineStringNodeList.size() < 1 ) 00453 { 00454 return 0; 00455 } 00456 currentLineStringElement = lineStringNodeList.at( 0 ).toElement(); 00457 currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); 00458 if ( currentCoordList.size() > 0 ) 00459 { 00460 std::list<QgsPoint> currentPointList; 00461 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) 00462 { 00463 return 0; 00464 } 00465 lineCoordinates.push_back( currentPointList ); 00466 } 00467 else 00468 { 00469 currentPosList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "posList" ); 00470 if ( currentPosList.size() < 1 ) 00471 { 00472 return 0; 00473 } 00474 std::list<QgsPoint> currentPointList; 00475 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 ) 00476 { 00477 return 0; 00478 } 00479 lineCoordinates.push_back( currentPointList ); 00480 } 00481 } 00482 } 00483 else 00484 { 00485 QDomNodeList lineStringList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "LineString" ); 00486 if ( lineStringList.size() > 0 ) //mapserver 00487 { 00488 for ( int i = 0; i < lineStringList.size(); ++i ) 00489 { 00490 currentLineStringElement = lineStringList.at( i ).toElement(); 00491 currentCoordList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); 00492 if ( currentCoordList.size() > 0 ) 00493 { 00494 std::list<QgsPoint> currentPointList; 00495 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 ) 00496 { 00497 return 0; 00498 } 00499 lineCoordinates.push_back( currentPointList ); 00500 return 0; 00501 } 00502 else 00503 { 00504 currentPosList = currentLineStringElement.elementsByTagNameNS( GML_NAMESPACE, "posList" ); 00505 if ( currentPosList.size() < 1 ) 00506 { 00507 return 0; 00508 } 00509 std::list<QgsPoint> currentPointList; 00510 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 ) 00511 { 00512 return 0; 00513 } 00514 lineCoordinates.push_back( currentPointList ); 00515 } 00516 } 00517 } 00518 else 00519 { 00520 return 0; 00521 } 00522 } 00523 00524 int nLines = lineCoordinates.size(); 00525 if ( nLines < 1 ) 00526 return 0; 00527 00528 00529 //calculate the required wkb size 00530 int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 * sizeof( int ) ); 00531 for ( std::list<std::list<QgsPoint> >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) 00532 { 00533 size += it->size() * 2 * sizeof( double ); 00534 } 00535 00536 QGis::WkbType type = QGis::WKBMultiLineString; 00537 unsigned char* wkb = new unsigned char[size]; 00538 00539 //fill the wkb content 00540 //char e = QgsApplication::endian(); 00541 char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; 00542 int wkbPosition = 0; //current offset from wkb beginning (in bytes) 00543 int nPoints; //number of points in a line 00544 double x, y; 00545 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00546 wkbPosition += 1; 00547 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00548 wkbPosition += sizeof( int ); 00549 memcpy( &( wkb )[wkbPosition], &nLines, sizeof( int ) ); 00550 wkbPosition += sizeof( int ); 00551 for ( std::list<std::list<QgsPoint> >::const_iterator it = lineCoordinates.begin(); it != lineCoordinates.end(); ++it ) 00552 { 00553 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00554 wkbPosition += 1; 00555 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00556 wkbPosition += sizeof( int ); 00557 nPoints = it->size(); 00558 memcpy( &( wkb )[wkbPosition], &nPoints, sizeof( int ) ); 00559 wkbPosition += sizeof( int ); 00560 for ( std::list<QgsPoint>::const_iterator iter = it->begin(); iter != it->end(); ++iter ) 00561 { 00562 x = iter->x(); 00563 //qWarning("x is: " + QString::number(x)); 00564 y = iter->y(); 00565 //qWarning("y is: " + QString::number(y)); 00566 memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); 00567 wkbPosition += sizeof( double ); 00568 memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); 00569 wkbPosition += sizeof( double ); 00570 } 00571 } 00572 00573 QgsGeometry* g = new QgsGeometry(); 00574 g->fromWkb( wkb, size ); 00575 return g; 00576 } 00577 00578 QgsGeometry* QgsOgcUtils::geometryFromGMLMultiPolygon( const QDomElement& geometryElement ) 00579 { 00580 //first list: different polygons, second list: different rings, third list: different points 00581 std::list<std::list<std::list<QgsPoint> > > multiPolygonPoints; 00582 QDomElement currentPolygonMemberElement; 00583 QDomNodeList polygonList; 00584 QDomElement currentPolygonElement; 00585 // rings in GML2 00586 QDomNodeList outerBoundaryList; 00587 QDomElement currentOuterBoundaryElement; 00588 QDomNodeList innerBoundaryList; 00589 QDomElement currentInnerBoundaryElement; 00590 // rings in GML3 00591 QDomNodeList exteriorList; 00592 QDomElement currentExteriorElement; 00593 QDomElement currentInteriorElement; 00594 QDomNodeList interiorList; 00595 // lienar ring 00596 QDomNodeList linearRingNodeList; 00597 QDomElement currentLinearRingElement; 00598 // Coordinates or position list 00599 QDomNodeList currentCoordinateList; 00600 QDomNodeList currentPosList; 00601 00602 QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "polygonMember" ); 00603 for ( int i = 0; i < polygonMemberList.size(); ++i ) 00604 { 00605 std::list<std::list<QgsPoint> > currentPolygonList; 00606 currentPolygonMemberElement = polygonMemberList.at( i ).toElement(); 00607 polygonList = currentPolygonMemberElement.elementsByTagNameNS( GML_NAMESPACE, "Polygon" ); 00608 if ( polygonList.size() < 1 ) 00609 { 00610 continue; 00611 } 00612 currentPolygonElement = polygonList.at( 0 ).toElement(); 00613 00614 //find exterior ring 00615 outerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "outerBoundaryIs" ); 00616 if ( outerBoundaryList.size() > 0 ) 00617 { 00618 currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement(); 00619 std::list<QgsPoint> ringCoordinates; 00620 00621 linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); 00622 if ( linearRingNodeList.size() < 1 ) 00623 { 00624 continue; 00625 } 00626 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); 00627 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); 00628 if ( currentCoordinateList.size() < 1 ) 00629 { 00630 continue; 00631 } 00632 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) 00633 { 00634 continue; 00635 } 00636 currentPolygonList.push_back( ringCoordinates ); 00637 00638 //find interior rings 00639 QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "innerBoundaryIs" ); 00640 for ( int j = 0; j < innerBoundaryList.size(); ++j ) 00641 { 00642 std::list<QgsPoint> ringCoordinates; 00643 currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement(); 00644 linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); 00645 if ( linearRingNodeList.size() < 1 ) 00646 { 00647 continue; 00648 } 00649 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); 00650 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" ); 00651 if ( currentCoordinateList.size() < 1 ) 00652 { 00653 continue; 00654 } 00655 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 ) 00656 { 00657 continue; 00658 } 00659 currentPolygonList.push_back( ringCoordinates ); 00660 } 00661 } 00662 else 00663 { 00664 //find exterior ring 00665 exteriorList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "exterior" ); 00666 if ( exteriorList.size() < 1 ) 00667 { 00668 continue; 00669 } 00670 00671 currentExteriorElement = exteriorList.at( 0 ).toElement(); 00672 std::list<QgsPoint> ringPositions; 00673 00674 linearRingNodeList = currentExteriorElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); 00675 if ( linearRingNodeList.size() < 1 ) 00676 { 00677 continue; 00678 } 00679 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); 00680 currentPosList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "posList" ); 00681 if ( currentPosList.size() < 1 ) 00682 { 00683 continue; 00684 } 00685 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 ) 00686 { 00687 continue; 00688 } 00689 currentPolygonList.push_back( ringPositions ); 00690 00691 //find interior rings 00692 QDomNodeList interiorList = currentPolygonElement.elementsByTagNameNS( GML_NAMESPACE, "interior" ); 00693 for ( int j = 0; j < interiorList.size(); ++j ) 00694 { 00695 std::list<QgsPoint> ringPositions; 00696 currentInteriorElement = interiorList.at( j ).toElement(); 00697 linearRingNodeList = currentInteriorElement.elementsByTagNameNS( GML_NAMESPACE, "LinearRing" ); 00698 if ( linearRingNodeList.size() < 1 ) 00699 { 00700 continue; 00701 } 00702 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement(); 00703 currentPosList = currentLinearRingElement.elementsByTagNameNS( GML_NAMESPACE, "posList" ); 00704 if ( currentPosList.size() < 1 ) 00705 { 00706 continue; 00707 } 00708 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 ) 00709 { 00710 continue; 00711 } 00712 currentPolygonList.push_back( ringPositions ); 00713 } 00714 } 00715 multiPolygonPoints.push_back( currentPolygonList ); 00716 } 00717 00718 int nPolygons = multiPolygonPoints.size(); 00719 if ( nPolygons < 1 ) 00720 return 0; 00721 00722 int size = 1 + 2 * sizeof( int ); 00723 //calculate the wkb size 00724 for ( std::list<std::list<std::list<QgsPoint> > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) 00725 { 00726 size += 1 + 2 * sizeof( int ); 00727 for ( std::list<std::list<QgsPoint> >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) 00728 { 00729 size += sizeof( int ) + 2 * iter->size() * sizeof( double ); 00730 } 00731 } 00732 00733 QGis::WkbType type = QGis::WKBMultiPolygon; 00734 unsigned char* wkb = new unsigned char[size]; 00735 00736 int polygonType = QGis::WKBPolygon; 00737 //char e = QgsApplication::endian(); 00738 char e = ( htonl( 1 ) == 1 ) ? 0 : 1 ; 00739 int wkbPosition = 0; //current offset from wkb beginning (in bytes) 00740 double x, y; 00741 int nRings; 00742 int nPointsInRing; 00743 00744 //fill the contents into *wkb 00745 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00746 wkbPosition += 1; 00747 memcpy( &( wkb )[wkbPosition], &type, sizeof( int ) ); 00748 wkbPosition += sizeof( int ); 00749 memcpy( &( wkb )[wkbPosition], &nPolygons, sizeof( int ) ); 00750 wkbPosition += sizeof( int ); 00751 00752 for ( std::list<std::list<std::list<QgsPoint> > >::const_iterator it = multiPolygonPoints.begin(); it != multiPolygonPoints.end(); ++it ) 00753 { 00754 memcpy( &( wkb )[wkbPosition], &e, 1 ); 00755 wkbPosition += 1; 00756 memcpy( &( wkb )[wkbPosition], &polygonType, sizeof( int ) ); 00757 wkbPosition += sizeof( int ); 00758 nRings = it->size(); 00759 memcpy( &( wkb )[wkbPosition], &nRings, sizeof( int ) ); 00760 wkbPosition += sizeof( int ); 00761 for ( std::list<std::list<QgsPoint> >::const_iterator iter = it->begin(); iter != it->end(); ++iter ) 00762 { 00763 nPointsInRing = iter->size(); 00764 memcpy( &( wkb )[wkbPosition], &nPointsInRing, sizeof( int ) ); 00765 wkbPosition += sizeof( int ); 00766 for ( std::list<QgsPoint>::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator ) 00767 { 00768 x = iterator->x(); 00769 y = iterator->y(); 00770 memcpy( &( wkb )[wkbPosition], &x, sizeof( double ) ); 00771 wkbPosition += sizeof( double ); 00772 memcpy( &( wkb )[wkbPosition], &y, sizeof( double ) ); 00773 wkbPosition += sizeof( double ); 00774 } 00775 } 00776 } 00777 00778 QgsGeometry* g = new QgsGeometry(); 00779 g->fromWkb( wkb, size ); 00780 return g; 00781 } 00782 00783 bool QgsOgcUtils::readGMLCoordinates( std::list<QgsPoint>& coords, const QDomElement elem ) 00784 { 00785 QString coordSeparator = ","; 00786 QString tupelSeparator = " "; 00787 //"decimal" has to be "." 00788 00789 coords.clear(); 00790 00791 if ( elem.hasAttribute( "cs" ) ) 00792 { 00793 coordSeparator = elem.attribute( "cs" ); 00794 } 00795 if ( elem.hasAttribute( "ts" ) ) 00796 { 00797 tupelSeparator = elem.attribute( "ts" ); 00798 } 00799 00800 QStringList tupels = elem.text().split( tupelSeparator, QString::SkipEmptyParts ); 00801 QStringList tupel_coords; 00802 double x, y; 00803 bool conversionSuccess; 00804 00805 QStringList::const_iterator it; 00806 for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it ) 00807 { 00808 tupel_coords = ( *it ).split( coordSeparator, QString::SkipEmptyParts ); 00809 if ( tupel_coords.size() < 2 ) 00810 { 00811 continue; 00812 } 00813 x = tupel_coords.at( 0 ).toDouble( &conversionSuccess ); 00814 if ( !conversionSuccess ) 00815 { 00816 return 1; 00817 } 00818 y = tupel_coords.at( 1 ).toDouble( &conversionSuccess ); 00819 if ( !conversionSuccess ) 00820 { 00821 return 1; 00822 } 00823 coords.push_back( QgsPoint( x, y ) ); 00824 } 00825 return 0; 00826 } 00827 00828 QgsRectangle QgsOgcUtils::rectangleFromGMLBox( const QDomNode& boxNode ) 00829 { 00830 QgsRectangle rect; 00831 00832 QDomElement boxElem = boxNode.toElement(); 00833 if ( boxElem.tagName() != "Box" ) 00834 return rect; 00835 00836 QDomElement bElem = boxElem.firstChild().toElement(); 00837 QString coordSeparator = ","; 00838 QString tupelSeparator = " "; 00839 if ( bElem.hasAttribute( "cs" ) ) 00840 { 00841 coordSeparator = bElem.attribute( "cs" ); 00842 } 00843 if ( bElem.hasAttribute( "ts" ) ) 00844 { 00845 tupelSeparator = bElem.attribute( "ts" ); 00846 } 00847 00848 QString bString = bElem.text(); 00849 bool ok1, ok2, ok3, ok4; 00850 double xmin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &ok1 ); 00851 double ymin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &ok2 ); 00852 double xmax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &ok3 ); 00853 double ymax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &ok4 ); 00854 00855 if ( ok1 && ok2 && ok3 && ok4 ) 00856 { 00857 rect = QgsRectangle( xmin, ymin, xmax, ymax ); 00858 rect.normalize(); 00859 } 00860 00861 return rect; 00862 } 00863 00864 bool QgsOgcUtils::readGMLPositions( std::list<QgsPoint>& coords, const QDomElement elem ) 00865 { 00866 //tupel and coord separator are the same 00867 QString coordSeparator = " "; 00868 QString tupelSeparator = " "; 00869 //"decimal" has to be "." 00870 00871 00872 coords.clear(); 00873 00874 QStringList pos = elem.text().split( " ", QString::SkipEmptyParts ); 00875 double x, y; 00876 bool conversionSuccess; 00877 int posSize = pos.size(); 00878 00879 int srsDimension = 2; 00880 if ( elem.hasAttribute( "srsDimension" ) ) 00881 { 00882 srsDimension = elem.attribute( "srsDimension" ).toInt( &conversionSuccess ); 00883 if ( !conversionSuccess ) 00884 { 00885 srsDimension = 2; 00886 } 00887 } 00888 else if ( elem.hasAttribute( "dimension" ) ) 00889 { 00890 srsDimension = elem.attribute( "dimension" ).toInt( &conversionSuccess ); 00891 if ( !conversionSuccess ) 00892 { 00893 srsDimension = 2; 00894 } 00895 } 00896 00897 for ( int i = 0; i < posSize / srsDimension; i++ ) 00898 { 00899 x = pos.at( i * srsDimension ).toDouble( &conversionSuccess ); 00900 if ( !conversionSuccess ) 00901 { 00902 return 1; 00903 } 00904 y = pos.at( i * srsDimension + 1 ).toDouble( &conversionSuccess ); 00905 if ( !conversionSuccess ) 00906 { 00907 return 1; 00908 } 00909 coords.push_back( QgsPoint( x, y ) ); 00910 } 00911 return 0; 00912 } 00913 00914 00915 QgsRectangle QgsOgcUtils::rectangleFromGMLEnvelope( const QDomNode& envelopeNode ) 00916 { 00917 QgsRectangle rect; 00918 00919 QDomElement envelopeElem = envelopeNode.toElement(); 00920 if ( envelopeElem.tagName() != "Envelope" ) 00921 return rect; 00922 00923 QDomNodeList lowerCornerList = envelopeElem.elementsByTagNameNS( GML_NAMESPACE, "lowerCorner" ); 00924 if ( lowerCornerList.size() < 1 ) 00925 return rect; 00926 00927 QDomNodeList upperCornerList = envelopeElem.elementsByTagNameNS( GML_NAMESPACE, "upperCorner" ); 00928 if ( upperCornerList.size() < 1 ) 00929 return rect; 00930 00931 bool conversionSuccess; 00932 int srsDimension = 2; 00933 00934 QDomElement elem = lowerCornerList.at( 0 ).toElement(); 00935 if ( elem.hasAttribute( "srsDimension" ) ) 00936 { 00937 srsDimension = elem.attribute( "srsDimension" ).toInt( &conversionSuccess ); 00938 if ( !conversionSuccess ) 00939 { 00940 srsDimension = 2; 00941 } 00942 } 00943 else if ( elem.hasAttribute( "dimension" ) ) 00944 { 00945 srsDimension = elem.attribute( "dimension" ).toInt( &conversionSuccess ); 00946 if ( !conversionSuccess ) 00947 { 00948 srsDimension = 2; 00949 } 00950 } 00951 QString bString = elem.text(); 00952 00953 double xmin = bString.section( " ", 0, 0 ).toDouble( &conversionSuccess ); 00954 if ( !conversionSuccess ) 00955 return rect; 00956 double ymin = bString.section( " ", 1, 1 ).toDouble( &conversionSuccess ); 00957 if ( !conversionSuccess ) 00958 return rect; 00959 00960 elem = upperCornerList.at( 0 ).toElement(); 00961 if ( elem.hasAttribute( "srsDimension" ) ) 00962 { 00963 srsDimension = elem.attribute( "srsDimension" ).toInt( &conversionSuccess ); 00964 if ( !conversionSuccess ) 00965 { 00966 srsDimension = 2; 00967 } 00968 } 00969 else if ( elem.hasAttribute( "dimension" ) ) 00970 { 00971 srsDimension = elem.attribute( "dimension" ).toInt( &conversionSuccess ); 00972 if ( !conversionSuccess ) 00973 { 00974 srsDimension = 2; 00975 } 00976 } 00977 00978 Q_UNUSED( srsDimension ); 00979 00980 bString = elem.text(); 00981 double xmax = bString.section( " ", 0, 0 ).toDouble( &conversionSuccess ); 00982 if ( !conversionSuccess ) 00983 return rect; 00984 double ymax = bString.section( " ", 1, 1 ).toDouble( &conversionSuccess ); 00985 if ( !conversionSuccess ) 00986 return rect; 00987 00988 rect = QgsRectangle( xmin, ymin, xmax, ymax ); 00989 rect.normalize(); 00990 00991 return rect; 00992 } 00993 00994 QDomElement QgsOgcUtils::rectangleToGMLBox( QgsRectangle* box, QDomDocument& doc ) 00995 { 00996 if ( !box ) 00997 { 00998 return QDomElement(); 00999 } 01000 01001 QDomElement boxElem = doc.createElement( "gml:Box" ); 01002 QDomElement coordElem = doc.createElement( "gml:coordinates" ); 01003 coordElem.setAttribute( "cs", "," ); 01004 coordElem.setAttribute( "ts", " " ); 01005 01006 QString coordString; 01007 coordString += QString::number( box->xMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01008 coordString += ","; 01009 coordString += QString::number( box->yMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01010 coordString += " "; 01011 coordString += QString::number( box->xMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01012 coordString += ","; 01013 coordString += QString::number( box->yMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01014 01015 QDomText coordText = doc.createTextNode( coordString ); 01016 coordElem.appendChild( coordText ); 01017 boxElem.appendChild( coordElem ); 01018 01019 return boxElem; 01020 } 01021 01022 QDomElement QgsOgcUtils::rectangleToGMLEnvelope( QgsRectangle* env, QDomDocument& doc ) 01023 { 01024 if ( !env ) 01025 { 01026 return QDomElement(); 01027 } 01028 01029 QDomElement envElem = doc.createElement( "gml:Envelope" ); 01030 QString posList; 01031 01032 QDomElement lowerCornerElem = doc.createElement( "gml:lowerCorner" ); 01033 posList = QString::number( env->xMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01034 posList += " "; 01035 posList += QString::number( env->yMinimum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01036 QDomText lowerCornerText = doc.createTextNode( posList ); 01037 lowerCornerElem.appendChild( lowerCornerText ); 01038 envElem.appendChild( lowerCornerElem ); 01039 01040 QDomElement upperCornerElem = doc.createElement( "gml:upperCorner" ); 01041 posList = QString::number( env->xMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01042 posList += " "; 01043 posList += QString::number( env->yMaximum(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01044 QDomText upperCornerText = doc.createTextNode( posList ); 01045 upperCornerElem.appendChild( upperCornerText ); 01046 envElem.appendChild( upperCornerElem ); 01047 01048 return envElem; 01049 } 01050 01051 QDomElement QgsOgcUtils::geometryToGML( QgsGeometry* geometry, QDomDocument& doc, QString format ) 01052 { 01053 if ( !geometry || !geometry->asWkb() ) 01054 return QDomElement(); 01055 01056 // coordinate separator 01057 QString cs = ","; 01058 // tupel separator 01059 QString ts = " "; 01060 // coord element tagname 01061 QDomElement baseCoordElem; 01062 01063 bool hasZValue = false; 01064 double *x, *y; 01065 unsigned char* wkb = geometry->asWkb(); 01066 01067 if ( format == "GML3" ) 01068 { 01069 switch ( geometry->wkbType() ) 01070 { 01071 case QGis::WKBPoint25D: 01072 case QGis::WKBPoint: 01073 case QGis::WKBMultiPoint25D: 01074 case QGis::WKBMultiPoint: 01075 baseCoordElem = doc.createElement( "gml:pos" );; 01076 break; 01077 default: 01078 baseCoordElem = doc.createElement( "gml:posList" );; 01079 break; 01080 } 01081 baseCoordElem.setAttribute( "srsDimension", "2" ); 01082 cs = " "; 01083 } 01084 else 01085 { 01086 baseCoordElem = doc.createElement( "gml:coordinates" );; 01087 baseCoordElem.setAttribute( "cs", cs ); 01088 baseCoordElem.setAttribute( "ts", ts ); 01089 } 01090 01091 switch ( geometry->wkbType() ) 01092 { 01093 case QGis::WKBPoint25D: 01094 case QGis::WKBPoint: 01095 { 01096 QDomElement pointElem = doc.createElement( "gml:Point" ); 01097 QDomElement coordElem = baseCoordElem.cloneNode().toElement(); 01098 QString coordString; 01099 x = ( double * )( wkb + 5 ); 01100 coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01101 coordString += cs; 01102 y = ( double * )( wkb + 5 + sizeof( double ) ); 01103 coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01104 QDomText coordText = doc.createTextNode( coordString ); 01105 coordElem.appendChild( coordText ); 01106 pointElem.appendChild( coordElem ); 01107 return pointElem; 01108 } 01109 case QGis::WKBMultiPoint25D: 01110 hasZValue = true; 01111 case QGis::WKBMultiPoint: 01112 { 01113 unsigned char *ptr; 01114 int idx; 01115 int *nPoints; 01116 01117 QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" ); 01118 nPoints = ( int* )( wkb + 5 ); 01119 ptr = wkb + 5 + sizeof( int ); 01120 for ( idx = 0; idx < *nPoints; ++idx ) 01121 { 01122 ptr += ( 1 + sizeof( int ) ); 01123 QDomElement pointMemberElem = doc.createElement( "gml:pointMember" ); 01124 QDomElement pointElem = doc.createElement( "gml:Point" ); 01125 QDomElement coordElem = baseCoordElem.cloneNode().toElement(); 01126 QString coordString; 01127 x = ( double * )( ptr ); 01128 coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01129 coordString += cs; 01130 ptr += sizeof( double ); 01131 y = ( double * )( ptr ); 01132 coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01133 QDomText coordText = doc.createTextNode( coordString ); 01134 coordElem.appendChild( coordText ); 01135 pointElem.appendChild( coordElem ); 01136 01137 ptr += sizeof( double ); 01138 if ( hasZValue ) 01139 { 01140 ptr += sizeof( double ); 01141 } 01142 pointMemberElem.appendChild( pointElem ); 01143 multiPointElem.appendChild( pointMemberElem ); 01144 } 01145 return multiPointElem; 01146 } 01147 case QGis::WKBLineString25D: 01148 hasZValue = true; 01149 case QGis::WKBLineString: 01150 { 01151 unsigned char *ptr; 01152 int *nPoints; 01153 int idx; 01154 01155 QDomElement lineStringElem = doc.createElement( "gml:LineString" ); 01156 // get number of points in the line 01157 ptr = wkb + 5; 01158 nPoints = ( int * ) ptr; 01159 ptr = wkb + 1 + 2 * sizeof( int ); 01160 QDomElement coordElem = baseCoordElem.cloneNode().toElement(); 01161 QString coordString; 01162 for ( idx = 0; idx < *nPoints; ++idx ) 01163 { 01164 if ( idx != 0 ) 01165 { 01166 coordString += ts; 01167 } 01168 x = ( double * ) ptr; 01169 coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01170 coordString += cs; 01171 ptr += sizeof( double ); 01172 y = ( double * ) ptr; 01173 coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01174 ptr += sizeof( double ); 01175 if ( hasZValue ) 01176 { 01177 ptr += sizeof( double ); 01178 } 01179 } 01180 QDomText coordText = doc.createTextNode( coordString ); 01181 coordElem.appendChild( coordText ); 01182 lineStringElem.appendChild( coordElem ); 01183 return lineStringElem; 01184 } 01185 case QGis::WKBMultiLineString25D: 01186 hasZValue = true; 01187 case QGis::WKBMultiLineString: 01188 { 01189 unsigned char *ptr; 01190 int idx, jdx, numLineStrings; 01191 int *nPoints; 01192 01193 QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" ); 01194 numLineStrings = ( int )( wkb[5] ); 01195 ptr = wkb + 9; 01196 for ( jdx = 0; jdx < numLineStrings; jdx++ ) 01197 { 01198 QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" ); 01199 QDomElement lineStringElem = doc.createElement( "gml:LineString" ); 01200 ptr += 5; // skip type since we know its 2 01201 nPoints = ( int * ) ptr; 01202 ptr += sizeof( int ); 01203 QDomElement coordElem = baseCoordElem.cloneNode().toElement(); 01204 QString coordString; 01205 for ( idx = 0; idx < *nPoints; idx++ ) 01206 { 01207 if ( idx != 0 ) 01208 { 01209 coordString += ts; 01210 } 01211 x = ( double * ) ptr; 01212 coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01213 ptr += sizeof( double ); 01214 coordString += cs; 01215 y = ( double * ) ptr; 01216 coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01217 ptr += sizeof( double ); 01218 if ( hasZValue ) 01219 { 01220 ptr += sizeof( double ); 01221 } 01222 } 01223 QDomText coordText = doc.createTextNode( coordString ); 01224 coordElem.appendChild( coordText ); 01225 lineStringElem.appendChild( coordElem ); 01226 lineStringMemberElem.appendChild( lineStringElem ); 01227 multiLineStringElem.appendChild( lineStringMemberElem ); 01228 } 01229 return multiLineStringElem; 01230 } 01231 case QGis::WKBPolygon25D: 01232 hasZValue = true; 01233 case QGis::WKBPolygon: 01234 { 01235 unsigned char *ptr; 01236 int idx, jdx; 01237 int *numRings, *nPoints; 01238 01239 QDomElement polygonElem = doc.createElement( "gml:Polygon" ); 01240 // get number of rings in the polygon 01241 numRings = ( int * )( wkb + 1 + sizeof( int ) ); 01242 if ( !( *numRings ) ) // sanity check for zero rings in polygon 01243 { 01244 return QDomElement(); 01245 } 01246 int *ringStart; // index of first point for each ring 01247 int *ringNumPoints; // number of points in each ring 01248 ringStart = new int[*numRings]; 01249 ringNumPoints = new int[*numRings]; 01250 ptr = wkb + 1 + 2 * sizeof( int ); // set pointer to the first ring 01251 for ( idx = 0; idx < *numRings; idx++ ) 01252 { 01253 QString boundaryName = "gml:outerBoundaryIs"; 01254 if ( idx != 0 ) 01255 { 01256 boundaryName = "gml:innerBoundaryIs"; 01257 } 01258 QDomElement boundaryElem = doc.createElement( boundaryName ); 01259 QDomElement ringElem = doc.createElement( "gml:LinearRing" ); 01260 // get number of points in the ring 01261 nPoints = ( int * ) ptr; 01262 ringNumPoints[idx] = *nPoints; 01263 ptr += 4; 01264 QDomElement coordElem = baseCoordElem.cloneNode().toElement(); 01265 QString coordString; 01266 for ( jdx = 0; jdx < *nPoints; jdx++ ) 01267 { 01268 if ( jdx != 0 ) 01269 { 01270 coordString += ts; 01271 } 01272 x = ( double * ) ptr; 01273 coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01274 coordString += cs; 01275 ptr += sizeof( double ); 01276 y = ( double * ) ptr; 01277 coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01278 ptr += sizeof( double ); 01279 if ( hasZValue ) 01280 { 01281 ptr += sizeof( double ); 01282 } 01283 } 01284 QDomText coordText = doc.createTextNode( coordString ); 01285 coordElem.appendChild( coordText ); 01286 ringElem.appendChild( coordElem ); 01287 boundaryElem.appendChild( ringElem ); 01288 polygonElem.appendChild( boundaryElem ); 01289 } 01290 delete [] ringStart; 01291 delete [] ringNumPoints; 01292 return polygonElem; 01293 } 01294 case QGis::WKBMultiPolygon25D: 01295 hasZValue = true; 01296 case QGis::WKBMultiPolygon: 01297 { 01298 unsigned char *ptr; 01299 int idx, jdx, kdx; 01300 int *numPolygons, *numRings, *nPoints; 01301 01302 QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" ); 01303 ptr = wkb + 5; 01304 numPolygons = ( int * ) ptr; 01305 ptr = wkb + 9; 01306 for ( kdx = 0; kdx < *numPolygons; kdx++ ) 01307 { 01308 QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" ); 01309 QDomElement polygonElem = doc.createElement( "gml:Polygon" ); 01310 ptr += 5; 01311 numRings = ( int * ) ptr; 01312 ptr += 4; 01313 for ( idx = 0; idx < *numRings; idx++ ) 01314 { 01315 QString boundaryName = "gml:outerBoundaryIs"; 01316 if ( idx != 0 ) 01317 { 01318 boundaryName = "gml:innerBoundaryIs"; 01319 } 01320 QDomElement boundaryElem = doc.createElement( boundaryName ); 01321 QDomElement ringElem = doc.createElement( "gml:LinearRing" ); 01322 nPoints = ( int * ) ptr; 01323 ptr += 4; 01324 QDomElement coordElem = baseCoordElem.cloneNode().toElement(); 01325 QString coordString; 01326 for ( jdx = 0; jdx < *nPoints; jdx++ ) 01327 { 01328 if ( jdx != 0 ) 01329 { 01330 coordString += ts; 01331 } 01332 x = ( double * ) ptr; 01333 coordString += QString::number( *x, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01334 ptr += sizeof( double ); 01335 coordString += cs; 01336 y = ( double * ) ptr; 01337 coordString += QString::number( *y, 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01338 ptr += sizeof( double ); 01339 if ( hasZValue ) 01340 { 01341 ptr += sizeof( double ); 01342 } 01343 } 01344 QDomText coordText = doc.createTextNode( coordString ); 01345 coordElem.appendChild( coordText ); 01346 ringElem.appendChild( coordElem ); 01347 boundaryElem.appendChild( ringElem ); 01348 polygonElem.appendChild( boundaryElem ); 01349 polygonMemberElem.appendChild( polygonElem ); 01350 multiPolygonElem.appendChild( polygonMemberElem ); 01351 } 01352 } 01353 return multiPolygonElem; 01354 } 01355 default: 01356 return QDomElement(); 01357 } 01358 } 01359 01360 QDomElement QgsOgcUtils::geometryToGML( QgsGeometry* geometry, QDomDocument& doc ) 01361 { 01362 return geometryToGML( geometry, doc, "GML2" ); 01363 } 01364 01365 QDomElement QgsOgcUtils::createGMLCoordinates( const QVector<QgsPoint> points, QDomDocument& doc ) 01366 { 01367 QDomElement coordElem = doc.createElement( "gml:coordinates" ); 01368 coordElem.setAttribute( "cs", "," ); 01369 coordElem.setAttribute( "ts", " " ); 01370 01371 QString coordString; 01372 QVector<QgsPoint>::const_iterator pointIt = points.constBegin(); 01373 for ( ; pointIt != points.constEnd(); ++pointIt ) 01374 { 01375 if ( pointIt != points.constBegin() ) 01376 { 01377 coordString += " "; 01378 } 01379 coordString += QString::number( pointIt->x(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01380 coordString += ","; 01381 coordString += QString::number( pointIt->y(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01382 } 01383 01384 QDomText coordText = doc.createTextNode( coordString ); 01385 coordElem.appendChild( coordText ); 01386 return coordElem; 01387 } 01388 01389 QDomElement QgsOgcUtils::createGMLPositions( const QVector<QgsPoint> points, QDomDocument& doc ) 01390 { 01391 QDomElement posElem = doc.createElement( "gml:pos" ); 01392 if ( points.size() > 1 ) 01393 posElem = doc.createElement( "gml:posList" ); 01394 posElem.setAttribute( "srsDimension", "2" ); 01395 01396 QString coordString; 01397 QVector<QgsPoint>::const_iterator pointIt = points.constBegin(); 01398 for ( ; pointIt != points.constEnd(); ++pointIt ) 01399 { 01400 if ( pointIt != points.constBegin() ) 01401 { 01402 coordString += " "; 01403 } 01404 coordString += QString::number( pointIt->x(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01405 coordString += " "; 01406 coordString += QString::number( pointIt->y(), 'f', 8 ).remove( QRegExp( "[0]{1,7}$" ) ); 01407 } 01408 01409 QDomText coordText = doc.createTextNode( coordString ); 01410 posElem.appendChild( coordText ); 01411 return posElem; 01412 } 01413 01414 01415 01416 // ----------------------------------------- 01417 01418 01419 QgsExpression* QgsOgcUtils::expressionFromOgcFilter( const QDomElement& element ) 01420 { 01421 if ( element.isNull() || !element.hasChildNodes() ) 01422 return NULL; 01423 01424 QgsExpression *expr = new QgsExpression(); 01425 01426 QDomElement childElem = element.firstChildElement(); 01427 while ( !childElem.isNull() ) 01428 { 01429 QString errorMsg; 01430 QgsExpression::Node *node = nodeFromOgcFilter( childElem, errorMsg ); 01431 if ( !node ) 01432 { 01433 // invalid expression, parser error 01434 expr->mParserErrorString = errorMsg; 01435 return expr; 01436 } 01437 01438 // use the concat binary operator to append to the root node 01439 if ( !expr->mRootNode ) 01440 { 01441 expr->mRootNode = node; 01442 } 01443 else 01444 { 01445 expr->mRootNode = new QgsExpression::NodeBinaryOperator( QgsExpression::boConcat, expr->mRootNode, node ); 01446 } 01447 01448 childElem = childElem.nextSiblingElement(); 01449 } 01450 01451 return expr; 01452 } 01453 01454 01455 static const QMap<QString, int>& binaryOperatorsTagNamesMap() 01456 { 01457 static QMap<QString, int> binOps; 01458 if ( binOps.isEmpty() ) 01459 { 01460 // logical 01461 binOps.insert( "Or", QgsExpression::boOr ); 01462 binOps.insert( "And", QgsExpression::boAnd ); 01463 // comparison 01464 binOps.insert( "PropertyIsEqualTo", QgsExpression::boEQ ); 01465 binOps.insert( "PropertyIsNotEqualTo", QgsExpression::boNE ); 01466 binOps.insert( "PropertyIsLessThanOrEqualTo", QgsExpression::boLE ); 01467 binOps.insert( "PropertyIsGreaterThanOrEqualTo", QgsExpression::boGE ); 01468 binOps.insert( "PropertyIsLessThan", QgsExpression::boLT ); 01469 binOps.insert( "PropertyIsGreaterThan", QgsExpression::boGT ); 01470 binOps.insert( "PropertyIsLike", QgsExpression::boLike ); 01471 // arithmetics 01472 binOps.insert( "Add", QgsExpression::boPlus ); 01473 binOps.insert( "Sub", QgsExpression::boMinus ); 01474 binOps.insert( "Mul", QgsExpression::boMul ); 01475 binOps.insert( "Div", QgsExpression::boDiv ); 01476 } 01477 return binOps; 01478 } 01479 01480 static int binaryOperatorFromTagName( const QString& tagName ) 01481 { 01482 01483 return binaryOperatorsTagNamesMap().value( tagName, -1 ); 01484 } 01485 01486 static QString binaryOperatorToTagName( QgsExpression::BinaryOperator op ) 01487 { 01488 return binaryOperatorsTagNamesMap().key( op, QString() ); 01489 } 01490 01491 static bool isBinaryOperator( const QString& tagName ) 01492 { 01493 return binaryOperatorFromTagName( tagName ) >= 0; 01494 } 01495 01496 01497 static bool isSpatialOperator( const QString& tagName ) 01498 { 01499 static QStringList spatialOps; 01500 if ( spatialOps.isEmpty() ) 01501 { 01502 spatialOps << "BBOX" << "Intersects" << "Contians" << "Crosses" << "Equals" 01503 << "Disjoint" << "Overlaps" << "Touches" << "Within"; 01504 } 01505 01506 return spatialOps.contains( tagName ); 01507 } 01508 01509 01510 01511 QgsExpression::Node* QgsOgcUtils::nodeFromOgcFilter( QDomElement &element, QString &errorMessage ) 01512 { 01513 if ( element.isNull() ) 01514 return NULL; 01515 01516 // check for binary operators 01517 if ( isBinaryOperator( element.tagName() ) ) 01518 { 01519 return nodeBinaryOperatorFromOgcFilter( element, errorMessage ); 01520 } 01521 01522 // check for spatial operators 01523 if ( isSpatialOperator( element.tagName() ) ) 01524 { 01525 return nodeSpatialOperatorFromOgcFilter( element, errorMessage ); 01526 } 01527 01528 // check for other OGC operators, convert them to expressions 01529 01530 if ( element.tagName() == "Not" ) 01531 { 01532 return nodeNotFromOgcFilter( element, errorMessage ); 01533 } 01534 else if ( element.tagName() == "PropertyIsNull" ) 01535 { 01536 return nodePropertyIsNullFromOgcFilter( element, errorMessage ); 01537 } 01538 else if ( element.tagName() == "Literal" ) 01539 { 01540 return nodeLiteralFromOgcFilter( element, errorMessage ); 01541 } 01542 else if ( element.tagName() == "Function" ) 01543 { 01544 return nodeFunctionFromOgcFilter( element, errorMessage ); 01545 } 01546 else if ( element.tagName() == "PropertyName" ) 01547 { 01548 return nodeColumnRefFromOgcFilter( element, errorMessage ); 01549 } 01550 else if ( element.tagName() == "PropertyIsBetween" ) 01551 { 01552 return nodeIsBetweenFromOgcFilter( element, errorMessage ); 01553 } 01554 01555 errorMessage += QString( "unable to convert '%1' element to a valid expression: it is not supported yet or it has invalid arguments" ).arg( element.tagName() ); 01556 return NULL; 01557 } 01558 01559 01560 01561 QgsExpression::NodeBinaryOperator* QgsOgcUtils::nodeBinaryOperatorFromOgcFilter( QDomElement &element, QString &errorMessage ) 01562 { 01563 if ( element.isNull() ) 01564 return NULL; 01565 01566 int op = binaryOperatorFromTagName( element.tagName() ); 01567 if ( op < 0 ) 01568 { 01569 if ( errorMessage.isEmpty() ) 01570 errorMessage = QString( "'%1' binary operator not supported." ).arg( element.tagName() ); 01571 return NULL; 01572 } 01573 01574 QDomElement operandElem = element.firstChildElement(); 01575 QgsExpression::Node* opLeft = nodeFromOgcFilter( operandElem, errorMessage ); 01576 if ( !opLeft ) 01577 { 01578 if ( errorMessage.isEmpty() ) 01579 errorMessage = QString( "invalid left operand for '%1' binary operator" ).arg( element.tagName() ); 01580 return NULL; 01581 } 01582 01583 operandElem = operandElem.nextSiblingElement(); 01584 QgsExpression::Node* opRight = nodeFromOgcFilter( operandElem, errorMessage ); 01585 if ( !opRight ) 01586 { 01587 if ( errorMessage.isEmpty() ) 01588 errorMessage = QString( "invalid right operand for '%1' binary operator" ).arg( element.tagName() ); 01589 delete opLeft; 01590 return NULL; 01591 } 01592 01593 return new QgsExpression::NodeBinaryOperator(( QgsExpression::BinaryOperator ) op, opLeft, opRight ); 01594 } 01595 01596 01597 QgsExpression::NodeFunction* QgsOgcUtils::nodeSpatialOperatorFromOgcFilter( QDomElement& element, QString& errorMessage ) 01598 { 01599 // we are exploiting the fact that our function names are the same as the XML tag names 01600 int opIdx = QgsExpression::functionIndex( element.tagName().toLower() ); 01601 01602 QgsExpression::NodeList *gml2Args = new QgsExpression::NodeList(); 01603 QDomElement childElem = element.firstChildElement(); 01604 QString gml2Str; 01605 while ( !childElem.isNull() && gml2Str.isEmpty() ) 01606 { 01607 if ( childElem.tagName() != "PropertyName" ) 01608 { 01609 QTextStream gml2Stream( &gml2Str ); 01610 childElem.save( gml2Stream, 0 ); 01611 } 01612 childElem = childElem.nextSiblingElement(); 01613 } 01614 if ( !gml2Str.isEmpty() ) 01615 { 01616 gml2Args->append( new QgsExpression::NodeLiteral( QVariant( gml2Str.remove( "\n" ) ) ) ); 01617 } 01618 else 01619 { 01620 errorMessage = QString( "No OGC Geometry found" ); 01621 return NULL; 01622 } 01623 01624 QgsExpression::NodeList *opArgs = new QgsExpression::NodeList(); 01625 opArgs->append( new QgsExpression::NodeFunction( QgsExpression::functionIndex( "$geometry" ), new QgsExpression::NodeList() ) ); 01626 opArgs->append( new QgsExpression::NodeFunction( QgsExpression::functionIndex( "geomFromGML" ), gml2Args ) ); 01627 01628 return new QgsExpression::NodeFunction( opIdx, opArgs ); 01629 } 01630 01631 01632 QgsExpression::NodeUnaryOperator* QgsOgcUtils::nodeNotFromOgcFilter( QDomElement &element, QString &errorMessage ) 01633 { 01634 if ( element.tagName() != "Not" ) 01635 return NULL; 01636 01637 QDomElement operandElem = element.firstChildElement(); 01638 QgsExpression::Node* operand = nodeFromOgcFilter( operandElem, errorMessage ); 01639 if ( !operand ) 01640 { 01641 if ( errorMessage.isEmpty() ) 01642 errorMessage = QString( "invalid operand for '%1' unary operator" ).arg( element.tagName() ); 01643 return NULL; 01644 } 01645 01646 return new QgsExpression::NodeUnaryOperator( QgsExpression::uoNot, operand ); 01647 } 01648 01649 01650 QgsExpression::NodeFunction* QgsOgcUtils::nodeFunctionFromOgcFilter( QDomElement &element, QString &errorMessage ) 01651 { 01652 if ( element.isNull() || element.tagName() != "Function" ) 01653 { 01654 errorMessage = QString( "ogc:Function expected, got %1" ).arg( element.tagName() ); 01655 return NULL; 01656 } 01657 01658 for ( int i = 0; i < QgsExpression::Functions().size(); i++ ) 01659 { 01660 QgsExpression::Function* funcDef = QgsExpression::Functions()[i]; 01661 01662 if ( element.attribute( "name" ) != funcDef->name() ) 01663 continue; 01664 01665 QgsExpression::NodeList *args = new QgsExpression::NodeList(); 01666 01667 QDomElement operandElem = element.firstChildElement(); 01668 while ( !operandElem.isNull() ) 01669 { 01670 QgsExpression::Node* op = nodeFromOgcFilter( operandElem, errorMessage ); 01671 if ( !op ) 01672 { 01673 delete args; 01674 return NULL; 01675 } 01676 args->append( op ); 01677 01678 operandElem = operandElem.nextSiblingElement(); 01679 } 01680 01681 return new QgsExpression::NodeFunction( i, args ); 01682 } 01683 01684 return NULL; 01685 } 01686 01687 01688 01689 QgsExpression::Node* QgsOgcUtils::nodeLiteralFromOgcFilter( QDomElement &element, QString &errorMessage ) 01690 { 01691 if ( element.isNull() || element.tagName() != "Literal" ) 01692 { 01693 errorMessage = QString( "ogc:Literal expected, got %1" ).arg( element.tagName() ); 01694 return NULL; 01695 } 01696 01697 QgsExpression::Node *root = 0; 01698 01699 // the literal content can have more children (e.g. CDATA section, text, ...) 01700 QDomNode childNode = element.firstChild(); 01701 while ( !childNode.isNull() ) 01702 { 01703 QgsExpression::Node* operand = 0; 01704 01705 if ( childNode.nodeType() == QDomNode::ElementNode ) 01706 { 01707 // found a element node (e.g. PropertyName), convert it 01708 QDomElement operandElem = childNode.toElement(); 01709 operand = nodeFromOgcFilter( operandElem, errorMessage ); 01710 if ( !operand ) 01711 { 01712 if ( root ) 01713 delete root; 01714 01715 errorMessage = QString( "'%1' is an invalid or not supported content for ogc:Literal" ).arg( operandElem.tagName() ); 01716 return NULL; 01717 } 01718 } 01719 else 01720 { 01721 // probably a text/CDATA node 01722 QVariant value = childNode.nodeValue(); 01723 01724 // try to convert the node content to number if possible, 01725 // otherwise let's use it as string 01726 bool ok; 01727 double d = value.toDouble( &ok ); 01728 if ( ok ) 01729 value = d; 01730 01731 operand = new QgsExpression::NodeLiteral( value ); 01732 if ( !operand ) 01733 continue; 01734 } 01735 01736 // use the concat operator to merge the ogc:Literal children 01737 if ( !root ) 01738 { 01739 root = operand; 01740 } 01741 else 01742 { 01743 root = new QgsExpression::NodeBinaryOperator( QgsExpression::boConcat, root, operand ); 01744 } 01745 01746 childNode = childNode.nextSibling(); 01747 } 01748 01749 if ( root ) 01750 return root; 01751 01752 return NULL; 01753 } 01754 01755 01756 QgsExpression::NodeColumnRef* QgsOgcUtils::nodeColumnRefFromOgcFilter( QDomElement &element, QString &errorMessage ) 01757 { 01758 if ( element.isNull() || element.tagName() != "PropertyName" ) 01759 { 01760 errorMessage = QString( "ogc:PropertyName expected, got %1" ).arg( element.tagName() ); 01761 return NULL; 01762 } 01763 01764 return new QgsExpression::NodeColumnRef( element.firstChild().nodeValue() ); 01765 } 01766 01767 01768 QgsExpression::Node* QgsOgcUtils::nodeIsBetweenFromOgcFilter( QDomElement& element, QString& errorMessage ) 01769 { 01770 // <ogc:PropertyIsBetween> encode a Range check 01771 QgsExpression::Node *operand = 0, *lowerBound = 0; 01772 QgsExpression::Node *operand2 = 0, *upperBound = 0; 01773 01774 QDomElement operandElem = element.firstChildElement(); 01775 while ( !operandElem.isNull() ) 01776 { 01777 if ( operandElem.tagName() == "LowerBoundary" ) 01778 { 01779 QDomElement lowerBoundElem = operandElem.firstChildElement(); 01780 lowerBound = nodeFromOgcFilter( lowerBoundElem, errorMessage ); 01781 } 01782 else if ( operandElem.tagName() == "UpperBoundary" ) 01783 { 01784 QDomElement upperBoundElem = operandElem.firstChildElement(); 01785 upperBound = nodeFromOgcFilter( upperBoundElem, errorMessage ); 01786 } 01787 else 01788 { 01789 // <ogc:expression> 01790 // both operand and operand2 contain the same expression, 01791 // they are respectively compared to lower bound and upper bound 01792 operand = nodeFromOgcFilter( operandElem, errorMessage ); 01793 operand2 = nodeFromOgcFilter( operandElem, errorMessage ); 01794 } 01795 01796 if ( operand && lowerBound && operand2 && upperBound ) 01797 break; 01798 01799 operandElem = operandElem.nextSiblingElement(); 01800 } 01801 01802 if ( !operand || !lowerBound || !operand2 || !upperBound ) 01803 { 01804 if ( operand ) 01805 delete operand; 01806 01807 if ( lowerBound ) 01808 delete lowerBound; 01809 01810 if ( upperBound ) 01811 delete upperBound; 01812 01813 errorMessage = "missing some required sub-elements in ogc:PropertyIsBetween"; 01814 return NULL; 01815 } 01816 01817 QgsExpression::Node *geOperator = new QgsExpression::NodeBinaryOperator( QgsExpression::boGE, operand, lowerBound ); 01818 QgsExpression::Node *leOperator = new QgsExpression::NodeBinaryOperator( QgsExpression::boLE, operand2, upperBound ); 01819 return new QgsExpression::NodeBinaryOperator( QgsExpression::boAnd, geOperator, leOperator ); 01820 } 01821 01822 01823 01824 QgsExpression::NodeBinaryOperator* QgsOgcUtils::nodePropertyIsNullFromOgcFilter( QDomElement& element, QString& errorMessage ) 01825 { 01826 // convert ogc:PropertyIsNull to IS operator with NULL right operand 01827 if ( element.tagName() != "PropertyIsNull" ) 01828 { 01829 return NULL; 01830 } 01831 01832 QDomElement operandElem = element.firstChildElement(); 01833 QgsExpression::Node* opLeft = nodeFromOgcFilter( operandElem, errorMessage ); 01834 if ( !opLeft ) 01835 return NULL; 01836 01837 QgsExpression::Node* opRight = new QgsExpression::NodeLiteral( QVariant() ); 01838 return new QgsExpression::NodeBinaryOperator( QgsExpression::boIs, opLeft, opRight ); 01839 } 01840 01841 01843 01844 01845 01846 01847 QDomElement QgsOgcUtils::expressionToOgcFilter( const QgsExpression& exp, QDomDocument& doc, QString* errorMessage ) 01848 { 01849 if ( !exp.rootNode() ) 01850 return QDomElement(); 01851 01852 QString localErrorMessage; // temporary that will be thrown away unused 01853 QString& refErrorMessage = ( errorMessage ? *errorMessage : localErrorMessage ); 01854 refErrorMessage.clear(); 01855 01856 QDomElement exprRootElem = expressionNodeToOgcFilter( exp.rootNode(), doc, refErrorMessage ); 01857 if ( exprRootElem.isNull() ) 01858 return QDomElement(); 01859 01860 QDomElement filterElem = doc.createElement( "ogc:Filter" ); 01861 filterElem.appendChild( exprRootElem ); 01862 return filterElem; 01863 } 01864 01865 01866 QDomElement QgsOgcUtils::expressionNodeToOgcFilter( const QgsExpression::Node* node, QDomDocument& doc, QString& errorMessage ) 01867 { 01868 switch ( node->nodeType() ) 01869 { 01870 case QgsExpression::ntUnaryOperator: 01871 return expressionUnaryOperatorToOgcFilter( static_cast<const QgsExpression::NodeUnaryOperator*>( node ), doc, errorMessage ); 01872 case QgsExpression::ntBinaryOperator: 01873 return expressionBinaryOperatorToOgcFilter( static_cast<const QgsExpression::NodeBinaryOperator*>( node ), doc, errorMessage ); 01874 case QgsExpression::ntInOperator: 01875 return expressionInOperatorToOgcFilter( static_cast<const QgsExpression::NodeInOperator*>( node ), doc, errorMessage ); 01876 case QgsExpression::ntFunction: 01877 return expressionFunctionToOgcFilter( static_cast<const QgsExpression::NodeFunction*>( node ), doc, errorMessage ); 01878 case QgsExpression::ntLiteral: 01879 return expressionLiteralToOgcFilter( static_cast<const QgsExpression::NodeLiteral*>( node ), doc, errorMessage ); 01880 case QgsExpression::ntColumnRef: 01881 return expressionColumnRefToOgcFilter( static_cast<const QgsExpression::NodeColumnRef*>( node ), doc, errorMessage ); 01882 01883 default: 01884 errorMessage = QString( "Node type not supported: %1" ).arg( node->nodeType() ); 01885 return QDomElement(); 01886 } 01887 } 01888 01889 01890 QDomElement QgsOgcUtils::expressionUnaryOperatorToOgcFilter( const QgsExpression::NodeUnaryOperator* node, QDomDocument& doc, QString& errorMessage ) 01891 { 01892 QDomElement uoElem; 01893 switch ( node->op() ) 01894 { 01895 case QgsExpression::uoMinus: 01896 uoElem = doc.createElement( "ogc:Literal" ); 01897 uoElem.appendChild( doc.createTextNode( "-" ) ); 01898 break; 01899 case QgsExpression::uoNot: 01900 uoElem = doc.createElement( "ogc:Not" ); 01901 break; 01902 01903 default: 01904 errorMessage = QString( "Unary operator %1 not implemented yet" ).arg( QgsExpression::UnaryOperatorText[node->op()] ); 01905 return QDomElement(); 01906 } 01907 01908 QDomElement operandElem = expressionNodeToOgcFilter( node->operand(), doc, errorMessage ); 01909 if ( !errorMessage.isEmpty() ) 01910 return QDomElement(); 01911 01912 uoElem.appendChild( operandElem ); 01913 return uoElem; 01914 } 01915 01916 01917 QDomElement QgsOgcUtils::expressionBinaryOperatorToOgcFilter( const QgsExpression::NodeBinaryOperator* node, QDomDocument& doc, QString& errorMessage ) 01918 { 01919 QDomElement leftElem = expressionNodeToOgcFilter( node->opLeft(), doc, errorMessage ); 01920 if ( !errorMessage.isEmpty() ) 01921 return QDomElement(); 01922 01923 QgsExpression::BinaryOperator op = node->op(); 01924 01925 // before right operator is parsed: to allow NULL handling 01926 if ( op == QgsExpression::boIs || op == QgsExpression::boIsNot ) 01927 { 01928 if ( node->opRight()->nodeType() == QgsExpression::ntLiteral ) 01929 { 01930 const QgsExpression::NodeLiteral* rightLit = static_cast<const QgsExpression::NodeLiteral*>( node->opRight() ); 01931 if ( rightLit->value().isNull() ) 01932 { 01933 01934 QDomElement elem = doc.createElement( "ogc:PropertyIsNull" ); 01935 elem.appendChild( leftElem ); 01936 01937 if ( op == QgsExpression::boIsNot ) 01938 { 01939 QDomElement notElem = doc.createElement( "ogc:Not" ); 01940 notElem.appendChild( elem ); 01941 return notElem; 01942 } 01943 01944 return elem; 01945 } 01946 01947 // continue with equal / not equal operator once the null case is handled 01948 op = ( op == QgsExpression::boIs ? QgsExpression::boEQ : QgsExpression::boNE ); 01949 } 01950 01951 } 01952 01953 QDomElement rightElem = expressionNodeToOgcFilter( node->opRight(), doc, errorMessage ); 01954 if ( !errorMessage.isEmpty() ) 01955 return QDomElement(); 01956 01957 01958 QString opText = binaryOperatorToTagName( op ); 01959 if ( opText.isEmpty() ) 01960 { 01961 // not implemented binary operators 01962 // TODO: regex, % (mod), ^ (pow) are not supported yet 01963 errorMessage = QString( "Binary operator %1 not implemented yet" ).arg( QgsExpression::BinaryOperatorText[op] ); 01964 return QDomElement(); 01965 } 01966 01967 QDomElement boElem = doc.createElement( "ogc:" + opText ); 01968 01969 if ( op == QgsExpression::boLike || op == QgsExpression::boILike ) 01970 { 01971 if ( op == QgsExpression::boILike ) 01972 boElem.setAttribute( "matchCase", "false" ); 01973 01974 // setup wildcards to <ogc:PropertyIsLike> 01975 boElem.setAttribute( "wildCard", "%" ); 01976 boElem.setAttribute( "singleChar", "?" ); 01977 boElem.setAttribute( "escapeChar", "!" ); 01978 } 01979 01980 boElem.appendChild( leftElem ); 01981 boElem.appendChild( rightElem ); 01982 return boElem; 01983 } 01984 01985 01986 QDomElement QgsOgcUtils::expressionLiteralToOgcFilter( const QgsExpression::NodeLiteral* node, QDomDocument& doc, QString& errorMessage ) 01987 { 01988 QString value; 01989 switch ( node->value().type() ) 01990 { 01991 case QVariant::Int: 01992 value = QString::number( node->value().toInt() ); 01993 break; 01994 case QVariant::Double: 01995 value = QString::number( node->value().toDouble() ); 01996 break; 01997 case QVariant::String: 01998 value = node->value().toString(); 01999 break; 02000 02001 default: 02002 errorMessage = QString( "Literal type not supported: %1" ).arg( node->value().type() ); 02003 return QDomElement(); 02004 } 02005 02006 QDomElement litElem = doc.createElement( "ogc:Literal" ); 02007 litElem.appendChild( doc.createTextNode( value ) ); 02008 return litElem; 02009 } 02010 02011 02012 QDomElement QgsOgcUtils::expressionColumnRefToOgcFilter( const QgsExpression::NodeColumnRef* node, QDomDocument& doc, QString& /*errorMessage*/ ) 02013 { 02014 QDomElement propElem = doc.createElement( "ogc:PropertyName" ); 02015 propElem.appendChild( doc.createTextNode( node->name() ) ); 02016 return propElem; 02017 } 02018 02019 02020 02021 QDomElement QgsOgcUtils::expressionInOperatorToOgcFilter( const QgsExpression::NodeInOperator* node, QDomDocument& doc, QString& errorMessage ) 02022 { 02023 if ( node->list()->list().size() == 1 ) 02024 return expressionNodeToOgcFilter( node->list()->list()[0], doc, errorMessage ); 02025 02026 QDomElement orElem = doc.createElement( "ogc:Or" ); 02027 QDomElement leftNode = expressionNodeToOgcFilter( node->node(), doc, errorMessage ); 02028 02029 foreach ( QgsExpression::Node* n, node->list()->list() ) 02030 { 02031 QDomElement listNode = expressionNodeToOgcFilter( n, doc, errorMessage ); 02032 if ( !errorMessage.isEmpty() ) 02033 return QDomElement(); 02034 02035 QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqualTo" ); 02036 eqElem.appendChild( leftNode.cloneNode() ); 02037 eqElem.appendChild( listNode ); 02038 02039 orElem.appendChild( eqElem ); 02040 } 02041 return orElem; 02042 } 02043 02044 static QMap<QString, QString> binarySpatialOpsMap() 02045 { 02046 static QMap<QString, QString> binSpatialOps; 02047 if ( binSpatialOps.isEmpty() ) 02048 { 02049 binSpatialOps.insert( "disjoint", "Disjoint" ); 02050 binSpatialOps.insert( "intersects", "Intersects" ); 02051 binSpatialOps.insert( "touches", "Touches" ); 02052 binSpatialOps.insert( "crosses", "Crosses" ); 02053 binSpatialOps.insert( "contains", "Contains" ); 02054 binSpatialOps.insert( "overlaps", "Overlaps" ); 02055 binSpatialOps.insert( "within", "Within" ); 02056 } 02057 return binSpatialOps; 02058 } 02059 02060 static bool isBinarySpatialOperator( const QString& fnName ) 02061 { 02062 return binarySpatialOpsMap().contains( fnName ); 02063 } 02064 02065 static QString tagNameForSpatialOperator( const QString& fnName ) 02066 { 02067 return binarySpatialOpsMap().value( fnName ); 02068 } 02069 02070 static bool isGeometryColumn( const QgsExpression::Node* node ) 02071 { 02072 if ( node->nodeType() != QgsExpression::ntFunction ) 02073 return false; 02074 02075 const QgsExpression::NodeFunction* fn = static_cast<const QgsExpression::NodeFunction*>( node ); 02076 QgsExpression::Function* fd = QgsExpression::Functions()[fn->fnIndex()]; 02077 return fd->name() == "$geometry"; 02078 } 02079 02080 02081 QDomElement QgsOgcUtils::expressionFunctionToOgcFilter( const QgsExpression::NodeFunction* node, QDomDocument& doc, QString& errorMessage ) 02082 { 02083 QgsExpression::Function* fd = QgsExpression::Functions()[node->fnIndex()]; 02084 02085 if ( fd->name() == "bbox" ) 02086 { 02087 errorMessage = QString( "<BBOX> is currently not supported." ); 02088 return QDomElement(); 02089 } 02090 02091 if ( isBinarySpatialOperator( fd->name() ) ) 02092 { 02093 QList<QgsExpression::Node*> argNodes = node->args()->list(); 02094 Q_ASSERT( argNodes.count() == 2 ); // binary spatial ops must have two args 02095 02096 QgsExpression::Node* otherNode = 0; 02097 if ( isGeometryColumn( argNodes[0] ) ) 02098 otherNode = argNodes[1]; 02099 else if ( isGeometryColumn( argNodes[1] ) ) 02100 otherNode = argNodes[0]; 02101 else 02102 { 02103 errorMessage = QString( "Unable to translate spatial operator: at least one must refer to geometry." ); 02104 return QDomElement(); 02105 } 02106 02107 QDomElement otherGeomElem; 02108 02109 // the other node must be a geometry constructor 02110 if ( otherNode->nodeType() != QgsExpression::ntFunction ) 02111 { 02112 errorMessage = "spatial operator: the other operator must be a geometry constructor function"; 02113 return QDomElement(); 02114 } 02115 02116 const QgsExpression::NodeFunction* otherFn = static_cast<const QgsExpression::NodeFunction*>( otherNode ); 02117 QgsExpression::Function* otherFnDef = QgsExpression::Functions()[otherFn->fnIndex()]; 02118 if ( otherFnDef->name() == "geomFromWKT" ) 02119 { 02120 QgsExpression::Node* firstFnArg = otherFn->args()->list()[0]; 02121 if ( firstFnArg->nodeType() != QgsExpression::ntLiteral ) 02122 { 02123 errorMessage = "geomFromWKT: argument must be string literal"; 02124 return QDomElement(); 02125 } 02126 QString wkt = static_cast<const QgsExpression::NodeLiteral*>( firstFnArg )->value().toString(); 02127 QgsGeometry* geom = QgsGeometry::fromWkt( wkt ); 02128 otherGeomElem = QgsOgcUtils::geometryToGML( geom, doc ); 02129 delete geom; 02130 } 02131 else if ( otherFnDef->name() == "geomFromGML" ) 02132 { 02133 QgsExpression::Node* firstFnArg = otherFn->args()->list()[0]; 02134 if ( firstFnArg->nodeType() != QgsExpression::ntLiteral ) 02135 { 02136 errorMessage = "geomFromGML: argument must be string literal"; 02137 return QDomElement(); 02138 } 02139 02140 QDomDocument geomDoc; 02141 QString gml = static_cast<const QgsExpression::NodeLiteral*>( firstFnArg )->value().toString(); 02142 if ( !geomDoc.setContent( gml, true ) ) 02143 { 02144 errorMessage = "geomFromGML: unable to parse XML"; 02145 return QDomElement(); 02146 } 02147 02148 QDomNode geomNode = doc.importNode( geomDoc.documentElement(), true ); 02149 otherGeomElem = geomNode.toElement(); 02150 } 02151 else 02152 { 02153 errorMessage = "spatial operator: unknown geometry constructor function"; 02154 return QDomElement(); 02155 } 02156 02157 QDomElement funcElem = doc.createElement( "ogc:" + tagNameForSpatialOperator( fd->name() ) ); 02158 QDomElement geomProperty = doc.createElement( "ogc:PropertyName" ); 02159 geomProperty.appendChild( doc.createTextNode( "geometry" ) ); 02160 funcElem.appendChild( geomProperty ); 02161 funcElem.appendChild( otherGeomElem ); 02162 return funcElem; 02163 } 02164 02165 if ( fd->params() == 0 ) 02166 { 02167 errorMessage = QString( "Special columns / constants are not supported." ); 02168 return QDomElement(); 02169 } 02170 02171 // this is somehow wrong - we are just hoping that the other side supports the same functions as we do... 02172 QDomElement funcElem = doc.createElement( "ogc:Function" ); 02173 funcElem.setAttribute( "name", fd->name() ); 02174 foreach ( QgsExpression::Node* n, node->args()->list() ) 02175 { 02176 QDomElement childElem = expressionNodeToOgcFilter( n, doc, errorMessage ); 02177 if ( !errorMessage.isEmpty() ) 02178 return QDomElement(); 02179 02180 funcElem.appendChild( childElem ); 02181 } 02182 02183 return funcElem; 02184 }