Example #1
0
void
MapNode::onModelLayerOverlayChanged( ModelLayer* layer )
{
    osg::ref_ptr<osg::Node> node = _modelLayerNodes[ layer ];
    if ( node.get() )
    {
        DrapeableNode* draper = dynamic_cast<DrapeableNode*>(node.get());
        if ( !draper && layer->getOverlay() )
        {
            draper = new DrapeableNode(this);
            draper->addChild( node.get() );
            _models->replaceChild( node.get(), draper );
        }
        else
        {
            draper->setDraped( layer->getOverlay() );
        }
    }

    //OE_NOTICE << "Overlay changed to "  << layer->getOverlay() << std::endl;
    //osg::ref_ptr< osg::Group > origParent = layer->getOverlay() ? _models.get() : _overlayModels.get();
    //osg::ref_ptr< osg::Group > newParent  = layer->getOverlay() ? _overlayModels.get() : _models.get();

    //osg::ref_ptr< osg::Node > node = layer->getOrCreateNode();
    //if (node.valid())
    //{
    //    //Remove it from the original parent and add it to the new parent
    //    origParent->removeChild( node.get() );
    //    newParent->addChild( node.get() );
    //}

    updateOverlayGraph();
}
Example #2
0
void
ImageOverlay::postCTOR()
{
    _geode = new osg::Geode;

    _transform = new osg::MatrixTransform;
    _transform->addChild( _geode );

    // place the geometry under a drapeable node so it will project onto the terrain    
    DrapeableNode* d = new DrapeableNode( getMapNode() );
    addChild( d );

    d->addChild( _transform );

    init();

    if ( Registry::capabilities().supportsGLSL() )
    {
        ShaderGenerator gen;
        d->accept( gen );
        //// need a shader that supports one texture
        //VirtualProgram* vp = new VirtualProgram();
        //vp->setName( "imageoverlay");
        //vp->installDefaultColoringShaders(1);
        //d->getOrCreateStateSet()->setAttributeAndModes( vp, 1 );
    }

    ADJUST_UPDATE_TRAV_COUNT( this, 1 );
}
osg::Node*
AnnotationUtils::installOverlayParent(osg::Node* node, const Style& style)
{
    AnnotationUtils::AltitudePolicy ap;

    AnnotationUtils::getAltitudePolicy( style, ap );

    // Draped (projected) geometry
    if ( ap.draping )
    {
        DrapeableNode* drapable = new DrapeableNode();
        drapable->addChild( node );
        node = drapable;
    }

    // gw - not sure whether is makes sense to support this for LocalizedNode
    // GPU-clamped geometry
    else if ( ap.gpuClamping )
    {
        ClampableNode* clampable = new ClampableNode();
        clampable->addChild( node );
        node = clampable;
    }

    return node;
}
Example #4
0
void
MapNode::onModelLayerAdded( ModelLayer* layer, unsigned int index )
{
    if ( !layer->getEnabled() )
        return;

    osg::Node* node = layer->getOrCreateNode();

    layer->addCallback(_modelLayerCallback.get() );

    if ( node )
    {
        if ( _modelLayerNodes.find( layer ) != _modelLayerNodes.end() )
        {
            OE_WARN
                << "Illegal: tried to add the name model layer more than once: " 
                << layer->getName()
                << std::endl;
        }
        else
        {
            if ( dynamic_cast<TerrainDecorator*>(node) || dynamic_cast<osgSim::OverlayNode*>(node) )
            {
                OE_INFO << LC << "Installing overlay node" << std::endl;
                addTerrainDecorator( node->asGroup() );
            }
            else
            {
                if ( layer->getOverlay() )
                {
#if 0
                    _overlayModels->addChild( node );
                    updateOverlayGraph();
#else
                    DrapeableNode* draper = new DrapeableNode( this );
                    draper->addChild( node );
                    _models->insertChild( index, draper );
#endif
                }
                else
                {
                    _models->insertChild( index, node );
                }
            }

            ModelSource* ms = layer->getModelSource();
            if ( ms && ms->getOptions().renderOrder().isSet() )
            {
                node->getOrCreateStateSet()->setRenderBinDetails(
                    ms->getOptions().renderOrder().value(), "RenderBin" );
            }

            _modelLayerNodes[ layer ] = node;
        }

        dirtyBound();
    }
}
Example #5
0
HTMNode::HTMNode(HTMSettings& settings,
                 const osg::Vec3d& v0, const osg::Vec3d& v1, const osg::Vec3d& v2,
                 const std::string& id) :
_settings(settings)
{
    setName(id);

    _isLeaf = true;
    _tri.set( v0, v1, v2 );

    if (settings._debugGeom)
    {
        const double R = SpatialReference::get("wgs84")->getEllipsoid()->getRadiusEquator();

        osg::Geometry* geom = new osg::Geometry();
        geom->setUseVertexBufferObjects(true);
    
        osg::Vec3Array* verts = new osg::Vec3Array();
        for (double t=0.0; t<1.0; t+=0.05)
            verts->push_back((v0 + (v1-v0)*t) * R);
        for (double t=0.0; t<1.0; t+=0.05)
            verts->push_back((v1 + (v2-v1)*t) * R);
        for (double t=0.0; t<1.0; t+=0.05)
            verts->push_back((v2 + (v0-v2)*t) * R);
        geom->setVertexArray(verts);

        osg::Vec4Array* color = new osg::Vec4Array();
        color->push_back(osg::Vec4(1,1,0,1));
        color->setBinding(color->BIND_OVERALL);
        geom->setColorArray(color);

        geom->addPrimitiveSet(new osg::DrawArrays(GL_LINE_LOOP, 0, verts->size()));
        geom->getOrCreateStateSet()->setAttribute(new osg::Program(), osg::StateAttribute::PROTECTED);

        osgText::Text* text = new osgText::Text();
        text->setText(Stringify() << getName() << "\nS=" << geom->getBound().radius()*2.0);
        text->setPosition((v0+v1+v2)/3 * R);
        text->setCharacterSizeMode(text->SCREEN_COORDS);
        text->setCharacterSize(48);
        text->setAutoRotateToScreen(true);
        text->setAlignment(text->CENTER_CENTER);
        text->getOrCreateStateSet()->setAttribute(new osg::Program(), osg::StateAttribute::PROTECTED);

        DrapeableNode* drape = new DrapeableNode();
        drape->addChild(geom);
        drape->addChild(text);
        _debug = drape;
    }
}
Example #6
0
osg::Node*
AnnotationUtils::installOverlayParent(osg::Node* node, const Style& style)
{
    AnnotationUtils::AltitudePolicy ap;

    AnnotationUtils::getAltitudePolicy( style, ap );

    // Draped (projected) geometry
    if ( ap.draping )
    {
        DrapeableNode* drapable = new DrapeableNode();
        drapable->addChild( node );
        node = drapable;
    }

    // gw - not sure whether is makes sense to support this for LocalizedNode
    // GPU-clamped geometry
    else if ( ap.gpuClamping )
    {
        ClampableNode* clampable = new ClampableNode( 0L );
        clampable->addChild( node );
        node = clampable;

        const RenderSymbol* render = style.get<RenderSymbol>();
        if ( render && render->depthOffset().isSet() )
        {
            clampable->setDepthOffsetOptions( *render->depthOffset() );
        }
    }

#if 0 // TODO -- constuct a callback instead.

    // scenegraph-clamped geometry
    else if ( ap.sceneClamping )
    {
        // save for later when we need to reclamp the mesh on the CPU
        _altitude = style.get<AltitudeSymbol>();

        // activate the terrain callback:
        setCPUAutoClamping( true );
    }

#endif

    return node;
}
Example #7
0
void
ImageOverlay::postCTOR()
{
    _geode = new osg::Geode;

    _transform = new osg::MatrixTransform;
    _transform->addChild( _geode );

    // place the geometry under a drapeable node so it will project onto the terrain    
    DrapeableNode* d = new DrapeableNode( getMapNode() );
    addChild( d );

    d->addChild( _transform );

    init();

    ADJUST_UPDATE_TRAV_COUNT( this, 1 );
}
Example #8
0
void
ImageOverlay::postCTOR()
{
    _updateScheduled = false;

    _root = new osg::Group;

    // place the geometry under a drapeable node so it will project onto the terrain    
    DrapeableNode* d = new DrapeableNode();
    d->setDrapingEnabled(*_draped);
    addChild( d );

    d->addChild( _root );

    init();

    ADJUST_EVENT_TRAV_COUNT(this, 1);
}
void
EllipseNode::rebuild()
{
    std::string currentDecoration = getDecoration();
    clearDecoration();

    //Remove all children from this node
    removeChildren( 0, getNumChildren() );

    //Remove all children from the attach point
    getAttachPoint()->removeChildren( 0, getAttachPoint()->getNumChildren() );

    // construct a local-origin ellipse.
    GeometryFactory factory;
    Geometry* geom = factory.createEllipse(osg::Vec3d(0,0,0), _radiusMajor, _radiusMinor, _rotationAngle, _numSegments);
    if ( geom )
    {
        GeometryCompiler compiler;
        osg::ref_ptr<Feature> feature = new Feature(geom, 0L); //todo: consider the SRS
        osg::Node* node = compiler.compile( feature.get(), _style, FilterContext(0L) );
        if ( node )
        {
            getAttachPoint()->addChild( node );

            if ( _draped )
            {
                DrapeableNode* drapeable = new DrapeableNode( _mapNode.get() );
                drapeable->addChild( getAttachPoint() );
                this->addChild( drapeable );
            }

            else
            {
                this->addChild( getAttachPoint() );
            }
        }

        applyStyle( _style, _draped );
    }

    setDecoration( currentDecoration );
}
Example #10
0
void
MapNode::onModelLayerAdded( ModelLayer* layer, unsigned int index )
{
    if ( !layer->getEnabled() )
        return;
    
    // install a noe operation that will associate this mapnode with
    // any MapNodeObservers loaded by the model layer:
    ModelSource* modelSource = layer->getModelSource();
    if ( modelSource )
    {
        // install a post-processing callback on the ModelLayer's source 
        // so we can update the MapNode on new data that comes in:
        modelSource->addPostProcessor( new MapNodeObserverInstaller(this) );
    }

    // create the scene graph:
    osg::Node* node = layer->getOrCreateNode();

    layer->addCallback(_modelLayerCallback.get() );

    if ( node )
    {
        if ( _modelLayerNodes.find( layer ) != _modelLayerNodes.end() )
        {
            OE_WARN
                << "Illegal: tried to add the name model layer more than once: " 
                << layer->getName()
                << std::endl;
        }
        else
        {
            if ( dynamic_cast<TerrainDecorator*>(node) )
            {
                OE_INFO << LC << "Installing overlay node" << std::endl;
                addTerrainDecorator( node->asGroup() );
            }
            else
            {
                if ( layer->getOverlay() )
                {
                    DrapeableNode* draper = new DrapeableNode( this );
                    draper->addChild( node );
                    node = draper;
                }

                _models->insertChild( index, node );
            }

            ModelSource* ms = layer->getModelSource();

            if ( ms )
            {
                // enfore a rendering bin if necessary:
                if ( ms->getOptions().renderOrder().isSet() )
                {
                    node->getOrCreateStateSet()->setRenderBinDetails(
                        ms->getOptions().renderOrder().value(), "RenderBin" );
                }
            }

            _modelLayerNodes[ layer ] = node;
        }

        dirtyBound();
    }
}
Example #11
0
void
FeatureNode::build()
{
    if ( !_clampCallback.valid() )
        _clampCallback = new ClampCallback(this);

    _attachPoint = 0L;

    // if there is existing geometry, kill it
    this->removeChildren( 0, this->getNumChildren() );

    if ( !getMapNode() )
        return;

    if ( _features.empty() )
        return;

    const Style &style = getStyle();

    // compilation options.
    GeometryCompilerOptions options = _options;

    // figure out what kind of altitude manipulation we need to perform.
    AnnotationUtils::AltitudePolicy ap;
    AnnotationUtils::getAltitudePolicy( style, ap );

    // If we're doing auto-clamping on the CPU, shut off compiler map clamping
    // clamping since it would be redundant.
    if ( ap.sceneClamping )
    {
        options.ignoreAltitudeSymbol() = true;
    }

    _clamperData.clear();

    osg::Node* node = _compiled.get();
    if (_needsRebuild || !_compiled.valid() )
    {
        // Clone the Features before rendering as the GeometryCompiler and it's filters can change the coordinates
        // of the geometry when performing localization or converting to geocentric.
        _extent = GeoExtent::INVALID;

        FeatureList clone;
        for(FeatureList::iterator itr = _features.begin(); itr != _features.end(); ++itr)
        {
            Feature* feature = new Feature( *itr->get(), osg::CopyOp::DEEP_COPY_ALL);
            GeoExtent featureExtent(feature->getSRS(), feature->getGeometry()->getBounds());

            if (_extent.isInvalid())
            {
                _extent = featureExtent;
            }
            else
            {
                _extent.expandToInclude( featureExtent );
            }
            clone.push_back( feature );
        }

        // prep the compiler:
        GeometryCompiler compiler( options );
        Session* session = new Session( getMapNode()->getMap(), _styleSheet.get() );

        FilterContext context( session, new FeatureProfile( _extent ), _extent, _index);

        _compiled = compiler.compile( clone, style, context );
        node = _compiled.get();
        _needsRebuild = false;

        // Compute the world bounds
        osg::BoundingSphered bounds;
        for( FeatureList::iterator itr = _features.begin(); itr != _features.end(); ++itr)
        {
            osg::BoundingSphered bs;
            itr->get()->getWorldBound(getMapNode()->getMapSRS(), bs);
            bounds.expandBy(bs);
        }

        // The polytope will ensure we only clamp to intersecting tiles:
        Feature::getWorldBoundingPolytope(bounds, getMapNode()->getMapSRS(), _featurePolytope);
    }

    if ( node )
    {
        if ( AnnotationUtils::styleRequiresAlphaBlending( style ) &&
             getStyle().get<ExtrusionSymbol>() )
        {
            node = AnnotationUtils::installTwoPassAlpha( node );
        }

        _attachPoint = new osg::Group();
        _attachPoint->addChild( node );

        // Draped (projected) geometry
        if ( ap.draping )
        {
            DrapeableNode* d = new DrapeableNode();
            d->addChild( _attachPoint );
            this->addChild( d );
        }

        // GPU-clamped geometry
        else if ( ap.gpuClamping )
        {
            ClampableNode* clampable = new ClampableNode();
            clampable->addChild( _attachPoint );
            this->addChild( clampable );
        }

        else
        {
            this->addChild( _attachPoint );

            // set default lighting based on whether we are extruding:
            setDefaultLighting( style.has<ExtrusionSymbol>() );
        }

        applyRenderSymbology(style);

        if ( getMapNode()->getTerrain() )
        {
            if ( ap.sceneClamping )
            {
                // Need dynamic data variance since scene clamping will change the verts
                SetDataVarianceVisitor sdv(osg::Object::DYNAMIC);
                this->accept(sdv);

                getMapNode()->getTerrain()->addTerrainCallback(_clampCallback.get());
                clamp(getMapNode()->getTerrain()->getGraph(), getMapNode()->getTerrain());
            }
            else
            {
                getMapNode()->getTerrain()->removeTerrainCallback( _clampCallback.get() );
            }
        }
    }
}
Example #12
0
void
FeatureNode::build()
{
    // if there's a decoration, clear it out first.
    this->clearDecoration();
    _attachPoint = 0L;

    // if there is existing geometry, kill it
    this->removeChildren( 0, this->getNumChildren() );

    if ( !getMapNode() )
        return;

    if ( _features.empty() )
        return;

    const Style &style = getStyle();

    // compilation options.
    GeometryCompilerOptions options = _options;
    
    // figure out what kind of altitude manipulation we need to perform.
    AnnotationUtils::AltitudePolicy ap;
    AnnotationUtils::getAltitudePolicy( style, ap );

    // If we're doing auto-clamping on the CPU, shut off compiler map clamping
    // clamping since it would be redundant.
    // TODO: I think this is OBE now that we have "scene" clamping technique..
    if ( ap.sceneClamping )
    {
        options.ignoreAltitudeSymbol() = true;
    }

    osg::Node* node = _compiled.get();
    if (_needsRebuild || !_compiled.valid() )
    {
        // Clone the Features before rendering as the GeometryCompiler and it's filters can change the coordinates
        // of the geometry when performing localization or converting to geocentric.
        _extent = GeoExtent::INVALID;

        FeatureList clone;
        for(FeatureList::iterator itr = _features.begin(); itr != _features.end(); ++itr)
        {
            Feature* feature = new Feature( *itr->get(), osg::CopyOp::DEEP_COPY_ALL);
            GeoExtent featureExtent(feature->getSRS(), feature->getGeometry()->getBounds());

            if (_extent.isInvalid())
            {
                _extent = featureExtent;
            }
            else
            {
                _extent.expandToInclude( featureExtent );
            }
            clone.push_back( feature );
        }

        // prep the compiler:
        GeometryCompiler compiler( options );
        Session* session = new Session( getMapNode()->getMap(), _styleSheet.get() );

        FilterContext context( session, new FeatureProfile( _extent ), _extent );

        _compiled = compiler.compile( clone, style, context );
        node = _compiled.get();
        _needsRebuild = false;

        // Compute the world bounds
        osg::BoundingSphered bounds;
        for( FeatureList::iterator itr = _features.begin(); itr != _features.end(); ++itr)
        {
            osg::BoundingSphered bs;
            itr->get()->getWorldBound(getMapNode()->getMapSRS(), bs);
            bounds.expandBy(bs);
        }
        // The polytope will ensure we only clamp to intersecting tiles:
        Feature::getWorldBoundingPolytope(bounds, getMapNode()->getMapSRS(), _featurePolytope);

    }

    if ( node )
    {
        if ( AnnotationUtils::styleRequiresAlphaBlending( style ) &&
             getStyle().get<ExtrusionSymbol>() )
        {
            node = AnnotationUtils::installTwoPassAlpha( node );
        }

        //OE_NOTICE << GeometryUtils::geometryToGeoJSON( _feature->getGeometry() ) << std::endl;

        _attachPoint = new osg::Group();
        _attachPoint->addChild( node );

        // Draped (projected) geometry
        if ( ap.draping )
        {
            DrapeableNode* d = new DrapeableNode(); // getMapNode() );
            d->addChild( _attachPoint );
            this->addChild( d );
        }

        // GPU-clamped geometry
        else if ( ap.gpuClamping )
        {
            ClampableNode* clampable = new ClampableNode( getMapNode() );
            clampable->addChild( _attachPoint );
            this->addChild( clampable );

            const RenderSymbol* render = style.get<RenderSymbol>();
            if ( render && render->depthOffset().isSet() )
            {
                clampable->setDepthOffsetOptions( *render->depthOffset() );
            }
        }

        else 
        {
            this->addChild( _attachPoint );

            // CPU-clamped geometry?
            if ( ap.sceneClamping )
            {
                // save for later when we need to reclamp the mesh on the CPU
                _altitude = style.get<AltitudeSymbol>();

                // activate the terrain callback:
                setCPUAutoClamping( true );

                // set default lighting based on whether we are extruding:
                setLightingIfNotSet( style.has<ExtrusionSymbol>() );

                // do an initial clamp to get started.
                clampMesh( getMapNode()->getTerrain()->getGraph() );
            } 

            applyRenderSymbology( style );
        }
    }

    updateClusterCulling();
}
Example #13
0
void
FeatureNode::init()
{
    // if there's a decoration, clear it out first.
    this->clearDecoration();
    _attachPoint = 0L;

    // if there is existing geometry, kill it
    this->removeChildren( 0, this->getNumChildren() );

    if ( !getMapNode() )
        return;

    if ( !_feature.valid() )
        return;

    // compilation options.
    GeometryCompilerOptions options = _options;
    
    // figure out what kind of altitude manipulation we need to perform.
    AnnotationUtils::AltitudePolicy ap;
    AnnotationUtils::getAltitudePolicy( *_feature->style(), ap );

    // If we're doing auto-clamping on the CPU, shut off compiler map clamping
    // clamping since it would be redundant.
    // TODO: I think this is OBE now that we have "scene" clamping technique..
    if ( ap.sceneClamping )
    {
        options.ignoreAltitudeSymbol() = true;
    }

    // prep the compiler:
    GeometryCompiler compiler( options );
    Session* session = new Session( getMapNode()->getMap() );
    GeoExtent extent(_feature->getSRS(), _feature->getGeometry()->getBounds());
    osg::ref_ptr<FeatureProfile> profile = new FeatureProfile( extent );
    FilterContext context( session, profile.get(), extent );

    // Clone the Feature before rendering as the GeometryCompiler and it's filters can change the coordinates
    // of the geometry when performing localization or converting to geocentric.
    osg::ref_ptr< Feature > clone = new Feature(*_feature.get(), osg::CopyOp::DEEP_COPY_ALL);

    osg::Node* node = compiler.compile( clone.get(), *clone->style(), context );
    if ( node )
    {
        if ( _feature->style().isSet() &&
            AnnotationUtils::styleRequiresAlphaBlending( *_feature->style() ) &&
            _feature->style()->get<ExtrusionSymbol>() )
        {
            node = AnnotationUtils::installTwoPassAlpha( node );
        }

        _attachPoint = new osg::Group();
        _attachPoint->addChild( node );

        // Draped (projected) geometry
        if ( ap.draping )
        {
            DrapeableNode* d = new DrapeableNode( getMapNode() );
            d->addChild( _attachPoint );
            this->addChild( d );
        }

        // GPU-clamped geometry
        else if ( ap.gpuClamping )
        {
            ClampableNode* clampable = new ClampableNode( getMapNode() );
            clampable->addChild( _attachPoint );
            this->addChild( clampable );

            const RenderSymbol* render = _feature->style()->get<RenderSymbol>();
            if ( render && render->depthOffset().isSet() )
            {
                clampable->setDepthOffsetOptions( *render->depthOffset() );
            }
        }

        else 
        {
            this->addChild( _attachPoint );

            // CPU-clamped geometry?
            if ( ap.sceneClamping )
            {
                // save for later when we need to reclamp the mesh on the CPU
                _altitude = _feature->style()->get<AltitudeSymbol>();

                // The polytope will ensure we only clamp to intersecting tiles:
                _feature->getWorldBoundingPolytope( getMapNode()->getMapSRS(), _featurePolytope );

                // activate the terrain callback:
                setCPUAutoClamping( true );

                // set default lighting based on whether we are extruding:
                setLightingIfNotSet( _feature->style()->has<ExtrusionSymbol>() );

                // do an initial clamp to get started.
                clampMesh( getMapNode()->getTerrain()->getGraph() );
            }
        }
    }
}
Example #14
0
void
FeatureNode::init()
{
    // if there's a decoration, clear it out first.
    this->clearDecoration();
    _attachPoint = 0L;

    // if there is existing geometry, kill it
    this->removeChildren( 0, this->getNumChildren() );

    if ( !getMapNode() )
        return;

    // build the new feature geometry
    {
        if ( _feature.valid() )
        {
            _feature->getWorldBoundingPolytope( getMapNode()->getMapSRS(), _featurePolytope );
        }

        GeometryCompilerOptions options = _options;
        
        // have to disable compiler clamping if we're doing auto-clamping; especially
        // in terrain-relative mode because the auto-clamper will think the clamped
        // coords are the relative coords.
        bool autoClamping = !_draped && supportsAutoClamping(*_feature->style());
        if ( autoClamping )
        {
            options.ignoreAltitudeSymbol() = true;
        }

        // prep the compiler:
        GeometryCompiler compiler( options );
        Session* session = new Session( getMapNode()->getMap() );
        GeoExtent extent(_feature->getSRS(), _feature->getGeometry()->getBounds());
        osg::ref_ptr<FeatureProfile> profile = new FeatureProfile( extent );
        FilterContext context( session, profile.get(), extent );

        // Clone the Feature before rendering as the GeometryCompiler and it's filters can change the coordinates
        // of the geometry when performing localization or converting to geocentric.
        osg::ref_ptr< Feature > clone = new Feature(*_feature.get(), osg::CopyOp::DEEP_COPY_ALL);        

        osg::Node* node = compiler.compile( clone.get(), *clone->style(), context );
        if ( node )
        {
            if ( _feature->style().isSet() &&
                AnnotationUtils::styleRequiresAlphaBlending( *_feature->style() ) &&
                _feature->style()->get<ExtrusionSymbol>() )
            {
                node = AnnotationUtils::installTwoPassAlpha( node );
            }

            _attachPoint = new osg::Group();
            _attachPoint->addChild( node );

            if ( _draped )
            {
                DrapeableNode* d = new DrapeableNode( getMapNode() );
                d->addChild( _attachPoint );
                this->addChild( d );
            }
            else
            {
                this->addChild( _attachPoint );
            }
        }

        // workaround until we can auto-clamp extruded/sub'd geometries.
        if ( autoClamping )
        {
            applyStyle( *_feature->style() );
            clampMesh( getMapNode()->getTerrain()->getGraph() );
        }
    }
}