void GosmoreRunnerPrivate::merge( GeoDataLineString* one, const GeoDataLineString& two ) { Q_ASSERT( one ); QVector<GeoDataCoordinates>::const_iterator iter = two.constBegin(); for( ; iter != two.constEnd(); ++iter ) { /** @todo: It might be needed to cut off some points at the start or end */ one->append( *iter ); } }
void PolylineAnnotation::setupRegionsLists( GeoPainter *painter ) { Q_ASSERT( state() == SceneGraphicsItem::DrawingPolyline || !m_regionsInitialized ); const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() ); // Add poyline nodes. QVector<GeoDataCoordinates>::ConstIterator itBegin = line.constBegin(); QVector<GeoDataCoordinates>::ConstIterator itEnd = line.constEnd(); m_nodesList.clear(); for ( ; itBegin != itEnd; ++itBegin ) { const PolylineNode newNode = PolylineNode( painter->regionFromEllipse( *itBegin, regularDim, regularDim ) ); m_nodesList.append( newNode ); } // Add region from polyline so that events on polyline's 'lines' could be caught. m_polylineRegion = painter->regionFromPolyline( line, 15 ); }
GeoDataLatLonAltBox GeoDataLatLonAltBox::fromLineString( const GeoDataLineString& lineString ) { // If the line string is empty return a boundingbox that contains everything if ( lineString.size() == 0 ) { return GeoDataLatLonAltBox(); } const qreal altitude = lineString.first().altitude(); GeoDataLatLonAltBox temp ( GeoDataLatLonBox::fromLineString( lineString ), altitude, altitude ); qreal maxAltitude = altitude; qreal minAltitude = altitude; // If there's only a single node stored then the boundingbox only contains that point if ( lineString.size() == 1 ) { temp.setMinAltitude( minAltitude ); temp.setMaxAltitude( maxAltitude ); return temp; } QVector<GeoDataCoordinates>::ConstIterator it( lineString.constBegin() ); QVector<GeoDataCoordinates>::ConstIterator itEnd( lineString.constEnd() ); for ( ; it != itEnd; ++it ) { // Get coordinates and normalize them to the desired range. const qreal altitude = (it)->altitude(); // Determining the maximum and minimum latitude if ( altitude > maxAltitude ) maxAltitude = altitude; if ( altitude < minAltitude ) minAltitude = altitude; } temp.setMinAltitude( minAltitude ); temp.setMaxAltitude( maxAltitude ); return temp; }
void GeoDataLineStringPrivate::toDateLineCorrected( const GeoDataLineString & q, QVector<GeoDataLineString*> & lineStrings ) { const bool isClosed = q.isClosed(); const QVector<GeoDataCoordinates>::const_iterator itStartPoint = q.constBegin(); const QVector<GeoDataCoordinates>::const_iterator itEndPoint = q.constEnd(); QVector<GeoDataCoordinates>::const_iterator itPoint = itStartPoint; QVector<GeoDataCoordinates>::const_iterator itPreviousPoint = itPoint; TessellationFlags f = q.tessellationFlags(); GeoDataLineString * unfinishedLineString = 0; GeoDataLineString * dateLineCorrected = isClosed ? new GeoDataLinearRing( f ) : new GeoDataLineString( f ); qreal currentLon = 0.0; qreal previousLon = 0.0; int previousSign = 1; bool unfinished = false; for (; itPoint != itEndPoint; ++itPoint ) { currentLon = itPoint->longitude(); int currentSign = ( currentLon < 0.0 ) ? -1 : +1 ; if( itPoint == q.constBegin() ) { previousSign = currentSign; previousLon = currentLon; } // If we are crossing the date line ... if ( previousSign != currentSign && fabs(previousLon) + fabs(currentLon) > M_PI ) { unfinished = !unfinished; GeoDataCoordinates previousTemp; GeoDataCoordinates currentTemp; interpolateDateLine( *itPreviousPoint, *itPoint, previousTemp, currentTemp, q.tessellationFlags() ); *dateLineCorrected << previousTemp; if ( isClosed && unfinished ) { // If it's a linear ring and if it crossed the IDL only once then // store the current string inside the unfinishedLineString for later use ... unfinishedLineString = dateLineCorrected; // ... and start a new linear ring for now. dateLineCorrected = new GeoDataLinearRing( f ); } else { // Now it can only be a (finished) line string or a finished linear ring. // Store it in the vector if the size is not zero. if ( dateLineCorrected->size() > 0 ) { lineStrings << dateLineCorrected; } else { // Or delete it. delete dateLineCorrected; } // If it's a finished linear ring restore the "remembered" unfinished String if ( isClosed && !unfinished && unfinishedLineString ) { dateLineCorrected = unfinishedLineString; } else { // if it's a line string just create a new line string. dateLineCorrected = new GeoDataLineString( f ); } } *dateLineCorrected << currentTemp; *dateLineCorrected << *itPoint; } else { *dateLineCorrected << *itPoint; } previousSign = currentSign; previousLon = currentLon; itPreviousPoint = itPoint; } // If the line string doesn't cross the dateline an even number of times // then need to take care of the data stored in the unfinishedLineString if ( unfinished && unfinishedLineString && !unfinishedLineString->isEmpty() ) { *dateLineCorrected << *unfinishedLineString; delete unfinishedLineString; } lineStrings << dateLineCorrected; }
bool CylindricalProjectionPrivate::lineStringToPolygon( const GeoDataLineString &lineString, const ViewportParams *viewport, QVector<QPolygonF *> &polygons ) const { const TessellationFlags f = lineString.tessellationFlags(); qreal x = 0; qreal y = 0; qreal previousX = -1.0; qreal previousY = -1.0; int mirrorCount = 0; qreal distance = repeatDistance( viewport ); polygons.append( new QPolygonF ); GeoDataLineString::ConstIterator itCoords = lineString.constBegin(); GeoDataLineString::ConstIterator itPreviousCoords = lineString.constBegin(); GeoDataLineString::ConstIterator itBegin = lineString.constBegin(); GeoDataLineString::ConstIterator itEnd = lineString.constEnd(); bool processingLastNode = false; // We use a while loop to be able to cover linestrings as well as linear rings: // Linear rings require to tessellate the path from the last node to the first node // which isn't really convenient to achieve with a for loop ... const bool isLong = lineString.size() > 10; const int maximumDetail = levelForResolution(viewport->angularResolution()); // The first node of optimized linestrings has a non-zero detail value. const bool hasDetail = itBegin->detail() != 0; while ( itCoords != itEnd ) { // Optimization for line strings with a big amount of nodes bool skipNode = (hasDetail ? itCoords->detail() > maximumDetail : itCoords != itBegin && isLong && !processingLastNode && !viewport->resolves( *itPreviousCoords, *itCoords ) ); if ( !skipNode ) { Q_Q( const CylindricalProjection ); q->screenCoordinates( *itCoords, viewport, x, y ); // Initializing variables that store the values of the previous iteration if ( !processingLastNode && itCoords == itBegin ) { itPreviousCoords = itCoords; previousX = x; previousY = y; } // This if-clause contains the section that tessellates the line // segments of a linestring. If you are about to learn how the code of // this class works you can safely ignore this section for a start. if ( lineString.tessellate() ) { mirrorCount = tessellateLineSegment( *itPreviousCoords, previousX, previousY, *itCoords, x, y, polygons, viewport, f, mirrorCount, distance ); } else { // special case for polys which cross dateline but have no Tesselation Flag // the expected rendering is a screen coordinates straight line between // points, but in projections with repeatX things are not smooth mirrorCount = crossDateLine( *itPreviousCoords, *itCoords, x, y, polygons, mirrorCount, distance ); } itPreviousCoords = itCoords; previousX = x; previousY = y; } // Here we modify the condition to be able to process the // first node after the last node in a LinearRing. if ( processingLastNode ) { break; } ++itCoords; if ( itCoords == itEnd && lineString.isClosed() ) { itCoords = itBegin; processingLastNode = true; } } GeoDataLatLonAltBox box = lineString.latLonAltBox(); // Closing e.g. in the Antarctica case. // This code makes the assumption that // - the first node is located at 180 E // - and the last node is located at 180 W // TODO: add a similar pattern in the crossDateLine() code. /* if( lineString.isClosed() && box.width() == 2*M_PI ) { QPolygonF *poly = polygons.last(); if( box.containsPole( NorthPole ) ) { qreal topMargin = 0.0; qreal dummy = 0.0; q_ptr->screenCoordinates(0.0, q_ptr->maxLat(), viewport, topMargin, dummy ); poly->push_back( QPointF( poly->last().x(), topMargin ) ); poly->push_back( QPointF( poly->first().x(), topMargin ) ); } else { qreal bottomMargin = 0.0; qreal dummy = 0.0; q_ptr->screenCoordinates(0.0, q_ptr->minLat(), viewport, bottomMargin, dummy ); poly->push_back( QPointF( poly->last().x(), bottomMargin ) ); poly->push_back( QPointF( poly->first().x(), bottomMargin ) ); } } */ repeatPolygons( viewport, polygons ); return polygons.isEmpty(); }