osgearth 中文顯示
1、osgearth 有關中文路徑問題
轉自:http://blog.sina.com.cn/s/blog_803fc5eb0100yqrc.html
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
2、有關osgearth緩存文件命名的問題
轉自:http://blog.sina.com.cn/s/blog_803fc5eb0100yqr3.html
當設置緩存文件類型為filesystem 時,進行以下設置:
<layer name="something" cacheid="something" ...>
此時,緩存文件名為"something_xxxxx"
若是在代碼中,進行以下設置:
sgEarth::Drivers::GDALOptions opt;
opt.url() = filePath;
opt.maxDataLevel() = 14;
opt.tileSize()=256;
osgEarth::ImageLayerOptions layerOpt(name, opt);
layerOpt.cacheId() = "my_cache_id";
ImageLayer* layer = new osgEarth::ImageLayer(layerOpt);
3、中文顯示
轉自:http://blog.sina.com.cn/s/blog_803fc5eb01012q66.html
BOOL StringToWString(const std::string &str,std::wstring &wstr)
{
int nLen = (int)str.length();
wstr.resize(nLen,L' ');
int nResult = MultiByteToWideChar(CP_ACP,0,(LPCSTR)str.c_str(),nLen,(LPWSTR)wstr.c_str(),nLen);
if (nResult == 0)
{
return FALSE;
}
return TRUE;
}
std::string convertUTF16toUTF8(const wchar_t* source, unsigned sourceLength)
{
if (sourceLength == 0)
{
return std::string();
}
int destLen = WideCharToMultiByte(CP_UTF8, 0, source, sourceLength, 0, 0, 0, 0);
if (destLen <= 0)
{
OSG_WARN << "Cannot convert UTF-16 string to UTF-8." << std::endl;
return std::string();
}
std::string sDest(destLen, '\0');
destLen = WideCharToMultiByte(CP_UTF8, 0, source, sourceLength, &sDest[0], destLen, 0, 0);
if (destLen <= 0)
{
OSG_WARN << "Cannot convert UTF-16 string to UTF-8." << std::endl;
return std::string();
}
return sDest;
}
std::string convertUTF16toUTF8(const std::wstring& s){return convertUTF16toUTF8(s.c_str(), s.length());}
1、先從string轉為wstring;
2、從wstring轉為string;
即為 wstring wstr;
StringToWString(str, wstr);
string r = convertUTF16toUTF8(wstr);
osgText::Text text = new osgText::Text();
text->setText(r, osgText::String::ENCODING_UTF8);
4、osg、osgearth和qt中文顯示
轉自:http://blog.sina.com.cn/s/blog_6c922b4501014469.html
Q:同時導入多個模型,想鼠標點擊其中的一個,使其高亮顯示,並且可以單獨控制該模型移動(如拖動或擺動等),怎么可以實現
A:方法有很多,例如設置顏色數組,材質,或者用着色器等
計算鼠標的偏移,相應事件中重繪模型,但是效率可能比較低
單擊-射線求交,通過鼠標Drag消息計算平移,賦到上層transform結點,不就完了。
使用osg中的自帶的drag拖拽器就可以完成場景模型的拖動功能。
Q:求教:一個模型的不同部件,如何顯示鼠標所指位置模型不同部件的名稱?有什么好的方法?
A:直接求交,從交集的nodepath里找
如果你的一個部件就是一個node的話,那么從交集的nodepath里就可以確定。
交集的nodepath保存了從相交的drawable開始到root的父節點鏈
所有部件屬於同一模型,同一Node該怎么辦呢? 拆!
我試過FLT文件可以通過交集測試獲取模型的部件
Q:請問如何在漫游中能像默認操作器那樣用鼠標拖拽模型?
A:拖曳的識別是通過GUIEventHandler中的DRAG事件來完成的
解決QT中文字符串在osg中顯示亂碼的問題
網上有很多例子,但是幾乎都沒有正常顯示中文,經過痛苦的試驗和折磨,終於解決了QT字符串在osg中的正常顯示問題,下面貼出主要
代碼,分享給大家。
QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
QTextCodec* code = QTextCodec::codecForName("UTF-8");
QString qstr = QObject::tr("中國");
string str = code->fromUnicode(qstr).data();
osgText::Text* text = new osgText::Text;
textOne->setFont("C:/WINDOWS/Fonts/STSONG.ttf");//設置中文字體
text->setText(str, osgText::String::ENCODING_UTF8);
Q:關於Google earth影像坐標准不准?
http://bbs.esrichina-bj.cn/ESRI/viewthread.php?action=printable&tid=78315
http://topic.csdn.net/u/20100412/13/d81d7f70-c82c-4e71-883c-77555aee5c74.html
Q:模型的朝向
elevationManager.getPlacementMatrix(geoPoint.x(),geoPoint.y(),10.0,0.0,NULL,n_matrix,elevationInMap,resolution);
要設一個節點來專門調整模型的朝向
一開始模型太小了
轉自:http://blog.csdn.net/l_andy/article/details/44204741
做osg相關的項目有一段時間了,一直想寫幾篇這方面的博文,今天終於開始了。今天主要介紹一下怎么解決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中的中文都是這個方法,先轉換在顯示。
注明:這些方法都是在看了許多例子和博客的才解決的問題,其實我沒什么創新只是整合了一下供大家參考,在這里感謝那些大牛們的無私奉獻。
方法一:
通過自己寫函數轉換類型。
下面這三個函數先復制過去吧。
void unicodeToUTF8(const std::wstring &src, std::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 std::string& src, std::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());
}
void gb2312ToUtf8(const std::string& src, std::string& result)
{
std::wstring strWideChar;
gb2312ToUnicode(src, strWideChar);
unicodeToUTF8(strWideChar, result);
}
接下來把需要顯示的中文進行如下轉換便可以使用了。
std::string _strName;
_strName = "你好";
std::string _strWideName;
gb2312ToUtf8(_strName,_strWideName)
-------------等等還是亂碼。好吧的確有可能還是亂碼,這里需要設置字體樣式:
Style pin;
pin.getOrCreate<IconSymbol>()->url()->setLiteral("D:/osgearth/OSGOK/data/placemark32.png");//指定標注圖片路徑
pin.getOrCreate<osgEarth::Symbology::TextSymbol>()->font()="C:/Windows/Fonts/simhei.ttf";//指定中文字體路徑
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;
root->addChild( new PlaceNode(mapNode, GeoPoint(mapNode->getMapSRS(), 117.5, 39.38), _strWideName , pin));
把這個字體樣式加上就可以成功顯示中文了,好了吧。
方法二:
這是一種很酷炫的方法(其實跟方法二差不多啦)。
方法就是利用Qt的函數來處理中文,代碼很簡單,如下:
QString name="你好";
std::string _strWideName = std::string(name.toUtf8());
--------------等等別忘記額,這種方法任然需要設置字體樣式(跟方法二相同)。
方法三:
修改源碼重新編譯。好吧,這種方式一勞永逸(網上有很多重新編譯的需要修改源碼的案例),這里我就不多做累述。
無圖無真相:
摘要:
使用osgearth的人越來越多,開源的工程大家都喜歡。
osgearth的底層引擎是OSG,OSG中文支持良好,但osgearth里面直接舍棄了wstring,中文沒法顯示,讓很多程序員很蛋疼。
很多情況下載osgearth當中使用中文可能僅僅是為了添加個地標。這里就針對地標做中文支持,修改源碼又不是一個好的方式,這里就使用的繼承的方法來實現。有興趣的朋友拿走。
參考:http://blog.sina.com.cn/s/blog_7cdaf8b60102v21q.html
這里表示感謝!!
我封裝了兩個類來實現,其實一個類也可以,這里為了使繼承關系保持清晰,使用了兩個
下面直接粘貼代碼:
類1:AnnotationUtilsEXP
頭文件:AnnotationUtilsEXP.h
#ifndef ANNOTATION_UTILS_EXP_H_ #define ANNOTATION_UTILS_EXP_H_ #include <osgEarthAnnotation/AnnotationUtils> using namespace osgEarth; using namespace osgEarth::Symbology; using namespace osgEarth::Annotation; struct AnnotationUtilsEXP : AnnotationUtils { public: /** * Creates a std::wstring drawable representing a symbolized text label in * pixel space. */ static osg::Drawable* createTextDrawable( const std::wstring& text, const TextSymbol* symbol, const osg::Vec3& positionOffset ); }; #endif
AnnotationUtilsEXP.cpp
#include "AnnotationUtilsEXP.h" #include <osgEarthSymbology/Color> #include <osgEarthSymbology/MeshSubdivider> #include <osgEarth/ThreadingUtils> #include <osgEarth/Registry> #include <osgEarth/VirtualProgram> #include <osgEarth/Capabilities> #include <osgText/Text> #include <osg/Depth> #include <osg/BlendFunc> #include <osg/CullFace> #include <osg/MatrixTransform> #include <osg/LightModel> using namespace osgEarth; using namespace osgEarth::Annotation; osg::Drawable* AnnotationUtilsEXP::createTextDrawable( const std::wstring& text, const TextSymbol* symbol, const osg::Vec3& positionOffset ) { osgText::Text* t = new osgText::Text(); osgText::String::Encoding text_encoding = osgText::String::ENCODING_UNDEFINED; if ( symbol && symbol->encoding().isSet() ) { text_encoding = AnnotationUtils::convertTextSymbolEncoding(symbol->encoding().value()); } t->setText( text.c_str()); // osgText::Text turns on depth writing by default, even if you turned it off.. t->setEnableDepthWrites( false ); if ( symbol && symbol->layout().isSet() ) { if(symbol->layout().value() == TextSymbol::LAYOUT_RIGHT_TO_LEFT) { t->setLayout(osgText::TextBase::RIGHT_TO_LEFT); } else if(symbol->layout().value() == TextSymbol::LAYOUT_LEFT_TO_RIGHT) { t->setLayout(osgText::TextBase::LEFT_TO_RIGHT); } else if(symbol->layout().value() == TextSymbol::LAYOUT_VERTICAL) { t->setLayout(osgText::TextBase::VERTICAL); } } if ( symbol && symbol->pixelOffset().isSet() ) { t->setPosition( osg::Vec3( positionOffset.x() + symbol->pixelOffset()->x(), positionOffset.y() + symbol->pixelOffset()->y(), positionOffset.z() ) ); } else { t->setPosition( positionOffset ); } t->setAutoRotateToScreen( false ); t->setCharacterSizeMode( osgText::Text::OBJECT_COORDS ); t->setCharacterSize( symbol && symbol->size().isSet() ? (float)(symbol->size()->eval()) : 16.0f ); t->setColor( symbol && symbol->fill().isSet() ? symbol->fill()->color() : Color::White ); osgText::Font* font = 0L; if ( symbol && symbol->font().isSet() ) font = osgText::readFontFile( *symbol->font() ); if ( !font ) font = Registry::instance()->getDefaultFont(); if ( font ) t->setFont( font ); if ( symbol ) { // they're the same enum. osgText::Text::AlignmentType at = (osgText::Text::AlignmentType)symbol->alignment().value(); t->setAlignment( at ); } if ( symbol && symbol->halo().isSet() ) { t->setBackdropColor( symbol->halo()->color() ); t->setBackdropType( osgText::Text::OUTLINE ); if ( symbol->haloOffset().isSet() ) { t->setBackdropOffset( *symbol->haloOffset(), *symbol->haloOffset() ); } } else if ( !symbol ) { // if no symbol at all is provided, default to using a black halo. t->setBackdropColor( osg::Vec4(.3,.3,.3,1) ); t->setBackdropType( osgText::Text::OUTLINE ); } // this disables the default rendering bin set by osgText::Font. Necessary if we're // going to do decluttering. // TODO: verify that it's still OK to share the font stateset (think so) or does it // need to be marked DYNAMIC if ( t->getStateSet() ) t->getStateSet()->setRenderBinToInherit(); return t; }
類2:PlaceNodeEXP
頭文件:PlaceNodeEXP.h
#ifndef PLACENODE_EXP_H_
#define PLACENODE_EXP_H_
#include <osgEarthAnnotation/OrthoNode>
#include <osgEarthSymbology/Style>
using namespace osgEarth;
using namespace osgEarth::Symbology;
using namespace osgEarth::Annotation;
class PlaceNodeEXP : public OrthoNode { public: /** * Constructs a std::wstring new place node * * @param mapNode MapNode that helps position this annotation * @param position Initial location of the annotation * @param iconImage Image of the place icon * @param labelText Text to place next to the icon * @param style Optional style settings. */ PlaceNodeEXP( MapNode* mapNode, const GeoPoint& position, osg::Image* iconImage, const std::wstring& labelText, const Style& style =Style() ); /** * Constructs a new place node. You can specify an icon marker by * adding a IconSymbol to the Style. * * @param mapNode MapNode that helps position this annotation * @param position Initial location of the annotation * @param labelText Text to place next to the icon * @param style Optional style settings. */ PlaceNodeEXP( MapNode* mapNode, const GeoPoint& position, const std::wstring& labelText, const Style& style =Style() ); /** * Image to use for the icon */ void setIconImage(osg::Image* image); osg::Image* getIconImage() const { return _image.get(); } /** * Text label content */ void setText( const std::wstring& text ); const std::wstring& getText() const { return _text; } /** * Style (for text and placement) */ void setStyle( const Style& style ); const Style& getStyle() const { return _style; } public: // OrthoNode override virtual void setAnnotationData( AnnotationData* data ); virtual void setDynamic( bool value ); virtual Config getConfig() const; std::wstring StringToWString(const std::string& s); protected: virtual ~PlaceNodeEXP() { } private: osg::ref_ptr<osg::Image> _image; std::wstring _text; Style _style; class osg::Geode* _geode; osg::ref_ptr<const osgDB::Options> _dbOptions; void init(); // required by META_Node, but this object is not cloneable PlaceNodeEXP() { } PlaceNodeEXP(const PlaceNodeEXP& rhs, const osg::CopyOp& op =osg::CopyOp::DEEP_COPY_ALL) : OrthoNode(rhs, op) { } }; #endif
cpp文件:PlaceNodeEXP.cpp
#include "PlaceNodeEXP.h" #include "AnnotationUtilsEXP.h" #include <osgEarthAnnotation/AnnotationRegistry> #include <osgEarthFeatures/BuildTextFilter> #include <osgEarthFeatures/LabelSource> #include <osgEarth/Utils> #include <osgEarth/Registry> #include <osgEarth/ShaderGenerator> #include <osg/Depth> #include <osgText/Text> using namespace osgEarth; using namespace osgEarth::Annotation; using namespace osgEarth::Features; using namespace osgEarth::Symbology; PlaceNodeEXP::PlaceNodeEXP(MapNode* mapNode, const GeoPoint& position, osg::Image* image, const std::wstring& text, const Style& style ) : OrthoNode( mapNode, position ), _image ( image ), _text ( text ), _style ( style ), _geode ( 0L ) { init(); } PlaceNodeEXP::PlaceNodeEXP(MapNode* mapNode, const GeoPoint& position, const std::wstring& text, const Style& style ): OrthoNode( mapNode, position ), _text ( text ), _style ( style ), _geode ( 0L ) { init(); } void PlaceNodeEXP::setIconImage( osg::Image* image ) { // changing the icon requires a complete rebuild. _image = image; init(); } void PlaceNodeEXP::setText( const std::wstring& text ) { if ( !_dynamic ) { //OE_WARN << LC << "Illegal state: cannot change a LabelNode that is not dynamic" << std::endl; return; } _text = text; for(unsigned i=0; i<_geode->getNumDrawables(); ++i) { osgText::Text* d = dynamic_cast<osgText::Text*>( _geode->getDrawable(i) ); if ( d ) { TextSymbol* symbol = _style.getOrCreate<TextSymbol>(); osgText::String::Encoding text_encoding = osgText::String::ENCODING_UNDEFINED; if ( symbol && symbol->encoding().isSet() ) { text_encoding = AnnotationUtils::convertTextSymbolEncoding(symbol->encoding().value()); } d->setText( text.c_str() ); break; } } } void PlaceNodeEXP::setStyle( const Style& style ) { // changing the style requires a complete rebuild. _style = style; init(); } void PlaceNodeEXP::init() { //reset. this->clearDecoration(); getAttachPoint()->removeChildren(0, getAttachPoint()->getNumChildren()); _geode = new osg::Geode(); osg::Drawable* text = 0L; // If there's no explicit text, look to the text symbol for content. if ( _text.empty() && _style.has<TextSymbol>() ) { _text = StringToWString(_style.get<TextSymbol>()->content()->eval()); } osg::ref_ptr<const InstanceSymbol> instance = _style.get<InstanceSymbol>(); // backwards compability, support for deprecated MarkerSymbol if ( !instance.valid() && _style.has<MarkerSymbol>() ) { instance = _style.get<MarkerSymbol>()->convertToInstanceSymbol(); } const IconSymbol* icon = instance->asIcon(); if ( !_image.valid() ) { URI imageURI; if ( icon ) { if ( icon->url().isSet() ) { imageURI = URI( icon->url()->eval(), icon->url()->uriContext() ); } } if ( !imageURI.empty() ) { _image = imageURI.getImage( _dbOptions.get() ); } } // found an image; now format it: if ( _image.get() ) { // Scale the icon if necessary double scale = 1.0; if ( icon && icon->scale().isSet() ) { scale = icon->scale()->eval(); } double s = scale * _image->s(); double t = scale * _image->t(); // this offset anchors the image at the bottom osg::Vec2s offset; if ( !icon || !icon->alignment().isSet() ) { // default to bottom center offset.set(0.0, t / 2.0); } else { // default to bottom center switch (icon->alignment().value()) { case IconSymbol::ALIGN_LEFT_TOP: offset.set((s / 2.0), -(t / 2.0)); break; case IconSymbol::ALIGN_LEFT_CENTER: offset.set((s / 2.0), 0.0); break; case IconSymbol::ALIGN_LEFT_BOTTOM: offset.set((s / 2.0), (t / 2.0)); break; case IconSymbol::ALIGN_CENTER_TOP: offset.set(0.0, -(t / 2.0)); break; case IconSymbol::ALIGN_CENTER_CENTER: offset.set(0.0, 0.0); break; case IconSymbol::ALIGN_CENTER_BOTTOM: default: offset