osgEarth 2.1.1
|
Classes | |
struct | Level |
Public Member Functions | |
Graticule (const Map *map) | |
void | setLineColor (const osg::Vec4f &value) |
void | setTextColor (const osg::Vec4f &value) |
void | addLevel (float maxRange, unsigned int cellsX, unsigned int cellsY, double lineWidth) |
Private Member Functions | |
unsigned int | getID () const |
bool | getLevel (unsigned int level, Graticule::Level &out_level) const |
unsigned int | getNumLevels () const |
osg::Node * | createGridLevel (unsigned int levelNum) const |
osg::Node * | createTextLevel (unsigned int levelNum) const |
Private Attributes | |
unsigned int | _id |
bool | _autoLevels |
osg::observer_ptr< const Map > | _map |
std::vector< Level > | _levels |
osg::Vec4f | _textColor |
Style | _lineStyle |
Friends | |
class | GraticuleFactory |
Implements a map graticule.
NOTE: So far, this only works for geocentric maps. TODO: Add projected support; add text label support
Graticule::Graticule | ( | const Map * | map | ) |
Constructs a new graticule for use with the specified map. The graticule is created with several default levels. If you call addLevel(), the default levels are deleted.
map | Map with which you will use this graticule |
Definition at line 80 of file Graticule.cpp.
: _autoLevels( true ), _map( map ), _textColor( 1,1,0,1 ) { // safely generate a unique ID for this graticule: _id = Registry::instance()->createUID(); { ScopedLock<Mutex> lock( s_graticuleMutex ); s_graticuleRegistry[_id] = this; } setLineColor( osg::Vec4f(1,1,1,0.7) ); setTextColor( osg::Vec4f(1,1,0,1) ); if ( _map->isGeocentric() ) { double r = map->getProfile()->getSRS()->getEllipsoid()->getRadiusEquator(); int x=8, y=4; double d = 3.5*r; double lw=0.15; addLevel( FLT_MAX, x, y, lw ); for(int i=0; i<9; i++) { x *= 2, y *= 2; lw *= 0.5; d *= 0.5; addLevel( r+d, x, y, lw ); } } // Prime the grid: { std::stringstream buf; buf << "0_" << _id << "." << GRID_MARKER << "." << GRATICLE_EXTENSION; std::string bufStr = buf.str(); osg::ProxyNode* proxy = new osg::ProxyNode(); proxy->setFileName( 0, bufStr ); proxy->setCenterMode( osg::ProxyNode::USER_DEFINED_CENTER ); proxy->setCenter( osg::Vec3(0,0,0) ); proxy->setRadius( 1e10 ); this->addChild( proxy ); } // Prime the text: { std::stringstream buf; buf << "0_" << _id << "." << TEXT_MARKER << "." << GRATICLE_EXTENSION; std::string bufStr = buf.str(); osg::ProxyNode* proxy = new osg::ProxyNode(); proxy->setFileName( 0, bufStr ); proxy->setCenterMode( osg::ProxyNode::USER_DEFINED_CENTER ); proxy->setCenter( osg::Vec3(0,0,0) ); proxy->setRadius( 1e10 ); this->addChild( proxy ); } osg::StateSet* set = this->getOrCreateStateSet(); set->setRenderBinDetails( 9999, "RenderBin" ); set->setAttributeAndModes( new osg::Depth( osg::Depth::ALWAYS ), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); set->setMode( GL_LIGHTING, 0 ); //osg::Program* program = new osg::Program(); //program->addShader( new osg::Shader( osg::Shader::VERTEX, s_vertexShader ) ); //program->addShader( new osg::Shader( osg::Shader::FRAGMENT, s_fragmentShader ) ); //set->setAttributeAndModes( program, osg::StateAttribute::ON ); this->addEventCallback( new AutoClipPlaneCallback( _map.get() ) ); }
void Graticule::addLevel | ( | float | maxRange, |
unsigned int | cellsX, | ||
unsigned int | cellsY, | ||
double | lineWidth | ||
) |
Adds a new level to the profile. Levels are sorted by maxRange. Calling this method deletes any automatically created default levels.
maxRange | Maximum camera range for this level. |
cellsX,cellsY | Number of grid cells in each direction at this level. |
lineWidth | Width of the grid lines, in map units, at this level. |
Definition at line 156 of file Graticule.cpp.
{ if ( _autoLevels ) { _autoLevels = false; _levels.clear(); } Level level; level._maxRange = maxRange; level._cellsX = cellsX; level._cellsY = cellsY; level._lineWidth = lineWidth; for( std::vector<Level>::iterator i = _levels.begin(); i != _levels.end(); ++i ) { if ( maxRange > i->_maxRange ) { _levels.insert( i, level ); return; } } _levels.push_back( level ); }
osg::Node * Graticule::createGridLevel | ( | unsigned int | levelNum | ) | const [private] |
Definition at line 293 of file Graticule.cpp.
{ if ( !_map->isGeocentric() ) { OE_WARN << "Graticule: only supports geocentric maps" << std::endl; return 0L; } Graticule::Level level; if ( !getLevel( levelNum, level ) ) return 0L; OE_DEBUG << "Graticule: creating grid level " << levelNum << std::endl; osg::Group* group = new osg::Group(); const Profile* mapProfile = _map->getProfile(); const GeoExtent& pex = mapProfile->getExtent(); double tw = pex.width() / (double)level._cellsX; double th = pex.height() / (double)level._cellsY; for( unsigned int x=0; x<level._cellsX; ++x ) { for( unsigned int y=0; y<level._cellsY; ++y ) { GeoExtent tex( mapProfile->getSRS(), pex.xMin() + tw * (double)x, pex.yMin() + th * (double)y, pex.xMin() + tw * (double)(x+1), pex.yMin() + th * (double)(y+1) ); Geometry* geom = createCellGeometry( tex, level._lineWidth, pex, _map->isGeocentric() ); Feature* feature = new Feature(); feature->setGeometry( geom ); FeatureList features; features.push_back( feature ); FilterContext cx; cx.profile() = new FeatureProfile( tex ); cx.isGeocentric() = _map->isGeocentric(); if ( _map->isGeocentric() ) { // We need to make sure that on a round globe, the points are sampled such that // long segments follow the curvature of the earth. ResampleFilter resample; resample.maxLength() = tex.width() / 10.0; cx = resample.push( features, cx ); } TransformFilter xform( mapProfile->getSRS() ); xform.setMakeGeocentric( _map->isGeocentric() ); xform.setLocalizeCoordinates( true ); cx = xform.push( features, cx ); osg::ref_ptr<osg::Node> output; BuildGeometryFilter bg; bg.setStyle( _lineStyle ); //cx = bg.push( features, cx ); output = bg.push( features, cx ); //.getNode(); if ( cx.isGeocentric() ) { // get the geocentric control point: double cplon, cplat, cpx, cpy, cpz; tex.getCentroid( cplon, cplat ); tex.getSRS()->getEllipsoid()->convertLatLongHeightToXYZ( osg::DegreesToRadians( cplat ), osg::DegreesToRadians( cplon ), 0.0, cpx, cpy, cpz ); osg::Vec3 controlPoint(cpx, cpy, cpz); // get the horizon point: tex.getSRS()->getEllipsoid()->convertLatLongHeightToXYZ( osg::DegreesToRadians( tex.yMin() ), osg::DegreesToRadians( tex.xMin() ), 0.0, cpx, cpy, cpz ); osg::Vec3 horizonPoint(cpx, cpy, cpz); // the deviation is the dot product of the control vector and the vector from the // control point to the horizon point. osg::Vec3 controlPointNorm = controlPoint; controlPointNorm.normalize(); osg::Vec3 horizonVecNorm = horizonPoint - controlPoint; horizonVecNorm.normalize(); float deviation = controlPointNorm * horizonVecNorm; // construct the culling callback using the deviation. osg::ClusterCullingCallback* ccc = new osg::ClusterCullingCallback(); ccc->set( controlPoint, controlPointNorm, deviation, (controlPoint-horizonPoint).length() ); // need a new group, because never put a cluster culler on a matrixtransform (doesn't work) osg::Group* me = new osg::Group(); me->setCullCallback( ccc ); me->addChild( output.get() ); output = me; } group->addChild( output.get() ); } } // organize it for better culling osgUtil::Optimizer opt; opt.optimize( group, osgUtil::Optimizer::SPATIALIZE_GROUPS ); osg::Node* result = group; if ( levelNum < getNumLevels() ) { Graticule::Level nextLevel; if ( getLevel( levelNum+1, nextLevel ) ) { osg::PagedLOD* plod = new osg::PagedLOD(); plod->addChild( group, nextLevel._maxRange, level._maxRange ); std::stringstream buf; buf << levelNum+1 << "_" << getID() << "." << GRID_MARKER << "." << GRATICLE_EXTENSION; std::string bufStr = buf.str(); plod->setFileName( 1, bufStr ); plod->setRange( 1, 0, nextLevel._maxRange ); result = plod; } } return result; }
osg::Node * Graticule::createTextLevel | ( | unsigned int | levelNum | ) | const [private] |
Definition at line 419 of file Graticule.cpp.
{ if ( !_map->isGeocentric() ) { OE_WARN << "Graticule: only supports geocentric maps" << std::endl; return 0L; } Graticule::Level level; if ( !getLevel( levelNum, level ) ) return 0L; OE_DEBUG << "Graticule: creating text level " << levelNum << std::endl; osg::Group* group = new osg::Group(); const Profile* mapProfile = _map->getProfile(); const GeoExtent& pex = mapProfile->getExtent(); double tw = pex.width() / (double)level._cellsX; double th = pex.height() / (double)level._cellsY; const osg::EllipsoidModel* ell = _map->getProfile()->getSRS()->getEllipsoid(); for( unsigned int x=0; x<level._cellsX; ++x ) { for( unsigned int y=0; y<level._cellsY; ++y ) { GeoExtent tex( mapProfile->getSRS(), pex.xMin() + tw * (double)x, pex.yMin() + th * (double)y, pex.xMin() + tw * (double)(x+1), pex.yMin() + th * (double)(y+1) ); double offset = 2.0 * level._lineWidth; double cx, cy; tex.getCentroid( cx, cy ); // y value on the x-axis: group->addChild( createTextTransform( cx, tex.yMin() + offset, tex.yMin(), ell, 20.0f, _textColor ) ); // x value on the y-axis: group->addChild( createTextTransform( tex.xMin() + offset, cy, tex.xMin(), ell, 20.0f, _textColor, -90.0f ) ); } } // organize it for better culling osgUtil::Optimizer opt; opt.optimize( group, osgUtil::Optimizer::SPATIALIZE_GROUPS ); osg::Node* result = group; if ( levelNum+1 < getNumLevels() ) { Graticule::Level nextLevel; if ( getLevel( levelNum+1, nextLevel ) ) { osg::PagedLOD* plod = new osg::PagedLOD(); plod->addChild( group, nextLevel._maxRange, level._maxRange ); std::stringstream buf; buf << levelNum+1 << "_" << getID() << "." << TEXT_MARKER << "." << GRATICLE_EXTENSION; std::string bufStr = buf.str(); plod->setFileName( 1, bufStr ); plod->setRange( 1, 0, nextLevel._maxRange ); result = plod; } } return result; }
unsigned int osgEarth::Util::Graticule::getID | ( | ) | const [inline, private] |
bool Graticule::getLevel | ( | unsigned int | level, |
Graticule::Level & | out_level | ||
) | const [private] |
Definition at line 182 of file Graticule.cpp.
{ if ( level < _levels.size() ) { out_level = _levels[level]; return true; } else { return false; } }
unsigned int osgEarth::Util::Graticule::getNumLevels | ( | ) | const [inline, private] |
void Graticule::setLineColor | ( | const osg::Vec4f & | value | ) |
Sets the color of the grid lines
Definition at line 287 of file Graticule.cpp.
{ _lineStyle.getOrCreateSymbol<LineSymbol>()->stroke()->color() = color; }
void osgEarth::Util::Graticule::setTextColor | ( | const osg::Vec4f & | value | ) | [inline] |
Sets the color of the text labels
Definition at line 60 of file Graticule.
{ _textColor = value; }
friend class GraticuleFactory [friend] |
bool osgEarth::Util::Graticule::_autoLevels [private] |
unsigned int osgEarth::Util::Graticule::_id [private] |
std::vector<Level> osgEarth::Util::Graticule::_levels [private] |
Style osgEarth::Util::Graticule::_lineStyle [private] |
osg::observer_ptr<const Map> osgEarth::Util::Graticule::_map [private] |
osg::Vec4f osgEarth::Util::Graticule::_textColor [private] |