osgEarth 2.1.1
Classes | Public Member Functions | Private Member Functions | Private Attributes | Friends

osgEarth::Util::Graticule Class Reference

Collaboration diagram for osgEarth::Util::Graticule:

List of all members.

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

Detailed Description

Implements a map graticule.

NOTE: So far, this only works for geocentric maps. TODO: Add projected support; add text label support

Definition at line 38 of file Graticule.


Constructor & Destructor Documentation

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.

Parameters:
mapMap 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:


Member Function Documentation

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.

Parameters:
maxRangeMaximum camera range for this level.
cellsX,cellsYNumber of grid cells in each direction at this level.
lineWidthWidth 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]

Definition at line 83 of file Graticule.

{ return _id; }

Here is the caller graph for this function:

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]

Definition at line 87 of file Graticule.

{ return _levels.size(); }

Here is the caller graph for this function:

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:


Friends And Related Function Documentation

friend class GraticuleFactory [friend]

Definition at line 99 of file Graticule.


Member Data Documentation

Definition at line 90 of file Graticule.

unsigned int osgEarth::Util::Graticule::_id [private]

Definition at line 89 of file Graticule.

std::vector<Level> osgEarth::Util::Graticule::_levels [private]

Definition at line 92 of file Graticule.

Definition at line 94 of file Graticule.

osg::observer_ptr<const Map> osgEarth::Util::Graticule::_map [private]

Definition at line 91 of file Graticule.

Definition at line 93 of file Graticule.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines