Style buildStyle( const osg::Vec4 &color, float width )
{
    // Define a style for the feature data. Since we are going to render the
    // vectors as lines, configure the line symbolizer:
    Style style;

    LineSymbol* ls = style.getOrCreateSymbol<LineSymbol>();
    ls->stroke()->color() = color;
    ls->stroke()->width() = width;    
    ls->tessellation() = 10;

    AltitudeSymbol* as = style.getOrCreate<AltitudeSymbol>();
    as->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
    as->technique() = AltitudeSymbol::TECHNIQUE_SCENE;

    RenderSymbol* rs = style.getOrCreateSymbol<RenderSymbol>();
    rs->depthOffset()->enabled() = true;
    rs->depthOffset()->minBias() = 1000;

    return style;    
}
Ejemplo n.º 2
0
void
GeodeticGraticule::initLabelPool(CameraData& cdata)
{
    const osgEarth::SpatialReference* srs = osgEarth::SpatialReference::create("wgs84");

    Style style;
    TextSymbol* text = style.getOrCreateSymbol<TextSymbol>();
    text->alignment() = TextSymbol::ALIGN_CENTER_CENTER;
    text->fill()->color() = options().labelColor().get();
    AltitudeSymbol* alt = style.getOrCreateSymbol<AltitudeSymbol>();
    alt->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;

    unsigned int labelPoolSize = 8 * options().gridLines().get();
    for (unsigned int i = 0; i < labelPoolSize; i++)
    {
        GeoPoint pt(srs, 0,0,0);
        LabelNode* label = new LabelNode(_mapNode.get(), pt, "0,0");
        label->setDynamic(true);
        label->setStyle(style);
        cdata._labelPool.push_back(label);
    }
}
Ejemplo n.º 3
0
void
KML_Geometry::parseStyle( const Config& conf, KMLContext& cx, Style& style )
{
    _extrude = conf.value("extrude") == "1";
    _tessellate = conf.value("tessellate") == "1";

    std::string am = conf.value("altitudemode");

    // clampToGround is the default. We will be draping the geometry UNLESS tessellate is
    // set to true.
    if ( (am.empty() || am == "clampToGround") && _tessellate )
    {
        AltitudeSymbol* af = style.getOrCreate<AltitudeSymbol>();
        af->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
        _extrude = false;
    }

    // "relativeToGround" means the coordinates' Z values are relative to the Z of the
    // terrain at that point. NOTE: GE flattens rooftops in this mode when extrude=1,
    // which seems wrong..
    else if ( am == "relativeToGround" )
    {
        AltitudeSymbol* af = style.getOrCreate<AltitudeSymbol>();
        af->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
    }

    // "absolute" means to treat the Z values as-is
    else if ( am == "absolute" )
    {
        AltitudeSymbol* af = style.getOrCreate<AltitudeSymbol>();
        af->clamping() = AltitudeSymbol::CLAMP_ABSOLUTE;
    }

    if ( _extrude )
    {
        ExtrusionSymbol* es = style.getOrCreate<ExtrusionSymbol>();
        es->flatten() = false;
    }
}
Ejemplo n.º 4
0
void
ExtrudeGeometryFilter::reset( const FilterContext& context )
{
    _cosWallAngleThresh = cos( _wallAngleThresh_deg );
    _geodes.clear();
    
    if ( _styleDirty )
    {
        const StyleSheet* sheet = context.getSession() ? context.getSession()->styles() : 0L;

        _wallSkinSymbol    = 0L;
        _wallPolygonSymbol = 0L;
        _roofSkinSymbol    = 0L;
        _roofPolygonSymbol = 0L;
        _extrusionSymbol   = 0L;
        _outlineSymbol     = 0L;

        _extrusionSymbol = _style.get<ExtrusionSymbol>();
        if ( _extrusionSymbol.valid() )
        {
            // make a copy of the height expression so we can use it:
            if ( _extrusionSymbol->heightExpression().isSet() )
            {
                _heightExpr = *_extrusionSymbol->heightExpression();
            }

            // If there is no height expression, and we have either absolute or terrain-relative
            // clamping, THAT means that we want to extrude DOWN from the geometry to the ground
            // (instead of from the geometry.)
            AltitudeSymbol* alt = _style.get<AltitudeSymbol>();
            if ( alt && !_extrusionSymbol->heightExpression().isSet() && !_extrusionSymbol->height().isSet() )
            {
                if (alt->clamping() == AltitudeSymbol::CLAMP_ABSOLUTE ||
                    alt->clamping() == AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN )
                {
                    _heightExpr = NumericExpression( "0-[__max_hat]" );
                }
            }
            
            // attempt to extract the wall symbols:
            if ( _extrusionSymbol->wallStyleName().isSet() && sheet != 0L )
            {
                const Style* wallStyle = sheet->getStyle( *_extrusionSymbol->wallStyleName(), false );
                if ( wallStyle )
                {
                    _wallSkinSymbol = wallStyle->get<SkinSymbol>();
                    _wallPolygonSymbol = wallStyle->get<PolygonSymbol>();
                }
            }

            // attempt to extract the rooftop symbols:
            if ( _extrusionSymbol->roofStyleName().isSet() && sheet != 0L )
            {
                const Style* roofStyle = sheet->getStyle( *_extrusionSymbol->roofStyleName(), false );
                if ( roofStyle )
                {
                    _roofSkinSymbol = roofStyle->get<SkinSymbol>();
                    _roofPolygonSymbol = roofStyle->get<PolygonSymbol>();
                }
            }

            // if there's a line symbol, use it to outline the extruded data.
            _outlineSymbol = _style.get<LineSymbol>();
        }

        // backup plan for skin symbols:
        const SkinSymbol* skin = _style.get<SkinSymbol>();
        if ( skin )
        {
            if ( !_wallSkinSymbol.valid() )
                _wallSkinSymbol = skin;
            if ( !_roofSkinSymbol.valid() )
                _roofSkinSymbol = skin;
        }

        // backup plan for poly symbols:
        const PolygonSymbol* poly = _style.get<PolygonSymbol>();
        if ( poly )
        {
            if ( !_wallPolygonSymbol.valid() )
                _wallPolygonSymbol = poly;
            if ( !_roofPolygonSymbol.valid() )
                _roofPolygonSymbol = poly;
        }

        _styleDirty = false;
    }
}
Ejemplo n.º 5
0
void 
KML_Placemark::build( xml_node<>* node, KMLContext& cx )
{
	Style masterStyle;

	std::string styleUrl = getValue(node, "styleurl");

	if (!styleUrl.empty())
	{	// process a "stylesheet" style
		const Style* ref_style = cx._sheet->getStyle( styleUrl, false );
		if (ref_style)
		{
			masterStyle = masterStyle.combineWith(*ref_style);
		}
	}

	xml_node<>* style = node->first_node("style", 0, false);
	if ( style )
	{	// process an "inline" style
		KML_Style kmlStyle;
		kmlStyle.scan(style, cx);
		masterStyle = masterStyle.combineWith(cx._activeStyle);
	}

    // parse the geometry. the placemark must have geometry to be valid. The 
    // geometry parse may optionally specify an altitude mode as well.
    KML_Geometry geometry;
    geometry.build(node, cx, masterStyle);

    Geometry* allGeom = geometry._geom.get();
    if ( allGeom )
    {
        GeometryIterator giter( allGeom, false );
        while( giter.hasMore() )
        {
            Geometry* geom = giter.next();
            Style style = masterStyle;

            AltitudeSymbol* alt = style.get<AltitudeSymbol>();
            
            if ( geom && geom->getTotalPointCount() > 0 )
            {
                // resolve the proper altitude mode for the anchor point
                AltitudeMode altMode = ALTMODE_RELATIVE;
                if (alt && 
                    !alt->clamping().isSetTo( alt->CLAMP_TO_TERRAIN ) &&
                    !alt->clamping().isSetTo( alt->CLAMP_RELATIVE_TO_TERRAIN ) )
                {
                    altMode = ALTMODE_ABSOLUTE;
                }

                GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode);

                bool isPoly = geom->getComponentType() == Geometry::TYPE_POLYGON;
                bool isPoint = geom->getComponentType() == Geometry::TYPE_POINTSET;

                // check for symbols.
                ModelSymbol*    model = style.get<ModelSymbol>();
                IconSymbol*     icon  = style.get<IconSymbol>();
                TextSymbol*     text  = style.get<TextSymbol>();

                // the annotation name:
                std::string name = getValue(node, "name");

                AnnotationNode* featureNode = 0L;
                AnnotationNode* iconNode    = 0L;
                AnnotationNode* modelNode   = 0L;

                // one coordinate? It's a place marker or a label.
                if ( (model || icon || text) && geom->getTotalPointCount() == 1 )
                {
                    // load up the default icon if there we don't have one.
                    if ( !model && !icon )
                    {
                        icon = cx._options->defaultIconSymbol().get();
                        if ( icon )
                            style.add( icon );
                    }

                    // if there's a model, render that - models do NOT get labels.
                    if ( model )
                    {
                        ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions );
                        node->setPosition( position );

                        // model scale:
                        if ( cx._options->modelScale() != 1.0f )
                        {
                            float s = *cx._options->modelScale();
                            node->setScale( osg::Vec3f(s,s,s) );
                        }

                        // model local tangent plane rotation:
                        if ( !cx._options->modelRotation()->zeroRotation() )
                        {
                            node->setLocalRotation( *cx._options->modelRotation() );
                        }

                        modelNode = node;
                    }

                    // is there a label?
                    else if ( !name.empty() )
                    {
                        if ( !text && cx._options->defaultTextSymbol().valid() )
                        {
                            text = cx._options->defaultTextSymbol().get();
                            style.addSymbol( text );

                        }
                        else
                        {
                            text = style.getOrCreate<TextSymbol>();
                            text->encoding() = TextSymbol::ENCODING_UTF8;
                        }
                        text->content()->setLiteral( name );
                    }

                    // is there an icon?
                    if ( icon )
                    {
                        iconNode = new PlaceNode( cx._mapNode, position, style, cx._dbOptions );
                    }

                    else if ( !model && text && !name.empty() )
                    {
                        // note: models do not get labels.
                        iconNode = new LabelNode( cx._mapNode, position, style );
                    }
                }

                // multiple coords? feature:
                if ( geom->getTotalPointCount() > 1 )
                {
                    ExtrusionSymbol* extruded = style.get<ExtrusionSymbol>();

                    // Remove symbols that we have already processed so the geometry
                    // compiler doesn't get confused.
                    if ( model )
                        style.removeSymbol( model );
                    if ( icon )
                        style.removeSymbol( icon );
                    if ( text )
                        style.removeSymbol( text );

                    Feature* feature = new Feature(geom, cx._srs.get(), style);
                    featureNode = new FeatureNode( cx._mapNode, feature );
                }


                // assemble the results:
                if ( (iconNode || modelNode) && featureNode )
                {
                    osg::Group* group = new osg::Group();
                    group->addChild( featureNode );
                    if ( iconNode )
                        group->addChild( iconNode );
                    if ( modelNode )
                        group->addChild( modelNode );

                    cx._groupStack.top()->addChild( group );

                    if ( iconNode && cx._options->declutter() == true )
                    {
                        Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true );
                    }

                    if ( iconNode )
                        KML_Feature::build( node, cx, iconNode );
                    if ( modelNode )
                        KML_Feature::build( node, cx, modelNode );
                    if ( featureNode )
                        KML_Feature::build( node, cx, featureNode );
                }

                else
                {
                    if ( iconNode )
                    {
                        if ( cx._options->iconAndLabelGroup().valid() )
                        {
                            cx._options->iconAndLabelGroup()->addChild( iconNode );
                        }
                        else
                        {
                            cx._groupStack.top()->addChild( iconNode );
                            if ( cx._options->declutter() == true )
                            {
                                Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true );
                            }
                        }
                        KML_Feature::build( node, cx, iconNode );
                    }
                    if ( modelNode )
                    {
                        cx._groupStack.top()->addChild( modelNode );
                        KML_Feature::build( node, cx, modelNode );
                    }
                    if ( featureNode )
                    {
                        cx._groupStack.top()->addChild( featureNode );
                        KML_Feature::build( node, cx, featureNode );
                    }
                }
            }
        }
    }
}
Ejemplo n.º 6
0
int
main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc,argv);
    if ( arguments.read("--help") )
        return usage(argv[0]);

    // general setup:
    osgViewer::Viewer viewer(arguments);
    viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false );
    viewer.setCameraManipulator( new EarthManipulator(arguments) );
    viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
    viewer.getCamera()->setNearFarRatio(0.00002);

    // load an earth file, and support all or our example command-line options
    // and earth file <external> tags    
    osg::Node* node = MapNodeHelper().load( arguments, &viewer );
    if ( node )
    {        
        MapNode* mapNode = MapNode::get(node);
        if ( !mapNode )
            return usage(argv[0]);

        // Create the WFS driver:
        osgEarth::Drivers::WFSFeatureOptions wfs;
        wfs.url()          = osgEarth::URI("http://demo.opengeo.org/geoserver/wfs"); 
        wfs.typeName()     = "states"; 
        wfs.outputFormat() = "json";     // JSON or GML

        // Configure a rendering style:
        Style style;
        style.setName( "states" ); 

        LineSymbol* line = style.getOrCreate<LineSymbol>(); 
        line->stroke()->color() = Color::Yellow; 
        line->stroke()->width() = 5.0f;
        line->stroke()->widthUnits() = Units::PIXELS;

        AltitudeSymbol* alt = style.getOrCreate<AltitudeSymbol>();
        alt->clamping()  = AltitudeSymbol::CLAMP_TO_TERRAIN;
        alt->technique() = AltitudeSymbol::TECHNIQUE_DRAPE;

        // Configure a model layer to render the features:
        osgEarth::Drivers::FeatureGeomModelOptions geom; 
        geom.featureOptions() = wfs;
        geom.styles()         = new StyleSheet(); 
        geom.styles()->addStyle(style); 

        // Make the new layer and add it to the map.
        ModelLayerOptions layerOptions("states", geom); 
        ModelLayer* layer = new ModelLayer(layerOptions); 
        mapNode->getMap()->addModelLayer(layer);
        
        viewer.setSceneData( node );
        return viewer.run();
    }
    else
    {
        return usage(argv[0]);
    }
}
Ejemplo n.º 7
0
void
KML_Geometry::parseStyle( xml_node<>* node, KMLContext& cx, Style& style )
{
    _extrude = getValue(node, "extrude") == "1";
    _tessellate = getValue(node, "tessellate") == "1";

    std::string am = getValue(node, "altitudemode");
    if ( am.empty() )
        am = "clampToGround"; // default.

    bool isPoly = _geom.valid() && _geom->getComponentType() == Geometry::TYPE_POLYGON;
    bool isLine = _geom.valid() && _geom->getComponentType() == Geometry::TYPE_LINESTRING;

    // Resolve the correct altitude symbol. CLAMP_TO_TERRAIN is the default, but the
    // technique will depend on the geometry's type and setup.
    AltitudeSymbol* alt = style.getOrCreate<AltitudeSymbol>();
    alt->clamping() = alt->CLAMP_TO_TERRAIN;


    // Compute some info about the geometry

    // Are all of the elevations zero?
    bool zeroElev = true;
    // Are all of the the elevations the same?
    bool sameElev = true;

    double maxElevation = -DBL_MAX;

    //if ( isPoly ) //compute maxElevation also for line strings for extrusion height
    {
        bool first = true;
        double e = 0.0;
        ConstGeometryIterator gi( _geom.get(), false );
        while(gi.hasMore() )
        {
            const Geometry* g = gi.next();
            for( Geometry::const_iterator ji = g->begin(); ji != g->end(); ++ji )
            {
                if ( !osg::equivalent(ji->z(), 0.0) )
                    zeroElev = false;

                if (first)
                {
                    first = false;
                    e = ji->z();
                }
                else
                {
                    if (!osg::equivalent(e, ji->z()))
                    {
                        sameElev = false;
                    }
                }

                if (ji->z() > maxElevation) maxElevation = ji->z();
            }
        }
    }

    // clamp to ground mode:
    if ( am == "clampToGround" )
    {
        if ( _extrude )
        {
            alt->technique() = alt->TECHNIQUE_MAP;
        }
        else if ( isPoly )
        {
            alt->technique() = alt->TECHNIQUE_DRAPE;
        }
        else if ( isLine)
        {
            alt->technique() = alt->TECHNIQUE_DRAPE; // or could be GPU.
        }
        else // line or point
        {
            alt->technique() = alt->TECHNIQUE_SCENE;
        }

        // extrusion is not compatible with clampToGround.
        _extrude = false;
    }

    // "relativeToGround" means the coordinates' Z values are relative to the Z of the
    // terrain at that point. NOTE: GE flattens rooftops in this mode when extrude=1,
    // which seems wrong..
    else if ( am == "relativeToGround" )
    {
        alt->clamping() = alt->CLAMP_RELATIVE_TO_TERRAIN;

        if (isPoly)
        {
            // If all of the verts have the same elevation then assume that it should be clamped at the centroid and not per vertex.
            if (sameElev)
            {
                alt->binding() = AltitudeSymbol::BINDING_CENTROID;
            }

            if ( _extrude )
            {
                alt->technique() = alt->TECHNIQUE_MAP;
            }
            else
            {
                alt->technique() = alt->TECHNIQUE_SCENE;

                if ( zeroElev )
                {
                    alt->clamping()  = alt->CLAMP_TO_TERRAIN;
                    alt->technique() = alt->TECHNIQUE_DRAPE;
                }
            }
        }
    }

    // "absolute" means to treat the Z values as-is
    else if ( am == "absolute" )
    {
        alt->clamping() = AltitudeSymbol::CLAMP_NONE;
    }

    if ( _extrude )
    {
        ExtrusionSymbol* es = style.getOrCreate<ExtrusionSymbol>();
        es->flatten() = false;
        if (*alt->clamping() == AltitudeSymbol::CLAMP_NONE)
        {
            // Set the height to the max elevation + the approx depth of the mariana trench so that it will extend low enough to be always go to the surface of the earth.
            // This lets us avoid clamping absolute absolute extruded polygons completely.
            es->height() = -(maxElevation + 11100.0);
        }
    }
    else
    {
        // remove polystyle since it doesn't apply to non-extruded lines and points
        if ( !isPoly )
        {
            style.remove<PolygonSymbol>();
        }
    }
}
Ejemplo n.º 8
0
bool
SLDReader::readStyleFromCSSParams( const Config& conf, Style& sc )
{
    sc.setName( conf.key() );

    LineSymbol*      line      = 0L;
    PolygonSymbol*   polygon   = 0L;
    PointSymbol*     point     = 0L;
    TextSymbol*      text      = 0L;
    ExtrusionSymbol* extrusion = 0L;
    MarkerSymbol*    marker     = 0L;
    AltitudeSymbol*  altitude  = 0L;

    for(Properties::const_iterator p = conf.attrs().begin(); p != conf.attrs().end(); p++ )
    {
        if ( p->first == CSS_STROKE )
        {
            if (!line) line = sc.getOrCreateSymbol<LineSymbol>();
            line->stroke()->color() = htmlColorToVec4f( p->second );
        }
        else if ( p->first == CSS_STROKE_OPACITY )
        {
            if (!line) line = sc.getOrCreateSymbol<LineSymbol>();
            line->stroke()->color().a() = as<float>( p->second, 1.0f );
        }
        else if ( p->first == CSS_STROKE_WIDTH )
        {
            if (!line) line = sc.getOrCreateSymbol<LineSymbol>();
            line->stroke()->width() = as<float>( p->second, 1.0f );
        }
        else if ( p->first == CSS_STROKE_LINECAP )
        {
            if (!line) line = sc.getOrCreateSymbol<LineSymbol>();
            parseLineCap( p->second, line->stroke()->lineCap() );
        }
        else if ( p->first == CSS_FILL )
        {
            if (!polygon) polygon = sc.getOrCreateSymbol<PolygonSymbol>();
            polygon->fill()->color() = htmlColorToVec4f( p->second );

            if ( !point ) point = sc.getOrCreateSymbol<PointSymbol>();
            point->fill()->color() = htmlColorToVec4f( p->second );

            if ( !text ) text = new TextSymbol();
            text->fill()->color() = htmlColorToVec4f( p->second );
        }
        else if ( p->first == CSS_FILL_OPACITY )
        {
            if (!polygon) polygon = sc.getOrCreateSymbol<PolygonSymbol>();
            polygon->fill()->color().a() = as<float>( p->second, 1.0f );

            if (!polygon) polygon = sc.getOrCreateSymbol<PolygonSymbol>();
            point->fill()->color().a() = as<float>( p->second, 1.0f );

            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            text->fill()->color().a() = as<float>( p->second, 1.0f );
        }
        else if (p->first == CSS_POINT_SIZE)
        {
            if ( !point ) point = sc.getOrCreateSymbol<PointSymbol>();
            point->size() = as<float>(p->second, 1.0f);
        }
        else if (p->first == CSS_TEXT_SIZE)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            text->size() = as<float>(p->second, 32.0f);
        }
        else if (p->first == CSS_TEXT_FONT)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            text->font() = p->second;
        }
        else if (p->first == CSS_TEXT_HALO)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            text->halo()->color() = htmlColorToVec4f( p->second );
        }
        //else if (p->first == CSS_TEXT_ATTRIBUTE)
        //{
        //    if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
        //    text->attribute() = p->second;
        //}
        else if (p->first == CSS_TEXT_ROTATE_TO_SCREEN)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            if (p->second == "true") text->rotateToScreen() = true;
            else if (p->second == "false") text->rotateToScreen() = false;
        }
        else if (p->first == CSS_TEXT_SIZE_MODE)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            if (p->second == "screen") text->sizeMode() = TextSymbol::SIZEMODE_SCREEN;
            else if (p->second == "object") text->sizeMode() = TextSymbol::SIZEMODE_OBJECT;
        }
        else if (p->first == CSS_TEXT_REMOVE_DUPLICATE_LABELS)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            if (p->second == "true") text->removeDuplicateLabels() = true;
            else if (p->second == "false") text->removeDuplicateLabels() = false;
        } 
        else if (p->first == CSS_TEXT_LINE_ORIENTATION)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            if (p->second == "parallel") text->lineOrientation() = TextSymbol::LINEORIENTATION_PARALLEL;
            else if (p->second == "horizontal") text->lineOrientation() = TextSymbol::LINEORIENTATION_HORIZONTAL;
            else if (p->second == "perpendicular") text->lineOrientation() = TextSymbol::LINEORIENTATION_PERPENDICULAR;
        }
        else if (p->first == CSS_TEXT_LINE_PLACEMENT)
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            if (p->second == "centroid") text->linePlacement() = TextSymbol::LINEPLACEMENT_CENTROID;
            else if (p->second == "along-line") text->linePlacement() = TextSymbol::LINEPLACEMENT_ALONG_LINE;
        }
        else if (p->first == "text-content")
        {
            if (!text) text = sc.getOrCreate<TextSymbol>();
            text->content() = StringExpression( p->second );
        }
        else if (p->first == "text-priority")
        {
            if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
            text->priority() = NumericExpression( p->second );
        }
        else if (p->first == "text-provider")
        {
            if (!text) text = sc.getOrCreate<TextSymbol>();
            text->provider() = p->second;
        }

        //else if (p->first == CSS_TEXT_CONTENT)
        //{
        //    if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
        //    text->content() = p->second;
        //}
        //else if (p->first == CSS_TEXT_CONTENT_ATTRIBUTE_DELIMITER)
        //{
        //    if (!text) text = sc.getOrCreateSymbol<TextSymbol>();
        //    text->contentAttributeDelimiter() = p->second;
        //}

        else if (p->first == "marker")
        {
            if (!marker) marker = sc.getOrCreateSymbol<MarkerSymbol>();
            marker->url() = p->second;
        }
        else if (p->first == "marker-placement")
        {
            if (!marker) marker = sc.getOrCreateSymbol<MarkerSymbol>();
            if      (p->second == "centroid") marker->placement() = MarkerSymbol::PLACEMENT_CENTROID;
            else if (p->second == "interval") marker->placement() = MarkerSymbol::PLACEMENT_INTERVAL;
            else if (p->second == "random"  ) marker->placement() = MarkerSymbol::PLACEMENT_RANDOM;
        }
        else if (p->first == "marker-density")
        {
            if (!marker) marker = sc.getOrCreateSymbol<MarkerSymbol>();
            marker->density() = as<float>(p->second, 1.0f);
        }
        else if (p->first == "marker-random-seed")
        {
            if (!marker) marker = sc.getOrCreateSymbol<MarkerSymbol>();
            marker->randomSeed() = as<unsigned>(p->second, 0);
        }
        else if (p->first == "marker-scale")
        {
            if (!marker) marker = sc.getOrCreateSymbol<MarkerSymbol>();
            marker->scale() = stringToVec3f(p->second, osg::Vec3f(1,1,1));
        }

        else if (p->first == "extrusion-height")
        {
            if (!extrusion) extrusion = sc.getOrCreateSymbol<ExtrusionSymbol>();
            extrusion->heightExpression() = NumericExpression(p->second);
        }
        else if (p->first == "extrusion-flatten")
        {
            if (!extrusion) extrusion = sc.getOrCreateSymbol<ExtrusionSymbol>();
            extrusion->flatten() = as<bool>(p->second, true);
        }
                
        else if (p->first == "altitude-clamping")
        {
            if (!altitude) altitude = sc.getOrCreateSymbol<AltitudeSymbol>();
            if      (p->second == "none"    ) altitude->clamping() = AltitudeSymbol::CLAMP_NONE;
            else if (p->second == "terrain" ) altitude->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
            else if (p->second == "relative") altitude->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
        }
        else if (p->first == "altitude-offset")
        {
            if (!altitude) altitude = sc.getOrCreateSymbol<AltitudeSymbol>();
            altitude->verticalOffset() = as<float>( p->second, 0.0f );
        }
    }

#if 0
    if (line)
        sc.addSymbol(line);
    if (polygon)
        sc.addSymbol(polygon);
    if (point)
        sc.addSymbol(point);
    if (text)
        sc.addSymbol(text);
    if (extrusion)
        sc.addSymbol(extrusion);
    if (marker)
        sc.addSymbol(marker);
    if (altitude)
        sc.addSymbol(altitude);
#endif

    return true;
}
Ejemplo n.º 9
0
void 
KML_Placemark::build( xml_node<>* node, KMLContext& cx )
{
	Style masterStyle;

	std::string styleUrl = getValue(node, "styleurl");

	if (!styleUrl.empty())
	{	// process a "stylesheet" style
		const Style* ref_style = cx._sheet->getStyle( styleUrl, false );
		if (ref_style)
		{
			masterStyle = masterStyle.combineWith(*ref_style);
		}
	}

	xml_node<>* style = node->first_node("style", 0, false);
	if ( style )
	{	// process an "inline" style
		KML_Style kmlStyle;
		kmlStyle.scan(style, cx);
		masterStyle = masterStyle.combineWith(cx._activeStyle);
	}

    // parse the geometry. the placemark must have geometry to be valid. The 
    // geometry parse may optionally specify an altitude mode as well.
    KML_Geometry geometry;
    geometry.build(node, cx, masterStyle);

    Geometry* allGeom = geometry._geom.get();
    if ( allGeom )
    {
        GeometryIterator giter( allGeom, false );
        while( giter.hasMore() )
        {
            Geometry* geom = giter.next();
            Style style = masterStyle;

            AltitudeSymbol* alt = style.get<AltitudeSymbol>();
            
            if ( geom && geom->getTotalPointCount() > 0 )
            {
                // resolve the proper altitude mode for the anchor point
                AltitudeMode altMode = ALTMODE_RELATIVE;
                if (alt && 
                    !alt->clamping().isSetTo( alt->CLAMP_TO_TERRAIN ) &&
                    !alt->clamping().isSetTo( alt->CLAMP_RELATIVE_TO_TERRAIN ) )
                {
                    altMode = ALTMODE_ABSOLUTE;
                }

                GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode);

                // check for symbols.
                ModelSymbol* model = style.get<ModelSymbol>();
                IconSymbol*  icon  = style.get<IconSymbol>();
                TextSymbol*  text  = style.get<TextSymbol>();

                // for a single point placemark, apply the default icon and text symbols
                // if none are specified in the KML.
                if (geom->getTotalPointCount() == 1)
                {
                    if (!model && !icon && cx._options->defaultIconSymbol().valid())
                    {
                        icon = cx._options->defaultIconSymbol().get();
                        style.add(icon);
                    }

                    if (!text && cx._options->defaultTextSymbol().valid())
                    {
                        text = cx._options->defaultTextSymbol().get();
                        style.add(text);
                    }
                }

                // the annotation name:
                std::string name = getValue(node, "name");

                if (!name.empty())
                {
                    OE_INFO << LC << "Placemark: " << name << std::endl;
                }

                AnnotationNode* featureNode = 0L;
                AnnotationNode* iconNode    = 0L;
                AnnotationNode* modelNode   = 0L;

                // one coordinate? It's a place marker or a label.
                if ( (model || icon || text) && geom->getTotalPointCount() == 1 )
                {
                    // if there's a model, render that - models do NOT get labels.
                    if ( model )
                    {
                        ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions.get() );
                        node->setPosition( position );

                        // model scale:
                        if ( cx._options->modelScale() != 1.0f )
                        {
                            float s = *cx._options->modelScale();
                            node->getPositionAttitudeTransform()->setScale(osg::Vec3d(s,s,s));
                        }

                        // model local tangent plane rotation:
                        if ( !cx._options->modelRotation()->zeroRotation() )
                        {
                            node->getPositionAttitudeTransform()->setAttitude( *cx._options->modelRotation() );
                        }

                        modelNode = node;
                    }

                    // is there a label?
                    else if ( !name.empty() )
                    {
                        if ( !text )
                        {
                            text = style.getOrCreate<TextSymbol>();
                            text->encoding() = TextSymbol::ENCODING_UTF8;
                        }
                        text->content()->setLiteral( name );
                    }

                    // is there an icon?
                    if ( icon )
                    {
                        PlaceNode* placeNode = new PlaceNode( position );
                        placeNode->setStyle(style, cx._dbOptions.get());
                        iconNode = placeNode;
                    }

                    else if ( !model && text && !name.empty() )
                    {
                        // note: models do not get labels.
                        iconNode = new LabelNode();
                        iconNode->setStyle(style);
                    }
                }

                // multiple coords? feature:
                if ( geom->getTotalPointCount() > 1 )
                {
                    // Remove symbols that we have already processed so the geometry
                    // compiler doesn't get confused.
                    if ( model )
                        style.removeSymbol( model );
                    if ( icon )
                        style.removeSymbol( icon );
                    if ( text )
                        style.removeSymbol( text );

                    Feature* feature = new Feature(geom, cx._srs.get(), style);
                    featureNode = new FeatureNode(feature );
                    featureNode->setMapNode( cx._mapNode );
                }

                if ( iconNode )
                {
                    Registry::objectIndex()->tagNode( iconNode, iconNode );
                }

                if ( modelNode )
                {
                    Registry::objectIndex()->tagNode( modelNode, modelNode );
                }

                if ( featureNode )
                {
                    Registry::objectIndex()->tagNode( featureNode, featureNode );
                }


                // assemble the results:
                if ( (iconNode || modelNode) && featureNode )
                {
                    osg::Group* group = new osg::Group();
                    group->addChild( featureNode );
                    if ( iconNode )
                        group->addChild( iconNode );
                    if ( modelNode )
                        group->addChild( modelNode );

                    cx._groupStack.top()->addChild( group );

                    if ( iconNode )
                        KML_Feature::build( node, cx, iconNode );
                    if ( modelNode )
                        KML_Feature::build( node, cx, modelNode );
                    if ( featureNode )
                        KML_Feature::build( node, cx, featureNode );
                }

                else
                {
                    if ( iconNode )
                    {
                        if ( cx._options->iconAndLabelGroup().valid() )
                        {
                            cx._options->iconAndLabelGroup()->addChild( iconNode );
                        }
                        else
                        {
                            cx._groupStack.top()->addChild( iconNode );
                        }
                        KML_Feature::build( node, cx, iconNode );
                    }
                    if ( modelNode )
                    {
                        cx._groupStack.top()->addChild( modelNode );
                        KML_Feature::build( node, cx, modelNode );
                    }
                    if ( featureNode )
                    {
                        osg::Node* child = featureNode;

                        // If this feature node is map-clamped, we most likely need a depth-offset
                        // shader to prevent z-fighting with the terrain.
                        if (alt && alt->clamping() == alt->CLAMP_TO_TERRAIN && alt->technique() == alt->TECHNIQUE_MAP)
                        {
                            DepthOffsetGroup* g = new DepthOffsetGroup();
                            g->addChild( featureNode );
                            child = g;
                        }
                
                        cx._groupStack.top()->addChild( child );
                        KML_Feature::build( node, cx, featureNode );
                    }
                }
            }
        }
    }
}
Ejemplo n.º 10
0
void 
KML_Placemark::build( const Config& conf, KMLContext& cx )
{
    Style style;
    if ( conf.hasValue("styleurl") )
    {
        // process a "stylesheet" style
        const Style* ref_style = cx._sheet->getStyle( conf.value("styleurl"), false );
        if ( ref_style )
            style = *ref_style;
    }
    else if ( conf.hasChild("style") )
    {
        // process an "inline" style
        KML_Style kmlStyle;
        kmlStyle.scan( conf.child("style"), cx );
        style = cx._activeStyle;
    }

    // parse the geometry. the placemark must have geometry to be valid. The 
    // geometry parse may optionally specify an altitude mode as well.
    KML_Geometry geometry;
    geometry.build(conf, cx, style);

    // KML's default altitude mode is clampToGround.
    AltitudeMode altMode = ALTMODE_RELATIVE;

    AltitudeSymbol* altSym = style.get<AltitudeSymbol>();
    if ( !altSym )
    {
        altSym = style.getOrCreate<AltitudeSymbol>();
        altSym->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
    }
    else if ( !altSym->clamping().isSetTo(AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN) )
    {
        altMode = ALTMODE_ABSOLUTE;
    }
    
    if ( geometry._geom.valid() && geometry._geom->getTotalPointCount() > 0 )
    {
        Geometry* geom = geometry._geom.get();

        GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode);

        bool isPoly = geom->getComponentType() == Geometry::TYPE_POLYGON;
        bool isPoint = geom->getComponentType() == Geometry::TYPE_POINTSET;

        // read in the Marker if there is one.
        URI                      markerURI;
        osg::ref_ptr<osg::Image> markerImage;
        osg::ref_ptr<osg::Node>  markerModel;

        MarkerSymbol* marker = style.get<MarkerSymbol>();

        if ( marker && marker->url().isSet() )
        {
            if ( marker->isModel() == false )
            {
                markerImage = marker->getImage( *cx._options->iconMaxSize() );
            }
            else
            {
                markerURI = URI( marker->url()->eval(), marker->url()->uriContext() );
                markerModel = markerURI.getNode();

                // We can't leave the marker symbol in the style, or the GeometryCompiler will
                // think we want to do Point-model substitution. So remove it. A bit of a hack
                if ( marker )
                    style.removeSymbol(marker);
            }
        }

        std::string text = conf.hasValue("name") ? conf.value("name") : "";

        AnnotationNode* fNode = 0L;
        AnnotationNode* pNode = 0L;

        // place a 3D model:
        if ( markerModel.valid() )
        {
            LocalGeometryNode* lg = new LocalGeometryNode(cx._mapNode, markerModel.get(), style, false);
            lg->setPosition( position );
            if ( marker )
            {
                if ( marker->scale().isSet() )
                {
                    float scale = marker->scale()->eval();
                    lg->setScale( osg::Vec3f(scale,scale,scale) );
                }
                if ( marker->orientation().isSet() )
                {
                   // lg->setRotation( );
                }
            }

            fNode = lg;
            //Feature* feature = new Feature(geometry._geom.get(), cx._srs.get(), style);
            //fNode = new FeatureNode( cx._mapNode, feature, false );
        }

        // Place node (icon + text) or Label node (text only)
        else if ( marker || geometry._geom->getTotalPointCount() == 1 )
        {
            if ( !markerImage.valid() )
            {
                markerImage = cx._options->defaultIconImage().get();
                if ( !markerImage.valid() )
                {
                    markerImage = cx._options->defaultIconURI()->getImage();
                }
            }
            
            if ( !style.get<TextSymbol>() && cx._options->defaultTextSymbol().valid() )
            {
                style.addSymbol( cx._options->defaultTextSymbol().get() );
            }

            if ( markerImage.valid() )
                pNode = new PlaceNode( cx._mapNode, position, markerImage.get(), text, style );
            else
                pNode = new LabelNode( cx._mapNode, position, text, style );
        }

        if ( geometry._geom->getTotalPointCount() > 1 )
        {
            const ExtrusionSymbol* ex = style.get<ExtrusionSymbol>();
            const AltitudeSymbol* alt = style.get<AltitudeSymbol>();    

            if ( style.get<MarkerSymbol>() )
                style.removeSymbol(style.get<MarkerSymbol>());

            bool draped =
                isPoly   && 
                ex == 0L && 
                (alt == 0L || alt->clamping() == AltitudeSymbol::CLAMP_TO_TERRAIN);

            // Make a feature node; drape if we're not extruding.
            GeometryCompilerOptions options;
            options.clustering() = false;            
            Feature* feature = new Feature(geometry._geom.get(), cx._srs.get(), style);
            fNode = new FeatureNode( cx._mapNode, feature, draped, options );

            if ( !ex )
            {
                fNode->getOrCreateStateSet()->setMode(GL_LIGHTING, 0);
            }
        }
        
        if ( pNode && fNode )
        {
            osg::Group* group = new osg::Group();
            group->addChild( fNode );
            group->addChild( pNode );
            cx._groupStack.top()->addChild( group );
            if ( cx._options->declutter() == true )
                Decluttering::setEnabled( pNode->getOrCreateStateSet(), true );
            KML_Feature::build( conf, cx, pNode );
            KML_Feature::build( conf, cx, fNode );
        }

        else if ( pNode )
        {
            if ( cx._options->iconAndLabelGroup().valid() )
            {
                cx._options->iconAndLabelGroup()->addChild( pNode );
            }
            else
            {
                cx._groupStack.top()->addChild( pNode );
                if ( cx._options->declutter() == true )
                    Decluttering::setEnabled( pNode->getOrCreateStateSet(), true );
            }
            KML_Feature::build( conf, cx, pNode );
        }

        else if ( fNode )
        {
            cx._groupStack.top()->addChild( fNode );
            KML_Feature::build( conf, cx, fNode );
        }
    }
}
Ejemplo n.º 11
0
void
GeodeticGraticule::rebuild()
{
    this->removeChildren( 0, this->getNumChildren() );

    if ( !getMapNode() )
    {
        OE_WARN << LC << "Illegal NULL map node" << std::endl;
        return;
    }

    if ( !getMapNode()->isGeocentric() )
    {
        OE_WARN << LC << "Projected map mode is not yet supported" << std::endl;
        return;
    }

    const Profile* mapProfile = _mapNode->getMap()->getProfile();

    _profile = Profile::create(
                   mapProfile->getSRS(),
                   mapProfile->getExtent().xMin(),
                   mapProfile->getExtent().yMin(),
                   mapProfile->getExtent().xMax(),
                   mapProfile->getExtent().yMax(),
                   8, 4 );

    _featureProfile = new FeatureProfile(_profile->getSRS());

    //todo: do this right..
    osg::StateSet* set = this->getOrCreateStateSet();
    set->setRenderBinDetails( 9999, "RenderBin" );
    set->setMode( GL_LIGHTING, 0 );

    // set up default options if the caller did not supply them
    if ( !_options.isSet() )
    {
        _options->lineStyle() = Style();

        LineSymbol* line = _options->lineStyle()->getOrCreate<LineSymbol>();
        line->stroke()->color() = Color::Gray;
        line->stroke()->width() = 1.0;

        AltitudeSymbol* alt = _options->lineStyle()->getOrCreate<AltitudeSymbol>();
        alt->verticalOffset() = NumericExpression(5000.0);

        _options->textStyle() = Style();
        TextSymbol* text = _options->textStyle()->getOrCreate<TextSymbol>();
        text->alignment() = TextSymbol::ALIGN_CENTER_CENTER;

        if ( _mapNode->isGeocentric() )
        {
            double r = _mapNode->getMapSRS()->getEllipsoid()->getRadiusEquator();
            _options->addLevel( FLT_MAX, 0.0f, 1u );
            double d = 4.5*r;
            for(int i=0; i<3; i++)
            {
                d *= 0.5;
                _options->addLevel( d, d*0.25 );
            }
        }
        else
        {
            //todo?
        }
    }

    _root = new DrapeableNode( _mapNode.get(), false );
    this->addChild( _root );

    // need at least one level
    if ( _options->levels().size() < 1 )
        return;

    const GeodeticGraticuleOptions::Level& level0 = _options->levels()[0];

    // build the top level cell grid.
    unsigned tilesX, tilesY;
    _profile->getNumTiles( 0, tilesX, tilesY );

    for( unsigned tx = 0; tx < tilesX; ++tx )
    {
        for( unsigned ty = 0; ty < tilesY; ++ty )
        {
            TileKey key( 0, tx, ty, _profile.get() );
            osg::Node* tile = buildTile( key, getMapNode()->getMap() );
            if ( tile )
                _root->addChild( tile );
        }
    }
}
Ejemplo n.º 12
0
void 
KML_Placemark::build( const Config& conf, KMLContext& cx )
{
    Style masterStyle;

    if ( conf.hasValue("styleurl") )
    {
        // process a "stylesheet" style
        const Style* ref_style = cx._sheet->getStyle( conf.value("styleurl"), false );
        if ( ref_style )
            masterStyle = *ref_style;
    }
    else if ( conf.hasChild("style") )
    {
        // process an "inline" style
        KML_Style kmlStyle;
        kmlStyle.scan( conf.child("style"), cx );
        masterStyle = cx._activeStyle;
    }

    // parse the geometry. the placemark must have geometry to be valid. The 
    // geometry parse may optionally specify an altitude mode as well.
    KML_Geometry geometry;
    geometry.build(conf, cx, masterStyle);

    Geometry* allGeom = geometry._geom.get();
    if ( allGeom )
    {
        GeometryIterator giter( allGeom, false );
        while( giter.hasMore() )
        {
            Geometry* geom = giter.next();
            Style style = masterStyle;

            // KML's default altitude mode is clampToGround.
            AltitudeMode altMode = ALTMODE_RELATIVE;

            AltitudeSymbol* altSym = style.get<AltitudeSymbol>();
            if ( !altSym )
            {
                altSym = style.getOrCreate<AltitudeSymbol>();
                altSym->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
                altSym->technique() = AltitudeSymbol::TECHNIQUE_SCENE;
            }
            else if ( !altSym->clamping().isSetTo(AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN) )
            {
                altMode = ALTMODE_ABSOLUTE;
            }
            
            if ( geom && geom->getTotalPointCount() > 0 )
            {
                GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode);

                bool isPoly = geom->getComponentType() == Geometry::TYPE_POLYGON;
                bool isPoint = geom->getComponentType() == Geometry::TYPE_POINTSET;

                // check for symbols.
                ModelSymbol*    model = style.get<ModelSymbol>();
                IconSymbol*     icon  = style.get<IconSymbol>();
                TextSymbol*     text  = style.get<TextSymbol>();

                if ( !text && cx._options->defaultTextSymbol().valid() )
                    text = cx._options->defaultTextSymbol().get();

                // the annotation name:
                std::string name = conf.hasValue("name") ? conf.value("name") : "";
                if ( text && !name.empty() )
                {
                    text->content()->setLiteral( name );
                }

                AnnotationNode* featureNode = 0L;
                AnnotationNode* iconNode    = 0L;
                AnnotationNode* modelNode   = 0L;

                // one coordinate? It's a place marker or a label.
                if ( model || icon || text || geom->getTotalPointCount() == 1 )
                {
                    // load up the default icon if there we don't have one.
                    if ( !model && !icon )
                    {
                        icon = cx._options->defaultIconSymbol().get();
                        if ( icon )
                            style.add( icon );
                    }

                    // if there's a model, render that - models do NOT get labels.
                    if ( model )
                    {
                        ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions );
                        node->setPosition( position );

                        if ( cx._options->modelScale() != 1.0f )
                        {
                            float s = *cx._options->modelScale();
                            node->setScale( osg::Vec3f(s,s,s) );
                        }

                        if ( !cx._options->modelRotation()->zeroRotation() )
                        {
                            node->setLocalRotation( *cx._options->modelRotation() );
                        }

                        modelNode = node;
                    }

                    else if ( !text && !name.empty() )
                    {
                        text = style.getOrCreate<TextSymbol>();
                        text->content()->setLiteral( name );
                    }

                    if ( icon )
                    {
                        iconNode = new PlaceNode( cx._mapNode, position, style, cx._dbOptions );
                    }

                    else if ( !model && text && !name.empty() )
                    {
                        // note: models do not get labels.
                        iconNode = new LabelNode( cx._mapNode, position, style );
                    }
                }

                // multiple coords? feature:
                if ( geom->getTotalPointCount() > 1 )
                {
                    ExtrusionSymbol* extruded = style.get<ExtrusionSymbol>();
                    AltitudeSymbol*  altitude = style.get<AltitudeSymbol>();

                    // Remove symbols that we have already processed so the geometry
                    // compiler doesn't get confused.
                    if ( model )
                        style.removeSymbol( model );
                    if ( icon )
                        style.removeSymbol( icon );
                    if ( text )
                        style.removeSymbol( text );

                    // analyze the data; if the Z coords are all 0.0, enable draping.
                    if ( /*isPoly &&*/ !extruded && altitude && altitude->clamping() != AltitudeSymbol::CLAMP_TO_TERRAIN )
                    {
                        bool zeroElev = true;
                        ConstGeometryIterator gi( geom, false );
                        while( zeroElev == true && gi.hasMore() )
                        {
                            const Geometry* g = gi.next();
                            for( Geometry::const_iterator ji = g->begin(); ji != g->end() && zeroElev == true; ++ji )
                            {
                                if ( !osg::equivalent(ji->z(), 0.0) )
                                    zeroElev = false;
                            }
                        }
                        if ( zeroElev )
                        {
                            altitude->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
                            altitude->technique() = AltitudeSymbol::TECHNIQUE_GPU;
                        }
                    }

                    // Make a feature node; drape if we're not extruding.
                    bool draped =
                        isPoly    && 
                        !extruded &&
                        (!altitude || altitude->clamping() == AltitudeSymbol::CLAMP_TO_TERRAIN);

                    if ( draped && style.get<LineSymbol>() && !style.get<PolygonSymbol>() )
                    {
                        draped = false;
                    }

                    // turn off the clamping if we're draping.
                    if ( draped && altitude )
                    {
                        altitude->technique() = AltitudeSymbol::TECHNIQUE_DRAPE;
                    }

                    GeometryCompilerOptions compilerOptions;

                    // Check for point-model substitution:
                    if ( style.has<ModelSymbol>() )
                    {
                        compilerOptions.instancing() = true;
                    }

                    Feature* feature = new Feature(geom, cx._srs.get(), style);
                    featureNode = new FeatureNode( cx._mapNode, feature, draped, compilerOptions );
                }


                // assemble the results:
                if ( (iconNode || modelNode) && featureNode )
                {
                    osg::Group* group = new osg::Group();
                    group->addChild( featureNode );
                    if ( iconNode )
                        group->addChild( iconNode );
                    if ( modelNode )
                        group->addChild( modelNode );

                    cx._groupStack.top()->addChild( group );

                    if ( iconNode && cx._options->declutter() == true )
                        Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true );

                    if ( iconNode )
                        KML_Feature::build( conf, cx, iconNode );
                    if ( modelNode )
                        KML_Feature::build( conf, cx, modelNode );
                    if ( featureNode )
                        KML_Feature::build( conf, cx, featureNode );
                }

                else
                {
                    if ( iconNode )
                    {
                        if ( cx._options->iconAndLabelGroup().valid() )
                        {
                            cx._options->iconAndLabelGroup()->addChild( iconNode );
                        }
                        else
                        {
                            cx._groupStack.top()->addChild( iconNode );
                            if ( cx._options->declutter() == true )
                                Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true );
                        }
                        KML_Feature::build( conf, cx, iconNode );
                    }
                    if ( modelNode )
                    {
                        cx._groupStack.top()->addChild( modelNode );
                        KML_Feature::build( conf, cx, modelNode );
                    }
                    if ( featureNode )
                    {
                        cx._groupStack.top()->addChild( featureNode );
                        KML_Feature::build( conf, cx, featureNode );
                    }
                }
            }
        }
    }
}