QGraphicsView实现简易地图5『经纬网格』

前文链接:QGraphicsView实现简易地图4『局部加载-地图漫游』
由于GCJ02 Web 墨卡托投影 纬度并不随像素等分,且两极跨度较大,因此本次演示采用的经纬网等分逻辑为等分像素。同等像素跨度之间,两级纬度变化较小,越靠近赤道附近纬度变化越大。以下将提供实现此需求的核心代码。
1、动态演示效果

2、静态展示图片

核心代码

void MapView::showGraticules()
{
	// 计算等分像素后的经纬度步长
	int gridCount = MapUtility::graticulesGridCount(m_curLevel);
	int mapSideCount = apUtility::mapSideCount(m_curLevel);
	double perLon = PIXMAP_SIZE * mapSideCount * 1.0 / gridCount;
	double perLat = perLon;

	// 计算呈现的瓦片地图左上角和右下角的场景坐标
	QPoint topLeftScenePos(m_topLeftTileCoord.x * PIXMAP_SIZE, m_topLeftTileCoord.y * PIXMAP_SIZE);
	QPoint bottomRightScenePos((m_bottomRightTileCoord.x + 1) * PIXMAP_SIZE, (m_bottomRightTileCoord.y + 1) * PIXMAP_SIZE);
	// 计算经纬线覆盖范围,此处采用的逻辑是经纬网覆盖区域>=呈现的瓦片地图区域
	int leftGridIndex = qFloor(topLeftScenePos.x() / perLon);
	int rightGridIndex = qCeil(bottomRightScenePos.x() / perLon);
	int topGridIndex = qFloor(topLeftScenePos.y() / perLat);
	int bottomGridIndex = qCeil(bottomRightScenePos.y() / perLat);
	if (leftGridIndex < 0)
		leftGridIndex = 0;
	if (rightGridIndex > gridCount)
		rightGridIndex = gridCount;
	if (topGridIndex < 0)
		topGridIndex = 0;
	if (bottomGridIndex > gridCount)
		bottomGridIndex = gridCount;

	// 视口宽度和高度
	int vw = viewport()->width();
	int vh = viewport()->height();
	// 场景宽度和高度
	int sw = MapUtility::sceneSize(m_curLevel);
	int sh = sw;
	// 视口右下角对应场景坐标
	QPointF bottomRightViewToScenePos = mapToScene(viewport()->rect().bottomRight());
	// 经纬网线条颜色、文本颜色
	QColor gridLineColor(255, 163, 70);
	QColor textColor(Qt::white);
	
	// 绘制经纬网:纬度线
	for (int row = topGridIndex; row <= bottomGridIndex; ++row)
	{	
		// 纬度线
		double sceneY = row * perLat;
		QGraphicsLineItem *item = m_scene->addLine(topLeftScenePos.x(), sceneY, bottomRightScenePos.x(), sceneY);
		item->setPen(QPen(gridLineColor, 1, Qt::DotLine));
		item->setZValue(50);
		m_vecGraticulesItems.append(item);
		// 纬度文本
		double lat = MapUtility::latFromSceneY(sceneY, m_curLevel);
		QGraphicsTextItem *textItem = m_scene->addText(CommonUtility::convertToDMSLatSymbol(lat));
		textItem->setDefaultTextColor(Qt::white);
		QFont font = textItem->font();
		font.setFamily("微软雅黑");
		textItem->setFont(font);
		// 调整文本位置
		QRectF textBoundingRect = textItem->boundingRect();
		int sceneX = sw <= vw ? bottomRightScenePos.x() : bottomRightViewToScenePos.x();
		textItem->setPos(sceneX - textItem->boundingRect().width(), sceneY - textBoundingRect.height() / 2);
		m_vecGraticulesTextItems.append(textItem);
	}

	// 绘制经纬网:经度线
	for (int col = leftGridIndex; col <= rightGridIndex; ++col)
	{
		// 经度线
		double sceneX = col * perLon;
		QGraphicsLineItem *item = m_scene->addLine(sceneX, topLeftScenePos.y(), sceneX, bottomRightScenePos.y());
		item->setPen(QPen(gridLineColor, 1, Qt::DotLine));
		item->setZValue(50);
		m_vecGraticulesItems.append(item);
		// 经度文本
		double lon = MapUtility::lonFromSceneX(sceneX, m_curLevel);
		QGraphicsTextItem *textItem = m_scene->addText(CommonUtility::convertToDMSLonSymbol(lon));
		textItem->setDefaultTextColor(Qt::white);
		QFont font = textItem->font();
		font.setFamily("微软雅黑");
		textItem->setFont(font);
		// 调整文本位置
		QRectF textBoundingRect = textItem->boundingRect();
		int sceneY = sh <= vh ? bottomRightScenePos.y() : bottomRightViewToScenePos.y();
		textItem->setPos(sceneX - textBoundingRect.width() / 2, sceneY - textItem->boundingRect().height());
		m_vecGraticulesTextItems.append(textItem);
	}
}

辅助代码

void CommonUtility::convertToDMS(double value, int &d, int &m, int &s)
{
	d = (int)(value);                       
	m = (int)((value - d) * 60);
	s = (int)(((value - d) * 60 - m) * 60);
	
	// 四舍五入
	float e = ((value - d) * 60 - m) * 60 - s;
	if (5 <= (int)(e * 10))
		s += 1;

	// 秒进位
	if (60 == s)
	{
		s = 0;
		m += 1;
	}

	// 分进位
	if (60 == m)
	{
		m = 0;
		d += 1;
	}
}

QString CommonUtility::convertToDMS(double value)
{
	int d, m, s;
	convertToDMS(value, d, m, s);
	QString strM = QString::number(m).rightJustified(2, '0');
	QString strS = QString::number(s).rightJustified(2, '0');

	return QString("%1°%2′%3″").arg(d).arg(strM).arg(strS);
}

QString CommonUtility::convertToDMSLonSymbol(double value)
{
	return QString("%1%2").arg(convertToDMS(fabs(value))).arg(value > 0 ? "E" : (value != 0 ? "W" : ""));
}

QString CommonUtility::convertToDMSLatSymbol(double value)
{
	return QString("%1%2").arg(convertToDMS(fabs(value))).arg(value > 0 ? "N" : (value != 0 ? "S" : ""));
}

你可能感兴趣的:(地图,qt,c++)