Marble

GeoDataLineString.cpp
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2008 Torsten Rahn <[email protected]>
9 // Copyright 2009 Patrick Spendrin <[email protected]>
10 //
11 
12 
13 #include "GeoDataLineString.h"
14 #include "GeoDataLineString_p.h"
15 
16 #include "GeoDataLinearRing.h"
17 #include "GeoDataTypes.h"
18 #include "Quaternion.h"
19 #include "MarbleDebug.h"
20 
21 #include <QDataStream>
22 
23 
24 namespace Marble
25 {
27  : GeoDataGeometry( new GeoDataLineStringPrivate( f ) )
28 {
29 // mDebug() << "1) GeoDataLineString created:" << p();
30 }
31 
32 GeoDataLineString::GeoDataLineString( GeoDataLineStringPrivate* priv )
33  : GeoDataGeometry( priv )
34 {
35 // mDebug() << "2) GeoDataLineString created:" << p();
36 }
37 
39  : GeoDataGeometry( other )
40 {
41 // mDebug() << "3) GeoDataLineString created:" << p();
42 }
43 
45 {
46 #ifdef DEBUG_GEODATA
47  mDebug() << "delete Linestring";
48 #endif
49 }
50 
51 const char *GeoDataLineString::nodeType() const
52 {
53  return GeoDataTypes::GeoDataLineStringType;
54 }
55 
56 EnumGeometryId GeoDataLineString::geometryId() const
57 {
58  return GeoDataLineStringId;
59 }
60 
61 GeoDataGeometry *GeoDataLineString::copy() const
62 {
63  return new GeoDataLineString(*this);
64 }
65 
66 void GeoDataLineStringPrivate::interpolateDateLine( const GeoDataCoordinates & previousCoords,
67  const GeoDataCoordinates & currentCoords,
68  GeoDataCoordinates & previousAtDateLine,
69  GeoDataCoordinates & currentAtDateLine,
70  TessellationFlags f ) const
71 {
72  GeoDataCoordinates dateLineCoords;
73 
74 // mDebug() << Q_FUNC_INFO;
75 
76  if ( f.testFlag( RespectLatitudeCircle ) && previousCoords.latitude() == currentCoords.latitude() ) {
77  dateLineCoords = currentCoords;
78  }
79  else {
80  int recursionCounter = 0;
81  dateLineCoords = findDateLine( previousCoords, currentCoords, recursionCounter );
82  }
83 
84  previousAtDateLine = dateLineCoords;
85  currentAtDateLine = dateLineCoords;
86 
87  if ( previousCoords.longitude() < 0 ) {
88  previousAtDateLine.setLongitude( -M_PI );
89  currentAtDateLine.setLongitude( +M_PI );
90  }
91  else {
92  previousAtDateLine.setLongitude( +M_PI );
93  currentAtDateLine.setLongitude( -M_PI );
94  }
95 }
96 
97 GeoDataCoordinates GeoDataLineStringPrivate::findDateLine( const GeoDataCoordinates & previousCoords,
98  const GeoDataCoordinates & currentCoords,
99  int recursionCounter ) const
100 {
101  int currentSign = ( currentCoords.longitude() < 0.0 ) ? -1 : +1 ;
102  int previousSign = ( previousCoords.longitude() < 0.0 ) ? -1 : +1 ;
103 
104  qreal longitudeDiff = fabs( previousSign * M_PI - previousCoords.longitude() )
105  + fabs( currentSign * M_PI - currentCoords.longitude() );
106 
107  if ( longitudeDiff < 0.001 || recursionCounter == 100 ) {
108 // mDebug() << "stopped at recursion" << recursionCounter << " and longitude difference " << longitudeDiff;
109  return currentCoords;
110  }
111  ++recursionCounter;
112 
113  const GeoDataCoordinates interpolatedCoords = previousCoords.nlerp(currentCoords, 0.5);
114 
115  int interpolatedSign = ( interpolatedCoords.longitude() < 0.0 ) ? -1 : +1 ;
116 
117 /*
118  mDebug() << "SRC" << previousCoords.toString();
119  mDebug() << "TAR" << currentCoords.toString();
120  mDebug() << "IPC" << interpolatedCoords.toString();
121 */
122 
123  if ( interpolatedSign != currentSign ) {
124  return findDateLine( interpolatedCoords, currentCoords, recursionCounter );
125  }
126 
127  return findDateLine( previousCoords, interpolatedCoords, recursionCounter );
128 }
129 
130 quint8 GeoDataLineStringPrivate::levelForResolution(qreal resolution) const {
131  if (m_previousResolution == resolution) return m_level;
132 
133  m_previousResolution = resolution;
134 
135  if (resolution < 0.0000005) m_level = 17;
136  else if (resolution < 0.0000010) m_level = 16;
137  else if (resolution < 0.0000020) m_level = 15;
138  else if (resolution < 0.0000040) m_level = 14;
139  else if (resolution < 0.0000080) m_level = 13;
140  else if (resolution < 0.0000160) m_level = 12;
141  else if (resolution < 0.0000320) m_level = 11;
142  else if (resolution < 0.0000640) m_level = 10;
143  else if (resolution < 0.0001280) m_level = 9;
144  else if (resolution < 0.0002560) m_level = 8;
145  else if (resolution < 0.0005120) m_level = 7;
146  else if (resolution < 0.0010240) m_level = 6;
147  else if (resolution < 0.0020480) m_level = 5;
148  else if (resolution < 0.0040960) m_level = 4;
149  else if (resolution < 0.0081920) m_level = 3;
150  else if (resolution < 0.0163840) m_level = 2;
151  else m_level = 1;
152 
153  return m_level;
154 }
155 
156 qreal GeoDataLineStringPrivate::resolutionForLevel(int level)
157 {
158  switch (level) {
159  case 0:
160  return 0.0655360;
161  case 1:
162  return 0.0327680;
163  case 2:
164  return 0.0163840;
165  case 3:
166  return 0.0081920;
167  case 4:
168  return 0.0040960;
169  case 5:
170  return 0.0020480;
171  case 6:
172  return 0.0010240;
173  case 7:
174  return 0.0005120;
175  case 8:
176  return 0.0002560;
177  case 9:
178  return 0.0001280;
179  case 10:
180  return 0.0000640;
181  case 11:
182  return 0.0000320;
183  case 12:
184  return 0.0000160;
185  case 13:
186  return 0.0000080;
187  case 14:
188  return 0.0000040;
189  case 15:
190  return 0.0000020;
191  case 16:
192  return 0.0000010;
193  default:
194  case 17:
195  return 0.0000005;
196  }
197 }
198 
199 void GeoDataLineStringPrivate::optimize (GeoDataLineString& lineString) const
200 {
201 
202  QVector<GeoDataCoordinates>::iterator itCoords = lineString.begin();
204 
205  if (lineString.size() < 2) return;
206 
207  // Calculate the least non-zero detail-level by checking the bounding box
208  quint8 startLevel = levelForResolution( ( lineString.latLonAltBox().width() + lineString.latLonAltBox().height() ) / 2 );
209 
210  quint8 currentLevel = startLevel;
211  quint8 maxLevel = startLevel;
212  GeoDataCoordinates currentCoords;
213  lineString.first().setDetail(startLevel);
214 
215  // Iterate through the linestring to assign different detail levels to the nodes.
216  // In general the first and last node should have the start level assigned as
217  // a detail level.
218  // Starting from the first node the algorithm picks those nodes which
219  // have a distance from each other that is just above the resolution that is
220  // associated with the start level (which we use as a "current level").
221  // Each of those nodes get the current level assigned as the detail level.
222  // After iterating through the linestring we increment the current level value
223  // and starting again with the first node we assign detail values in a similar way
224  // to the remaining nodes which have no final detail level assigned yet.
225  // We do as many iterations through the lineString as needed and bump up the
226  // current level until all nodes have a non-zero detail level assigned.
227 
228  while ( currentLevel < 16 && currentLevel <= maxLevel + 1 ) {
229  itCoords = lineString.begin();
230 
231  currentCoords = *itCoords;
232  ++itCoords;
233 
234  for( ; itCoords != itEnd; ++itCoords) {
235  if (itCoords->detail() != 0 && itCoords->detail() < currentLevel) continue;
236 
237  if ( currentLevel == startLevel && (itCoords->longitude() == -M_PI || itCoords->longitude() == M_PI
238  || itCoords->latitude() < -89 * DEG2RAD || itCoords->latitude() > 89 * DEG2RAD)) {
239  itCoords->setDetail(startLevel);
240  currentCoords = *itCoords;
241  maxLevel = currentLevel;
242  continue;
243  }
244  if (currentCoords.sphericalDistanceTo(*itCoords) < resolutionForLevel(currentLevel + 1)) {
245  itCoords->setDetail(currentLevel + 1);
246  }
247  else {
248  itCoords->setDetail(currentLevel);
249  currentCoords = *itCoords;
250  maxLevel = currentLevel;
251  }
252  }
253  ++currentLevel;
254  }
255  lineString.last().setDetail(startLevel);
256 }
257 
259 {
260  Q_D(const GeoDataLineString);
261  return d->m_vector.isEmpty();
262 }
263 
265 {
266  Q_D(const GeoDataLineString);
267  return d->m_vector.size();
268 }
269 
271 {
272  detach();
273 
274  Q_D(GeoDataLineString);
275  d->m_dirtyRange = true;
276  d->m_dirtyBox = true;
277  return d->m_vector[pos];
278 }
279 
281 {
282  Q_D(const GeoDataLineString);
283  return d->m_vector.at(pos);
284 }
285 
287 {
288  detach();
289 
290  Q_D(GeoDataLineString);
291  d->m_dirtyRange = true;
292  d->m_dirtyBox = true;
293  return d->m_vector[pos];
294 }
295 
297 {
298  GeoDataLineString substring;
299  auto d = substring.d_func();
300  d->m_vector = d_func()->m_vector.mid(pos, length);
301  d->m_dirtyBox = true;
302  d->m_dirtyRange = true;
303  d->m_tessellationFlags = d_func()->m_tessellationFlags;
304  d->m_extrude = d_func()->m_extrude;
305  return substring;
306 }
307 
309 {
310  Q_D(const GeoDataLineString);
311  return d->m_vector[pos];
312 }
313 
315 {
316  detach();
317 
318  Q_D(GeoDataLineString);
319  d->m_dirtyRange = true;
320  d->m_dirtyBox = true;
321  return d->m_vector.last();
322 }
323 
325 {
326  detach();
327 
328  Q_D(GeoDataLineString);
329  return d->m_vector.first();
330 }
331 
333 {
334  Q_D(const GeoDataLineString);
335  return d->m_vector.last();
336 }
337 
339 {
340  Q_D(const GeoDataLineString);
341  return d->m_vector.first();
342 }
343 
345 {
346  detach();
347 
348  Q_D(GeoDataLineString);
349  return d->m_vector.begin();
350 }
351 
353 {
354  Q_D(const GeoDataLineString);
355  return d->m_vector.constBegin();
356 }
357 
359 {
360  detach();
361 
362  Q_D(GeoDataLineString);
363  return d->m_vector.end();
364 }
365 
367 {
368  Q_D(const GeoDataLineString);
369  return d->m_vector.constEnd();
370 }
371 
373 {
374  Q_D(const GeoDataLineString);
375  return d->m_vector.constBegin();
376 }
377 
379 {
380  Q_D(const GeoDataLineString);
381  return d->m_vector.constEnd();
382 }
383 
384 void GeoDataLineString::insert( int index, const GeoDataCoordinates& value )
385 {
386  detach();
387 
388  Q_D(GeoDataLineString);
389  delete d->m_rangeCorrected;
390  d->m_rangeCorrected = nullptr;
391  d->m_dirtyRange = true;
392  d->m_dirtyBox = true;
393  d->m_vector.insert( index, value );
394 }
395 
397 {
398  detach();
399 
400  Q_D(GeoDataLineString);
401  delete d->m_rangeCorrected;
402  d->m_rangeCorrected = nullptr;
403  d->m_dirtyRange = true;
404  d->m_dirtyBox = true;
405  d->m_vector.append( value );
406 }
407 
409 {
410  Q_D(GeoDataLineString);
411  d->m_vector.reserve(size);
412 }
413 
415 {
416  detach();
417 
418  Q_D(GeoDataLineString);
419  delete d->m_rangeCorrected;
420  d->m_rangeCorrected = nullptr;
421  d->m_dirtyRange = true;
422  d->m_dirtyBox = true;
423 
424 #if QT_VERSION >= 0x050500
425  d->m_vector.append(values);
426 #else
427  d->m_vector.reserve(d->m_vector.size() + values.size());
428  for (const GeoDataCoordinates &coordinates: values) {
429  d->m_vector.append(coordinates);
430  }
431 #endif
432 }
433 
435 {
436  detach();
437 
438  Q_D(GeoDataLineString);
439  delete d->m_rangeCorrected;
440  d->m_rangeCorrected = nullptr;
441  d->m_dirtyRange = true;
442  d->m_dirtyBox = true;
443  d->m_vector.append( value );
444  return *this;
445 }
446 
448 {
449  detach();
450 
451  Q_D(GeoDataLineString);
452  delete d->m_rangeCorrected;
453  d->m_rangeCorrected = nullptr;
454  d->m_dirtyRange = true;
455  d->m_dirtyBox = true;
456 
459 
460  d->m_vector.reserve(d->m_vector.size() + value.size());
461  for( ; itCoords != itEnd; ++itCoords ) {
462  d->m_vector.append( *itCoords );
463  }
464 
465  return *this;
466 }
467 
469 {
470  if ( !GeoDataGeometry::equals(other) ||
471  size() != other.size() ||
472  tessellate() != other.tessellate() ) {
473  return false;
474  }
475 
476  Q_D(const GeoDataLineString);
477  const GeoDataLineStringPrivate* other_d = other.d_func();
478 
480  QVector<GeoDataCoordinates>::const_iterator otherItCoords = other_d->m_vector.constBegin();
482  QVector<GeoDataCoordinates>::const_iterator otherItEnd = other_d->m_vector.constEnd();
483 
484  for ( ; itCoords != itEnd && otherItCoords != otherItEnd; ++itCoords, ++otherItCoords ) {
485  if ( *itCoords != *otherItCoords ) {
486  return false;
487  }
488  }
489 
490  Q_ASSERT ( itCoords == itEnd && otherItCoords == otherItEnd );
491  return true;
492 }
493 
494 bool GeoDataLineString::operator!=( const GeoDataLineString &other ) const
495 {
496  return !this->operator==(other);
497 }
498 
500 {
501  detach();
502 
503  Q_D(GeoDataLineString);
504  delete d->m_rangeCorrected;
505  d->m_rangeCorrected = nullptr;
506  d->m_dirtyRange = true;
507  d->m_dirtyBox = true;
508 
509  d->m_vector.clear();
510 }
511 
513 {
514  return false;
515 }
516 
518 {
519  Q_D(const GeoDataLineString);
520  return d->m_tessellationFlags.testFlag(Tessellate);
521 }
522 
524 {
525  detach();
526 
527  Q_D(GeoDataLineString);
528  // According to the KML reference the tesselation of line strings in Google Earth
529  // is generally done along great circles. However for subsequent points that share
530  // the same latitude the latitude circles are followed. Our Tesselate and RespectLatitude
531  // Flags provide this behaviour. For true polygons the latitude circles don't get considered.
532 
533  if (tessellate) {
534  d->m_tessellationFlags |= (Tessellate | RespectLatitudeCircle);
535  } else {
536  d->m_tessellationFlags &= ~(Tessellate | RespectLatitudeCircle);
537  }
538 }
539 
541 {
542  Q_D(const GeoDataLineString);
543  return d->m_tessellationFlags;
544 }
545 
547 {
548  detach();
549 
550  Q_D(GeoDataLineString);
551  d->m_tessellationFlags = f;
552 }
553 
555 {
556  detach();
557 
558  Q_D(GeoDataLineString);
559  delete d->m_rangeCorrected;
560  d->m_rangeCorrected = nullptr;
561  d->m_dirtyRange = true;
562  d->m_dirtyBox = true;
563  std::reverse(begin(), end());
564 }
565 
567 {
568  Q_D(const GeoDataLineString);
569 
570  GeoDataLineString normalizedLineString;
571 
572  normalizedLineString.setTessellationFlags( tessellationFlags() );
573 
574  qreal lon;
575  qreal lat;
576 
577  // FIXME: Think about how we can avoid unnecessary copies
578  // if the linestring stays the same.
579  QVector<GeoDataCoordinates>::const_iterator end = d->m_vector.constEnd();
581  = d->m_vector.constBegin();
582  itCoords != end;
583  ++itCoords ) {
584 
585  itCoords->geoCoordinates( lon, lat );
586  qreal alt = itCoords->altitude();
588 
589  GeoDataCoordinates normalizedCoords( *itCoords );
590  normalizedCoords.set( lon, lat, alt );
591  normalizedLineString << normalizedCoords;
592  }
593 
594  return normalizedLineString;
595 }
596 
598 {
599  Q_D(const GeoDataLineString);
600 
601  if (d->m_dirtyRange) {
602 
603  delete d->m_rangeCorrected;
604 
605  if( isClosed() ) {
606  d->m_rangeCorrected = new GeoDataLinearRing(toPoleCorrected());
607  } else {
608  d->m_rangeCorrected = new GeoDataLineString(toPoleCorrected());
609  }
610  d->m_dirtyRange = false;
611  }
612 
613  return *d->m_rangeCorrected;
614 }
615 
617 {
618  Q_D(const GeoDataLineString);
619 
620  QVector<GeoDataLineString*> lineStrings;
621 
622  d->toDateLineCorrected(*this, lineStrings);
623 
624  return lineStrings;
625 }
626 
628 {
629  Q_D(const GeoDataLineString);
630 
631  if( isClosed() ) {
632  GeoDataLinearRing poleCorrected;
633  d->toPoleCorrected(*this, poleCorrected);
634  return poleCorrected;
635  } else {
636  GeoDataLineString poleCorrected;
637  d->toPoleCorrected(*this, poleCorrected);
638  return poleCorrected;
639  }
640 }
641 
642 void GeoDataLineStringPrivate::toPoleCorrected( const GeoDataLineString& q, GeoDataLineString& poleCorrected ) const
643 {
644  poleCorrected.setTessellationFlags( q.tessellationFlags() );
645 
646  GeoDataCoordinates previousCoords;
647  GeoDataCoordinates currentCoords;
648 
649  if ( q.isClosed() ) {
650  if ( !( m_vector.first().isPole() ) &&
651  ( m_vector.last().isPole() ) ) {
652  qreal firstLongitude = ( m_vector.first() ).longitude();
653  GeoDataCoordinates modifiedCoords( m_vector.last() );
654  modifiedCoords.setLongitude( firstLongitude );
655  poleCorrected << modifiedCoords;
656  }
657  }
658 
661 
662  for( ; itCoords != itEnd; ++itCoords ) {
663 
664  currentCoords = *itCoords;
665 
666  if ( itCoords == m_vector.constBegin() ) {
667  previousCoords = currentCoords;
668  }
669 
670  if ( currentCoords.isPole() ) {
671  if ( previousCoords.isPole() ) {
672  continue;
673  }
674  else {
675  qreal previousLongitude = previousCoords.longitude();
676  GeoDataCoordinates currentModifiedCoords( currentCoords );
677  currentModifiedCoords.setLongitude( previousLongitude );
678  poleCorrected << currentModifiedCoords;
679  }
680  }
681  else {
682  if ( previousCoords.isPole() ) {
683  qreal currentLongitude = currentCoords.longitude();
684  GeoDataCoordinates previousModifiedCoords( previousCoords );
685  previousModifiedCoords.setLongitude( currentLongitude );
686  poleCorrected << previousModifiedCoords;
687  poleCorrected << currentCoords;
688  }
689  else {
690  // No poles at all. Nothing special to handle
691  poleCorrected << currentCoords;
692  }
693  }
694  previousCoords = currentCoords;
695  }
696 
697  if ( q.isClosed() ) {
698  if ( ( m_vector.first().isPole() ) &&
699  !( m_vector.last().isPole() ) ) {
700  qreal lastLongitude = ( m_vector.last() ).longitude();
701  GeoDataCoordinates modifiedCoords( m_vector.first() );
702  modifiedCoords.setLongitude( lastLongitude );
703  poleCorrected << modifiedCoords;
704  }
705  }
706 }
707 
708 void GeoDataLineStringPrivate::toDateLineCorrected(
709  const GeoDataLineString & q,
710  QVector<GeoDataLineString*> & lineStrings
711  ) const
712 {
713  const bool isClosed = q.isClosed();
714 
717  QVector<GeoDataCoordinates>::const_iterator itPoint = itStartPoint;
718  QVector<GeoDataCoordinates>::const_iterator itPreviousPoint = itPoint;
719 
721 
722  GeoDataLineString * unfinishedLineString = nullptr;
723 
724  GeoDataLineString * dateLineCorrected = isClosed ? new GeoDataLinearRing( f )
725  : new GeoDataLineString( f );
726 
727  qreal previousLon = 0.0;
728  int previousSign = 1;
729 
730  bool unfinished = false;
731 
732  for (; itPoint != itEndPoint; ++itPoint ) {
733  const qreal currentLon = itPoint->longitude();
734 
735  int currentSign = ( currentLon < 0.0 ) ? -1 : +1 ;
736 
737  if( itPoint == q.constBegin() ) {
738  previousSign = currentSign;
739  previousLon = currentLon;
740  }
741 
742  // If we are crossing the date line ...
743  if ( previousSign != currentSign && fabs(previousLon) + fabs(currentLon) > M_PI ) {
744 
745  unfinished = !unfinished;
746 
747  GeoDataCoordinates previousTemp;
748  GeoDataCoordinates currentTemp;
749 
750  interpolateDateLine( *itPreviousPoint, *itPoint,
751  previousTemp, currentTemp, q.tessellationFlags() );
752 
753  *dateLineCorrected << previousTemp;
754 
755  if ( isClosed && unfinished ) {
756  // If it's a linear ring and if it crossed the IDL only once then
757  // store the current string inside the unfinishedLineString for later use ...
758  unfinishedLineString = dateLineCorrected;
759  // ... and start a new linear ring for now.
760  dateLineCorrected = new GeoDataLinearRing( f );
761  }
762  else {
763  // Now it can only be a (finished) line string or a finished linear ring.
764  // Store it in the vector if the size is not zero.
765  if ( dateLineCorrected->size() > 0 ) {
766  lineStrings << dateLineCorrected;
767  }
768  else {
769  // Or delete it.
770  delete dateLineCorrected;
771  }
772 
773  // If it's a finished linear ring restore the "remembered" unfinished String
774  if ( isClosed && !unfinished && unfinishedLineString ) {
775  dateLineCorrected = unfinishedLineString;
776  }
777  else {
778  // if it's a line string just create a new line string.
779  dateLineCorrected = new GeoDataLineString( f );
780  }
781  }
782 
783  *dateLineCorrected << currentTemp;
784  *dateLineCorrected << *itPoint;
785 
786  }
787  else {
788  *dateLineCorrected << *itPoint;
789  }
790 
791  previousSign = currentSign;
792  previousLon = currentLon;
793  itPreviousPoint = itPoint;
794  }
795 
796  // If the line string doesn't cross the dateline an even number of times
797  // then need to take care of the data stored in the unfinishedLineString
798  if ( unfinished && unfinishedLineString && !unfinishedLineString->isEmpty() ) {
799  *dateLineCorrected << *unfinishedLineString;
800  delete unfinishedLineString;
801  }
802 
803  lineStrings << dateLineCorrected;
804 }
805 
807 {
808  Q_D(const GeoDataLineString);
809 
810  // GeoDataLatLonAltBox::fromLineString is very expensive
811  // that's why we recreate it only if the m_dirtyBox
812  // is TRUE.
813  // DO NOT REMOVE THIS CONSTRUCT OR MARBLE WILL BE SLOW.
814  if (d->m_dirtyBox) {
815  d->m_latLonAltBox = GeoDataLatLonAltBox::fromLineString(*this);
816  d->m_dirtyBox = false;
817  }
818 
819  return d->m_latLonAltBox;
820 }
821 
822 qreal GeoDataLineString::length( qreal planetRadius, int offset ) const
823 {
824  if( offset < 0 || offset >= size() ) {
825  return 0;
826  }
827 
828  Q_D(const GeoDataLineString);
829  qreal length = 0.0;
830  QVector<GeoDataCoordinates> const & vector = d->m_vector;
831  int const start = qMax(offset+1, 1);
832  int const end = d->m_vector.size();
833  for( int i=start; i<end; ++i )
834  {
835  length += vector[i-1].sphericalDistanceTo(vector[i]);
836  }
837 
838  return planetRadius * length;
839 }
840 
842 {
843  detach();
844 
845  Q_D(GeoDataLineString);
846  delete d->m_rangeCorrected;
847  d->m_rangeCorrected = nullptr;
848  d->m_dirtyRange = true;
849  d->m_dirtyBox = true;
850  return d->m_vector.erase( pos );
851 }
852 
855 {
856  detach();
857 
858  Q_D(GeoDataLineString);
859  delete d->m_rangeCorrected;
860  d->m_rangeCorrected = nullptr;
861  d->m_dirtyRange = true;
862  d->m_dirtyBox = true;
863  return d->m_vector.erase( begin, end );
864 }
865 
867 {
868  detach();
869 
870  Q_D(GeoDataLineString);
871  d->m_dirtyRange = true;
872  d->m_dirtyBox = true;
873  d->m_vector.remove( i );
874 }
875 
877 {
878  Q_D(const GeoDataLineString);
879 
880  if( isClosed() ) {
881  GeoDataLinearRing linearRing(*this);
882  d->optimize(linearRing);
883  return linearRing;
884  } else {
885  GeoDataLineString lineString(*this);
886  d->optimize(lineString);
887  return lineString;
888  }
889 }
890 
892 {
893  Q_D(const GeoDataLineString);
894 
895  GeoDataGeometry::pack( stream );
896 
897  stream << size();
898  stream << (qint32)(d->m_tessellationFlags);
899 
901  = d->m_vector.constBegin();
902  iterator != d->m_vector.constEnd();
903  ++iterator ) {
904  mDebug() << "innerRing: size" << d->m_vector.size();
905  GeoDataCoordinates coord = ( *iterator );
906  coord.pack( stream );
907  }
908 
909 }
910 
912 {
913  detach();
914 
915  Q_D(GeoDataLineString);
916 
917  GeoDataGeometry::unpack( stream );
918  qint32 size;
919  qint32 tessellationFlags;
920 
921  stream >> size;
922  stream >> tessellationFlags;
923 
924  d->m_tessellationFlags = (TessellationFlags)(tessellationFlags);
925 
926  d->m_vector.reserve(d->m_vector.size() + size);
927 
928  for(qint32 i = 0; i < size; i++ ) {
929  GeoDataCoordinates coord;
930  coord.unpack( stream );
931  d->m_vector.append( coord );
932  }
933 }
934 
935 }
QVector< GeoDataCoordinates >::Iterator begin()
Returns an iterator that points to the begin of the LineString.
virtual QVector< GeoDataLineString * > toDateLineCorrected() const
The line string corrected for date line crossing.
virtual qreal length(qreal planetRadius, int offset=0) const
Returns the length of LineString across a sphere starting from a coordinate in LineString This method...
qreal height(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the height of the latitude interval.
void unpack(QDataStream &stream)
Unserialize the contents of the feature from stream.
static GeoDataLatLonAltBox fromLineString(const GeoDataLineString &lineString)
Create the smallest bounding box from a line string.
A 3d point representation.
void setTessellate(bool tessellate)
Sets the tessellation property for the LineString.
GeoDataCoordinates & last()
Returns a reference to the last node in the LineString. This method detaches the returned coordinate ...
qreal width(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the width of the longitude interval.
GeoDataLineString & operator<<(const GeoDataCoordinates &value)
Appends a given geodesic position as a new node to the LineString.
QVector< GeoDataCoordinates >::ConstIterator constEnd() const
Returns a const iterator that points to the end of the LineString.
void setDetail(quint8 detail)
set the detail flag
~GeoDataLineString() override
Destroys a LineString.
A LinearRing that allows to store a closed, contiguous set of line segments.
void insert(int index, const GeoDataCoordinates &value)
Inserts a new node at the given index.
void pack(QDataStream &stream) const override
Serialize the LineString to a stream.
Binds a QML item to a specific geodetic location in screen coordinates.
int size() const
Returns the number of nodes in a LineString.
A base class for all geodata features.
QVector::const_iterator constEnd() const const
void reserve(int size)
Attempts to allocate memory for at least size coordinates.
bool operator==(const GeoDataLineString &other) const
Returns true/false depending on whether this and other are/are not equal.
QVector< GeoDataCoordinates >::Iterator end()
Returns an iterator that points to the end of the LineString.
const GeoDataLatLonAltBox & latLonAltBox() const override
Returns the smallest latLonAltBox that contains the LineString.
void pack(QDataStream &stream) const override
Serialize the contents of the feature to stream.
qreal sphericalDistanceTo(const GeoDataCoordinates &other) const
This method calculates the shortest distance between two points on a sphere.
virtual GeoDataLineString toRangeCorrected() const
Provides a more generic representation of the LineString.
TessellationFlags tessellationFlags() const
Returns the tessellation flags for a LineString.
virtual GeoDataLineString toPoleCorrected() const
The line string with more generic pole values.
GeoDataLineString mid(int pos, int length=-1) const
Returns a sub-string which contains elements from this vector, starting at position pos...
virtual bool isClosed() const
Returns whether a LineString is a closed polygon.
QVector< GeoDataCoordinates >::Iterator erase(const QVector< GeoDataCoordinates >::Iterator &position)
Removes the node at the given position and returns it.
void setTessellationFlags(TessellationFlags f)
Sets the given tessellation flags for a LineString.
GeoDataCoordinates nlerp(const GeoDataCoordinates &target, double t) const
nlerp (normalized linear interpolation) between this coordinates and the given target coordinates ...
GeoDataCoordinates & first()
Returns a reference to the first node in the LineString. This method detaches the returned coordinate...
static void normalizeLonLat(qreal &lon, qreal &lat, GeoDataCoordinates::Unit=GeoDataCoordinates::Radian)
normalize both longitude and latitude at the same time This method normalizes both latitude and longi...
void set(qreal lon, qreal lat, qreal alt=0, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian)
(re)set the coordinates in a GeoDataCoordinates object
A LineString that allows to store a contiguous set of line segments.
GeoDataCoordinates & at(int pos)
Returns a reference to the coordinates of a node at a given position. This method detaches the return...
void remove(int i)
Removes the node at the given position and destroys it.
void setLongitude(qreal lon, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian)
set the longitude in a GeoDataCoordinates object
QVector::const_iterator constBegin() const const
void append(const GeoDataCoordinates &value)
Appends a given geodesic position as a new node to the LineString.
bool isEmpty() const
Returns whether the LineString has no nodes at all.
GeoDataCoordinates & operator[](int pos)
Returns a reference to the coordinates of a node at a given position. This method detaches the return...
void reverse()
Reverses the LineString.
QVector< GeoDataCoordinates >::ConstIterator constBegin() const
Returns a const iterator that points to the begin of the LineString.
bool isPole(Pole=AnyPole) const
return whether our coordinates represent a pole This method can be used to check whether the coordina...
void clear()
Destroys all nodes in a LineString.
virtual GeoDataLineString toNormalized() const
The line string with nodes that have proper longitude/latitude ranges.
const char * nodeType() const override
Provides type information for downcasting a GeoNode.
GeoDataLineString(TessellationFlags f=NoTessellation)
Creates a new LineString.
qreal longitude(GeoDataCoordinates::Unit unit) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
qreal latitude(GeoDataCoordinates::Unit unit) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
int size() const const
GeoDataLineString optimized() const
Returns a linestring with detail values assigned to each node.
bool testFlag(Enum flag) const const
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:36
A class that defines a 3D bounding box for geographic data.
void unpack(QDataStream &stream) override
Unserialize the LineString from a stream.
bool tessellate() const
Returns whether the LineString follows the earth&#39;s surface.
void unpack(QDataStream &stream) override
Unserialize the contents of the feature from stream.
void pack(QDataStream &stream) const
Serialize the contents of the feature to stream.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 1 2020 22:32:00 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.