예제 #1
0
/**
 * 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;
    }