void LocalOsmSearchRunner::search( const QString &searchTerm, const GeoDataLatLonBox &preferred ) { const DatabaseQuery userQuery( model(), searchTerm, preferred ); QVector<OsmPlacemark> placemarks = m_database.find( userQuery ); QVector<GeoDataPlacemark*> result; for( const OsmPlacemark &placemark: placemarks ) { GeoDataPlacemark* hit = new GeoDataPlacemark; hit->setName( placemark.name() ); if ( placemark.category() == OsmPlacemark::Address && !placemark.houseNumber().isEmpty() ) { hit->setName(hit->name() + QLatin1Char(' ') + placemark.houseNumber()); } if ( !placemark.additionalInformation().isEmpty() ) { hit->setName(hit->name() + QLatin1Char('(') + placemark.additionalInformation() + QLatin1Char(')')); } if ( placemark.category() != OsmPlacemark::UnknownCategory ) { hit->setVisualCategory( m_categoryMap[placemark.category()] ); } hit->setGeometry( new GeoDataPoint( placemark.longitude(), placemark.latitude(), 0.0, GeoDataCoordinates::Degree ) ); result << hit; } emit searchFinished( result ); }
void PlasmaRunner::collectMatches(QList<Plasma::QueryMatch> &matches, const QString &query, const GeoDataFolder *folder) { const QString queryLower = query.toLower(); QVector<GeoDataFeature*>::const_iterator it = folder->constBegin(); QVector<GeoDataFeature*>::const_iterator end = folder->constEnd(); for (; it != end; ++it) { GeoDataFolder *folder = dynamic_cast<GeoDataFolder*>(*it); if ( folder ) { collectMatches(matches, query, folder); continue; } GeoDataPlacemark *placemark = dynamic_cast<GeoDataPlacemark*>( *it ); if ( placemark ) { // For short query strings only match exactly, to get a sane number of matches if (query.length() < minContainsMatchLength) { if ( placemark->name().toLower() != queryLower && ( placemark->descriptionIsCDATA() || // TODO: support also with CDATA placemark->description().toLower() != queryLower ) ) { continue; } } else { if ( ! placemark->name().toLower().contains(queryLower) && ( placemark->descriptionIsCDATA() || // TODO: support also with CDATA ! placemark->description().toLower().contains(queryLower) ) ) { continue; } } const GeoDataCoordinates coordinates = placemark->coordinate(); const qreal lon = coordinates.longitude(GeoDataCoordinates::Degree); const qreal lat = coordinates.latitude(GeoDataCoordinates::Degree); const QVariant coordinatesData = QVariantList() << QVariant(lon) << QVariant(lat) << QVariant(placemark->lookAt()->range()*METER2KM); Plasma::QueryMatch match(this); match.setIcon(QIcon::fromTheme(QStringLiteral("marble"))); match.setText(placemark->name()); match.setSubtext(i18n("Show in OpenStreetMap with Marble")); match.setData(coordinatesData); match.setId(placemark->name()+QString::number(lat)+QString::number(lon)); match.setRelevance(1.0); match.setType(Plasma::QueryMatch::ExactMatch); matches << match; } } }
void CountryByFlag::postQuestion( QObject *gameObject ) { /** * Find a random placemark */ Q_ASSERT_X( d->m_countryNames, "CountryByFlag::postQuestion", "CountryByFlagPrivate::m_countryNames is NULL" ); QVector<GeoDataPlacemark*> countryPlacemarks = d->m_countryNames->placemarkList(); uint randomSeed = uint(QTime::currentTime().msec()); qsrand( randomSeed ); bool found = false; GeoDataPlacemark *placemark = 0; QVariantList answerOptions; QString flagPath; while ( !found ) { int randomIndex = qrand()%countryPlacemarks.size(); placemark = countryPlacemarks[randomIndex]; if ( !d->m_continentsAndOceans.contains(placemark->name(), Qt::CaseSensitive) ) { flagPath = MarbleDirs::path( QString("flags/flag_%1.svg").arg(placemark->countryCode().toLower()) ); QImage flag = QFile::exists( flagPath ) ? QImage( flagPath ) : QImage(); if ( !flag.isNull() ) { flagPath = QString("%1flag_%2.svg").arg("../../../data/flags/").arg(placemark->countryCode().toLower()); found = true; } } } answerOptions << placemark->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name(); // Randomize the options in the list answerOptions for ( int i = 0; i < answerOptions.size(); ++i ) { QVariant option = answerOptions.takeAt( qrand()%answerOptions.size() ); answerOptions.append( option ); } if ( gameObject ) { QMetaObject::invokeMethod( gameObject, "countryByFlagQuestion", Q_ARG(QVariant, QVariant::fromValue(answerOptions)), Q_ARG(QVariant, QVariant::fromValue(flagPath)), Q_ARG(QVariant, QVariant::fromValue(placemark->name())) ); } }
void MonavMap::parseBoundingBox( const QFileInfo &file ) { GeoDataLineString points; bool tooLarge = false; QFile input( file.absoluteFilePath() ); if ( input.open( QFile::ReadOnly ) ) { GeoDataParser parser( GeoData_KML ); if ( !parser.read( &input ) ) { mDebug() << "Could not parse file: " << parser.errorString(); return; } GeoDocument *doc = parser.releaseDocument(); input.close(); GeoDataDocument *document = dynamic_cast<GeoDataDocument*>( doc ); QVector<GeoDataPlacemark*> placemarks = document->placemarkList(); if ( placemarks.size() == 1 ) { GeoDataPlacemark* placemark = placemarks.first(); m_name = placemark->name(); m_version = placemark->extendedData().value( "version" ).value().toString(); m_date = placemark->extendedData().value( "date" ).value().toString(); m_transport = placemark->extendedData().value( "transport" ).value().toString(); m_payload = placemark->extendedData().value( "payload" ).value().toString(); GeoDataMultiGeometry* geometry = dynamic_cast<GeoDataMultiGeometry*>( placemark->geometry() ); if ( geometry->size() > 1500 ) { tooLarge = true; } for ( int i = 0; geometry && i < geometry->size(); ++i ) { GeoDataLinearRing* poly = dynamic_cast<GeoDataLinearRing*>( geometry->child( i ) ); if ( poly ) { for ( int j = 0; j < poly->size(); ++j ) { points << poly->at( j ); } m_tiles.push_back( *poly ); } if ( poly->size() > 1500 ) { tooLarge = true; } } } else { mDebug() << "File " << file.absoluteFilePath() << " does not contain one placemark, but " << placemarks.size(); } delete doc; } m_boundingBox = points.latLonAltBox(); if ( tooLarge ) { // The bounding box polygon is rather complicated, therefore not allowing a quick check // and also occupying memory. Discard the polygon and only store the rectangular bounding // box. Only happens for non-simplified bounding box polygons. mDebug() << "Discarding too large bounding box poylgon for " << file.absoluteFilePath() << ". Please check for a map update."; m_tiles.clear(); } }
void OsmNode::create(GeoDataDocument *document) const { GeoDataFeature::GeoDataVisualCategory const category = OsmPresetLibrary::determineVisualCategory(m_osmData); if (category == GeoDataFeature::None || (category >= GeoDataFeature::HighwaySteps && category <= GeoDataFeature::HighwayMotorway)) { return; } GeoDataPlacemark* placemark = new GeoDataPlacemark; placemark->setOsmData(m_osmData); placemark->setCoordinate(m_coordinates); if ((category == GeoDataFeature::TransportCarShare || category == GeoDataFeature::MoneyAtm) && m_osmData.containsTagKey("operator")) { placemark->setName(m_osmData.tagValue("operator")); } else { placemark->setName(m_osmData.tagValue("name")); } placemark->setVisualCategory(category); placemark->setStyle( GeoDataStyle::Ptr() ); if (category == GeoDataFeature::NaturalTree) { qreal const lat = m_coordinates.latitude(GeoDataCoordinates::Degree); if (qAbs(lat) > 15) { /** @todo Should maybe auto-adjust to MarbleClock at some point */ QDate const date = QDate::currentDate(); bool const southernHemisphere = lat < 0; QDate const autumnStart = QDate(date.year(), southernHemisphere ? 3 : 9, 15); QDate const winterEnd = southernHemisphere ? QDate(date.year(), 8, 15) : QDate(date.year()+1, 2, 15); if (date > autumnStart && date < winterEnd) { QDate const autumnEnd = QDate(date.year(), southernHemisphere ? 5 : 11, 15); QString const season = date < autumnEnd ? "autumn" : "winter"; GeoDataIconStyle iconStyle = placemark->style()->iconStyle(); QString const bitmap = QString("bitmaps/osmcarto/symbols/48/individual/tree-29-%1.png").arg(season); iconStyle.setIconPath(MarbleDirs::path(bitmap)); GeoDataStyle::Ptr style(new GeoDataStyle(*placemark->style())); style->setIconStyle(iconStyle); placemark->setStyle(style); } } } placemark->setZoomLevel( 18 ); if (category >= GeoDataFeature::PlaceCity && category <= GeoDataFeature::PlaceVillage) { int const population = m_osmData.tagValue("population").toInt(); placemark->setPopulation(qMax(0, population)); if (population > 0) { placemark->setZoomLevel(populationIndex(population)); placemark->setPopularity(population); } else { switch (category) { case GeoDataFeature::PlaceCity: placemark->setZoomLevel(9); break; case GeoDataFeature::PlaceSuburb: placemark->setZoomLevel(13); break; case GeoDataFeature::PlaceHamlet: placemark->setZoomLevel(15); break; case GeoDataFeature::PlaceLocality: placemark->setZoomLevel(15); break; case GeoDataFeature::PlaceTown: placemark->setZoomLevel(11); break; case GeoDataFeature::PlaceVillage: placemark->setZoomLevel(13); break; default: placemark->setZoomLevel(10); break; } } } else if (category == GeoDataFeature::NaturalPeak) { placemark->setZoomLevel(11); bool isInteger = false; int const elevation = m_osmData.tagValue("ele").toInt(&isInteger); if (isInteger) { placemark->setName(QString("%1 (%2 m)").arg(placemark->name()).arg(elevation)); } } OsmObjectManager::registerId(m_osmData.id()); document->append(placemark); }
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; } }
void CountryByShape::postQuestion( QObject *gameObject ) { //Find a random placemark Q_ASSERT_X( d->m_countryNames, "CountryByShape::postQuestion", "CountryByShapePrivate::m_countryNames is NULL" ); QVector<GeoDataPlacemark*> countryPlacemarks = d->m_countryNames->placemarkList(); uint randomSeed = uint(QTime::currentTime().msec()); qsrand( randomSeed ); bool found = false; GeoDataPlacemark *placemark =0; GeoDataPoint *point = 0; GeoDataCoordinates coord; GeoDataLatLonAltBox box; QVariantList answerOptions; while ( !found ) { int randomIndex = qrand()%countryPlacemarks.size(); placemark = countryPlacemarks[randomIndex]; point = dynamic_cast<GeoDataPoint*>( placemark->geometry() ); coord = point->coordinates(); if ( point ) { /** * Find the country geometry and fetch corresponding * GeoDataLatLonAltBox to zoom in to that country so that * it fills the viewport. */ Q_ASSERT_X( d->m_countryBoundaries, "CountryByShape::postQuestion", "CountryByShapePrivate::m_countryBoundaries is NULL" ); QVector<GeoDataFeature*>::Iterator i = d->m_countryBoundaries->begin(); QVector<GeoDataFeature*>::Iterator const end = d->m_countryBoundaries->end(); for ( ; i != end; ++i ) { GeoDataPlacemark *country = static_cast<GeoDataPlacemark*>( *i ); GeoDataPolygon *polygon = dynamic_cast<GeoDataPolygon*>( country->geometry() ); GeoDataLinearRing *linearring = dynamic_cast<GeoDataLinearRing*>( country->geometry() ); GeoDataMultiGeometry *multigeom = dynamic_cast<GeoDataMultiGeometry*>( country->geometry() ); if ( polygon && polygon->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = polygon->latLonAltBox(); found = true; break; } if ( linearring && linearring->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = linearring->latLonAltBox(); found = true; break; } if ( multigeom ) { QVector<GeoDataGeometry*>::Iterator iter = multigeom->begin(); QVector<GeoDataGeometry*>::Iterator const end = multigeom->end(); for ( ; iter != end; ++iter ) { GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( *iter ); if ( poly && poly->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = poly->latLonAltBox(); found = true; break; } } } if ( found ) { break; } } } } d->m_marbleWidget->setHighlightEnabled( true ); emit announceHighlight( coord.longitude(GeoDataCoordinates::Degree), coord.latitude(GeoDataCoordinates::Degree), GeoDataCoordinates::Degree ); /** * Now disable the highlight feature so that * the user click doesn't disturbe the highlight * we did to ask question. */ d->m_marbleWidget->setHighlightEnabled( false ); d->m_marbleWidget->centerOn( box, true ); answerOptions << placemark->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name(); // Randomize options in list answerOptions for ( int i = 0; i < answerOptions.size(); ++i ) { QVariant option = answerOptions.takeAt( qrand()%answerOptions.size() ); answerOptions.append( option ); } if ( gameObject ) { QMetaObject::invokeMethod( gameObject, "countryByShapeQuestion", Q_ARG(QVariant, QVariant(answerOptions)), Q_ARG(QVariant, QVariant(placemark->name())) ); } }