Marble

KmlCoordinatesTagHandler.cpp
1 /*
2  SPDX-FileCopyrightText: 2008 Patrick Spendrin <[email protected]>
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 
25 namespace Marble
26 {
27 namespace kml
28 {
29 KML_DEFINE_TAG_HANDLER( coordinates )
30 
31 static 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
35 static GeoTagHandlerRegistrar s_handlercoordkmlTag_nameSpaceGx22(GeoParser::QualifiedName(QLatin1String(kmlTag_coord), QLatin1String(kmlTag_nameSpaceGx22)),
36  new KmlcoordinatesTagHandler());
37 
38 GeoNode* 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 }
void append(const T &value)
int size() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString trimmed() const const
int size() const const
const T & at(int i) const const
Binds a QML item to a specific geodetic location in screen coordinates.
QString & replace(int position, int n, QChar after)
QString & remove(int position, int n)
QString & insert(int position, QChar ch)
QString mid(int position, int n) const const
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:27 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.