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