28 errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP(
"KML",
"File not found: %1")).arg(kmlFile));
29 return QDomDocument();
32 if (!file.open(QIODevice::ReadOnly)) {
33 errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP(
"KML",
"Unable to open file: %1 error: %2")).arg(kmlFile, file.errorString()));
34 return QDomDocument();
38 const QDomDocument::ParseResult result = doc.setContent(&file, QDomDocument::ParseOption::Default);
40 errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP(
"KML",
"Unable to parse KML file: %1 error: %2 line: %3")).arg(kmlFile).arg(result.errorMessage).arg(result.errorLine));
41 return QDomDocument();
50 const QString simplified = coordinatesString.simplified();
51 if (simplified.isEmpty()) {
52 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"Empty coordinates string"));
56 const QStringList rgCoordinateStrings = simplified.split(
' ');
57 for (
const QString &coordinateString : rgCoordinateStrings) {
58 if (coordinateString.isEmpty()) {
61 const QStringList rgValueStrings = coordinateString.split(
',');
62 if (rgValueStrings.size() < 2) {
63 qCWarning(KMLHelperLog) <<
"Invalid coordinate format, expected lon,lat[,alt]:" << coordinateString;
66 bool lonOk =
false, latOk =
false;
67 const double lon = rgValueStrings[0].toDouble(&lonOk);
68 const double lat = rgValueStrings[1].toDouble(&latOk);
69 if (!lonOk || !latOk) {
70 qCWarning(KMLHelperLog) <<
"Failed to parse coordinate values:" << coordinateString;
73 if (lat < -90.0 || lat > 90.0) {
74 qCWarning(KMLHelperLog) <<
"Latitude out of range [-90, 90]:" << lat <<
"in:" << coordinateString;
77 if (lon < -180.0 || lon > 180.0) {
78 qCWarning(KMLHelperLog) <<
"Longitude out of range [-180, 180]:" << lon <<
"in:" << coordinateString;
82 if (rgValueStrings.size() >= 3) {
83 alt = rgValueStrings[2].toDouble();
85 coords.append(QGeoCoordinate(lat, lon, alt));
88 if (coords.isEmpty()) {
89 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"No valid coordinates found"));
97 if (filterMeters <= 0 || vertices.count() <= minVertices) {
102 while (i < (vertices.count() - 1)) {
103 if ((vertices.count() > minVertices) && (vertices[i].distanceTo(vertices[i + 1]) < filterMeters)) {
104 vertices.removeAt(i + 1);
115 const QDomNode altModeNode = geometryNode.namedItem(
"altitudeMode");
116 if (!altModeNode.isNull()) {
117 const QString mode = altModeNode.toElement().text();
118 if (mode.isEmpty()) {
122 const QString location = QStringLiteral(
"(line %1)").arg(altModeNode.lineNumber());
123 if (!validator->isValidEnumValue(
"altitudeModeEnumType", mode)) {
124 qCWarning(KMLHelperLog) << geometryType << index << location <<
"has invalid altitudeMode:" << mode
125 <<
"- valid values are:" << validator->validEnumValues(
"altitudeModeEnumType").join(
", ");
126 }
else if (mode !=
"absolute") {
127 qCWarning(KMLHelperLog) << geometryType << index << location <<
"uses altitudeMode:" << mode
128 <<
"- QGC will treat coordinates as absolute (AMSL)";
135 using ShapeType = ShapeFileHelper::ShapeType;
139 return ShapeType::Error;
142 const QDomNodeList rgNodesPolygon = domDocument.elementsByTagName(
"Polygon");
143 if (!rgNodesPolygon.isEmpty()) {
144 return ShapeType::Polygon;
147 const QDomNodeList rgNodesLineString = domDocument.elementsByTagName(
"LineString");
148 if (!rgNodesLineString.isEmpty()) {
149 return ShapeType::Polyline;
152 const QDomNodeList rgNodesPoint = domDocument.elementsByTagName(
"Point");
153 if (!rgNodesPoint.isEmpty()) {
154 return ShapeType::Point;
157 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"No supported type found in KML file."));
158 return ShapeType::Error;
185 const QDomNodeList rgNodes = domDocument.elementsByTagName(
"Polygon");
186 if (rgNodes.isEmpty()) {
187 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"Unable to find Polygon node in KML"));
191 for (
int nodeIdx = 0; nodeIdx < rgNodes.count(); nodeIdx++) {
192 const QDomNode polygonNode = rgNodes.item(nodeIdx);
195 const QDomNode coordinatesNode = polygonNode.namedItem(
"outerBoundaryIs").namedItem(
"LinearRing").namedItem(
"coordinates");
196 if (coordinatesNode.isNull()) {
197 qCWarning(KMLHelperLog) <<
"Polygon" << nodeIdx << QStringLiteral(
"(line %1)").arg(polygonNode.lineNumber())
198 <<
"missing coordinates node, skipping";
202 QList<QGeoCoordinate> rgCoords;
204 qCWarning(KMLHelperLog) <<
"Polygon" << nodeIdx << QStringLiteral(
"(line %1)").arg(coordinatesNode.lineNumber())
210 if (rgCoords.count() < 3) {
211 qCWarning(KMLHelperLog) <<
"Polygon" << nodeIdx << QStringLiteral(
"(line %1)").arg(polygonNode.lineNumber())
212 <<
"has fewer than 3 vertices, skipping";
217 if (rgCoords.count() > 3 && rgCoords.first().latitude() == rgCoords.last().latitude() &&
218 rgCoords.first().longitude() == rgCoords.last().longitude()) {
219 rgCoords.removeLast();
224 for (
int i = 0; i < rgCoords.count(); i++) {
225 const QGeoCoordinate &coord1 = rgCoords[i];
226 const QGeoCoordinate &coord2 = rgCoords[(i + 1) % rgCoords.count()];
227 sum += (coord2.longitude() - coord1.longitude()) * (coord2.latitude() + coord1.latitude());
230 std::reverse(rgCoords.begin(), rgCoords.end());
234 polygons.append(rgCoords);
237 if (polygons.isEmpty()) {
238 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"No valid polygons found in KML file"));
255 const QDomNodeList rgNodes = domDocument.elementsByTagName(
"LineString");
256 if (rgNodes.isEmpty()) {
257 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"Unable to find LineString node in KML"));
261 for (
int nodeIdx = 0; nodeIdx < rgNodes.count(); nodeIdx++) {
262 const QDomNode lineStringNode = rgNodes.item(nodeIdx);
265 const QDomNode coordinatesNode = lineStringNode.namedItem(
"coordinates");
266 if (coordinatesNode.isNull()) {
267 qCWarning(KMLHelperLog) <<
"LineString" << nodeIdx << QStringLiteral(
"(line %1)").arg(lineStringNode.lineNumber())
268 <<
"missing coordinates node, skipping";
272 QList<QGeoCoordinate> rgCoords;
274 qCWarning(KMLHelperLog) <<
"LineString" << nodeIdx << QStringLiteral(
"(line %1)").arg(coordinatesNode.lineNumber())
280 if (rgCoords.count() < 2) {
281 qCWarning(KMLHelperLog) <<
"LineString" << nodeIdx << QStringLiteral(
"(line %1)").arg(lineStringNode.lineNumber())
282 <<
"has fewer than 2 vertices, skipping";
287 polylines.append(rgCoords);
290 if (polylines.isEmpty()) {
291 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"No valid polylines found in KML file"));
308 const QDomNodeList rgNodes = domDocument.elementsByTagName(
"Point");
309 if (rgNodes.isEmpty()) {
310 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"Unable to find Point node in KML"));
314 for (
int nodeIdx = 0; nodeIdx < rgNodes.count(); nodeIdx++) {
315 const QDomNode pointNode = rgNodes.item(nodeIdx);
318 const QDomNode coordinatesNode = pointNode.namedItem(
"coordinates");
319 if (coordinatesNode.isNull()) {
320 qCWarning(KMLHelperLog) <<
"Point" << nodeIdx << QStringLiteral(
"(line %1)").arg(pointNode.lineNumber())
321 <<
"missing coordinates node, skipping";
325 QList<QGeoCoordinate> coords;
327 qCWarning(KMLHelperLog) <<
"Point" << nodeIdx << QStringLiteral(
"(line %1)").arg(coordinatesNode.lineNumber())
333 if (!coords.isEmpty()) {
334 points.append(coords.first());
338 if (points.isEmpty()) {
339 errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP(
"KML",
"No valid points found in KML file"));