// A workaround for circle path to be drawn correctly using a polygon geometry
void QDeclarativeCircleMapItem::updateCirclePathForRendering(QList<QGeoCoordinate> &path,
                                                             const QGeoCoordinate &center,
                                                             qreal distance)
{
    qreal poleLat = 90;
    qreal distanceToNorthPole = center.distanceTo(QGeoCoordinate(poleLat, 0));
    qreal distanceToSouthPole = center.distanceTo(QGeoCoordinate(-poleLat, 0));
    bool crossNorthPole = distanceToNorthPole < distance;
    bool crossSouthPole = distanceToSouthPole < distance;
    if (!crossNorthPole && !crossSouthPole)
        return;
    QList<int> wrapPathIndex;
    // calculate actual width of map on screen in pixels
    QDoubleVector2D midPoint = map()->coordinateToItemPosition(map()->cameraData().center(), false);
    QDoubleVector2D midPointPlusOne(midPoint.x() + 1.0, midPoint.y());
    QGeoCoordinate coord1 = map()->itemPositionToCoordinate(midPointPlusOne, false);
    qreal geoDistance = coord1.longitude() - map()->cameraData().center().longitude();
    if ( geoDistance < 0 )
        geoDistance += 360;
    qreal mapWidth = 360.0 / geoDistance;
    mapWidth = qMin(static_cast<int>(mapWidth), map()->width());
    QDoubleVector2D prev = map()->coordinateToItemPosition(path.at(0), false);
    // find the points in path where wrapping occurs
    for (int i = 1; i <= path.count(); ++i) {
        int index = i % path.count();
        QDoubleVector2D point = map()->coordinateToItemPosition(path.at(index), false);
        if ( (qAbs(point.x() - prev.x())) >= mapWidth/2.0 ) {
            wrapPathIndex << index;
            if (wrapPathIndex.size() == 2 || !(crossNorthPole && crossSouthPole))
                break;
        }
        prev = point;
    }
    // insert two additional coords at top/bottom map corners of the map for shape
    // to be drawn correctly
    if (wrapPathIndex.size() > 0) {
        qreal newPoleLat = 90;
        QGeoCoordinate wrapCoord = path.at(wrapPathIndex[0]);
        if (wrapPathIndex.size() == 2) {
            QGeoCoordinate wrapCoord2 = path.at(wrapPathIndex[1]);
            if (wrapCoord2.latitude() > wrapCoord.latitude())
                newPoleLat = -90;
        } else if (center.latitude() < 0) {
            newPoleLat = -90;
        }
        for (int i = 0; i < wrapPathIndex.size(); ++i) {
            int index = wrapPathIndex[i] == 0 ? 0 : wrapPathIndex[i] + i*2;
            int prevIndex = (index - 1) < 0 ? (path.count() - 1): index - 1;
            QGeoCoordinate coord0 = path.at(prevIndex);
            QGeoCoordinate coord1 = path.at(index);
            coord0.setLatitude(newPoleLat);
            coord1.setLatitude(newPoleLat);
            path.insert(index ,coord1);
            path.insert(index, coord0);
            newPoleLat = -newPoleLat;
        }
    }
}
Пример #2
0
void QDeclarativeGeoMap::fitViewportToGeoShape()
{
    double bboxWidth;
    double bboxHeight;
    QGeoCoordinate centerCoordinate;

    switch (m_region.type()) {
    case QGeoShape::RectangleType:
    {
        QGeoRectangle rect = m_region;
        QDoubleVector2D topLeftPoint = m_map->coordinateToItemPosition(rect.topLeft(), false);
        QDoubleVector2D botRightPoint = m_map->coordinateToItemPosition(rect.bottomRight(), false);
        bboxWidth = qAbs(topLeftPoint.x() - botRightPoint.x());
        bboxHeight = qAbs(topLeftPoint.y() - botRightPoint.y());
        centerCoordinate = rect.center();
        break;
    }
    case QGeoShape::CircleType:
    {
        QGeoCircle circle = m_region;
        centerCoordinate = circle.center();
        QGeoCoordinate edge = centerCoordinate.atDistanceAndAzimuth(circle.radius(), 90);
        QDoubleVector2D centerPoint = m_map->coordinateToItemPosition(centerCoordinate, false);
        QDoubleVector2D edgePoint = m_map->coordinateToItemPosition(edge, false);
        bboxWidth = qAbs(centerPoint.x() - edgePoint.x()) * 2;
        bboxHeight = bboxWidth;
        break;
    }
    case QGeoShape::UnknownType:
        //Fallthrough to default
    default:
        return;
    }

    // position camera to the center of bounding box
    setProperty("center", QVariant::fromValue(centerCoordinate));

    //If the shape is empty we just change centerposition, not zoom
    if (bboxHeight == 0 && bboxWidth == 0)
        return;

    // adjust zoom
    double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight);
    double mapWidthRatio = width() / (width() + height());
    double zoomRatio;

    if (bboxWidthRatio > mapWidthRatio)
        zoomRatio = bboxWidth / width();
    else
        zoomRatio = bboxHeight / height();

    qreal newZoom = std::log10(zoomRatio) / std::log10(0.5);

    newZoom = std::floor(qMax(minimumZoomLevel(), (m_map->mapController()->zoom() + newZoom)));
    setProperty("zoomLevel", QVariant::fromValue(newZoom));
}
Пример #3
0
QGeoCoordinate QGeoTiledMapData::screenPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport) const
{
    Q_D(const QGeoTiledMapData);
    if (clipToViewport) {
        int w = width();
        int h = height();

        if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
            return QGeoCoordinate();
    }

    return d->screenPositionToCoordinate(pos);
}
Пример #4
0
QDoubleVector2D QGeoTiledMapData::coordinateToScreenPosition(const QGeoCoordinate &coordinate, bool clipToViewport) const
{
    Q_D(const QGeoTiledMapData);
    QDoubleVector2D pos = d->coordinateToScreenPosition(coordinate);

    if (clipToViewport) {
        int w = width();
        int h = height();

        if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
            return QDoubleVector2D(qQNaN(), qQNaN());
    }

    return pos;
}
Пример #5
0
QGeoCoordinate QGeoProjection::mercatorToCoord(const QDoubleVector2D &mercator)
{
    const double pi = M_PI;

    double fx = mercator.x();
    double fy = mercator.y();

    if (fy < 0.0)
        fy = 0.0;
    else if (fy > 1.0)
        fy = 1.0;

    double lat;

    if (fy == 0.0)
        lat = 90.0;
    else if (fy == 1.0)
        lat = -90.0;
    else
        lat = (180.0 / pi) * (2.0 * std::atan(std::exp(pi * (1.0 - 2.0 * fy))) - (pi / 2.0));

    double lng;
    if (fx >= 0) {
        lng = realmod(fx, 1.0);
    } else {
        lng = realmod(1.0 - realmod(-1.0 * fx, 1.0), 1.0);
    }

    lng = lng * 360.0 - 180.0;

    return QGeoCoordinate(lat, lng, 0.0);
}
/*!
    \internal
*/
void QGeoMapRectangleGeometry::updatePoints(const QGeoMap &map,
                                            const QGeoCoordinate &topLeft,
                                            const QGeoCoordinate &bottomRight)
{
    if (!screenDirty_ && !sourceDirty_)
        return;

    QDoubleVector2D tl = map.coordinateToItemPosition(topLeft, false);
    QDoubleVector2D br = map.coordinateToItemPosition(bottomRight, false);

    // We can get NaN if the map isn't set up correctly, or the projection
    // is faulty -- probably best thing to do is abort
    if (!qIsFinite(tl.x()) || !qIsFinite(tl.y()))
        return;
    if (!qIsFinite(br.x()) || !qIsFinite(br.y()))
        return;

    if ( preserveGeometry_ ) {
        double unwrapBelowX = map.coordinateToItemPosition(geoLeftBound_, false).x();
        if (br.x() < unwrapBelowX)
            br.setX(tl.x() + screenBounds_.width());
    }

    QRectF re(tl.toPointF(), br.toPointF());
    re.translate(-1 * tl.toPointF());

    clear();
    screenVertices_.reserve(6);

    screenVertices_ << re.topLeft();
    screenVertices_ << re.topRight();
    screenVertices_ << re.bottomLeft();

    screenVertices_ << re.topRight();
    screenVertices_ << re.bottomLeft();
    screenVertices_ << re.bottomRight();

    firstPointOffset_ = QPointF(0,0);
    srcOrigin_ = topLeft;
    screenBounds_ = re;

    screenOutline_ = QPainterPath();
    screenOutline_.addRect(re);

    geoLeftBound_ = topLeft;
}
Пример #7
0
QGeoCoordinate QGeoProjection::coordinateInterpolation(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
{
    QDoubleVector2D s = QGeoProjection::coordToMercator(from);
    QDoubleVector2D e = QGeoProjection::coordToMercator(to);

    double x = s.x();

    if (0.5 < qAbs(e.x() - s.x())) {
        // handle dateline crossing
        double ex = e.x();
        double sx = s.x();
        if (ex < sx)
            sx -= 1.0;
        else if (sx < ex)
            ex -= 1.0;

        x = (1.0 - progress) * sx + progress * ex;

        if (!qFuzzyIsNull(x) && (x < 0.0))
            x += 1.0;

    } else {
        x = (1.0 - progress) * s.x() + progress * e.x();
    }

    double y = (1.0 - progress) * s.y() + progress * e.y();

    QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y));
    result.setAltitude((1.0 - progress) * from.altitude() + progress * to.altitude());

    return result;
}
QGeoCoordinate QGeoTiledMapGoogle::itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport) const
{
    if (clipToViewport) {
        int w = width();
        int h = height();

        if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
            return QGeoCoordinate();
    }
    
    QGeoCoordinate coor = QGeoTiledMap::itemPositionToCoordinate(pos, clipToViewport);
    //GCJ-02 to WGS84 
    if("cn" == m_szLocale)
    {
        //qDebug() << "transformFromGCJToWGS:";
        //qDebug() << "lat:" << coor.latitude() << ";lng:" << coor.longitude();
        coor = QCoordTrans::GCJToWGS(coor);
        //qDebug() << "lat:" << coor.latitude() << ";lng:" << coor.longitude();
    }
    return coor;
}
QDoubleVector2D QGeoTiledMapGoogle::coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport) const
{
    QGeoCoordinate coor = coordinate;
    //WGS84 to GCJ-02  
    if("cn" == m_szLocale)
    {
        //qDebug() << "transformFromWGSToGCJ:";
        //qDebug() << "lat:" << coor.latitude() << ";lng:" << coor.longitude();
        coor = QCoordTrans::WGSToGCJ(coor);
        //qDebug() << "lat:" << coor.latitude() << ";lng:" << coor.longitude();
    }
    QDoubleVector2D pos = QGeoTiledMap::coordinateToItemPosition(coor, clipToViewport);

    if (clipToViewport) {
        int w = width();
        int h = height();

        if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
            return QDoubleVector2D(qQNaN(), qQNaN());
    }

    return pos;
}
Пример #10
0
QGeoCoordinate QGeoCoordinateInterpolator2D::interpolate(const QGeoCoordinate &start, const QGeoCoordinate &end, qreal progress)
{
    if (start == end) {
        if (progress < 0.5) {
            return start;
        } else {
            return end;
        }
    }

    QGeoCoordinate s2 = start;
    QGeoCoordinate e2 = end;
    QDoubleVector2D s = QGeoProjection::coordToMercator(s2);
    QDoubleVector2D e = QGeoProjection::coordToMercator(e2);

    double x = s.x();

    if (0.5 < qAbs(e.x() - s.x())) {
        // handle dateline crossing
        double ex = e.x();
        double sx = s.x();
        if (ex < sx)
            sx -= 1.0;
        else if (sx < ex)
            ex -= 1.0;

        x = (1.0 - progress) * sx + progress * ex;

        if (!qFuzzyIsNull(x) && (x < 0.0))
            x += 1.0;

    } else {
        x = (1.0 - progress) * s.x() + progress * e.x();
    }

    double y = (1.0 - progress) * s.y() + progress * e.y();

    QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y));
    result.setAltitude((1.0 - progress) * start.altitude() + progress * end.altitude());
    return result;
}
Пример #11
0
void QDeclarativeGeoMap::fitViewportToGeoShape()
{
    int margins  = 10;
    if (!m_map || width() <= margins || height() <= margins)
        return;

    QGeoCoordinate topLeft;
    QGeoCoordinate bottomRight;

    switch (m_region.type()) {
    case QGeoShape::RectangleType:
    {
        QGeoRectangle rect = m_region;
        topLeft = rect.topLeft();
        bottomRight = rect.bottomRight();
        break;
    }
    case QGeoShape::CircleType:
    {
        const double pi = M_PI;
        QGeoCircle circle = m_region;
        QGeoCoordinate centerCoordinate = circle.center();

        // calculate geo bounding box of the circle
        // circle tangential points with meridians and the north pole create
        // spherical triangle, we use spherical law of sines
        // sin(lon_delta_in_rad)/sin(r_in_rad) =
        // sin(alpha_in_rad)/sin(pi/2 - lat_in_rad), where:
        // * lon_delta_in_rad - delta of longitudes of circle center
        //   and tangential points
        // * r_in_rad - angular radius of the circle
        // * lat_in_rad - latitude of circle center
        // * alpha_in_rad - angle between meridian and radius to the circle =>
        //   this is tangential point => sin(alpha) = 1
        // * lat_delta_in_rad - delta of latitudes of circle center and
        //   latitude of points where great circle (going through circle
        //   center) crosses circle and the pole

        double r_in_rad = circle.radius() / EARTH_MEAN_RADIUS; // angular r
        double lat_delta_in_deg = r_in_rad * 180 / pi;
        double lon_delta_in_deg = std::asin(std::sin(r_in_rad) /
               std::cos(centerCoordinate.latitude() * pi / 180)) * 180 / pi;

        topLeft.setLatitude(centerCoordinate.latitude() + lat_delta_in_deg);
        topLeft.setLongitude(centerCoordinate.longitude() - lon_delta_in_deg);
        bottomRight.setLatitude(centerCoordinate.latitude()
                                - lat_delta_in_deg);
        bottomRight.setLongitude(centerCoordinate.longitude()
                                 + lon_delta_in_deg);

        // adjust if circle reaches poles => cross all meridians and
        // fit into Mercator projection bounds
        if (topLeft.latitude() > 90 || bottomRight.latitude() < -90) {
            topLeft.setLatitude(qMin(topLeft.latitude(), 85.05113));
            topLeft.setLongitude(-180.0);
            bottomRight.setLatitude(qMax(bottomRight.latitude(),
                                                 -85.05113));
            bottomRight.setLongitude(180.0);
        }
        break;
    }
    case QGeoShape::UnknownType:
        //Fallthrough to default
    default:
        return;
    }

    // adjust zoom, use reference world to keep things simple
    // otherwise we would need to do the error prone longitudes
    // wrapping
    QDoubleVector2D topLeftPoint =
            m_map->referenceCoordinateToItemPosition(topLeft);
    QDoubleVector2D bottomRightPoint =
            m_map->referenceCoordinateToItemPosition(bottomRight);

    double bboxWidth = bottomRightPoint.x() - topLeftPoint.x();
    double bboxHeight = bottomRightPoint.y() - topLeftPoint.y();

    // find center of the bounding box
    QGeoCoordinate centerCoordinate =
            m_map->referenceItemPositionToCoordinate(
                (topLeftPoint + bottomRightPoint)/2);

    // position camera to the center of bounding box
    setCenter(centerCoordinate);

    // if the shape is empty we just change center position, not zoom
    if (bboxHeight == 0 && bboxWidth == 0)
        return;

    double zoomRatio = qMax(bboxWidth / (width() - margins),
                            bboxHeight / (height() - margins));
    // fixme: use log2 with c++11
    zoomRatio = std::log(zoomRatio) / std::log(2.0);
    double newZoom = qMax((double)minimumZoomLevel(), m_map->mapController()->zoom()
                          - zoomRatio);
    setZoomLevel(newZoom);
    m_validRegion = true;
}
Пример #12
0
/*!
    \qmlmethod QtLocation::Map::fitViewportToGeoShape(QGeoShape shape)

    Fits the current viewport to the boundary of the shape. The camera is positioned
    in the center of the shape, and at the largest integral zoom level possible which
    allows the whole shape to be visible on screen

*/
void QDeclarativeGeoMap::fitViewportToGeoShape(const QVariant &variantShape)
{
    if (!map_ || !mappingManagerInitialized_)
        return;

    QGeoShape shape;

    if (variantShape.userType() == qMetaTypeId<QGeoRectangle>())
        shape = variantShape.value<QGeoRectangle>();
    else if (variantShape.userType() == qMetaTypeId<QGeoCircle>())
        shape = variantShape.value<QGeoCircle>();
    else if (variantShape.userType() == qMetaTypeId<QGeoShape>())
        shape = variantShape.value<QGeoShape>();

    if (!shape.isValid())
        return;

    double bboxWidth;
    double bboxHeight;
    QGeoCoordinate centerCoordinate;

    switch (shape.type()) {
    case QGeoShape::RectangleType:
    {
        QGeoRectangle rect = shape;
        QDoubleVector2D topLeftPoint = map_->coordinateToScreenPosition(rect.topLeft(), false);
        QDoubleVector2D botRightPoint = map_->coordinateToScreenPosition(rect.bottomRight(), false);
        bboxWidth = qAbs(topLeftPoint.x() - botRightPoint.x());
        bboxHeight = qAbs(topLeftPoint.y() - botRightPoint.y());
        centerCoordinate = rect.center();
        break;
    }
    case QGeoShape::CircleType:
    {
        QGeoCircle circle = shape;
        centerCoordinate = circle.center();
        QGeoCoordinate edge = centerCoordinate.atDistanceAndAzimuth(circle.radius(), 90);
        QDoubleVector2D centerPoint = map_->coordinateToScreenPosition(centerCoordinate, false);
        QDoubleVector2D edgePoint = map_->coordinateToScreenPosition(edge, false);
        bboxWidth = qAbs(centerPoint.x() - edgePoint.x()) * 2;
        bboxHeight = bboxWidth;
        break;
    }
    case QGeoShape::UnknownType:
        //Fallthrough to default
    default:
        return;
    }

    // position camera to the center of bounding box
    setProperty("center", QVariant::fromValue(centerCoordinate));

    //If the shape is empty we just change centerposition, not zoom
    if (bboxHeight == 0 && bboxWidth == 0)
        return;

    // adjust zoom
    double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight);
    double mapWidthRatio = width() / (width() + height());
    double zoomRatio;

    if (bboxWidthRatio > mapWidthRatio)
        zoomRatio = bboxWidth / width();
    else
        zoomRatio = bboxHeight / height();

    qreal newZoom = log10(zoomRatio) / log10(0.5);
    newZoom = floor(qMax(minimumZoomLevel(), (map_->mapController()->zoom() + newZoom)));
    setProperty("zoomLevel", QVariant::fromValue(newZoom));
}
/*!
    \internal
*/
void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
                                                 const QList<QGeoCoordinate> &path)
{
    bool foundValid = false;
    double minX = -1.0;
    double minY = -1.0;
    double maxX = -1.0;
    double maxY = -1.0;

    if (!sourceDirty_)
        return;

    // clear the old data and reserve enough memory
    srcPoints_.clear();
    srcPoints_.reserve(path.size() * 2);
    srcPointTypes_.clear();
    srcPointTypes_.reserve(path.size());

    QDoubleVector2D origin, lastPoint, lastAddedPoint;

    double unwrapBelowX = 0;
    if (preserveGeometry_)
        unwrapBelowX = map.coordinateToScreenPosition(geoLeftBound_, false).x();

    for (int i = 0; i < path.size(); ++i) {
        const QGeoCoordinate &coord = path.at(i);

        if (!coord.isValid())
            continue;

        QDoubleVector2D point = map.coordinateToScreenPosition(coord, false);

        // We can get NaN if the map isn't set up correctly, or the projection
        // is faulty -- probably best thing to do is abort
        if (!qIsFinite(point.x()) || !qIsFinite(point.y()))
            return;

        // unwrap x to preserve geometry if moved to border of map
        if (preserveGeometry_ && point.x() < unwrapBelowX && !qFuzzyCompare(point.x(), unwrapBelowX))
            point.setX(unwrapBelowX + geoDistanceToScreenWidth(map, geoLeftBound_, coord));

        if (!foundValid) {
            foundValid = true;
            srcOrigin_ = coord;
            origin = point;
            point = QDoubleVector2D(0,0);

            minX = point.x();
            maxX = minX;
            minY = point.y();
            maxY = minY;

            srcPoints_ << point.x() << point.y();
            srcPointTypes_ << QPainterPath::MoveToElement;
            lastAddedPoint = point;
        } else {
            point -= origin;

            minX = qMin(point.x(), minX);
            minY = qMin(point.y(), minY);
            maxX = qMax(point.x(), maxX);
            maxY = qMax(point.y(), maxY);

            if ((point - lastAddedPoint).manhattanLength() > 3 ||
                    i == path.size() - 1) {
                srcPoints_ << point.x() << point.y();
                srcPointTypes_ << QPainterPath::LineToElement;
                lastAddedPoint = point;
            }
        }

        lastPoint = point;
    }

    sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
    geoLeftBound_ = map.screenPositionToCoordinate(
                                    QDoubleVector2D(minX + origin.x(), minY + origin.y()), false);
}
Пример #14
0
QSet<QGeoTileSpec> QGeoCameraTilesPrivate::tilesFromPolygon(const Polygon &polygon) const
{
    int numPoints = polygon.size();

    if (numPoints == 0)
        return QSet<QGeoTileSpec>();

    QVector<int> tilesX(polygon.size());
    QVector<int> tilesY(polygon.size());

    // grab tiles at the corners of the polygon
    for (int i = 0; i < numPoints; ++i) {

        QDoubleVector2D p = polygon.at(i).toVector2D();

        int x = 0;
        int y = 0;

        if (qFuzzyCompare(p.x(), sideLength_ * 1.0))
            x = sideLength_ - 1;
        else {
            x = static_cast<int>(p.x()) % sideLength_;
            if ( !qFuzzyCompare(p.x(), 1.0 * x) && qFuzzyCompare(p.x(), 1.0 * (x + 1)) )
                x++;
        }

        if (qFuzzyCompare(p.y(), sideLength_ * 1.0))
            y = sideLength_ - 1;
        else {
            y = static_cast<int>(p.y()) % sideLength_;
            if ( !qFuzzyCompare(p.y(), 1.0 * y) && qFuzzyCompare(p.y(), 1.0 * (y + 1)) )
                y++;
        }

        tilesX[i] = x;
        tilesY[i] = y;
    }

    QGeoCameraTilesPrivate::TileMap map;

    // walk along the edges of the polygon and add all tiles covered by them
    for (int i1 = 0; i1 < numPoints; ++i1) {
        int i2 = (i1 + 1) % numPoints;

        double x1 = polygon.at(i1).get(0);
        double x2 = polygon.at(i2).get(0);

        bool xFixed = qFuzzyCompare(x1, x2);
        bool xIntegral = qFuzzyCompare(x1, std::floor(x1)) || qFuzzyCompare(x1 + 1.0, std::floor(x1 + 1.0));

        QList<QPair<double, int> > xIntersects
                = tileIntersections(x1,
                                    tilesX.at(i1),
                                    x2,
                                    tilesX.at(i2));

        double y1 = polygon.at(i1).get(1);
        double y2 = polygon.at(i2).get(1);

        bool yFixed = qFuzzyCompare(y1, y2);
        bool yIntegral = qFuzzyCompare(y1, std::floor(y1)) || qFuzzyCompare(y1 + 1.0, std::floor(y1 + 1.0));

        QList<QPair<double, int> > yIntersects
                = tileIntersections(y1,
                                    tilesY.at(i1),
                                    y2,
                                    tilesY.at(i2));

        int x = xIntersects.takeFirst().second;
        int y = yIntersects.takeFirst().second;


        /*
          If the polygon coincides with the tile edges we must be
          inclusive and grab all tiles on both sides. We also need
          to handle tiles with corners coindent with the
          corners of the polygon.
          e.g. all tiles marked with 'x' will be added

              "+" - tile boundaries
              "O" - polygon boundary

                + + + + + + + + + + + + + + + + + + + + +
                +       +       +       +       +       +
                +       +   x   +   x   +   x   +       +
                +       +       +       +       +       +
                + + + + + + + + O O O O O + + + + + + + +
                +       +       O       0       +       +
                +       +   x   O   x   0   x   +       +
                +       +       O       0       +       +
                + + + + + + + + O 0 0 0 0 + + + + + + + +
                +       +       +       +       +       +
                +       +   x   +   x   +   x   +       +
                +       +       +       +       +       +
                + + + + + + + + + + + + + + + + + + + + +
        */


        int xOther = x;
        int yOther = y;

        if (xFixed && xIntegral) {
             if (y2 < y1) {
                 xOther = qMax(0, x - 1);
            }
        }

        if (yFixed && yIntegral) {
            if (x1 < x2) {
                yOther = qMax(0, y - 1);

            }
        }

        if (xIntegral) {
            map.add(xOther, y);
            if (yIntegral)
                map.add(xOther, yOther);

        }

        if (yIntegral)
            map.add(x, yOther);

        map.add(x,y);

        // top left corner
        int iPrev =  (i1 + numPoints - 1) % numPoints;
        double xPrevious = polygon.at(iPrev).get(0);
        double yPrevious = polygon.at(iPrev).get(1);
        bool xPreviousFixed = qFuzzyCompare(xPrevious, x1);
        if (xIntegral && xPreviousFixed && yIntegral && yFixed) {
            if ((x2 > x1) && (yPrevious > y1)) {
                if ((x - 1) > 0 && (y - 1) > 0)
                    map.add(x - 1, y - 1);
            } else if ((x2 < x1) && (yPrevious < y1)) {
                // what?
            }
        }

        // for the simple case where intersections do not coincide with
        // the boundaries, we move along the edge and add tiles until
        // the x and y intersection lists are exhausted

        while (!xIntersects.isEmpty() && !yIntersects.isEmpty()) {
            QPair<double, int> nextX = xIntersects.first();
            QPair<double, int> nextY = yIntersects.first();
            if (nextX.first < nextY.first) {
                x = nextX.second;
                map.add(x, y);
                xIntersects.removeFirst();

            } else if (nextX.first > nextY.first) {
                y = nextY.second;
                map.add(x, y);
                yIntersects.removeFirst();

            } else {
                map.add(x, nextY.second);
                map.add(nextX.second, y);
                x = nextX.second;
                y = nextY.second;
                map.add(x, y);
                xIntersects.removeFirst();
                yIntersects.removeFirst();
            }
        }

        while (!xIntersects.isEmpty()) {
            x = xIntersects.takeFirst().second;
            map.add(x, y);
            if (yIntegral && yFixed)
                map.add(x, yOther);

        }

        while (!yIntersects.isEmpty()) {
            y = yIntersects.takeFirst().second;
            map.add(x, y);
            if (xIntegral && xFixed)
                map.add(xOther, y);
        }
    }

    QSet<QGeoTileSpec> results;

    int z = intZoomLevel_;

    typedef QMap<int, QPair<int, int> >::const_iterator iter;
    iter i = map.data.constBegin();
    iter end = map.data.constEnd();

    for (; i != end; ++i) {
        int y = i.key();
        int minX = i->first;
        int maxX = i->second;
        for (int x = minX; x <= maxX; ++x) {
            results.insert(QGeoTileSpec(pluginString_, mapType_.mapId(), z, x, y, mapVersion_));
        }
    }

    return results;
}
Пример #15
0
QDebug operator<<(QDebug dbg, const QDoubleVector2D &vector)
{
    dbg.nospace() << "QDoubleVector2D(" << vector.x() << ", " << vector.y() << ')';
    return dbg.space();
}
/*!
    \internal
*/
void QGeoMapCircleGeometry::updateScreenPointsInvert(const QGeoMap &map)
{
    if (!screenDirty_)
        return;

    if (map.width() == 0 || map.height() == 0) {
        clear();
        return;
    }

    QPointF origin = map.coordinateToItemPosition(srcOrigin_, false).toPointF();

    QPainterPath ppi = srcPath_;

    clear();

    // a circle requires at least 3 points;
    if (ppi.elementCount() < 3)
        return;

    // translate the path into top-left-centric coordinates
    QRectF bb = ppi.boundingRect();
    ppi.translate(-bb.left(), -bb.top());
    firstPointOffset_ = -1 * bb.topLeft();

    ppi.closeSubpath();

    // calculate actual width of map on screen in pixels
    QGeoCoordinate mapCenter(0, map.cameraData().center().longitude());
    QDoubleVector2D midPoint = map.coordinateToItemPosition(mapCenter, false);
    QDoubleVector2D midPointPlusOne = QDoubleVector2D(midPoint.x() + 1.0, midPoint.y());
    QGeoCoordinate coord1 = map.itemPositionToCoordinate(midPointPlusOne, false);
    double geoDistance = coord1.longitude() - map.cameraData().center().longitude();
    if ( geoDistance < 0 )
        geoDistance += 360.0;
    double mapWidth = 360.0 / geoDistance;

    qreal leftOffset = origin.x() - (map.width()/2.0 - mapWidth/2.0) - firstPointOffset_.x();
    qreal topOffset = origin.y() - (midPoint.y() - mapWidth/2.0) - firstPointOffset_.y();
    QPainterPath ppiBorder;
    ppiBorder.moveTo(QPointF(-leftOffset, -topOffset));
    ppiBorder.lineTo(QPointF(mapWidth - leftOffset, -topOffset));
    ppiBorder.lineTo(QPointF(mapWidth - leftOffset, mapWidth - topOffset));
    ppiBorder.lineTo(QPointF(-leftOffset, mapWidth - topOffset));

    screenOutline_ = ppiBorder;

    std::vector<p2t::Point*> borderPts;
    borderPts.reserve(4);

    std::vector<p2t::Point*> curPts;
    curPts.reserve(ppi.elementCount());
    for (int i = 0; i < ppi.elementCount(); ++i) {
        const QPainterPath::Element e = ppi.elementAt(i);
        if (e.isMoveTo() || i == ppi.elementCount() - 1
                || (qAbs(e.x - curPts.front()->x) < 0.1
                    && qAbs(e.y - curPts.front()->y) < 0.1)) {
            if (curPts.size() > 2) {
                for (int j = 0; j < 4; ++j) {
                    const QPainterPath::Element e2 = ppiBorder.elementAt(j);
                    borderPts.push_back(new p2t::Point(e2.x, e2.y));
                }
                p2t::CDT *cdt = new p2t::CDT(borderPts);
                cdt->AddHole(curPts);
                cdt->Triangulate();
                std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
                screenVertices_.reserve(screenVertices_.size() + int(tris.size()));
                for (size_t i = 0; i < tris.size(); ++i) {
                    p2t::Triangle *t = tris.at(i);
                    for (int j = 0; j < 3; ++j) {
                        p2t::Point *p = t->GetPoint(j);
                        screenVertices_ << QPointF(p->x, p->y);
                    }
                }
                delete cdt;
            }
            curPts.clear();
            curPts.reserve(ppi.elementCount() - i);
            curPts.push_back(new p2t::Point(e.x, e.y));
        } else if (e.isLineTo()) {
            curPts.push_back(new p2t::Point(e.x, e.y));
        } else {
            qWarning("Unhandled element type in circle painterpath");
        }
    }

    if (curPts.size() > 0) {
        qDeleteAll(curPts.begin(), curPts.end());
        curPts.clear();
    }

    if (borderPts.size() > 0) {
        qDeleteAll(borderPts.begin(), borderPts.end());
        borderPts.clear();
    }

    screenBounds_ = ppiBorder.boundingRect();

}