File indexing completed on 2025-01-05 03:59:30
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2011 Thibaut Gridel <tgridel@free.fr> 0004 // SPDX-FileCopyrightText: 2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0005 0006 #include "PntRunner.h" 0007 0008 #include <qmath.h> 0009 #include <QFile> 0010 #include <QFileInfo> 0011 #include <QDataStream> 0012 0013 #include "GeoDataDocument.h" 0014 #include "GeoDataLineString.h" 0015 #include "GeoDataLinearRing.h" 0016 #include "GeoDataPlacemark.h" 0017 #include "MarbleGlobal.h" 0018 0019 #include "digikam_debug.h" 0020 0021 namespace Marble 0022 { 0023 0024 // distance of 180deg in arcminutes 0025 const qreal INT2RAD = M_PI / 10800.0; 0026 0027 PntRunner::PntRunner(QObject *parent) 0028 : ParsingRunner(parent) 0029 { 0030 } 0031 0032 PntRunner::~PntRunner() 0033 { 0034 } 0035 0036 GeoDataDocument *PntRunner::parseFile(const QString &fileName, DocumentRole role, QString &errorString) 0037 { 0038 QFileInfo fileinfo( fileName ); 0039 if (fileinfo.suffix().compare(QLatin1String("pnt"), Qt::CaseInsensitive) != 0) { 0040 errorString = QStringLiteral("File %1 does not have a pnt suffix").arg(fileName); 0041 qCDebug(DIGIKAM_MARBLE_LOG) << errorString; 0042 return nullptr; 0043 } 0044 0045 QFile file( fileName ); 0046 if ( !file.exists() ) { 0047 errorString = QStringLiteral("File %1 does not exist").arg(fileName); 0048 qCDebug(DIGIKAM_MARBLE_LOG) << errorString; 0049 return nullptr; 0050 } 0051 0052 file.open( QIODevice::ReadOnly ); 0053 QDataStream stream( &file ); // read the data serialized from the file 0054 stream.setByteOrder( QDataStream::LittleEndian ); 0055 0056 GeoDataDocument *document = new GeoDataDocument(); 0057 document->setDocumentRole( role ); 0058 GeoDataPlacemark *placemark = nullptr; 0059 0060 int count = 0; 0061 bool error = false; 0062 while( !stream.atEnd() || error ){ 0063 short header = -1; 0064 short iLat = -5400 - 1; 0065 short iLon = -10800 - 1; 0066 0067 stream >> header >> iLat >> iLon; 0068 0069 // make sure iLat is within valid range 0070 if ( !( -5400 <= iLat && iLat <= 5400 ) ) { 0071 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "invalid iLat =" << iLat << "(" << ( iLat * INT2RAD ) * RAD2DEG << ") in dataset" << count << "of file" << fileName; 0072 error = true; 0073 } 0074 0075 // make sure iLon is within valid range 0076 if ( !( -10800 <= iLon && iLon <= 10800 ) ) { 0077 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "invalid iLon =" << iLon << "(" << ( iLon * INT2RAD ) * RAD2DEG << ") in dataset" << count << "of file" << fileName; 0078 error = true; 0079 } 0080 0081 if (header >= 1000 && !document->isEmpty()) { 0082 GeoDataLineString *const polyline = static_cast<GeoDataLineString*>( placemark->geometry() ); 0083 if ( polyline->size() == 1 ) { 0084 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << fileName << "contains single-point polygon at" << count << ". Aborting."; 0085 error = true; 0086 break; 0087 } 0088 } 0089 0090 if ( header < 1 ) { 0091 /* invalid header */ 0092 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "invalid header:" << header << "in" << fileName << "at" << count; 0093 error = true; 0094 break; 0095 } 0096 else if ( header <= 5 ) { 0097 /* header represents level of detail */ 0098 /* nothing to do */ 0099 } 0100 else if ( header < 1000 ) { 0101 /* invalid header */ 0102 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "invalid header:" << header << "in" << fileName << "at" << count; 0103 error = true; 0104 break; 0105 } 0106 else if ( header < 2000 ) { 0107 /* header represents start of coastline */ 0108 placemark = new GeoDataPlacemark; 0109 document->append( placemark ); 0110 placemark->setGeometry( new GeoDataLinearRing ); 0111 } 0112 else if ( header < 4000 ) { 0113 /* header represents start of country border */ 0114 placemark = new GeoDataPlacemark; 0115 document->append( placemark ); 0116 placemark->setGeometry( new GeoDataLineString ); 0117 } 0118 else if ( header < 5000 ) { 0119 /* header represents start of internal political border */ 0120 placemark = new GeoDataPlacemark; 0121 document->append( placemark ); 0122 placemark->setGeometry( new GeoDataLineString ); 0123 } 0124 else if ( header < 6000 ) { 0125 /* header represents start of island */ 0126 placemark = new GeoDataPlacemark; 0127 document->append( placemark ); 0128 placemark->setGeometry( new GeoDataLinearRing ); 0129 } 0130 else if ( header < 7000 ) { 0131 /* header represents start of lake */ 0132 placemark = new GeoDataPlacemark; 0133 document->append( placemark ); 0134 placemark->setGeometry( new GeoDataLinearRing ); 0135 } 0136 else if ( header < 8000 ) { 0137 /* header represents start of river */ 0138 placemark = new GeoDataPlacemark; 0139 document->append( placemark ); 0140 placemark->setGeometry( new GeoDataLineString ); 0141 } 0142 else if ( header < 9000 ) { 0143 /* custom header represents start of glaciers, lakes or islands */ 0144 placemark = new GeoDataPlacemark; 0145 document->append( placemark ); 0146 placemark->setGeometry( new GeoDataLinearRing ); 0147 } 0148 else if ( header < 10000 ) { 0149 /* custom header represents start of political borders */ 0150 placemark = new GeoDataPlacemark; 0151 document->append( placemark ); 0152 placemark->setGeometry( new GeoDataLineString ); 0153 } 0154 else if ( header < 14000 ) { 0155 /* invalid header */ 0156 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "invalid header:" << header << "in" << fileName << "at" << count; 0157 error = true; 0158 break; 0159 } 0160 else if ( header < 15000 ) { 0161 /* custom header represents start of political borders */ 0162 placemark = new GeoDataPlacemark; 0163 document->append( placemark ); 0164 placemark->setGeometry( new GeoDataLineString ); 0165 } 0166 else if ( header < 19000 ) { 0167 /* invalid header */ 0168 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "invalid header:" << header << "in" << fileName << "at" << count; 0169 error = true; 0170 break; 0171 } 0172 else if ( header < 20000 ) { 0173 /* custom header represents start of dateline */ 0174 placemark = new GeoDataPlacemark; 0175 document->append( placemark ); 0176 placemark->setGeometry( new GeoDataLineString ); 0177 } 0178 else { 0179 /* invalid header */ 0180 qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "invalid header:" << header << "in" << fileName << "at" << count; 0181 error = true; 0182 break; 0183 } 0184 0185 GeoDataLineString *polyline = static_cast<GeoDataLineString*>( placemark->geometry() ); 0186 0187 // Transforming Range of Coordinates to iLat [0,ARCMINUTE] , iLon [0,2 * ARCMINUTE] 0188 polyline->append( GeoDataCoordinates( (qreal)(iLon) * INT2RAD, (qreal)(iLat) * INT2RAD, 0189 0.0, GeoDataCoordinates::Radian, 0190 5 - qMin( 5, (int)header ) ) ); // if 1 <= header <= 5, header contains level of detail 0191 // else pick most sparse level of detail, which equals 0 0192 0193 ++count; 0194 } 0195 0196 file.close(); 0197 if (document->isEmpty() || error) { 0198 delete document; 0199 document = nullptr; 0200 return nullptr; 0201 } 0202 document->setFileName( fileName ); 0203 return document; 0204 } 0205 0206 } 0207 0208 #include "moc_PntRunner.cpp"