/** * Builds a collection of style groups by processing a StyleSelector. */ void FeatureModelGraph::buildStyleGroups(const StyleSelector* selector, const Query& baseQuery, FeatureSourceIndex* index, osg::Group* parent) { // if the selector uses an expression to select the style name, then we must perform the // query and then SORT the features into style groups. if ( selector->styleExpression().isSet() ) { // merge the selector's query into the existing query Query combinedQuery = baseQuery.combineWith( *selector->query() ); // query, sort, and add each style group to the parent: queryAndSortIntoStyleGroups( combinedQuery, *selector->styleExpression(), index, parent ); } // otherwise, all feature returned by this query will have the same style: else { // combine the selection style with the incoming base style: const Style* selectedStyle = _session->styles()->getStyle(selector->getSelectedStyleName()); Style style; if ( selectedStyle ) style = *selectedStyle; // .. and merge it's query into the existing query Query combinedQuery = baseQuery.combineWith( *selector->query() ); // then create the node. osg::Node* node = createStyleGroup( style, combinedQuery, index ); if ( node && !parent->containsNode(node) ) parent->addChild( node ); } }
osg::Group* FeatureModelGraph::build( const FeatureLevel& level, const GeoExtent& extent, const TileKey* key ) { osg::ref_ptr<osg::Group> group = new osg::Group(); // form the baseline query, which does a spatial query based on the working extent. Query query; if ( extent.isValid() ) query.bounds() = extent.bounds(); // add a tile key to the query if there is one, to support TFS-style queries if ( key ) query.tileKey() = *key; // now, go through any level-based selectors. const StyleSelectorVector& levelSelectors = level.selectors(); // if there are none, just build once with the default style and query. if ( levelSelectors.size() == 0 ) { osg::Node* node = build( Style(), query, extent ); if ( node ) group->addChild( node ); } else { for( StyleSelectorVector::const_iterator i = levelSelectors.begin(); i != levelSelectors.end(); ++i ) { const StyleSelector& selector = *i; // fetch the selector's style: Style selectorStyle; _styles.getStyle( selector.getSelectedStyleName(), selectorStyle ); // combine the selector's query, if it has one: Query selectorQuery = selector.query().isSet() ? query.combineWith( *selector.query() ) : query; osg::Node* node = build( selectorStyle, selectorQuery, extent ); if ( node ) group->addChild( node ); } } if ( group->getNumChildren() > 0 ) { // account for a min-range here. if ( level.minRange() > 0.0f ) { osg::LOD* lod = new osg::LOD(); lod->addChild( group.get(), level.minRange(), FLT_MAX ); group = lod; } if ( _session->getMapInfo().isGeocentric() && _options.clusterCulling() == true ) { const GeoExtent& ccExtent = extent.isValid() ? extent : _source->getFeatureProfile()->getExtent(); if ( ccExtent.isValid() ) { // if the extent is more than 90 degrees, bail GeoExtent geodeticExtent = ccExtent.transform( ccExtent.getSRS()->getGeographicSRS() ); if ( geodeticExtent.width() < 90.0 && geodeticExtent.height() < 90.0 ) { // get the geocentric tile center: osg::Vec3d tileCenter; ccExtent.getCentroid( tileCenter.x(), tileCenter.y() ); osg::Vec3d centerECEF; ccExtent.getSRS()->transformToECEF( tileCenter, centerECEF ); osg::NodeCallback* ccc = ClusterCullerFactory::create( group.get(), centerECEF ); if ( ccc ) group->addCullCallback( ccc ); } } } return group.release(); } else { return 0L; } }