void GeoDataLineStringPrivate::optimize (GeoDataLineString& lineString) const { QVector<GeoDataCoordinates>::iterator itCoords = lineString.begin(); QVector<GeoDataCoordinates>::const_iterator itEnd = lineString.constEnd(); if (lineString.size() < 2) return; // Calculate the least non-zero detail-level by checking the bounding box int startLevel = levelForResolution( ( lineString.latLonAltBox().width() + lineString.latLonAltBox().height() ) / 2 ); int currentLevel = startLevel; int maxLevel = startLevel; GeoDataCoordinates currentCoords; lineString.first().setDetail(startLevel); // Iterate through the linestring to assign different detail levels to the nodes. // In general the first and last node should have the start level assigned as // a detail level. // Starting from the first node the algorithm picks those nodes which // have a distance from each other that is just above the resolution that is // associated with the start level (which we use as a "current level"). // Each of those nodes get the current level assigned as the detail level. // After iterating through the linestring we increment the current level value // and starting again with the first node we assign detail values in a similar way // to the remaining nodes which have no final detail level assigned yet. // We do as many iterations through the lineString as needed and bump up the // current level until all nodes have a non-zero detail level assigned. while ( currentLevel < 16 && currentLevel <= maxLevel + 1 ) { itCoords = lineString.begin(); currentCoords = *itCoords; ++itCoords; for( ; itCoords != itEnd; ++itCoords) { if (itCoords->detail() != 0 && itCoords->detail() < currentLevel) continue; if ( currentLevel == startLevel && (itCoords->longitude() == -M_PI || itCoords->longitude() == M_PI || itCoords->latitude() < -89 * DEG2RAD || itCoords->latitude() > 89 * DEG2RAD)) { itCoords->setDetail(startLevel); currentCoords = *itCoords; maxLevel = currentLevel; continue; } if (distanceSphere( currentCoords, *itCoords ) < resolutionForLevel(currentLevel + 1)) { itCoords->setDetail(currentLevel + 1); } else { itCoords->setDetail(currentLevel); currentCoords = *itCoords; maxLevel = currentLevel; } } ++currentLevel; } lineString.last().setDetail(startLevel); }
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 PolylineAnnotation::drawNodes( GeoPainter *painter ) { // These are the 'real' dimensions of the drawn nodes. The ones which have class scope are used // to generate the regions and they are a little bit larger, because, for example, it would be // a little bit too hard to select nodes. static const int d_regularDim = 10; static const int d_selectedDim = 10; static const int d_mergedDim = 20; static const int d_hoveredDim = 20; const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() ); QColor glowColor = QApplication::palette().highlightedText().color(); glowColor.setAlpha(120); for ( int i = 0; i < line.size(); ++i ) { // The order here is important, because a merged node can be at the same time selected. if ( m_nodesList.at(i).isBeingMerged() ) { painter->setBrush( mergedColor ); painter->drawEllipse( line.at(i), d_mergedDim, d_mergedDim ); } else if ( m_nodesList.at(i).isSelected() ) { painter->setBrush( selectedColor ); painter->drawEllipse( line.at(i), d_selectedDim, d_selectedDim ); if ( m_nodesList.at(i).isEditingHighlighted() || m_nodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setBrush( Qt::NoBrush ); painter->setPen( newPen ); painter->drawEllipse( line.at(i), d_selectedDim + 2, d_selectedDim + 2 ); painter->setPen( defaultPen ); } } else { painter->setBrush( regularColor ); painter->drawEllipse( line.at(i), d_regularDim, d_regularDim ); if ( m_nodesList.at(i).isEditingHighlighted() || m_nodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setPen( newPen ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( line.at(i), d_regularDim + 2, d_regularDim + 2 ); painter->setPen( defaultPen ); } } } if ( m_virtualHoveredNode != -1 ) { painter->setBrush( hoveredColor ); GeoDataCoordinates newCoords; if ( m_virtualHoveredNode + 1 ) { newCoords = line.at( m_virtualHoveredNode + 1 ).interpolate( line.at( m_virtualHoveredNode ), 0.5 ); } else { newCoords = line.first().interpolate( line.last(), 0.5 ); } painter->drawEllipse( newCoords, d_hoveredDim, d_hoveredDim ); } }