|
osgEarth 2.1.1
|
Collaboration diagram for osgEarth::Util::Graticule: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() ) ); }
Here is the call graph for this function:| 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 );
}
Here is the caller graph for this function:| 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;
}
Here is the call graph for this function:| 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;
}
Here is the call graph for this function:| 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;
}
}
Here is the caller graph for this function:| 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;
}
Here is the caller graph for this function:| 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; }
Here is the caller graph for this function: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] |
1.7.3