问题的提出:
当按如下代码,在地图画布插入底图和自己业务形成的矢量图层:
CExquisiteGIS:: CExquisiteGIS()
{
loadBaseMap(); // 加载底图
addVectorLayer(); // 加载业务图层
}
// 加载业务图层
void CExquisiteGIS::addVectorLayer()
{
// 创建一个基于WSG84坐标系的点的矢量图层,点的数据来自内存,而不是文件或数据库
QgsVectorLayer* pLayer = new QgsVectorLayer("Point?crs=epsg:4326&", "Point", "memory", QgsVectorLayer::LayerOptions(QgsCoordinateTransformContext()));
if ((nullptr == pLayer) || !pLayer->isValid())
{
Q_ASSERT(0);
return;
}
pLayer->startEditing();
QgsPointXY pt(116.9444, 40.5274); // 北京密云水库中的某个点
QgsGeometry ptGeometry = QgsGeometry::fromPointXY(pt); // 将该点转为QGIS的点
QgsFeature feature;
feature.setGeometry(ptGeometry);
auto bb = pLayer->addFeature(feature); // 将该点加入到矢量图层
QVariantMap varMap;
varMap["size"] = 10.0; // 点的大小为10
varMap["color"] = "0,255,0"; // 点的颜色为绿色
auto symbol = QgsMarkerSymbol::createSimple(varMap);
auto renderer = new QgsSingleSymbolRenderer(symbol); // 设置点的渲染器
pLayer->setRenderer(renderer);
m_lstLayers.append(pLayer);
//m_lstLayers.move(1, 0);
m_pMapCanvas->setLayers(m_lstLayers);
m_pMapCanvas->setCurrentLayer(pLayer);
m_pMapCanvas->zoomToProjectExtent();
auto b = pLayer->commitChanges();
m_pMapCanvas->refresh();
}
void CExquisiteGIS::loadBaseMap()
{
auto pBaseMapLayer = .......... // 这里加载中华人民共和国版图作为底图,暂略。
auto baseMapExtent = pBaseMapLayer->extent();
m_pMapCanvas->setExtent(baseMapExtent);
m_lstLayers.append(pBaseMapLayer);
m_pMapCanvas->setLayers(m_lstLayers);
m_pMapCanvas->zoomToFullExtent();
}
上述代码中的m_pMapCanvas是QgsMapCanvas类对象的指针,也即地图画布;m_lstLayers是QList<QgsMapLayer*>类型。执行上述代码,当底图未放大时,效果如下:
当底图放大时,效果如下:
上面代码是先加载底图后加载业务图层,按理说业务图层应该在底图上面的,但可以发现,底图图层 pBaseMapLayer对象把业务图层(绿色圆点所在图层)完全遮挡了,这不是我们想要的结果,我们想要的结果是绿色圆点紧贴在底图即中国版图的北京市密云水库,即绿色圆点在底图上面而不是底图的后面
。即如下那样的效果:
解决方法如下:
第1种方法:将上面第37行的
m_lstLayers.move(1, 0);
取消注释。
第2种方法:加载图层时,将位于最顶部的图层先加载,位于最底部的图层最后加载,即本例中,在构造函数中将第3行和第5行代码交换位置即可。
QList类的move实现底图和业务图层在地图画布上位置交换,也就是说如果需要图层位于画布最上面,则该图层必须位于m_lstLayers第0个索引处,也就是说m_lstLayers列表中的图层索引越小,越位于画布最上层;m_lstLayers列表中的图层索引越大,越位于画布最底层。可以基于这一规则,当所有图层加载后,对图层列表m_lstLayers进行排序后再传入地图画布QgsMapCanvas类的setLayers方法。