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  d->m_vector.append(values);
425 }
426 
428 {
429  detach();
430 
431  Q_D(GeoDataLineString);
432  delete d->m_rangeCorrected;
433  d->m_rangeCorrected = nullptr;
434  d->m_dirtyRange = true;
435  d->m_dirtyBox = true;
436  d->m_vector.append( value );
437  return *this;
438 }
439 
441 {
442  detach();
443 
444  Q_D(GeoDataLineString);
445  delete d->m_rangeCorrected;
446  d->m_rangeCorrected = nullptr;
447  d->m_dirtyRange = true;
448  d->m_dirtyBox = true;
449 
452 
453  d->m_vector.reserve(d->m_vector.size() + value.size());
454  for( ; itCoords != itEnd; ++itCoords ) {
455  d->m_vector.append( *itCoords );
456  }
457 
458  return *this;
459 }
460 
462 {
463  if ( !GeoDataGeometry::equals(other) ||
464  size() != other.size() ||
465  tessellate() != other.tessellate() ) {
466  return false;
467  }
468 
469  Q_D(const GeoDataLineString);
470  const GeoDataLineStringPrivate* other_d = other.d_func();
471 
473  QVector<GeoDataCoordinates>::const_iterator otherItCoords = other_d->m_vector.constBegin();
475  QVector<GeoDataCoordinates>::const_iterator otherItEnd = other_d->m_vector.constEnd();
476 
477  for ( ; itCoords != itEnd && otherItCoords != otherItEnd; ++itCoords, ++otherItCoords ) {
478  if ( *itCoords != *otherItCoords ) {
479  return false;
480  }
481  }
482 
483  Q_ASSERT ( itCoords == itEnd && otherItCoords == otherItEnd );
484  return true;
485 }
486 
487 bool GeoDataLineString::operator!=( const GeoDataLineString &other ) const
488 {
489  return !this->operator==(other);
490 }
491 
493 {
494  detach();
495 
496  Q_D(GeoDataLineString);
497  delete d->m_rangeCorrected;
498  d->m_rangeCorrected = nullptr;
499  d->m_dirtyRange = true;
500  d->m_dirtyBox = true;
501 
502  d->m_vector.clear();
503 }
504 
506 {
507  return false;
508 }
509 
511 {
512  Q_D(const GeoDataLineString);
513  return d->m_tessellationFlags.testFlag(Tessellate);
514 }
515 
517 {
518  detach();
519 
520  Q_D(GeoDataLineString);
521  // According to the KML reference the tesselation of line strings in Google Earth
522  // is generally done along great circles. However for subsequent points that share
523  // the same latitude the latitude circles are followed. Our Tesselate and RespectLatitude
524  // Flags provide this behaviour. For true polygons the latitude circles don't get considered.
525 
526  if (tessellate) {
527  d->m_tessellationFlags |= (Tessellate | RespectLatitudeCircle);
528  } else {
529  d->m_tessellationFlags &= ~(Tessellate | RespectLatitudeCircle);
530  }
531 }
532 
534 {
535  Q_D(const GeoDataLineString);
536  return d->m_tessellationFlags;
537 }
538 
540 {
541  detach();
542 
543  Q_D(GeoDataLineString);
544  d->m_tessellationFlags = f;
545 }
546 
548 {
549  detach();
550 
551  Q_D(GeoDataLineString);
552  delete d->m_rangeCorrected;
553  d->m_rangeCorrected = nullptr;
554  d->m_dirtyRange = true;
555  d->m_dirtyBox = true;
556  std::reverse(begin(), end());
557 }
558 
560 {
561  Q_D(const GeoDataLineString);
562 
563  GeoDataLineString normalizedLineString;
564 
565  normalizedLineString.setTessellationFlags( tessellationFlags() );
566 
567  qreal lon;
568  qreal lat;
569 
570  // FIXME: Think about how we can avoid unnecessary copies
571  // if the linestring stays the same.
572  QVector<GeoDataCoordinates>::const_iterator end = d->m_vector.constEnd();
574  = d->m_vector.constBegin();
575  itCoords != end;
576  ++itCoords ) {
577 
578  itCoords->geoCoordinates( lon, lat );
579  qreal alt = itCoords->altitude();
581 
582  GeoDataCoordinates normalizedCoords( *itCoords );
583  normalizedCoords.set( lon, lat, alt );
584  normalizedLineString << normalizedCoords;
585  }
586 
587  return normalizedLineString;
588 }
589 
591 {
592  Q_D(const GeoDataLineString);
593 
594  if (d->m_dirtyRange) {
595 
596  delete d->m_rangeCorrected;
597 
598  if( isClosed() ) {
599  d->m_rangeCorrected = new GeoDataLinearRing(toPoleCorrected());
600  } else {
601  d->m_rangeCorrected = new GeoDataLineString(toPoleCorrected());
602  }
603  d->m_dirtyRange = false;
604  }
605 
606  return *d->m_rangeCorrected;
607 }
608 
610 {
611  Q_D(const GeoDataLineString);
612 
613  QVector<GeoDataLineString*> lineStrings;
614 
615  d->toDateLineCorrected(*this, lineStrings);
616 
617  return lineStrings;
618 }
619 
621 {
622  Q_D(const GeoDataLineString);
623 
624  if( isClosed() ) {
625  GeoDataLinearRing poleCorrected;
626  d->toPoleCorrected(*this, poleCorrected);
627  return poleCorrected;
628  } else {
629  GeoDataLineString poleCorrected;
630  d->toPoleCorrected(*this, poleCorrected);
631  return poleCorrected;
632  }
633 }
634 
635 void GeoDataLineStringPrivate::toPoleCorrected( const GeoDataLineString& q, GeoDataLineString& poleCorrected ) const
636 {
637  poleCorrected.setTessellationFlags( q.tessellationFlags() );
638 
639  GeoDataCoordinates previousCoords;
640  GeoDataCoordinates currentCoords;
641 
642  if ( q.isClosed() ) {
643  if ( !( m_vector.first().isPole() ) &&
644  ( m_vector.last().isPole() ) ) {
645  qreal firstLongitude = ( m_vector.first() ).longitude();
646  GeoDataCoordinates modifiedCoords( m_vector.last() );
647  modifiedCoords.setLongitude( firstLongitude );
648  poleCorrected << modifiedCoords;
649  }
650  }
651 
654 
655  for( ; itCoords != itEnd; ++itCoords ) {
656 
657  currentCoords = *itCoords;
658 
659  if ( itCoords == m_vector.constBegin() ) {
660  previousCoords = currentCoords;
661  }
662 
663  if ( currentCoords.isPole() ) {
664  if ( previousCoords.isPole() ) {
665  continue;
666  }
667  else {
668  qreal previousLongitude = previousCoords.longitude();
669  GeoDataCoordinates currentModifiedCoords( currentCoords );
670  currentModifiedCoords.setLongitude( previousLongitude );
671  poleCorrected << currentModifiedCoords;
672  }
673  }
674  else {
675  if ( previousCoords.isPole() ) {
676  qreal currentLongitude = currentCoords.longitude();
677  GeoDataCoordinates previousModifiedCoords( previousCoords );
678  previousModifiedCoords.setLongitude( currentLongitude );
679  poleCorrected << previousModifiedCoords;
680  poleCorrected << currentCoords;
681  }
682  else {
683  // No poles at all. Nothing special to handle
684  poleCorrected << currentCoords;
685  }
686  }
687  previousCoords = currentCoords;
688  }
689 
690  if ( q.isClosed() ) {
691  if ( ( m_vector.first().isPole() ) &&
692  !( m_vector.last().isPole() ) ) {
693  qreal lastLongitude = ( m_vector.last() ).longitude();
694  GeoDataCoordinates modifiedCoords( m_vector.first() );
695  modifiedCoords.setLongitude( lastLongitude );
696  poleCorrected << modifiedCoords;
697  }
698  }
699 }
700 
701 void GeoDataLineStringPrivate::toDateLineCorrected(
702  const GeoDataLineString & q,
703  QVector<GeoDataLineString*> & lineStrings
704  ) const
705 {
706  const bool isClosed = q.isClosed();
707 
710  QVector<GeoDataCoordinates>::const_iterator itPoint = itStartPoint;
711  QVector<GeoDataCoordinates>::const_iterator itPreviousPoint = itPoint;
712 
714 
715  GeoDataLineString * unfinishedLineString = nullptr;
716 
717  GeoDataLineString * dateLineCorrected = isClosed ? new GeoDataLinearRing( f )
718  : new GeoDataLineString( f );
719 
720  qreal previousLon = 0.0;
721  int previousSign = 1;
722 
723  bool unfinished = false;
724 
725  for (; itPoint != itEndPoint; ++itPoint ) {
726  const qreal currentLon = itPoint->longitude();
727 
728  int currentSign = ( currentLon < 0.0 ) ? -1 : +1 ;
729 
730  if( itPoint == q.constBegin() ) {
731  previousSign = currentSign;
732  previousLon = currentLon;
733  }
734 
735  // If we are crossing the date line ...
736  if ( previousSign != currentSign && fabs(previousLon) + fabs(currentLon) > M_PI ) {
737 
738  unfinished = !unfinished;
739 
740  GeoDataCoordinates previousTemp;
741  GeoDataCoordinates currentTemp;
742 
743  interpolateDateLine( *itPreviousPoint, *itPoint,
744  previousTemp, currentTemp, q.tessellationFlags() );
745 
746  *dateLineCorrected << previousTemp;
747 
748  if ( isClosed && unfinished ) {
749  // If it's a linear ring and if it crossed the IDL only once then
750  // store the current string inside the unfinishedLineString for later use ...
751  unfinishedLineString = dateLineCorrected;
752  // ... and start a new linear ring for now.
753  dateLineCorrected = new GeoDataLinearRing( f );
754  }
755  else {
756  // Now it can only be a (finished) line string or a finished linear ring.
757  // Store it in the vector if the size is not zero.
758  if ( dateLineCorrected->size() > 0 ) {
759  lineStrings << dateLineCorrected;
760  }
761  else {
762  // Or delete it.
763  delete dateLineCorrected;
764  }
765 
766  // If it's a finished linear ring restore the "remembered" unfinished String
767  if ( isClosed && !unfinished && unfinishedLineString ) {
768  dateLineCorrected = unfinishedLineString;
769  }
770  else {
771  // if it's a line string just create a new line string.
772  dateLineCorrected = new GeoDataLineString( f );
773  }
774  }
775 
776  *dateLineCorrected << currentTemp;
777  *dateLineCorrected << *itPoint;
778 
779  }
780  else {
781  *dateLineCorrected << *itPoint;
782  }
783 
784  previousSign = currentSign;
785  previousLon = currentLon;
786  itPreviousPoint = itPoint;
787  }
788 
789  // If the line string doesn't cross the dateline an even number of times
790  // then need to take care of the data stored in the unfinishedLineString
791  if ( unfinished && unfinishedLineString && !unfinishedLineString->isEmpty() ) {
792  *dateLineCorrected << *unfinishedLineString;
793  delete unfinishedLineString;
794  }
795 
796  lineStrings << dateLineCorrected;
797 }
798 
800 {
801  Q_D(const GeoDataLineString);
802 
803  // GeoDataLatLonAltBox::fromLineString is very expensive
804  // that's why we recreate it only if the m_dirtyBox
805  // is TRUE.
806  // DO NOT REMOVE THIS CONSTRUCT OR MARBLE WILL BE SLOW.
807  if (d->m_dirtyBox) {
808  d->m_latLonAltBox = GeoDataLatLonAltBox::fromLineString(*this);
809  d->m_dirtyBox = false;
810  }
811 
812  return d->m_latLonAltBox;
813 }
814 
815 qreal GeoDataLineString::length( qreal planetRadius, int offset ) const
816 {
817  if( offset < 0 || offset >= size() ) {
818  return 0;
819  }
820 
821  Q_D(const GeoDataLineString);
822  qreal length = 0.0;
823  QVector<GeoDataCoordinates> const & vector = d->m_vector;
824  int const start = qMax(offset+1, 1);
825  int const end = d->m_vector.size();
826  for( int i=start; i<end; ++i )
827  {
828  length += vector[i-1].sphericalDistanceTo(vector[i]);
829  }
830 
831  return planetRadius * length;
832 }
833 
835 {
836  detach();
837 
838  Q_D(GeoDataLineString);
839  delete d->m_rangeCorrected;
840  d->m_rangeCorrected = nullptr;
841  d->m_dirtyRange = true;
842  d->m_dirtyBox = true;
843  return d->m_vector.erase( pos );
844 }
845 
848 {
849  detach();
850 
851  Q_D(GeoDataLineString);
852  delete d->m_rangeCorrected;
853  d->m_rangeCorrected = nullptr;
854  d->m_dirtyRange = true;
855  d->m_dirtyBox = true;
856  return d->m_vector.erase( begin, end );
857 }
858 
860 {
861  detach();
862 
863  Q_D(GeoDataLineString);
864  d->m_dirtyRange = true;
865  d->m_dirtyBox = true;
866  d->m_vector.remove( i );
867 }
868 
870 {
871  Q_D(const GeoDataLineString);
872 
873  if( isClosed() ) {
874  GeoDataLinearRing linearRing(*this);
875  d->optimize(linearRing);
876  return linearRing;
877  } else {
878  GeoDataLineString lineString(*this);
879  d->optimize(lineString);
880  return lineString;
881  }
882 }
883 
885 {
886  Q_D(const GeoDataLineString);
887 
888  GeoDataGeometry::pack( stream );
889 
890  stream << size();
891  stream << (qint32)(d->m_tessellationFlags);
892 
894  = d->m_vector.constBegin();
895  iterator != d->m_vector.constEnd();
896  ++iterator ) {
897  mDebug() << "innerRing: size" << d->m_vector.size();
898  GeoDataCoordinates coord = ( *iterator );
899  coord.pack( stream );
900  }
901 
902 }
903 
905 {
906  detach();
907 
908  Q_D(GeoDataLineString);
909 
910  GeoDataGeometry::unpack( stream );
911  qint32 size;
912  qint32 tessellationFlags;
913 
914  stream >> size;
915  stream >> tessellationFlags;
916 
917  d->m_tessellationFlags = (TessellationFlags)(tessellationFlags);
918 
919  d->m_vector.reserve(d->m_vector.size() + size);
920 
921  for(qint32 i = 0; i < size; i++ ) {
922  GeoDataCoordinates coord;
923  coord.unpack( stream );
924  d->m_vector.append( coord );
925  }
926 }
927 
928 }
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...
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 Wed Aug 5 2020 23:17:38 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.