//clustering: // troll the external model for geodes. for each geode, create a geode in the target // model. then, for each geometry in that geode, replicate it once for each instance of // the model in the feature batch and transform the actual verts to a local offset // relative to the tile centroid. Finally, reassemble all the geodes and optimize. // hopefully stateset sharing etc will work out. we may need to strip out LODs too. bool SubstituteModelFilter::cluster(const FeatureList& features, const MarkerSymbol* symbol, Session* session, osg::Group* attachPoint, FilterContext& cx ) { MarkerToFeatures markerToFeatures; MarkerFactory factory( session); for (FeatureList::const_iterator i = features.begin(); i != features.end(); ++i) { Feature* f = i->get(); osg::ref_ptr< osg::Node > model = factory.getOrCreateNode( f, symbol ); //Try to find the existing entry if (model.valid()) { MarkerToFeatures::iterator itr = markerToFeatures.find( model.get() ); if (itr == markerToFeatures.end()) { markerToFeatures[ model.get() ].push_back( f ); } else { itr->second.push_back( f ); } } } /* OE_NOTICE << "Sorted models into " << markerToFeatures.size() << " buckets" << std::endl; for (MarkerToFeatures::iterator i = markerToFeatures.begin(); i != markerToFeatures.end(); ++i) { OE_NOTICE << " Bucket has " << i->second.size() << " features" << std::endl; } */ //For each model, cluster the features that use that model for (MarkerToFeatures::iterator i = markerToFeatures.begin(); i != markerToFeatures.end(); ++i) { osg::Node* clone = dynamic_cast<osg::Node*>( i->first->clone( osg::CopyOp::DEEP_COPY_ALL ) ); // ..and apply the clustering to the copy. ClusterVisitor cv( i->second, _modelMatrix, this, cx ); clone->accept( cv ); attachPoint->addChild( clone ); } return true; }
//clustering: // troll the external model for geodes. for each geode, create a geode in the target // model. then, for each geometry in that geode, replicate it once for each instance of // the model in the feature batch and transform the actual verts to a local offset // relative to the tile centroid. Finally, reassemble all the geodes and optimize. // hopefully stateset sharing etc will work out. we may need to strip out LODs too. bool SubstituteModelFilter::cluster(const FeatureList& features, const MarkerSymbol* symbol, Session* session, osg::Group* attachPoint, FilterContext& context ) { 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, &context ), 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::ref_ptr<osg::Node> model = context.getSession()->getObject<osg::Node>( markerURI.full() ); if ( !model.valid() ) { osg::ref_ptr<MarkerResource> mres = new MarkerResource(); mres->uri() = markerURI; model = mres->createNode( context.getSession()->getDBOptions() ); if ( model.valid() ) { // store it, but only if there isn't already one in there. context.getSession()->putObject( markerURI.full(), model.get(), false ); } } if ( model.valid() ) { MarkerToFeatures::iterator itr = markerToFeatures.find( model.get() ); if (itr == markerToFeatures.end()) markerToFeatures[ model.get() ].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; }