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;
}
Example #3
0
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 );
    }
}