/** * 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; }
/** creates some UI controls for adjusting the decluttering parameters. */ void createControls( osgViewer::View* view ) { ControlCanvas* canvas = ControlCanvas::getOrCreate(view); // title bar VBox* vbox = canvas->addControl(new VBox(Control::ALIGN_NONE, Control::ALIGN_BOTTOM, 2, 1 )); vbox->setBackColor( Color(Color::Black, 0.5) ); vbox->addControl( new LabelControl("osgEarth Tracks Demo", Color::Yellow) ); // checkbox that toggles decluttering of tracks struct ToggleDecluttering : public ControlEventHandler { void onValueChanged( Control* c, bool on ) { Decluttering::setEnabled( on ); } }; HBox* dcToggle = vbox->addControl( new HBox() ); dcToggle->addControl( new CheckBoxControl(true, new ToggleDecluttering()) ); dcToggle->addControl( new LabelControl("Declutter") ); // checkbox that toggles the coordinate display struct ToggleCoords : public ControlEventHandler { void onValueChanged( Control* c, bool on ) { g_showCoords = on; } }; HBox* coordsToggle = vbox->addControl( new HBox() ); coordsToggle->addControl( new CheckBoxControl(true, new ToggleCoords()) ); coordsToggle->addControl( new LabelControl("Show locations") ); // grid for the slider controls so they look nice Grid* grid = vbox->addControl( new Grid() ); grid->setHorizFill( true ); grid->setChildHorizAlign( Control::ALIGN_LEFT ); grid->setChildSpacing( 6 ); unsigned r=0; // event handler for changing decluttering options struct ChangeFloatOption : public ControlEventHandler { optional<float>& _param; LabelControl* _label; ChangeFloatOption( optional<float>& param, LabelControl* label ) : _param(param), _label(label) { } void onValueChanged( Control* c, float value ) { _param = value; _label->setText( Stringify() << std::fixed << std::setprecision(1) << value ); Decluttering::setOptions( g_dcOptions ); } }; grid->setControl( 0, r, new LabelControl("Sim loop duration:") ); LabelControl* speedLabel = grid->setControl( 2, r, new LabelControl(Stringify() << std::fixed << std::setprecision(1) << *g_duration) ); HSliderControl* speedSlider = grid->setControl( 1, r, new HSliderControl( 600.0, 30.0, *g_duration, new ChangeFloatOption(g_duration, speedLabel) ) ); speedSlider->setHorizFill( true, 200 ); grid->setControl( 0, ++r, new LabelControl("Min scale:") ); LabelControl* minAnimationScaleLabel = grid->setControl( 2, r, new LabelControl(Stringify() << std::fixed << std::setprecision(1) << *g_dcOptions.minAnimationScale()) ); grid->setControl( 1, r, new HSliderControl( 0.0, 1.0, *g_dcOptions.minAnimationScale(), new ChangeFloatOption(g_dcOptions.minAnimationScale(), minAnimationScaleLabel) ) ); grid->setControl( 0, ++r, new LabelControl("Min alpha:") ); LabelControl* alphaLabel = grid->setControl( 2, r, new LabelControl(Stringify() << std::fixed << std::setprecision(1) << *g_dcOptions.minAnimationAlpha()) ); grid->setControl( 1, r, new HSliderControl( 0.0, 1.0, *g_dcOptions.minAnimationAlpha(), new ChangeFloatOption(g_dcOptions.minAnimationAlpha(), alphaLabel) ) ); grid->setControl( 0, ++r, new LabelControl("Activate time (s):") ); LabelControl* actLabel = grid->setControl( 2, r, new LabelControl(Stringify() << std::fixed << std::setprecision(1) << *g_dcOptions.inAnimationTime()) ); grid->setControl( 1, r, new HSliderControl( 0.0, 2.0, *g_dcOptions.inAnimationTime(), new ChangeFloatOption(g_dcOptions.inAnimationTime(), actLabel) ) ); grid->setControl( 0, ++r, new LabelControl("Deactivate time (s):") ); LabelControl* deactLabel = grid->setControl( 2, r, new LabelControl(Stringify() << std::fixed << std::setprecision(1) << *g_dcOptions.outAnimationTime()) ); grid->setControl( 1, r, new HSliderControl( 0.0, 2.0, *g_dcOptions.outAnimationTime(), new ChangeFloatOption(g_dcOptions.outAnimationTime(), deactLabel) ) ); }