void ModelNode::init() { // reset. this->clearDecoration(); osgEarth::clearChildren( this ); osgEarth::clearChildren( _xform.get() ); this->addChild( _xform.get() ); this->setHorizonCulling(false); osg::ref_ptr<const ModelSymbol> sym = _style.get<ModelSymbol>(); // backwards-compatibility: support for MarkerSymbol (deprecated) if ( !sym.valid() && _style.has<MarkerSymbol>() ) { osg::ref_ptr<InstanceSymbol> temp = _style.get<MarkerSymbol>()->convertToInstanceSymbol(); sym = dynamic_cast<const ModelSymbol*>( temp.get() ); } if ( sym.valid() ) { if ( ( sym->url().isSet() ) || (sym->getModel() != NULL) ) { // Try to get a model from symbol osg::ref_ptr<osg::Node> node = sym->getModel(); // Try to get a model from URI if (node.valid() == false) { URI uri = sym->url()->evalURI(); if ( sym->uriAliasMap()->empty() ) { node = uri.getNode( _dbOptions.get() ); } else { // install an alias map if there's one in the symbology. osg::ref_ptr<osgDB::Options> tempOptions = Registry::instance()->cloneOrCreateOptions(_dbOptions.get()); tempOptions->setReadFileCallback( new URIAliasMapReadCallback(*sym->uriAliasMap(), uri.full()) ); node = uri.getNode( tempOptions.get() ); } if (node.valid() == false) { OE_WARN << LC << "No model and failed to load data from " << uri.full() << std::endl; } } if (node.valid() == true) { if ( Registry::capabilities().supportsGLSL() ) { // generate shader code for the loaded model: Registry::shaderGenerator().run( node.get(), "osgEarth.ModelNode", Registry::stateSetCache() ); } // attach to the transform: _xform->addChild( node ); // insert a clamping agent if necessary: replaceChild( _xform.get(), applyAltitudePolicy(_xform.get(), _style) ); if ( sym->scale().isSet() ) { double s = sym->scale()->eval(); this->setScale( osg::Vec3f(s, s, s) ); } // auto scaling? if ( sym->autoScale() == true ) { this->getOrCreateStateSet()->setRenderBinDetails(0, osgEarth::AUTO_SCALE_BIN ); } // rotational offsets? if (sym && (sym->heading().isSet() || sym->pitch().isSet() || sym->roll().isSet()) ) { osg::Matrix rot; double heading = sym->heading().isSet() ? sym->heading()->eval() : 0.0; double pitch = sym->pitch().isSet() ? sym->pitch()->eval() : 0.0; double roll = sym->roll().isSet() ? sym->roll()->eval() : 0.0; rot.makeRotate( osg::DegreesToRadians(heading), osg::Vec3(0,0,1), osg::DegreesToRadians(pitch), osg::Vec3(1,0,0), osg::DegreesToRadians(roll), osg::Vec3(0,1,0) ); this->setLocalRotation( rot.getRotate() ); } this->applyRenderSymbology( _style ); } else { OE_WARN << LC << "No model" << std::endl; } } else { OE_WARN << LC << "Symbology: no URI or model" << std::endl; } } else { OE_WARN << LC << "Insufficient symbology" << std::endl; } }
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 ); } } }