GeoDataDocument *ShpRunner::parseFile(const QString &fileName, DocumentRole role, QString &error) { QFileInfo fileinfo( fileName ); if (fileinfo.suffix().compare(QLatin1String("shp"), Qt::CaseInsensitive) != 0) { error = QStringLiteral("File %1 does not have a shp suffix").arg(fileName); mDebug() << error; return nullptr; } SHPHandle handle = SHPOpen( fileName.toStdString().c_str(), "rb" ); if ( !handle ) { error = QStringLiteral("Failed to read %1").arg(fileName); mDebug() << error; return nullptr; } int entities; int shapeType; SHPGetInfo( handle, &entities, &shapeType, NULL, NULL ); mDebug() << " SHP info " << entities << " Entities " << shapeType << " Shape Type "; DBFHandle dbfhandle; dbfhandle = DBFOpen( fileName.toStdString().c_str(), "rb"); int nameField = DBFGetFieldIndex( dbfhandle, "Name" ); int noteField = DBFGetFieldIndex( dbfhandle, "Note" ); int mapColorField = DBFGetFieldIndex( dbfhandle, "mapcolor13" ); GeoDataDocument *document = new GeoDataDocument; document->setDocumentRole( role ); if ( mapColorField != -1 ) { GeoDataSchema schema; schema.setId(QStringLiteral("default")); GeoDataSimpleField simpleField; simpleField.setName(QStringLiteral("mapcolor13")); simpleField.setType( GeoDataSimpleField::Double ); schema.addSimpleField( simpleField ); document->addSchema( schema ); } for ( int i=0; i< entities; ++i ) { GeoDataPlacemark *placemark = 0; placemark = new GeoDataPlacemark; document->append( placemark ); SHPObject *shape = SHPReadObject( handle, i ); if (nameField != -1) { const char* info = DBFReadStringAttribute( dbfhandle, i, nameField ); // TODO: defaults to utf-8 encoding, but could be also something else, optionally noted in a .cpg file placemark->setName( info ); mDebug() << "name " << placemark->name(); } if (noteField != -1) { const char* note = DBFReadStringAttribute( dbfhandle, i, noteField ); // TODO: defaults to utf-8 encoding, see comment for name placemark->setDescription( note ); mDebug() << "desc " << placemark->description(); } double mapColor = DBFReadDoubleAttribute( dbfhandle, i, mapColorField ); if ( mapColor ) { GeoDataStyle::Ptr style(new GeoDataStyle); if ( mapColor >= 0 && mapColor <=255 ) { quint8 colorIndex = quint8( mapColor ); style->polyStyle().setColorIndex( colorIndex ); } else { quint8 colorIndex = 0; // mapColor is undefined in this case style->polyStyle().setColorIndex( colorIndex ); } placemark->setStyle( style ); } switch ( shapeType ) { case SHPT_POINT: { GeoDataPoint *point = new GeoDataPoint( *shape->padfX, *shape->padfY, 0, GeoDataCoordinates::Degree ); placemark->setGeometry( point ); mDebug() << "point " << placemark->name(); break; } case SHPT_MULTIPOINT: { GeoDataMultiGeometry *geom = new GeoDataMultiGeometry; for( int j=0; j<shape->nVertices; ++j ) { geom->append( new GeoDataPoint( GeoDataCoordinates( shape->padfX[j], shape->padfY[j], 0, GeoDataCoordinates::Degree ) ) ); } placemark->setGeometry( geom ); mDebug() << "multipoint " << placemark->name(); break; } case SHPT_ARC: { if ( shape->nParts != 1 ) { GeoDataMultiGeometry *geom = new GeoDataMultiGeometry; for( int j=0; j<shape->nParts; ++j ) { GeoDataLineString *line = new GeoDataLineString; int itEnd = (j + 1 < shape->nParts) ? shape->panPartStart[j+1] : shape->nVertices; for( int k=shape->panPartStart[j]; k<itEnd; ++k ) { line->append( GeoDataCoordinates( shape->padfX[k], shape->padfY[k], 0, GeoDataCoordinates::Degree ) ); } geom->append( line ); } placemark->setGeometry( geom ); mDebug() << "arc " << placemark->name() << " " << shape->nParts; } else { GeoDataLineString *line = new GeoDataLineString; for( int j=0; j<shape->nVertices; ++j ) { line->append( GeoDataCoordinates( shape->padfX[j], shape->padfY[j], 0, GeoDataCoordinates::Degree ) ); } placemark->setGeometry( line ); mDebug() << "arc " << placemark->name() << " " << shape->nParts; } break; } case SHPT_POLYGON: { if ( shape->nParts != 1 ) { bool isRingClockwise = false; GeoDataMultiGeometry *multigeom = new GeoDataMultiGeometry; GeoDataPolygon *poly = 0; int polygonCount = 0; for( int j=0; j<shape->nParts; ++j ) { GeoDataLinearRing ring; int itStart = shape->panPartStart[j]; int itEnd = (j + 1 < shape->nParts) ? shape->panPartStart[j+1] : shape->nVertices; for( int k = itStart; k<itEnd; ++k ) { ring.append( GeoDataCoordinates( shape->padfX[k], shape->padfY[k], 0, GeoDataCoordinates::Degree ) ); } isRingClockwise = ring.isClockwise(); if ( j == 0 || isRingClockwise ) { poly = new GeoDataPolygon; ++polygonCount; poly->setOuterBoundary( ring ); if ( polygonCount > 1 ) { multigeom->append( poly ); } } else { poly->appendInnerBoundary( ring ); } } if ( polygonCount > 1 ) { placemark->setGeometry( multigeom ); } else { placemark->setGeometry( poly ); delete multigeom; multigeom = 0; } mDebug() << "donut " << placemark->name() << " " << shape->nParts; } else { GeoDataPolygon *poly = new GeoDataPolygon; GeoDataLinearRing ring; for( int j=0; j<shape->nVertices; ++j ) { ring.append( GeoDataCoordinates( shape->padfX[j], shape->padfY[j], 0, GeoDataCoordinates::Degree ) ); } poly->setOuterBoundary( ring ); placemark->setGeometry( poly ); mDebug() << "poly " << placemark->name() << " " << shape->nParts; } break; } } } SHPClose( handle ); DBFClose( dbfhandle ); if ( document->size() ) { document->setFileName( fileName ); return document; } else { delete document; return nullptr; } }
bool JsonParser::read( QIODevice* device ) { // Assert previous document got released. delete m_document; m_document = new GeoDataDocument; Q_ASSERT( m_document ); // Read file data QJsonParseError error; const QJsonDocument jsonDoc = QJsonDocument::fromJson(device->readAll(), &error); if (jsonDoc.isNull()) { qDebug() << "Error parsing GeoJSON : " << error.errorString(); return false; } // Start parsing const QJsonValue featuresValue = jsonDoc.object().value(QStringLiteral("features")); // In GeoJSON format, geometries are stored in features, so we iterate on features if (featuresValue.isArray()) { const QJsonArray featureArray = featuresValue.toArray(); // Parse each feature for (int featureIndex = 0; featureIndex < featureArray.size(); ++featureIndex) { const QJsonObject featureObject = featureArray[featureIndex].toObject(); // Check if the feature contains a geometry const QJsonValue geometryValue = featureObject.value(QStringLiteral("geometry")); if (geometryValue.isObject()) { const QJsonObject geometryObject = geometryValue.toObject(); // Variables for creating the geometry QList<GeoDataGeometry*> geometryList; QList<GeoDataPlacemark*> placemarkList; // Create the different geometry types const QString geometryType = geometryObject.value(QStringLiteral("type")).toString().toUpper(); if (geometryType == QLatin1String("POLYGON")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); GeoDataPolygon * geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); // Coordinates first array will be the outer boundary, if there are more // positions those will be inner holes for (int ringIndex = 0 ; ringIndex < coordinateArray.size(); ++ringIndex) { const QJsonArray ringArray = coordinateArray[ringIndex].toArray(); GeoDataLinearRing linearRing; for (int coordinatePairIndex = 0; coordinatePairIndex < ringArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = ringArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); linearRing.append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } // Outer ring if (ringIndex == 0) { geom->setOuterBoundary( linearRing ); } // Inner holes else { geom->appendInnerBoundary( linearRing ); } } geometryList.append( geom ); } } else if (geometryType == QLatin1String("MULTIPOLYGON")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); for (int polygonIndex = 0; polygonIndex < coordinateArray.size(); ++polygonIndex) { const QJsonArray polygonArray = coordinateArray[polygonIndex].toArray(); GeoDataPolygon * geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); // Coordinates first array will be the outer boundary, if there are more // positions those will be inner holes for (int ringIndex = 0 ; ringIndex < polygonArray.size(); ++ringIndex) { const QJsonArray ringArray = polygonArray[ringIndex].toArray(); GeoDataLinearRing linearRing; for (int coordinatePairIndex = 0; coordinatePairIndex < ringArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = ringArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); linearRing.append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } // Outer ring if (ringIndex == 0) { geom->setOuterBoundary( linearRing ); } // Inner holes else { geom->appendInnerBoundary( linearRing ); } } geometryList.append( geom ); } } } else if (geometryType == QLatin1String("LINESTRING")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); GeoDataLineString * geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); for (int coordinatePairIndex = 0; coordinatePairIndex < coordinateArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = coordinateArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } geometryList.append( geom ); } } else if (geometryType == QLatin1String("MULTILINESTRING")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); for (int lineStringIndex = 0; lineStringIndex < coordinateArray.size(); ++lineStringIndex) { const QJsonArray lineStringArray = coordinateArray[lineStringIndex].toArray(); GeoDataLineString * geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); for (int coordinatePairIndex = 0; coordinatePairIndex < lineStringArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = lineStringArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } geometryList.append( geom ); } } } else if (geometryType == QLatin1String("POINT")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinatePairArray = coordinatesValue.toArray(); GeoDataPoint * geom = new GeoDataPoint(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->setCoordinates( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); geometryList.append( geom ); } } else if (geometryType == QLatin1String("MULTIPOINT")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); for (int pointIndex = 0; pointIndex < coordinateArray.size(); ++pointIndex) { const QJsonArray coordinatePairArray = coordinateArray[pointIndex].toArray(); GeoDataPoint * geom = new GeoDataPoint(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->setCoordinates( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); geometryList.append( geom ); } } } // Parse the features properties const QJsonValue propertiesValue = featureObject.value(QStringLiteral("properties")); if (!geometryList.isEmpty() && propertiesValue.isObject()) { const QJsonObject propertiesObject = propertiesValue.toObject(); // First create a placemark for each geometry, there could be multi geometries // that are translated into more than one geometry/placemark for ( int numberGeometries = 0 ; numberGeometries < geometryList.length() ; numberGeometries++ ) { GeoDataPlacemark * placemark = new GeoDataPlacemark(); placemarkList.append( placemark ); } OsmPlacemarkData osmData; QJsonObject::ConstIterator it = propertiesObject.begin(); const QJsonObject::ConstIterator end = propertiesObject.end(); for ( ; it != end; ++it) { if (it.value().isObject() || it.value().isArray()) { qDebug() << "Skipping property, values of type arrays and objects not supported:" << it.key(); continue; } // pass value through QVariant to also get bool & numbers osmData.addTag(it.key(), it.value().toVariant().toString()); } // If the property read, is the features name const auto tagIter = osmData.findTag(QStringLiteral("name")); if (tagIter != osmData.tagsEnd()) { const QString& name = tagIter.value(); for (int pl = 0 ; pl < placemarkList.length(); ++pl) { placemarkList.at(pl)->setName(name); } } const GeoDataPlacemark::GeoDataVisualCategory category = StyleBuilder::determineVisualCategory(osmData); if (category != GeoDataPlacemark::None) { // Add the visual category to all the placemarks for (int pl = 0 ; pl < placemarkList.length(); ++pl) { placemarkList.at(pl)->setVisualCategory(category); placemarkList.at(pl)->setOsmData(osmData); } } } // Add the geometry to the document if ( geometryList.length() == placemarkList.length() ) { while( placemarkList.length() > 0 ) { GeoDataPlacemark * placemark = placemarkList.last(); placemarkList.pop_back(); GeoDataGeometry * geom = geometryList.last(); geometryList.pop_back(); placemark->setGeometry( geom ); placemark->setVisible( true ); m_document->append( placemark ); } } // If geometries or placemarks missing inside the lists, delete them qDeleteAll( geometryList.begin(), geometryList.end() ); geometryList.clear(); qDeleteAll( placemarkList.begin(), placemarkList.end() ); placemarkList.clear(); } } } return true; }
bool JsonParser::read( QIODevice* device ) { // Assert previous document got released. delete m_document; m_document = new GeoDataDocument; Q_ASSERT( m_document ); // Fixes for test parsing device->seek(21); // Strip off 'onKothicDataRespone(' QString temp = QString::fromUtf8( device->readAll() ); int midIndex = temp.size(); int rightIndex = midIndex; for ( int i=0; i<4; ++i ) { rightIndex = midIndex; midIndex = temp.lastIndexOf( ',', midIndex-1 ); if ( i==1 ) { QString name = temp.mid( midIndex-1 ); name.remove( name.size()-2,2 ); m_document->setName( "Kothic " + name ); } } QString stream = temp.mid(0, midIndex); stream.prepend('('); stream.append("})"); bool hasGranularity = false; int const granularity = temp.mid(midIndex+15, rightIndex-midIndex-16).toInt( &hasGranularity ); if (!hasGranularity) { mDebug() << "Cannot parse json file (failed to parse granularity) " << temp; return false; } /** THIS IS A TEST PARSER FOR KOTHIK's JSON FORMAT **/ m_data = m_engine.evaluate( stream ); if (m_engine.hasUncaughtException()) { mDebug() << "Cannot parse json file: " << m_engine.uncaughtException().toString(); return false; } // Start parsing GeoDataPlacemark *placemark; GeoDataFeature::GeoDataVisualCategory category; // Bounding box coordinates float east; float south; float west; float north; // Global data (even if it is at the end of the json response // it is possible to read it now) if ( m_data.property( "bbox" ).isArray() ){ QStringList coors = m_data.property( "bbox" ).toString().split( QLatin1Char( ',' ) ); // Load the bounding box coordinates west = coors.at(0).toFloat(); east = coors.at(2).toFloat(); south = coors.at(1).toFloat(); north = coors.at(3).toFloat(); } else{ mDebug() << "Cannot parse bbox"; return false; } // All downloaded placemarks will be features, so we should iterate // on features QScriptValue const features = m_data.property( "features" ); if (features.isArray()){ QScriptValueIterator iterator( features ); // Add items to the list while ( iterator.hasNext() ) { iterator.next(); GeoDataGeometry * geom; placemark = new GeoDataPlacemark(); QString const typeProperty = iterator.value().property( "type" ).toString(); if ( typeProperty == "Polygon" ){ geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); } else if ( typeProperty == "LineString" ){ geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); } else if ( typeProperty == "Point" ){ geom = new GeoDataPoint(); } else geom = 0; QScriptValueIterator it (iterator.value().property( "properties" )); bool propertiesCorrect = false; // Parsing properties while ( it.hasNext() && geom != 0 ) { it.next(); if ( it.name() == "name" ){ placemark->setName( it.value().toString() ); }else if ( !propertiesCorrect ){ category = GeoDataFeature::OsmVisualCategory( it.name() + '=' + it.value().toString() ); if (category != 0){ placemark->setVisualCategory( category ); propertiesCorrect = true; } } } // Parsing coordinates QScriptValue const coordinatesProperty = iterator.value().property( "coordinates" ); if ( coordinatesProperty.isArray() ){ QScriptValueIterator it ( coordinatesProperty ); while ( it.hasNext() ) { it.next(); QStringList coors = it.value().toString().split( QLatin1Char( ',' ) ); for (int x = 0; x < coors.size()-1 && coors.size()>1 ;){ float auxX = ( coors.at(x++).toFloat() / granularity)*(east-west) + west; float auxY = ( coors.at(x++).toFloat() / granularity)*(north-south) + south; QString const typeProperty = iterator.value().property( "type" ).toString(); if (typeProperty == "Polygon"){ GeoDataLinearRing ring = ((GeoDataPolygon*)geom)->outerBoundary(); ring.append( GeoDataCoordinates(auxX, auxY,0, GeoDataCoordinates::Degree ) ); // FIXME appending to the ring could be done more efficiently ((GeoDataPolygon*)geom)->setOuterBoundary(ring); } else if (typeProperty == "LineString"){ ((GeoDataLineString*) geom)->append( GeoDataCoordinates(auxX, auxY,0, GeoDataCoordinates::Degree ) ); } else if (typeProperty == "Point"){ ((GeoDataPoint*) geom)->setCoordinates( GeoDataCoordinates(auxX,auxY,0, GeoDataCoordinates::Degree ) ); } } } } if ( propertiesCorrect && geom != 0 ){ placemark->setGeometry( geom ); placemark->setVisible( true ); m_document->append( placemark ); } } } return true; }