OSG和osgearth显示中文(转载)
一、知识储备
要想很好的理解和解决这个问题,首先要了解什么是多字节和宽字节。说实话我之前也知道这两个字节到底有什么区别,只是简单查了一下资料。这里引用了这篇博客,我感觉博主写的很有意思,通俗易懂,在这里先谢谢这位博主的奉献。http://blog.163.com/baijianguo00@126/blog/static/1375326052011018101334714/
二、问题提出
在大致了解了什么是多字节和款字节之后,我们来看看具体的问题。osg是老外开发的源码,没办法对中文支持很差,虽然这一点儿也不能影响osg带给我们的快感,我们在使用osg中肯定会或多或少要显示中文,但是你会发现你按显示英文那样就做显示的都是乱码。比如我使用LableNode 加一个标记在地球上,如下
labelGroup->addChild( new PlaceNode(mapNode, GeoPoint(geoSRS, 117.5, 39.38), "北京" , pin));
labelGroup->addChild( new PlaceNode(mapNode, GeoPoint(geoSRS, -100.10, 40.60), "U.S.A" , flag));
这时发现北京显示的乱码,而“U.S.A”显示是正确的,还有我们在加载矢量的shp数据时,如果是地名标记数据,显示在地球上也是乱码,还用LableControl显示中文时也是一样的。这里有两种成功的方法,一、改源码;二、转换字符,其实这两种方法本质都是在显示中文时转换字符。改源码一劳永逸但是难度大有风险而且还要重新编译,鉴于此我还是推荐第二种方法-------在程序实时地转换字符。
三、解决方法
中文显示要用宽字节,这里提供几个转换函数。
函数一:
void unicodeToUTF8(const wstring &src, string& result)
{
int n = WideCharToMultiByte( CP_UTF8, 0, src.c_str(), -1, 0, 0, 0, 0 );
result.resize(n);
::WideCharToMultiByte( CP_UTF8, 0, src.c_str(), -1, (char*)result.c_str(), result.length(), 0, 0 );
}
函数二:
void gb2312ToUnicode(const string& src, wstring& result)
{
int n = MultiByteToWideChar( CP_ACP, 0, src.c_str(), -1, NULL, 0 );
result.resize(n);
::MultiByteToWideChar( CP_ACP, 0, src.c_str(), -1, (LPWSTR)result.c_str(), result.length());
}
当物在osg程序中显示汉字时,就如下调用上述两个函数即可,
void gb2312ToUtf8(const string& src, string& result)
{
wstring strWideChar;
gb2312ToUnicode(src, strWideChar);
unicodeToUTF8(strWideChar, result);
}
我们拿上面显示的北京标记的做例子,
Style pin;
pin.getOrCreate<IconSymbol>()->url()->setLiteral(m_PngFilepath);//指定标注图片路径
pin.getOrCreate<osgEarth::Symbology::TextSymbol>()->font()=m_FontFilepath;//指定中文字体路径
pin.getOrCreate<osgEarth::Symbology::TextSymbol>()->encoding() = osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
pin.getOrCreate<TextSymbol>()->alignment() = TextSymbol::ALIGN_CENTER_CENTER;
pin.getOrCreate<TextSymbol>()->fill()->color() = Color::Red;
std::string _strName;
_strName = "北京";
std::string _strWideName;
gb2312ToUtf8(_strName,_strWideName);//这时的_strWideName就是宽字节用来显示就正确了
labelGroup->addChild( new PlaceNode(mapNode, GeoPoint(geoSRS, 117.5, 39.38), _strWideName , pin));
显示地名标记和LableControl中的中文都是这个方法,先转换在显示。
最近在osg官网上发现osgEarth升级到2.2版了,看了发布说明,增加了不少新功能,所以赶紧把源码下下来,发现确实多了不少新功能,最大的升级是在对Qt的支持、墨卡托坐标系的支持,还多了不少例子。
但是我添加中文标注的矢量数据时,标注出现乱码的情况,经过对源码的研究,对源码进行了修改,标注的代码在AnnotationUtils类的CreateTextDrawable函数中的t->setText(string)代码,将该代码修改如下:
Setlocale(LC_ALL,"chs");
int wSize = text.size()*2+2;
wchar_t* wtext=new wchar_t[wSize+1];
memset(wtext,0,wSize+1);
mbstowcs(wtext,text.c_str(),wSize);
t->setText(wtext);
delete[] wtext;
wtext=NULL ;
/*2012年 最近在osg官网上发现osgEarth升级到2.2版了,看了发布说明,增加了不少新功能,所以赶紧把源码下下来,发现确实多了不少新功能,最大的升级是在对Qt的支持、墨卡托坐标系的支持,还多了不少例子。 但是我添加中文标注的矢量数据时,标注出现乱码的情况,经过对源码的研究,对源码进行了修改,标注的代码在AnnotationUtils类的CreateTextDrawable函数中的t->setText(string)代码,将该代码修改如下: */ Setlocale(LC_ALL,"chs"); +; wchar_t* wtext=]; memset(wtext,,wSize+); mbstowcs(wtext,text.c_str(),wSize); t->setText(wtext); delete[] wtext; wtext=NULL ; /* LabelControl中也存在类似问题,解决方法和标注一样,修改的函数为LabelControl::calcSize函数中修改即可。 */
//显示label的代码src\osgEarthUtil\Controls.cpp的524行,修改如下。 LabelControl::calcSize(const ControlContext& cx, osg::Vec2f& out_size) { if ( visible() == true ) { // we have to create the drawable during the layout pass so we can calculate its size. LabelText* t = new LabelText(); #if 1 // needs a special shader // todo: doesn't work. why? osg::Program* program = new osg::Program(); program->addShader( new osg::Shader( osg::Shader::VERTEX, s_controlVertexShader ) ); program->addShader( new osg::Shader( osg::Shader::FRAGMENT, s_labelControlFragmentShader ) ); t->getOrCreateStateSet()->setAttributeAndModes( program, osg::StateAttribute::ON ); #endif // chinese support.part1 begin 2011-11-14 setlocale( LC_ALL, "chs" ); ); wchar_t* wtext = ]; mbstowcs(wtext, _text.c_str(), requiredSize+); t->setText(wtext); delete [] wtext; wtext = NULL; // chinese support. part1 end 2011-11-14 // chinese support.part1 begin 2011-11-14 //t->setText( _text ); // chinese support. part1 end 2011-11-14 // yes, object coords. screen coords won't work becuase the bounding box will be wrong. t->setCharacterSizeMode( osgText::Text::OBJECT_COORDS ); t->setCharacterSize( _fontSize ); // always align to top. layout alignment gets calculated layer in Control::calcPos(). t->setAlignment( osgText::Text::LEFT_TOP ); t->setColor( foreColor().value() ); if ( _font.valid() ) t->setFont( _font.get() ); // chinese support.part1 begin 2011-11-14 setlocale( LC_ALL,"C" ); // chinese support. part1 end 2011-11-14 if ( haloColor().isSet() ) { t->setBackdropType( osgText::Text::OUTLINE ); t->setBackdropOffset( 0.03 ); t->setBackdropColor( haloColor().value() ); } osg::BoundingBox bbox = t->getTextBB(); if ( cx._viewContextID != ~0u ) { //the Text's autoTransformCache matrix puts some mojo on the bounding box osg::Matrix m = t->getATMatrix( cx._viewContextID ); _bmin = osg::Vec3( bbox.xMin(), bbox.yMin(), bbox.zMin() ) * m; _bmax = osg::Vec3( bbox.xMax(), bbox.yMax(), bbox.zMax() ) * m; } else { _bmin = osg::Vec3( bbox.xMin(), bbox.yMin(), bbox.zMin() ); _bmax = osg::Vec3( bbox.xMax(), bbox.yMax(), bbox.zMax() ); } _renderSize.set( (_bmax.x() - _bmin.x()) + padding().x(), (_bmax.y() - _bmin.y()) + padding().y() ); _drawable = t; out_size.set( margin().x() + _renderSize.x(), margin().y() + _renderSize.y() ); } else { out_size.,); } //_dirty = false; } //原因是读取字符串的时候就没有支持双字节的字节,如中文。
//osgEarth中设置显示中文的label CString mss = _T("中国"); std::string ss = osgDB::convertUTF16toUTF8(mss.AllocSysString()); // set up a style to use for labels: osgEarth::Annotation::Symbology::Style labelStyle; labelStyle.getOrCreate<TextSymbol>()->encoding() = TextSymbol::ENCODING_UTF8; labelStyle.getOrCreate<TextSymbol>()->font() = std::string("fonts/SimHei.ttf");
osgearth打开中文路径失败,若是驱动器为gdal时,大体是由于gdal无法打开中文文件所造成的,可进行一下设置:
用的是最新的GDAL1.9,GDAL中有一个函数CPLGetConfigOption( "GDAL_FILENAME_IS_UTF8", "YES" )判断,通过判断是否是UTF8的编码,而且指定的默认值还是UTF8编码,在含有中文路径的字符串大多数的编码应该是GBK的编码,这样,系统就将GBK的编码当做UTF8的编码来进行转换,结果就是汉字全部是乱码,导致的结果就是找不到文件,所以打不开。
解决方法:
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");
包含的头文件为:cpl_conv.h
osgEarth支持中文过程详解
为使osgEarth支持中文,需对osgEarthAnnotation源码做出改动,现将过程记录如下以供参考。
①参考PlaceNode的构造函数发现,源码中使用了Init函数,其中需要对添加注记的CreateTextDrawable函数进行重载,步骤如下:
在AnnotationUtils.h中声明重载函数:
static osg::Drawable* createTextDrawable( const std::wstring& text, //支持宽字符 const TextSymbol* symbol, const osg::Vec3& positionOffset ); 在AnnotationUtils.cpp中定义重载函数(直接复制原createTextDrawable函数,本文只展示修改部分): osg::Drawable* AnnotationUtils::createTextDrawable(const std::wstring& text, const TextSymbol* symbol, const osg::Vec3& positionOffset ) { .... t->setText( text.c_str()); .... }
②在对AnnotationUtils修改后需要对PlaceNode做出修改。
首先需要添加宽字符变量,以与之前字符变量区分,在PlaceNode.h中添加 std::wstring _wtext;
此外对涉及文本的函数都需要重载,需要重载的函数在PlaceNode.h声明如下:
PlaceNode( MapNode* mapNode, const GeoPoint& position, osg::Image* iconImage, const std::wstring& labelText, const Style& style =Style() ); PlaceNode( MapNode* mapNode, const GeoPoint& position, const std::wstring& labelText, const Style& style =Style() ); void initw(); 重载的函数在PlaceNode.cpp中定义如下(直接复制原函数,本文只展示修改部分): PlaceNode::PlaceNode(MapNode* mapNode, const GeoPoint& position, osg::Image* image, const std::wstring& text, const Style& style ) : OrthoNode( mapNode, position ), _image ( image ), _wtext ( text ), _style ( style ), _geode ( 0L ) { initw(); } PlaceNode::PlaceNode(MapNode* mapNode, const GeoPoint& position, const std::wstring& text, const Style& style ) : OrthoNode( mapNode, position ), _wtext ( text ), _style ( style ), _geode ( 0L ) { initw(); } void PlaceNode::initw() { .... if ( _wtext.empty() && _style.has() ) { _wtext =StringToWString(_style.get()->content()->eval_r()); } .... text = AnnotationUtils::createTextDrawable( _wtext, _style.get(), osg::Vec3( (offset.x() + (s / ), offset.y(), ) ); }
在重写initw函数时涉及string转wstring的问题,参考网上转换方法,虽然我也不知道如何实现转换功能,但是确实成功转换了,共享如下:
首先需要在PlaceNode.h中声明函数(当然也可以声明在别的头文件中,自己知道如何调用即可):
std::wstring StringToWString(const std::string& s);
由于该函数涉及系统函数,所以需要在PlaceNode.h中包含系统头文件:
#include <windows.h>
在PlaceNode.cpp中定义函数:
std::wstring PlaceNode::StringToWString(const std::string& s) { std::wstring wszStr; , s.c_str(), -, NULL, NULL ); wszStr.resize(nLength); LPWSTR lpwszStr = new wchar_t[nLength]; MultiByteToWideChar( CP_ACP, , s.c_str(), -, lpwszStr, nLength ); wszStr = lpwszStr; delete [] lpwszStr; return wszStr; }
③所有修改完成之后需要对osgEarthAnnotation进行重新编译,将新生成的lib以及dll文件放到对应位置,此外,由于对源码做出了改动,所以需要将修改后的源码放到include文件夹中。
④编写地标添加程序,需要注意的是一定要设置字体以及字体编码,具体如何实现添加地标不做详解。
osgEarth::Style style;
osgEarth::Symbology::TextSymbol *textStyle=style.getOrCreateSymbol();
textStyle->font()="simsun.ttc";
textStyle->size()=30.0;
textStyle->encoding()=osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
修改效果如下:
OSG和osgearth显示中文(转载)的更多相关文章
- [osg]osg显示中文信息
转自:http://www.cnblogs.com/feixiang-peng/articles/3152754.html 写好了在osg中实时显示中文信息的效果.中间遇到两个问题,一个是中文显示,一 ...
- cocos2d-x 显示中文字符和解析XML文件 转载
源地址:http://codingnow.cn/cocos2d-x/1038.html 在cocos2d-x中直接显示中文的时候会出现乱码,虽然在实际开发中把字符串直接写在代码里也不是好的做法,但是有 ...
- [转载]centos 6.4中git如何正常显示中文
FROM: http://ju.outofmemory.cn/entry/63250 系统版本:centos 6.4 git版本:1.7.1,使用yum直接安装的. 当使用git status查看时, ...
- JUCE 界面库显示中文乱码问题
JUCE 界面库显示中文乱码问题 环境: Windows7 64位 旗舰版 Visual Studio Ultimate 2012 JUCE 4.1 问题描述: 直接使用juce::String存储中 ...
- UIImagePickerController显示中文界面
iOS开发中,我们经常遇到获取拍照.相册中图片的功能,就必然少不了UIImagePickerController,但是我们发现当我们使用它的时候,它的页面是英文的,看着很别扭,国人还是比较喜欢看中文界 ...
- MicroPython之TPYBoard v102开发板控制OLED显示中文
转载请以链接形式注明文章来源,公众号:MicroPython玩家汇 0x00前言 之前看到一篇文章是关于TPYBoardv102控制OLED屏显示的,看到之后就想尝试一下使用OLED屏来显示中文.最近 ...
- osgearth显示中文标签
首先将带有中文的字符串转换成string void unicodeToUTF8(const wstring &src, string& result){int n = WideChar ...
- IDA pro 6.8显示中文字符串的方法
IDA pro 6.8设置显示中文字符串的方法 M4x原创,转载请表明出处http://www.cnblogs.com/WangAoBo/p/7636335.html IDA是一款强大无比的反编译软件 ...
- three.js 显示中文字体 和 tween应用
今天郭先生说一下如何在three中显示中文字体,然后结合tween实现文字位置的动画.线案例请点击博客原文. 1. 生成中文字体 我们都使用过three.js的FontLoader加载typeface ...
随机推荐
- Nginx 502/504 Gateway time-out错误完美解决方案【转发】
在安装完Nginx+PHP-fpm+Mysql后,跑PHP的应用会经常出现504 Gateway Time-out 或者502 Bad Gateway的情况. Nginx 504 Gateway ...
- java网络之udp
import java.net.*; /** * InetAddress用法 * 获取本地主机名,ip * 通过主机名,ip获取InetAddress对象 */ public class Demo{ ...
- 写入cookie后只显示一次的DIV提示框代码
<script type="text/javascript"> function cookiesave(n, v, mins, dn, path){ if(n) { i ...
- SQL模擬死結產生
引用自:http://jengting.blogspot.tw/2012/06/sql.html 根據 MSDN 將死結數量降至最低 裡的圖型模擬死結產生 ~~ 在 SSMS 內開啟兩個 T-SQL ...
- linux查看系统的硬件信息
linux查看系统的硬件信息,并不像windows那么直观,这里我罗列了查看系统信息的实用命令,并做了分类,实例解说. cpu lscpu命令,查看的是cpu的统计信息. blue@blue-pc:~ ...
- Unexpected exception 'Cannot run program ... error=2, No such file or directory' ... adb'
Eclipse ADT Unexpected exception 'Cannot run program' up vote 8 down vote favorite 4 I have installe ...
- PS2鼠标+LCD12864实验(调试未成功)
此试验我一人调试许久都未成功,但发送ff时,读出来的数据确是对的,一开始让我窃喜,但发送f4时,读出来的数据确是错的,哎让苦恼啊,能力有限,只能先暂时就这样吧,那位什么还要贴出来呢,有两个原因: 1. ...
- HDU 1540 POJ 2892 Tunnel Warfare
线段树 区间合并 单点修改 区间查询.又是1秒钟构思,差错查了好久... ... 发现一个int型的定义成了char型,打脸. #include <stdio.h> #include &l ...
- EasyUI中dialog中嵌入form细节问题记录
当代码如下: function myClear() { $("#add_form").form("reset"); $("#add_dialog&qu ...
- 搭建git服务器及利用git hook自动布署代码
注意:服务器:Ubuntu Server 14.04,我的项目比较小,所有操作都使用root,建议最好新建一个用户(需要有管理员权限,否则在后面使用hooks自动部署代码时会出现各种权限问题,很蛋疼的 ...