File indexing completed on 2025-02-09 04:17:37
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org> 0004 // 0005 0006 #include "MonavMap.h" 0007 #include "MarbleDebug.h" 0008 0009 #include "GeoDataParser.h" 0010 #include "GeoDataMultiGeometry.h" 0011 #include "GeoDataPlacemark.h" 0012 #include "GeoDataDocument.h" 0013 #include "GeoDataExtendedData.h" 0014 #include "GeoDataData.h" 0015 #include "GeoDataLatLonAltBox.h" 0016 0017 namespace Marble 0018 { 0019 0020 void MonavMap::setDirectory( const QDir &dir ) 0021 { 0022 m_directory = dir; 0023 QFileInfo boundingBox( dir, "marble.kml" ); 0024 if ( boundingBox.exists() ) { 0025 parseBoundingBox( boundingBox ); 0026 } else { 0027 mDebug() << "No monav bounding box given for " << boundingBox.absoluteFilePath(); 0028 } 0029 } 0030 0031 void MonavMap::parseBoundingBox( const QFileInfo &file ) 0032 { 0033 GeoDataLineString points; 0034 bool tooLarge = false; 0035 QFile input( file.absoluteFilePath() ); 0036 if ( input.open( QFile::ReadOnly ) ) { 0037 GeoDataParser parser( GeoData_KML ); 0038 if ( !parser.read( &input ) ) { 0039 mDebug() << "Could not parse file: " << parser.errorString(); 0040 return; 0041 } 0042 0043 GeoDocument *doc = parser.releaseDocument(); 0044 input.close(); 0045 GeoDataDocument *document = dynamic_cast<GeoDataDocument*>( doc ); 0046 QVector<GeoDataPlacemark*> placemarks = document->placemarkList(); 0047 if ( placemarks.size() == 1 ) { 0048 GeoDataPlacemark* placemark = placemarks.first(); 0049 m_name = placemark->name(); 0050 m_version = placemark->extendedData().value( "version" ).value().toString(); 0051 m_date = placemark->extendedData().value( "date" ).value().toString(); 0052 m_transport = placemark->extendedData().value( "transport" ).value().toString(); 0053 m_payload = placemark->extendedData().value( "payload" ).value().toString(); 0054 const GeoDataMultiGeometry* geometry = dynamic_cast<const GeoDataMultiGeometry*>( placemark->geometry() ); 0055 if ( geometry->size() > 1500 ) { 0056 tooLarge = true; 0057 } 0058 for ( int i = 0; geometry && i < geometry->size(); ++i ) { 0059 const GeoDataLinearRing* poly = dynamic_cast<const GeoDataLinearRing*>( geometry->child( i ) ); 0060 if ( poly ) { 0061 for ( int j = 0; j < poly->size(); ++j ) { 0062 points << poly->at( j ); 0063 } 0064 m_tiles.push_back( *poly ); 0065 0066 if ( poly->size() > 1500 ) { 0067 tooLarge = true; 0068 } 0069 } 0070 } 0071 } else { 0072 mDebug() << "File " << file.absoluteFilePath() << " does not contain one placemark, but " << placemarks.size(); 0073 } 0074 0075 delete doc; 0076 } 0077 m_boundingBox = points.latLonAltBox(); 0078 0079 if ( tooLarge ) { 0080 // The bounding box polygon is rather complicated, therefore not allowing a quick check 0081 // and also occupying memory. Discard the polygon and only store the rectangular bounding 0082 // box. Only happens for non-simplified bounding box polygons. 0083 mDebug() << "Discarding too large bounding box polygon for " << file.absoluteFilePath() << ". Please check for a map update."; 0084 m_tiles.clear(); 0085 } 0086 } 0087 0088 bool MonavMap::containsPoint( const GeoDataCoordinates &point ) const 0089 { 0090 // If we do not have a bounding box at all, we err on the safe side 0091 if ( m_boundingBox.isEmpty() ) { 0092 return true; 0093 } 0094 0095 // Quick check for performance reasons 0096 if ( !m_boundingBox.contains( point ) ) { 0097 return false; 0098 } 0099 0100 if ( m_tiles.isEmpty() ) { 0101 return true; // Tiles discarded for performance reason 0102 } 0103 0104 // GeoDataLinearRing does a 3D check, but we only have 2D data for 0105 // the map bounding box. Therefore the 3D info of e.g. the GPS position 0106 // must be ignored. 0107 GeoDataCoordinates flatPosition = point; 0108 flatPosition.setAltitude( 0.0 ); 0109 for( const GeoDataLinearRing & box: m_tiles ) { 0110 if ( box.contains( flatPosition ) ) { 0111 return true; 0112 } 0113 } 0114 0115 return false; 0116 } 0117 0118 qint64 MonavMap::size() const 0119 { 0120 qint64 result = 0; 0121 for( const QFileInfo & file: files() ) { 0122 result += file.size(); 0123 } 0124 0125 return result; 0126 } 0127 0128 QList<QFileInfo> MonavMap::files() const 0129 { 0130 QList<QFileInfo> files; 0131 QStringList fileNames = QStringList() << "config" << "edges" << "names" << "paths" << "types"; 0132 for( const QString & file: fileNames ) { 0133 files << QFileInfo(m_directory, QLatin1String("Contraction Hierarchies_") + file); 0134 } 0135 0136 fileNames = QStringList() << "config" << "grid" << "index_1" << "index_2" << "index_3"; 0137 for( const QString & file: fileNames ) { 0138 files << QFileInfo(m_directory, QLatin1String("GPSGrid_") + file); 0139 } 0140 0141 files << QFileInfo( m_directory, "plugins.ini" ); 0142 QFileInfo moduleDotIni( m_directory, "Module.ini" ); 0143 if ( moduleDotIni.exists() ) { 0144 files << moduleDotIni; 0145 } 0146 files << QFileInfo( m_directory, "marble.kml" ); 0147 return files; 0148 } 0149 0150 void MonavMap::remove() const 0151 { 0152 for( const QFileInfo & file: files() ) { 0153 QFile ( file.absoluteFilePath() ).remove(); 0154 } 0155 } 0156 0157 bool MonavMap::areaLessThan( const MonavMap &first, const MonavMap &second ) 0158 { 0159 if ( !first.m_tiles.isEmpty() && second.m_tiles.isEmpty() ) { 0160 return true; 0161 } 0162 0163 if ( first.m_tiles.isEmpty() && !second.m_tiles.isEmpty() ) { 0164 return false; 0165 } 0166 0167 qreal const areaOne = first.m_boundingBox.width() * first.m_boundingBox.height(); 0168 qreal const areaTwo = second.m_boundingBox.width() * second.m_boundingBox.height(); 0169 return areaOne < areaTwo; 0170 } 0171 0172 bool MonavMap::nameLessThan( const MonavMap &first, const MonavMap &second ) 0173 { 0174 return first.name() < second.name(); 0175 } 0176 0177 QDir MonavMap::directory() const 0178 { 0179 return m_directory; 0180 } 0181 0182 QString MonavMap::transport() const 0183 { 0184 return m_transport; 0185 } 0186 0187 QString MonavMap::name() const 0188 { 0189 return m_name; 0190 } 0191 0192 QString MonavMap::version() const 0193 { 0194 return m_version; 0195 } 0196 0197 QString MonavMap::date() const 0198 { 0199 return m_date; 0200 } 0201 0202 QString MonavMap::payload() const 0203 { 0204 return m_payload; 0205 } 0206 0207 }