有关 QML QtLocation 的 Plugin 的使用问题



  • 这个 Plugin 是可以提供具体地图的地图在线插件,使用方法是:

    qml

    Plugin {
        name: "here"
        PluginParameter { name: "here.app_id"; value: "myapp" }
        PluginParameter { name: "here.token"; value: "abcdefg12345" }
    }
    

    c++

    QMap<QString,QVariant> params;
    params["here.app_id"] = "myapp";
    params["here.token"] = "abcdefg12345";
    
    QGeoServiceProvider *gsp = new QGeoServiceProvider("here", params);
    

    然后将其设置给 Map,用来显示实际的地图。

    然后 Qt 提供了三个内建的地图在线插件 hereosmmapbox三个,但是我们身处中国,自然有自己的在线地图,例如百度地图。

    这里的问题是,怎么把百度的在线地图封装成 QML 的地图在线插件?


  • 网站研运

    百度地图在中国范围内是最全的,不过呢,这里面的技术是他们的,目前提供了JS的API,不知道可不可以和Qt相结合。



  • @jcy

    http://lbsyun.baidu.com/index.php?title=webapi

    看来应该是可以的。

    另外 Qt5.5.1\5.5\Src\qtlocation\src\plugins\geoservices\nokia 这个路径下有 here 地图的封装实现。我不知道有没有人去研究过。


  • 网站研运

    @qyvlik 好像OpenStreetMap是可用的吧。



  • @jcy 其他的,例如 here 还有 mapbox 要设置 appid 和密钥。


  • 网站研运

    @qyvlik here是商业的,好像现在我们访问不了吧,被收购了。访问http://heremaps.cn,直接跳转了,没办法打开地图。mapbox未知。



  • @jcy 嘿,时隔这么久。我开始尝试使用 Qt 的地图插件将高德地图进行集成,现在遇到了一些难题。

    参考原型是 mapbox,但是发现这个原型对高德的 web 服务接口并不适合。现在尝试更换到 osm 这个插件。

    如下为运行的效果:

    0_1464873914645_U~G7)BP_1HIF0407S{TR0)B.png

    0_14648739g

    下面是参考资料。

    Slippy map tilenames(瓦片和经纬度换算)

    由经纬度计算Google卫星地图中瓦片Tile的地址

    百度与谷歌地图瓦片组织方式对比 (修正)!


  • 网站研运

    @qyvlik 这个好诡异!为什么Qt公司的位置在北京和非洲呢?
    是不是我们需要将The Qt Company移除呢?



  • @jcy 由于 Qt 的地图框架使用成熟的瓦片地图。

    OpenStreetMap/Google/百度/Bing瓦片地图服务(TMS)

    开源与成熟商业的瓦片地图服务(TMS 2 WMTS),都有如下共同的特性,基本成为了标准:
    (1) 坐标系:WGS84
    (2) 投影:墨卡托投影(Marcator,正轴等角圆柱投影)

    但是高德地图使用的坐标系是火星坐标系,Qt地图框架会以 WGS84 的瓦片坐标进行请求,在进行换算后,获取到的瓦片地图仍然有很多问题,获取不准确。

    一下为换算的代码:

    static double a = 6378245.0;
    static double ee = 0.00669342162296594323;
    
    static bool outOfChina(double lat, double lon) {
        if (lon < 72.004 || lon > 137.8347)
            return true;
        if (lat < 0.8293 || lat > 55.8271)
            return true;
        return false;
    }
    
    static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
                + 0.2 * std::sqrt(std::abs(x));
        ret += (20.0 * std::sin(6.0 * x * M_PI) + 20.0 * std::sin(2.0 * x * M_PI)) * 2.0 / 3.0;
        ret += (20.0 * std::sin(y * M_PI) + 40.0 * std::sin(y / 3.0 * M_PI)) * 2.0 / 3.0;
        ret += (160.0 * std::sin(y / 12.0 * M_PI) + 320 * std::sin(y * M_PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }
    
    static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
                * std::sqrt(std::abs(x));
        ret += (20.0 * std::sin(6.0 * x * M_PI) + 20.0 * std::sin(2.0 * x * M_PI)) * 2.0 / 3.0;
        ret += (20.0 * std::sin(x * M_PI) + 40.0 * std::sin(x / 3.0 * M_PI)) * 2.0 / 3.0;
        ret += (150.0 * std::sin(x / 12.0 * M_PI) + 300.0 * std::sin(x / 30.0
                                                                     * M_PI)) * 2.0 / 3.0;
        return ret;
    }
    
    static std::tuple<double, double> wgs84_To_Gcj02(double lat, double lon) {
        if (outOfChina(lat, lon)) {
    
            return std::tuple<double, double>(0, 0);
        }
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * M_PI;
        double magic = std::sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = std::sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * M_PI);
        dLon = (dLon * 180.0) / (a / sqrtMagic * std::cos(radLat) * M_PI);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;
        return std::tuple<double, double>(mgLat, mgLon);
    }
    
    // wgs84
    
    static int long2tilex(double lon, int z)
    {
        return (int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));
    }
    
    static int lat2tiley(double lat, int z) {
        return (int)(floor((1.0 - log( tan(lat * M_PI/180.0) + 1.0 / cos(lat * M_PI/180.0)) / M_PI) / 2.0 * pow(2.0, z)));
    }
    
    static double tilex2long(int x, int z)
    {
        return x / pow(2.0, z) * 360.0 - 180;
    }
    
    static double tiley2lat(int y, int z)
    {
        double n = M_PI - 2.0 * M_PI * y / pow(2.0, z);
        return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
    }
    

    通过换算代码,获取到瓦片的xyz,然后拼接 url,然后请求这个 url 所指向的图片。

    QGeoTiledMapReply *QGeoTileFetcherAMap::getTileImage(const QGeoTileSpec &spec)
    {
        QNetworkRequest request;
    
        /*
        http://restaM_PI.amap.com/v3/staticmap
        ?location=116.481485,39.990464
        &zoom=10
        &size=750*300
        &key=ee95e52bf08006f63fd29bcfbcf21df0
        */
    
        std::tuple<double, double> gcj02 = wgs84_To_Gcj02(-tiley2lat(spec.y(), spec.zoom()),-tilex2long(spec.x(), spec.y()));
    
        qDebug() << -tiley2lat(spec.y(), spec.zoom())
                 << -tilex2long(spec.x(), spec.y())
                 << std::get<0>(gcj02)
                 << std::get<1>(gcj02);
    
        QString latitude = QString::number(std::get<0>(gcj02));
        QString longitude = QString::number(std::get<1>(gcj02));
        QUrl url = QUrl(QStringLiteral("http://restaM_PI.amap.com/v3/staticmap") +
                        "?zoom=" + QString::number(spec.zoom()) +
                        "&size=" + QString::number(tileSize.width())+ "*" + QString::number(tileSize.height()) +
                        // "&location=" + QString::number(location.longitude()) +"," + QString::number(location.longitude()) +
                        "&location=" + latitude + "," + longitude +
                        "&key="+key
                        );
    }
    

    但是还是无法正确获取到高德的瓦片地图。


  • 网站研运

    @qyvlik 我觉得应该有一个高手会这部分,我可以引入他来一同做好这件事儿。



  • @qyvlik 坐标系不同导致的问题,可以看看这个有无帮助,
    起码转换后的坐标是匹配的坐标转换



  • @taadis 主要还是高德地图还未推出瓦片地图,还没有相关文档。





  • 查QML MAP问题正好查回论坛,真是缘分。目前不支持百度地图有点麻烦,准备找点webview控件绕过去,期待你们的更新。



  • 目前除了百度地图外,高德等其它地图是支持的,不过官方默认的配置是不支持的,需要自己重载里面的部分算法实现,这方面可以参看开源的Qgroundcontrol里面的qtlocaltion模块;



  • 隔了这么久,看看这个

    vladest/googlemaps

    QtLocation plugin for Google maps tile API

    有人封装了谷歌地图的 API

    vladest/Bing

    Bing plugin for QtLocation module

    还有bing的。。

    vladest/TomTom

    QtLocation TomTom plugin

    vladest好厉害



  • @qyvlik 这个就是Qt Location中使用谷歌地图的吧。不过不清楚这个会不会在国内无法使用呢?



  • 国内的百度地图,腾讯地图的瓦片接口,现在只找到一些支离破碎的信息

    搜搜地图服务示例

    以及这个~

    腾讯与百度地图瓦片规则分析



  • @qyvlik 谢谢无私的分享,这些以后在制作地图插件的时候肯定有用的!



  • 之前做过离线地图和瓦片获取这块,实现的是Google、bing、腾讯、osm、雅虎之类,原理就是墨卡托结构,网上都有。
    建议使用的是qmapcontrl、opmapcontrol、QGIS、qt location实现。
    正计划写实现方法博客,但又感觉太low了,应该没人看。。。
    对了,附一张图吧。![alt text](image url),怎么上传呢,不会,算了。。。


登录后回复
 

与 萌梦社区 的连接断开,我们正在尝试重连,请耐心等待