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 ...
随机推荐
- JavaBean--简介及基本使用
JavaBean本身就是一个类,属于java的面向对象编程 JavaBean是使用java语言开发的一个可重用的组建,在JSP开发中如果要应用JSP提供的JavaBean标签来操作简单的类的话,需要满 ...
- Vsftp配置都没有问题 连接不上 530 Login incorrect 解决方法
客户端输入正确的用户名和密码之后,却一直显示:530 Login incorrectLogin Failed后来发现在etc下面有个pam.d文件夹进去打开vsftpd这个文件, 发现里面对之前的用户 ...
- C++零食:使用Unicode版的预定义宏__FUNCTION__
在C++中支持一种预定义宏.比如: __FILE__: 就是当前源代码文件名 __LINE__: 就是当前源代码的行号 这些宏可以在printf等语句中直接作为字符串使用,调试的时候很方便. 如下代码 ...
- MOSFET与MOSFET驱动电路原理及应用(转)
源:http://www.micro-bridge.com/news/news.asp?id=258 在使用MOS管设计开关电源或者马达驱动电路的时候,大部分人都会考虑MOS的导通电阻,最大电压等,最 ...
- zf-关于平台的用户名密码的设置
比如说安徽桐城的用户名密码在哪张表里设置 桐城市人民统一电子政务平台是http://localhost:8088/tc/ptzwfw.action 这个链接 在zwfw_tc 数据库的 PT_LOGI ...
- Sasha and Array
Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input standard inp ...
- 自动获取访客QQ
http://jerring.cn/bizqq/index.html http://www.oicqzone.com/qqjiqiao/2015072322139.html
- css3的apprearance属性(转)
appearance使用方法: .elmClass{ -webkit-appearance: value; -moz-appearance: value; appearance: value; } 接 ...
- higncharts 编辑Highcharts.com链接
credits: { text: 'Example.com', href: 'http://www.example.com' }, 只 ...
- 关于go的不爽
这里想记录下,自己学习.使用go语言,对于go语言不爽的地方. 1. 函数返回类型接在参数类型后面,不容易一眼看清楚函数的返回类型 如下,是不是有种很花的感觉. func NewReader(s st ...