示例#1
0
bool AbstractGeoPolygonGraphicsItem::configurePainter(GeoPainter *painter, const ViewportParams &viewport) const
{
    QPen currentPen = painter->pen();
    GeoDataStyle::ConstPtr style = this->style();
    if (!style) {
        painter->setPen( QPen() ); // "style-less" polygons: a 1px black solid line
    }
    else {
        const GeoDataPolyStyle& polyStyle = style->polyStyle();

        if (polyStyle.outline()) {
            const GeoDataLineStyle& lineStyle = style->lineStyle();

            // To save performance we avoid making changes to the painter's pen.
            // So we first take a copy of the actual painter pen, make changes to it
            // and only if the resulting pen is different from the actual pen
            // we replace the painter's pen with our new pen.

            // We want to avoid the mandatory detach in QPen::setColor(),
            // so we carefully check whether applying the setter is needed
            currentPen.setColor(lineStyle.paintedColor());
            currentPen.setWidthF(lineStyle.width());
            currentPen.setCapStyle(lineStyle.capStyle());
            currentPen.setStyle(lineStyle.penStyle());

            if (painter->pen().color() != currentPen.color()) {
                painter->setPen(currentPen);
            }
        }
        else {
            // polygons without outline: Qt::NoPen (not drawn)
            if (currentPen.style() != Qt::NoPen) {
                painter->setPen(Qt::NoPen);
            }
        }

        if (!polyStyle.fill()) {            
            painter->setBrush(Qt::transparent);
        }
        else {
            const QColor paintedColor = polyStyle.paintedColor();
            if (painter->brush().color() != paintedColor ||
                painter->brush().style() != polyStyle.brushStyle()) {
                if (!polyStyle.texturePath().isEmpty() || !polyStyle.textureImage().isNull()) {
                    GeoDataCoordinates coords = latLonAltBox().center();
                    qreal x, y;
                    viewport.screenCoordinates(coords, x, y);
                    QBrush brush(texture(polyStyle.texturePath(), paintedColor));
                    painter->setBrush(brush);
                    painter->setBrushOrigin(QPoint(x,y));
                }
                else {
                    painter->setBrush(QBrush(paintedColor, polyStyle.brushStyle()));
                }
            }
        }
    }

    return true;
}
示例#2
0
void GeoPolygonGraphicsItem::paint( GeoPainter* painter, const ViewportParams* viewport )
{
    painter->save();

    bool const isBuildingFrame = isDecoration();
    bool const isBuildingRoof = !isDecoration() && !decorations().isEmpty();

    QPen currentPen = painter->pen();

    if ( !style() ) {
        painter->setPen( QPen() );
    }
    else {
        if ( !style()->polyStyle().outline() || isBuildingFrame ) {
            currentPen.setColor( Qt::transparent );
        }
        else {
            if ( currentPen.color() != style()->lineStyle().paintedColor() ||
                 currentPen.widthF() != style()->lineStyle().width() ) {
                currentPen.setColor( style()->lineStyle().paintedColor() );
                currentPen.setWidthF( style()->lineStyle().width() );
            }

            if ( currentPen.capStyle() != style()->lineStyle().capStyle() )
                currentPen.setCapStyle( style()->lineStyle().capStyle() );

            if ( currentPen.style() != style()->lineStyle().penStyle() )
                currentPen.setStyle( style()->lineStyle().penStyle() );
        }

        if ( painter->pen() != currentPen )
            painter->setPen( currentPen );

        if ( !style()->polyStyle().fill() ) {
            if ( painter->brush().color() != Qt::transparent )
                painter->setBrush( QColor( Qt::transparent ) );
        }
        else {
            if ( isBuildingFrame ) {
                painter->setBrush( style()->polyStyle().paintedColor().darker(150) );
            } else if ( painter->brush().color() != style()->polyStyle().paintedColor() ) {
                QImage textureImage = style()->polyStyle().textureImage();
                if( !textureImage.isNull()){
                    GeoDataCoordinates coords = latLonAltBox().center();
                    qreal x, y;
                    viewport->screenCoordinates(coords, x, y);
                    if (m_cachedTexturePath != style()->polyStyle().texturePath() || m_cachedTextureColor != style()->polyStyle().paintedColor() ) {
                        m_cachedTexture = QImage ( textureImage.size(), QImage::Format_ARGB32_Premultiplied );
                        m_cachedTexture.fill(style()->polyStyle().paintedColor());
                        QPainter imagePainter(&m_cachedTexture );
                        imagePainter.drawImage(0, 0, textureImage);
                        imagePainter.end();
                        m_cachedTexturePath = style()->polyStyle().texturePath();
                        m_cachedTextureColor = style()->polyStyle().paintedColor();
                    }
                    QBrush brush;
                    brush.setTextureImage(m_cachedTexture);
                    QTransform transform;
                    brush.setTransform(transform.translate(x,y));
                    painter->setBrush(brush);
                } else {
                    painter->setBrush( style()->polyStyle().paintedColor() );
                }
            }
        }
    }

    if ( isBuildingFrame || isBuildingRoof ) {

        bool drawAccurate3D = false;
        bool isCameraAboveBuilding = false;

        QPointF offsetAtCorner = buildingOffset(QPointF(0, 0), viewport, &isCameraAboveBuilding);
        qreal maxOffset = qMax( qAbs( offsetAtCorner.x() ), qAbs( offsetAtCorner.y() ) );
        drawAccurate3D = painter->mapQuality() == HighQuality ? maxOffset > 5.0 : maxOffset > 8.0;

        // Since subtracting one fully contained polygon from another results in a single
        // polygon with a "connecting line" between the inner and outer part we need
        // to first paint the inner area with no pen and then the outlines with the correct pen.
        QVector<QPolygonF*> outlines;
        QVector<QPolygonF*> innerPolygons;
        QVector<QPolygonF*> polygons;
        bool const hasInnerBoundaries = m_polygon ? !m_polygon->innerBoundaries().isEmpty() : false;
        if (m_polygon) {
            if (hasInnerBoundaries) {
                screenPolygons(viewport, m_polygon, innerPolygons, outlines);
            }
            viewport->screenCoordinates(m_polygon->outerBoundary(), polygons);
        } else if (m_ring) {
            viewport->screenCoordinates(*m_ring, polygons);
        }

        if ( isBuildingFrame ) {
            QVector<QPolygonF*> sides = (hasInnerBoundaries && drawAccurate3D && isCameraAboveBuilding) ? outlines : polygons;

            foreach(QPolygonF* polygon, sides) {
                if (polygon->isEmpty()) {
                    continue;
                }
                if ( drawAccurate3D && isCameraAboveBuilding ) {
                    // draw the building sides
                    int const size = polygon->size();
                    QPointF & a = (*polygon)[0];
                    QPointF shiftA = a + buildingOffset(a, viewport);
                    for (int i=1; i<size; ++i) {
                        QPointF const & b = (*polygon)[i];
                        QPointF const shiftB = b + buildingOffset(b, viewport);
                        QPolygonF buildingSide = QPolygonF() << a << shiftA << shiftB << b;
                        if (hasInnerBoundaries) {
                            //smoothen away our loss of antialiasing due to the QRegion Qt-bug workaround
                            painter->setPen(QPen(painter->brush().color(), 1.5));
                        }
                        painter->drawPolygon(buildingSide);
                        a = b;
                        shiftA = shiftB;
                    }
                } else {
                    // don't draw the building sides - just draw the base frame instead
                    if (hasInnerBoundaries) {
                        QRegion clip(polygon->toPolygon());

                        foreach(QPolygonF* clipPolygon, innerPolygons) {
                            clip-=QRegion(clipPolygon->toPolygon());
                        }
                        painter->setClipRegion(clip);
                    }
                    painter->drawPolygon(*polygon);
                }
            }
        } else if (isBuildingRoof) {