Example #1
0
osg::Node*
ResourceCache::getMarkerNode( MarkerResource* marker )
{
    osg::Node* result = 0L;

    if ( _threadSafe )
    {
        // first check if it exists
        {
            Threading::ScopedReadLock shared( _mutex );

            MarkerCache::Record rec = _markerCache.get( marker );
            if ( rec.valid() )
            {
                result = rec.value();
            }
        }

        // no? exclusive lock and create it.
        if ( !result )
        {
            Threading::ScopedWriteLock exclusive( _mutex );
            
            // double check to avoid race condition
            MarkerCache::Record rec = _markerCache.get( marker );
            if ( rec.valid() )
            {
                result = rec.value();
            }
            else
            {
                // still not there, make it.
                result = marker->createNode( _dbOptions.get() );
                if ( result )
                    _markerCache.insert( marker, result );
            }
        }
    }

    else
    {
        MarkerCache::Record rec = _markerCache.get( marker );
        if ( rec.valid() )
        {
            result = rec.value();
        }
        else
        {
            result = marker->createNode( _dbOptions.get() );
            if ( result )
                _markerCache.insert( marker, result );
        }
    }

    return result;
}
bool
SubstituteModelFilter::process(const FeatureList&           features,                               
                               const MarkerSymbol*          symbol,
                               Session*                     session,
                               osg::Group*                  attachPoint,
                               FilterContext&               context )
{
    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, &context), 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, &context );
            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( point, context.profile()->getSRS(), 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, &context);
                        if ( !name.empty() )
                            xform->setName( name );
                    }
                }
            }
        }
    }

    return true;
}