/** * Main application. * Creates some simulated track data and runs the simulation. */ int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); // initialize a viewer. osgViewer::Viewer viewer( arguments ); viewer.setCameraManipulator( new EarthManipulator ); // load a map from an earth file. osg::Node* earth = MapNodeHelper().load(arguments, &viewer); MapNode* mapNode = MapNode::findMapNode(earth); if ( !mapNode ) return usage("Missing required .earth file" ); // count on the cmd line? arguments.read("--count", g_numTracks); osg::Group* root = new osg::Group(); root->addChild( earth ); viewer.setSceneData( root ); // build a track field schema. TrackNodeFieldSchema schema; createFieldSchema( schema ); // create some track nodes. TrackSims trackSims; osg::Group* tracks = new osg::Group(); createTrackNodes( mapNode, tracks, schema, trackSims ); root->addChild( tracks ); // Set up the automatic decluttering. setEnabled() activates decluttering for // all drawables under that state set. We are also activating priority-based // sorting, which looks at the AnnotationData::priority field for each drawable. // (By default, objects are sorted by disatnce-to-camera.) Finally, we customize // a couple of the decluttering options to get the animation effects we want. g_dcOptions = Decluttering::getOptions(); g_dcOptions.inAnimationTime() = 1.0f; g_dcOptions.outAnimationTime() = 1.0f; g_dcOptions.sortByPriority() = true; Decluttering::setOptions( g_dcOptions ); // attach the simulator to the viewer. viewer.addUpdateOperation( new TrackSimUpdate(trackSims) ); viewer.setRunFrameScheme( viewer.CONTINUOUS ); // configure a UI for controlling the demo createControls( &viewer ); viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f); viewer.run(); }
void Decluttering::setOptions( const DeclutteringOptions& options ) { // pull our prototype osgEarthAnnotationDeclutterRenderBin* bin = dynamic_cast<osgEarthAnnotationDeclutterRenderBin*>( osgUtil::RenderBin::getRenderBinPrototype( OSGEARTH_DECLUTTER_BIN ) ); if ( bin ) { // activate priority-sorting through the options. if ( options.sortByPriority().isSetTo( true ) && bin->_context->_options.sortByPriority() == false ) { Decluttering::setSortFunctor(new DeclutterByPriority()); } // communicate the new options on the shared context. bin->_context->_options = options; } }
/** * Creates a complete set of positioned label nodes from a feature list. */ osg::Node* createNode( const FeatureList& input, const Style& style, const FilterContext& context ) { const TextSymbol* text = style.get<TextSymbol>(); if ( !text ) return 0L; osg::Group* group = new osg::Group(); Decluttering::setEnabled( group->getOrCreateStateSet(), true ); if ( text->priority().isSet() ) { DeclutteringOptions dco = Decluttering::getOptions(); dco.sortByPriority() = text->priority().isSet(); Decluttering::setOptions( dco ); } StringExpression contentExpr ( *text->content() ); NumericExpression priorityExpr( *text->priority() ); if ( text->removeDuplicateLabels() == true ) { // in remove-duplicates mode, make a list of unique features, selecting // the one with the largest area as the one we'll use for labeling. typedef std::pair<double, osg::ref_ptr<const Feature> > Entry; typedef std::map<std::string, Entry> EntryMap; EntryMap used; for( FeatureList::const_iterator i = input.begin(); i != input.end(); ++i ) { Feature* feature = i->get(); if ( feature && feature->getGeometry() ) { const std::string& value = feature->eval( contentExpr ); if ( !value.empty() ) { double area = feature->getGeometry()->getBounds().area2d(); if ( used.find(value) == used.end() ) { used[value] = Entry(area, feature); } else { Entry& biggest = used[value]; if ( area > biggest.first ) { biggest.first = area; biggest.second = feature; } } } } } for( EntryMap::iterator i = used.begin(); i != used.end(); ++i ) { const std::string& value = i->first; const Feature* feature = i->second.second.get(); group->addChild( makeLabelNode(context, feature, value, text, priorityExpr) ); } } else { for( FeatureList::const_iterator i = input.begin(); i != input.end(); ++i ) { const Feature* feature = i->get(); if ( !feature ) continue; const Geometry* geom = feature->getGeometry(); if ( !geom ) continue; const std::string& value = feature->eval( contentExpr, &context ); if ( value.empty() ) continue; group->addChild( makeLabelNode(context, feature, value, text, priorityExpr) ); } } #if 0 // good idea but needs work. DepthOffsetGroup* dog = new DepthOffsetGroup(); dog->setMinimumOffset( 500.0 ); dog->addChild( group ); return dog; #endif return group; }