osgEarth 2.1.1
Public Member Functions | Static Public Member Functions | Protected Types | Protected Member Functions | Protected Attributes

osgEarth::Features::SubstituteModelFilter Class Reference

Inheritance diagram for osgEarth::Features::SubstituteModelFilter:
Collaboration diagram for osgEarth::Features::SubstituteModelFilter:

List of all members.

Public Member Functions

 SubstituteModelFilter (const Style &style=Style())
void setClustering (bool value)
bool getClustering () const
void setMergeGeometry (bool value)
bool getMergeGeometry () const
void setFeatureNameExpr (const StringExpression &expr)
const StringExpressiongetFeatureNameExpr () const
virtual osg::Node * push (FeatureList &input, FilterContext &context)

Static Public Member Functions

static bool isSupported ()

Protected Types

typedef LRUCache< URI,
osg::ref_ptr< MarkerResource > > 
MarkerCache

Protected Member Functions

bool process (const FeatureList &features, const MarkerSymbol *symbol, Session *session, osg::Group *ap, FilterContext &context)
bool cluster (const FeatureList &features, const MarkerSymbol *symbol, Session *session, osg::Group *ap, FilterContext &context)

Protected Attributes

Style _style
bool _cluster
bool _merge
StringExpression _featureNameExpr
MarkerCache _markerCache

Detailed Description

Feature filter that will substitute external nodes for feature geometry.

TODO:

Definition at line 50 of file SubstituteModelFilter.


Member Typedef Documentation

Definition at line 86 of file SubstituteModelFilter.


Constructor & Destructor Documentation

SubstituteModelFilter::SubstituteModelFilter ( const Style style = Style())

Construct a new sub-model filter that will operate on the given style

Definition at line 47 of file SubstituteModelFilter.cpp.

                                                                 :
_style   ( style ),
_cluster ( false ),
_merge   ( true )
{
    //NOP
}

Member Function Documentation

bool SubstituteModelFilter::cluster ( const FeatureList features,
const MarkerSymbol symbol,
Session session,
osg::Group *  ap,
FilterContext context 
) [protected]

Definition at line 295 of file SubstituteModelFilter.cpp.

{    
    MarkerToFeatures markerToFeatures;

    // first, sort the features into buckets, each bucket corresponding to a
    // unique marker.
    for (FeatureList::const_iterator i = features.begin(); i != features.end(); ++i)
    {
        Feature* f = i->get();

        // resolve the URI for the marker:
        StringExpression uriEx( *symbol->url() );
        URI markerURI( f->eval( uriEx ), uriEx.uriContext() );

        // find and load the corresponding marker model. We're using the session-level
        // object store to cache models. This is thread-safe sine we are always going
        // to CLONE the model before using it.
        osg::Node* model = context.getSession()->getObject<osg::Node>( markerURI.full() );
        if ( !model )
        {
            osg::ref_ptr<MarkerResource> mres = new MarkerResource();
            mres->uri() = markerURI;
            model = mres->createNode();
            if ( model )
            {
                context.getSession()->putObject( markerURI.full(), model );
            }
        }

        if ( model )
        {
            MarkerToFeatures::iterator itr = markerToFeatures.find( model );
            if (itr == markerToFeatures.end())
                markerToFeatures[ model ].push_back( f );
            else
                itr->second.push_back( f );
        }
    }

    //For each model, cluster the features that use that marker
    for (MarkerToFeatures::iterator i = markerToFeatures.begin(); i != markerToFeatures.end(); ++i)
    {
        osg::Node* prototype = i->first;

        // we're using the Session cache since we know we'll be cloning.
        if ( prototype )
        {
            osg::Node* clone = osg::clone( prototype, osg::CopyOp::DEEP_COPY_ALL );

            // ..and apply the clustering to the copy.
            ClusterVisitor cv( i->second, symbol, this, context );
            clone->accept( cv );

            attachPoint->addChild( clone );
        }
    }

    return true;
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool osgEarth::Features::SubstituteModelFilter::getClustering ( ) const [inline]

Definition at line 62 of file SubstituteModelFilter.

{ return _cluster; }
const StringExpression& osgEarth::Features::SubstituteModelFilter::getFeatureNameExpr ( ) const [inline]

Definition at line 73 of file SubstituteModelFilter.

{ return _featureNameExpr; }
bool osgEarth::Features::SubstituteModelFilter::getMergeGeometry ( ) const [inline]

Definition at line 66 of file SubstituteModelFilter.

{ return _merge; }
static bool osgEarth::Features::SubstituteModelFilter::isSupported ( ) [inline, static]

Definition at line 54 of file SubstituteModelFilter.

{ return true; }

Here is the caller graph for this function:

bool SubstituteModelFilter::process ( const FeatureList features,
const MarkerSymbol symbol,
Session session,
osg::Group *  ap,
FilterContext context 
) [protected]

Definition at line 56 of file SubstituteModelFilter.cpp.

{
    bool makeECEF = context.getSession()->getMapInfo().isGeocentric();

    // first, go through the features and build the model cache. Apply the model matrix' scale
    // factor to any AutoTransforms directly (cloning them as necessary)
    std::map< std::pair<URI, float>, osg::ref_ptr<osg::Node> > uniqueModels;
    //std::map< Feature*, osg::ref_ptr<osg::Node> > featureModels;

    StringExpression  uriEx   = *symbol->url();
    NumericExpression scaleEx = *symbol->scale();

    for( FeatureList::const_iterator f = features.begin(); f != features.end(); ++f )
    {
        Feature* input = f->get();

        // evaluate the marker URI expression:
        StringExpression uriEx = *symbol->url();
        URI markerURI( input->eval(uriEx), uriEx.uriContext() );

        // find the corresponding marker in the cache
        MarkerResource* marker = 0L;
        MarkerCache::Record rec = _markerCache.get( markerURI );
        if ( rec.valid() ) {
            marker = rec.value();
        }
        else {
            marker = new MarkerResource();
            marker->uri() = markerURI;
            _markerCache.insert( markerURI, marker );
        }

        // evalute the scale expression (if there is one)
        float scale = 1.0f;
        osg::Matrixd scaleMatrix;

        if ( symbol->scale().isSet() )
        {
            scale = input->eval( scaleEx );
            if ( scale == 0.0 )
                scale = 1.0;
            scaleMatrix = osg::Matrix::scale( scale, scale, scale );
        }

        // how that we have a marker source, create a node for it
        std::pair<URI,float> key( markerURI, scale );
        osg::ref_ptr<osg::Node>& model = uniqueModels[key];
        if ( !model.valid() )
        {
            model = context.resourceCache()->getMarkerNode( marker );

            if ( scale != 1.0f && dynamic_cast<osg::AutoTransform*>( model.get() ) )
            {
                // clone the old AutoTransform, set the new scale, and copy over its children.
                osg::AutoTransform* oldAT = dynamic_cast<osg::AutoTransform*>(model.get());
                osg::AutoTransform* newAT = osg::clone( oldAT );

                // make a scaler and put it between the new AutoTransform and its kids
                osg::MatrixTransform* scaler = new osg::MatrixTransform(osg::Matrix::scale(scale,scale,scale));
                for( unsigned i=0; i<newAT->getNumChildren(); ++i )
                    scaler->addChild( newAT->getChild(0) );
                newAT->removeChildren(0, newAT->getNumChildren());
                newAT->addChild( scaler );
                model = newAT;
            }
        }

        if ( model.valid() )
        {
            GeometryIterator gi( input->getGeometry(), false );
            while( gi.hasMore() )
            {
                Geometry* geom = gi.next();

                for( unsigned i=0; i<geom->size(); ++i )
                {
                    osg::Matrixd mat;

                    osg::Vec3d point = (*geom)[i];
                    if ( makeECEF )
                    {
                        // the "rotation" element lets us re-orient the instance to ensure it's pointing up. We
                        // could take a shortcut and just use the current extent's local2world matrix for this,
                        // but if the tile is big enough the up vectors won't be quite right.
                        osg::Matrixd rotation;
                        ECEF::transformAndGetRotationMatrix( context.profile()->getSRS(), point, point, rotation );
                        mat = rotation * scaleMatrix * osg::Matrixd::translate( point ) * _world2local;
                    }
                    else
                    {
                        mat = scaleMatrix * osg::Matrixd::translate( point ) * _world2local;
                    }

                    osg::MatrixTransform* xform = new osg::MatrixTransform();
                    xform->setMatrix( mat );

                    xform->addChild( model.get() );

                    attachPoint->addChild( xform );

                    // name the feature if necessary
                    if ( !_featureNameExpr.empty() )
                    {
                        const std::string& name = input->eval( _featureNameExpr );
                        if ( !name.empty() )
                            xform->setName( name );
                    }
                }
            }
        }
    }

    return true;
}

Here is the call graph for this function:

Here is the caller graph for this function:

osg::Node * SubstituteModelFilter::push ( FeatureList input,
FilterContext context 
) [virtual]

Processes a new feature list

Implements osgEarth::Features::FeaturesToNodeFilter.

Definition at line 360 of file SubstituteModelFilter.cpp.

{
    if ( !isSupported() ) {
        OE_WARN << "SubstituteModelFilter support not enabled" << std::endl;
        return 0L;
    }

    if ( _style.empty() ) {
        OE_WARN << LC << "Empty style; cannot process features" << std::endl;
        return 0L;
    }

    const MarkerSymbol* symbol = _style.getSymbol<MarkerSymbol>();
    if ( !symbol ) {
        OE_WARN << LC << "No MarkerSymbol found in style; cannot process feautres" << std::endl;
        return 0L;
    }

    FilterContext newContext( context );

    computeLocalizers( context );

    osg::Group* group = createDelocalizeGroup();

    bool ok = true;

    if ( _cluster )
    {
        ok = cluster( features, symbol, context.getSession(), group, newContext );
    }

    else
    {
        process( features, symbol, context.getSession(), group, newContext );

#if 0
        // speeds things up a bit, at the expense of creating tons of geometry..

        // this optimizer pass will remove all the MatrixTransform nodes that we
        // used to offset each instance
        osgUtil::Optimizer optimizer;
        optimizer.optimize( group, osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS );
#endif

    }

    return group;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void osgEarth::Features::SubstituteModelFilter::setClustering ( bool  value) [inline]

Whether to cluster all the model instances into a single geode. Default is false.

Definition at line 61 of file SubstituteModelFilter.

{ _cluster = value; }

Here is the caller graph for this function:

void osgEarth::Features::SubstituteModelFilter::setFeatureNameExpr ( const StringExpression expr) [inline]

The matrix with which to transform each model instance after placement.

Definition at line 72 of file SubstituteModelFilter.

{ _featureNameExpr = expr; }

Here is the caller graph for this function:

void osgEarth::Features::SubstituteModelFilter::setMergeGeometry ( bool  value) [inline]

Whether to merge marker geometries into geodes

Definition at line 65 of file SubstituteModelFilter.

{ _merge = value; }

Member Data Documentation

Definition at line 81 of file SubstituteModelFilter.

Definition at line 84 of file SubstituteModelFilter.

Definition at line 87 of file SubstituteModelFilter.

Definition at line 82 of file SubstituteModelFilter.

Definition at line 80 of file SubstituteModelFilter.


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