osgEarth中文显示乱码

系列文章目录

文章目录

前言

在 OpenSceneGraph 3.6.5 和 osgEarth 3.2 中,文本渲染统一使用 UTF‑8 编码。如果传入的字符串不是 UTF‑8(例如 Windows 下的 GBK/ANSI),就会出现乱码。要显示中文,必须保证传入的 std::string 是 UTF‑8,并且指定一个支持中文的字体文件(如 simsun.ttc、msyh.ttc)。否则会出现显示中文乱码的情况

一、osgEarth中文乱码的原因是什么?

在 osgEarth 三维地图中出现中文乱码,核心原因是文本编码转换错误或显示端编码不匹配,具体可分为以下几点:

1.源文件编码与 Qt 字符串处理不匹配若项目源文件(如.cpp)使用 GBK 编码(非 UTF-8),在 Qt 中直接定义中文字符串(如QString text = "中文标签")时,Qt 会默认将其按源文件编码(GBK)解析为 Unicode 字符。但由于编码解析错误,QString内部可能存储的是乱码的 Unicode 数据,后续转换为 UTF-8 时自然会出现乱码。

2.osgEarth 文本显示编码未明确指定osgEarth 的TextSymbol默认编码可能不支持 UTF-8,若未显式设置encoding()为ENCODING_UTF8,即使传入的字符串是正确的 UTF-8 格式,osgEarth 也可能用其他编码(如 ASCII)解析,导致中文无法识别。

3.缺少中文字体支持若 osgEarth 使用的字体不包含中文字符集(如默认的英文字体),即使编码正确,中文也会显示为方块或空白(本质是 "无法渲染" 而非 "乱码",但常被归为同类问题)。

二、解决方法

解决方法总结

针对上述原因,代码中采用了以下解决方案,可彻底解决中文乱码问题:

修复源文件编码导致的字符串乱码若源文件为 GBK 编码,需先将错误解析的QString还原为正确的 Unicode 字符串,再转换为 UTF-8:

用QTextCodec::codecForName("GBK")获取 GBK 编码器;

通过fromUnicode(text)提取原始 GBK 字节(还原源文件编码的字节流);

用toUnicode(gbkBytes)重新解析为正确的 Unicode 字符串;

最终通过toStdString()转换为 UTF-8 格式的std::string,供 osgEarth 使用。

显式指定 osgEarth 文本编码为 UTF-8在TextSymbol中明确设置编码,确保 osgEarth 用 UTF-8 解析文本:

cpp

运行

osgEarth::TextSymbol* ts = style.getOrCreateSymbolosgEarth::TextSymbol();

ts->encoding() = osgEarth::TextSymbol::ENCODING_UTF8; // 强制UTF-8编码

确保使用支持中文的字体(补充建议)代码中注释了字体路径设置,实际使用时需指定包含中文字符的字体(如 "微软雅黑""黑体" 等):

cpp

运行

QString fontPath = QCoreApplication::applicationDirPath() + "/fonts/simhei.ttf"; // 黑体字体

ts->font() = fontPath.toStdString(); // 关联字体文件

通过以上步骤,可确保中文从 "字符串定义" 到 "osgEarth 渲染" 的全流程编码一致,彻底解决乱码问题。

cpp 复制代码
osg::ref_ptr<osgEarth::PlaceNode> AmainWidget::createLabel(const QString& text, double lon, double lat)
{
	const osgEarth::SpatialReference* wgs84 = osgEarth::SpatialReference::get("wgs84");
	osgEarth::GeoPoint geoPoint(wgs84, lon, lat, 0.0, osgEarth::ALTMODE_RELATIVE);


	// 调试输出(保留,用于验证编码)
	qDebug() << QString::fromLocal8Bit("[QString原始内容]:") << text;
	qDebug() << QString::fromLocal8Bit("[QString长度]:") << text.length();
	QByteArray utf8Bytes = text.toUtf8();
	qDebug() << QString::fromLocal8Bit("[UTF-8字节数]:") << utf8Bytes.size();
	qDebug() << QString::fromLocal8Bit("[UTF-8十六进制]:") << utf8Bytes.toHex();


	// 修正:正确的编码转换逻辑(解决QByteArray::toUtf8()错误)
	std::string utf8Text;

	// 情况1:若原始QString因源文件GBK编码导致内部乱码(常见于非UTF-8源文件)
	QTextCodec* gbkCodec = QTextCodec::codecForName("GBK");
	if (gbkCodec) {
		// 步骤1:将GBK编码的字节(错误解析的QString)还原为正确的Unicode QString
		// (原理:假设text内部是GBK字节误解析为Unicode,先提取GBK字节,再重新解析为Unicode)
		QByteArray gbkBytes = gbkCodec->fromUnicode(text); // 提取GBK字节
		QString correctText = gbkCodec->toUnicode(gbkBytes); // 用GBK重新解析为正确的QString

		// 步骤2:将正确的QString转为UTF-8的std::string
		utf8Text = correctText.toStdString(); // 用toUtf8()而非toLocal8Bit()
	}
	else {
		// 情况2:正常情况,直接转换
		utf8Text = text.toUtf8().toStdString();
	}


	// 验证转换结果
	qDebug() << QString::fromLocal8Bit("[转换后std::string]:") << QString::fromUtf8(utf8Text.c_str());


	// 创建 PlaceNode 及样式设置(保持不变)
	osg::ref_ptr<osgEarth::PlaceNode> placeNode = new osgEarth::PlaceNode(geoPoint, utf8Text);
	osgEarth::Style style;
	osgEarth::TextSymbol* ts = style.getOrCreateSymbol<osgEarth::TextSymbol>();
	ts->size() = osgEarth::NumericExpression("18");
	ts->fill()->color() = osgEarth::Color::Yellow;
	ts->halo()->color() = osgEarth::Color::Black;
	ts->alignment() = osgEarth::TextSymbol::ALIGN_CENTER_CENTER;
	QString fontPath = QCoreApplication::applicationDirPath() + "/fonts/simhei.ttf";
	ts->font() = fontPath.toStdString(); // 确保字体文件存在
	ts->encoding() = osgEarth::TextSymbol::ENCODING_UTF8; // 明确UTF-8编码

	placeNode->setStyle(style);

	return placeNode;
}

三、结果

相关推荐
扶尔魔ocy3 天前
【qt openGL入门笔记】windows编译MinGW版本的osgearth(2.10.1)
qt·opengl·osg
扶尔魔ocy4 天前
【QT OpenGL】知识点编目及传送门
qt·opengl·osg
扶尔魔ocy16 天前
【qt openGL入门笔记】OSG实现飞机模型在网格图上飞行并进行态势标绘(四)
qt·opengl·osg
扶尔魔ocy19 天前
【qt openGL入门笔记】OSG实现显示飞机模型飞行的点迹(二)
qt·opengl·osg
扶尔魔ocy19 天前
【qt openGL入门笔记】OSG实现飞机模型在网格图上飞行(三)
opengl·osg
扶尔魔ocy20 天前
【qt openGL入门笔记】OSG实现飞机模型在网格图上飞行
qt·opengl·osg
Being--3 个月前
搭建OsgEarth验证GIS数据发布服务的Agent
gis·agent·osgearth·ai落地
directx3d_beginner8 个月前
10,cookbook的lod示例
osg
directx3d_beginner8 个月前
8,将0级简模文件和精模文件同时放入pagedlod
osg
directx3d_beginner8 个月前
9,0级建模文件和0级精模文件写成根节点
osg