osgEarth 2.1.1
|
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 StringExpression & | getFeatureNameExpr () 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 |
Feature filter that will substitute external nodes for feature geometry.
TODO:
Definition at line 50 of file SubstituteModelFilter.
typedef LRUCache<URI, osg::ref_ptr<MarkerResource> > osgEarth::Features::SubstituteModelFilter::MarkerCache [protected] |
Definition at line 86 of file SubstituteModelFilter.
Construct a new sub-model filter that will operate on the given style
Definition at line 47 of file SubstituteModelFilter.cpp.
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; }
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; }
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; }
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; }
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; }
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; }
void osgEarth::Features::SubstituteModelFilter::setMergeGeometry | ( | bool | value | ) | [inline] |
Whether to merge marker geometries into geodes
Definition at line 65 of file SubstituteModelFilter.
{ _merge = value; }
bool osgEarth::Features::SubstituteModelFilter::_cluster [protected] |
Definition at line 81 of file SubstituteModelFilter.
Definition at line 84 of file SubstituteModelFilter.
Definition at line 87 of file SubstituteModelFilter.
bool osgEarth::Features::SubstituteModelFilter::_merge [protected] |
Definition at line 82 of file SubstituteModelFilter.
Definition at line 80 of file SubstituteModelFilter.