Marble

KmlCoordinatesTagHandler.cpp
1/*
2 SPDX-FileCopyrightText: 2008 Patrick Spendrin <ps_ml@gmx.de>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "KmlCoordinatesTagHandler.h"
8
9#include <QStringList>
10#include <QRegExp>
11
12#include "MarbleDebug.h"
13#include "KmlElementDictionary.h"
14#include "GeoDataTrack.h"
15#include "GeoDataPlacemark.h"
16#include "GeoDataPoint.h"
17#include "GeoDataModel.h"
18#include "GeoDataLineString.h"
19#include "GeoDataLinearRing.h"
20#include "GeoDataMultiGeometry.h"
21#include "GeoDataLatLonQuad.h"
22#include "GeoParser.h"
23#include "MarbleGlobal.h"
24
25namespace Marble
26{
27namespace kml
28{
29KML_DEFINE_TAG_HANDLER( coordinates )
30
31static const bool kmlStrictSpecs = false;
32
33// We can't use KML_DEFINE_TAG_HANDLER_GX22 because the name of the tag ("coord")
34// and the TagHandler ("KmlcoordinatesTagHandler") don't match
35static GeoTagHandlerRegistrar s_handlercoordkmlTag_nameSpaceGx22(GeoParser::QualifiedName(QLatin1String(kmlTag_coord), QLatin1String(kmlTag_nameSpaceGx22)),
36 new KmlcoordinatesTagHandler());
37
38GeoNode* KmlcoordinatesTagHandler::parse( GeoParser& parser ) const
39{
40 Q_ASSERT(parser.isStartElement()
41 && (parser.isValidElement(QLatin1String(kmlTag_coordinates))
42 || parser.isValidElement(QLatin1String(kmlTag_coord))));
43
44 GeoStackItem parentItem = parser.parentElement();
45
46 if( parentItem.represents( kmlTag_Point )
47 || parentItem.represents( kmlTag_LineString )
48 || parentItem.represents( kmlTag_MultiGeometry )
49 || parentItem.represents( kmlTag_LinearRing )
50 || parentItem.represents( kmlTag_LatLonQuad ) ) {
51 QStringList coordinatesLines;// = parser.readElementText().trimmed().split( QRegExp("\\s"), QString::SkipEmptyParts );
52 // Splitting using the "\\s" regexp is slow, split manually instead.
53 QString text = parser.readElementText().trimmed();
54
55 if ( !kmlStrictSpecs ) {
56 // Removing spaces before and after commas
57 for ( int i = 1; i < text.size() - 1; ++i ) {
58 if (text[i] == QLatin1Char(',')) {
59 // Before
60 int l = i - 1;
61 while ( l > 0 && text[l].isSpace() ) {
62 --l;
63 }
64
65 // After
66 int r = i + 1;
67 while ( r < text.size() && text[r].isSpace() ) {
68 ++r;
69 }
70
71 text.remove(l + 1, r - l - 1).insert(l + 1, QLatin1Char(','));
72 }
73 }
74 }
75
76 int index = 0;
77 bool inside = true;
78 int const size = text.size();
79 for ( int i=0; i<size; ++i ) {
80 if ( text[i].isSpace() ) {
81 if ( inside ) {
82 coordinatesLines.append( text.mid( index, i-index ) );
83 inside = false;
84 }
85 index = i+1;
86 } else {
87 inside = true;
88 }
89 }
90 coordinatesLines.append( text.mid( index ) );
91 int coordinatesIndex = 0;
92 for( const QString& line: coordinatesLines ) {
93 const QStringList coordinates = line.trimmed().split(QLatin1Char(','));
94 if ( parentItem.represents( kmlTag_Point ) && parentItem.is<GeoDataFeature>() ) {
95 GeoDataCoordinates coord;
96 if ( coordinates.size() == 2 ) {
97 coord.set( coordinates.at( 0 ).toDouble(),
98 coordinates.at( 1 ).toDouble(), 0.0, GeoDataCoordinates::Degree );
99 } else if( coordinates.size() == 3 ) {
100 coord.set( coordinates.at( 0 ).toDouble(),
101 coordinates.at( 1 ).toDouble(),
102 coordinates.at( 2 ).toDouble(),
103 GeoDataCoordinates::Degree );
104 }
105 parentItem.nodeAs<GeoDataPlacemark>()->setCoordinate( coord );
106 } else {
107 GeoDataCoordinates coord;
108 if ( coordinates.size() == 2 ) {
109 coord.set( DEG2RAD * coordinates.at( 0 ).toDouble(),
110 DEG2RAD * coordinates.at( 1 ).toDouble() );
111 } else if( coordinates.size() == 3 ) {
112 coord.set( DEG2RAD * coordinates.at( 0 ).toDouble(),
113 DEG2RAD * coordinates.at( 1 ).toDouble(),
114 coordinates.at( 2 ).toDouble() );
115 }
116
117 if ( parentItem.represents( kmlTag_LineString ) ) {
118 parentItem.nodeAs<GeoDataLineString>()->append( coord );
119 } else if ( parentItem.represents( kmlTag_LinearRing ) ) {
120 parentItem.nodeAs<GeoDataLinearRing>()->append( coord );
121 } else if ( parentItem.represents( kmlTag_MultiGeometry ) ) {
122 GeoDataPoint *point = new GeoDataPoint( coord );
123 parentItem.nodeAs<GeoDataMultiGeometry>()->append( point );
124 } else if ( parentItem.represents( kmlTag_Model) ) {
125 parentItem.nodeAs<GeoDataModel>()->setCoordinates( coord);
126 } else if ( parentItem.represents( kmlTag_Point ) ) {
127 // photo overlay
128 parentItem.nodeAs<GeoDataPoint>()->setCoordinates( coord );
129 } else if ( parentItem.represents( kmlTag_LatLonQuad ) ) {
130 switch ( coordinatesIndex ) {
131 case 0:
132 parentItem.nodeAs<GeoDataLatLonQuad>()->setBottomLeft( coord );
133 break;
134 case 1:
135 parentItem.nodeAs<GeoDataLatLonQuad>()->setBottomRight( coord );
136 break;
137 case 2:
138 parentItem.nodeAs<GeoDataLatLonQuad>()->setTopRight( coord );
139 break;
140 case 3:
141 parentItem.nodeAs<GeoDataLatLonQuad>()->setTopLeft( coord );
142 break;
143 case 4:
144 mDebug() << "Ignoring excessive coordinates in LatLonQuad (must not have more than 4 pairs)";
145 break;
146 default:
147 // Silently ignore any more coordinates
148 break;
149 }
150 } else {
151 // raise warning as coordinates out of valid parents found
152 }
153 }
154
155 ++coordinatesIndex;
156 }
157 }
158
159 if( parentItem.represents( kmlTag_Track ) ) {
160 QString input = parser.readElementText().trimmed();
161 if ( !kmlStrictSpecs ) {
162 input.replace(QRegExp(QStringLiteral("\\s*,\\s*")), QStringLiteral(","));
163 }
164 const QStringList coordinates = input.split(QLatin1Char(' '));
165
166 GeoDataCoordinates coord;
167 if ( coordinates.size() == 2 ) {
168 coord.set( DEG2RAD * coordinates.at( 0 ).toDouble(),
169 DEG2RAD * coordinates.at( 1 ).toDouble() );
170 } else if( coordinates.size() == 3 ) {
171 coord.set( DEG2RAD * coordinates.at( 0 ).toDouble(),
172 DEG2RAD * coordinates.at( 1 ).toDouble(),
173 coordinates.at( 2 ).toDouble() );
174 }
175 parentItem.nodeAs<GeoDataTrack>()->appendCoordinates( coord );
176 }
177
178 return nullptr;
179}
180
181}
182}
Binds a QML item to a specific geodetic location in screen coordinates.
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype size() const const
QString & insert(qsizetype position, QChar ch)
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
qsizetype size() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString trimmed() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.