void MGRSGraticule::setUpDefaultStyles() { if (!options().gzdStyle().isSet()) { LineSymbol* line = options().gzdStyle()->getOrCreate<LineSymbol>(); line->stroke()->color() = Color::Gray; line->stroke()->width() = 1.0; line->tessellation() = 20; TextSymbol* text = options().gzdStyle()->getOrCreate<TextSymbol>(); text->fill()->color() = Color(Color::White, 0.3f); text->halo()->color() = Color(Color::Black, 0.2f); text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; } if (!options().sqidStyle().isSet()) { LineSymbol* line = options().sqidStyle()->getOrCreate<LineSymbol>(); line->stroke()->color() = Color(Color::White, 0.5f); line->stroke()->stipplePattern() = 0x1111; TextSymbol* text = options().sqidStyle()->getOrCreate<TextSymbol>(); text->fill()->color() = Color(Color::White, 0.3f); text->halo()->color() = Color(Color::Black, 0.1f); text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; } }
/** * Creates a field schema that we'll later use as a labeling template for * TrackNode instances. */ void createFieldSchema( TrackNodeFieldSchema& schema ) { // draw the track name above the icon: TextSymbol* nameSymbol = new TextSymbol(); nameSymbol->pixelOffset()->set( 0, 2+ICON_SIZE/2 ); nameSymbol->alignment() = TextSymbol::ALIGN_CENTER_BOTTOM; nameSymbol->halo()->color() = Color::Black; nameSymbol->size() = nameSymbol->size()->eval() + 2.0f; schema[FIELD_NAME] = TrackNodeField(nameSymbol, false); // false => static label (won't change after set) // draw the track coordinates below the icon: TextSymbol* posSymbol = new TextSymbol(); posSymbol->pixelOffset()->set( 0, -2-ICON_SIZE/2 ); posSymbol->alignment() = TextSymbol::ALIGN_CENTER_TOP; posSymbol->fill()->color() = Color::Yellow; posSymbol->size() = posSymbol->size()->eval() - 2.0f; schema[FIELD_POSITION] = TrackNodeField(posSymbol, true); // true => may change at runtime // draw some other field to the left: TextSymbol* numberSymbol = new TextSymbol(); numberSymbol->pixelOffset()->set( -2-ICON_SIZE/2, 0 ); numberSymbol->alignment() = TextSymbol::ALIGN_RIGHT_CENTER; schema[FIELD_NUMBER] = TrackNodeField(numberSymbol, false); }
GraticuleLabelingEngine::GraticuleLabelingEngine(const SpatialReference* srs) { _srs = srs; // Set up the symbology for x-axis labels TextSymbol* xText = _xLabelStyle.getOrCreate<TextSymbol>(); xText->alignment() = TextSymbol::ALIGN_CENTER_BOTTOM; xText->halo()->color().set(0, 0, 0, 1); xText->declutter() = false; // Set up the symbology for y-axis labels TextSymbol* yText = _yLabelStyle.getOrCreate<TextSymbol>(); yText->alignment() = TextSymbol::ALIGN_LEFT_BOTTOM; yText->halo()->color().set(0, 0, 0, 1); yText->declutter() = false; }
void createTrackSchema(TrackNodeFieldSchema& schema) { // draw the track name above the icon: TextSymbol* nameSymbol = new TextSymbol(); nameSymbol->pixelOffset()->set( 0, 2+TRACK_ICON_SIZE/2 ); nameSymbol->alignment() = TextSymbol::ALIGN_CENTER_BOTTOM; nameSymbol->halo()->color() = Color::Black; schema[TRACK_FIELD_NAME] = TrackNodeField(nameSymbol, false); }
MGRSGraticule::MGRSGraticule( MapNode* mapNode ) : UTMGraticule( 0L ) { _mapNode = mapNode; init(); if ( !_options->secondaryStyle().isSet() ) { LineSymbol* line = _options->secondaryStyle()->getOrCreate<LineSymbol>(); line->stroke()->color() = Color(Color::White, 0.5f); line->stroke()->stipple() = 0x1111; TextSymbol* text = _options->secondaryStyle()->getOrCreate<TextSymbol>(); text->fill()->color() = Color(Color::White, 0.3f); text->halo()->color() = Color(Color::Black, 0.1f); text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; } _minDepthOffset = DepthOffsetUtils::createMinOffsetUniform(); _minDepthOffset->set( 11000.0f ); }
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); } }
void UTMGraticule::rebuild() { if (_root.valid() == false) return; osg::ref_ptr<const Map> map; if (!_map.lock(map)) return; // clear everything out _root->removeChildren( 0, _root->getNumChildren() ); // requires a geocentric map if ( !map->isGeocentric() ) { OE_WARN << LC << "Projected map mode is not yet supported" << std::endl; return; } const Profile* mapProfile = map->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(); GLUtils::setLighting(set, 0); set->setMode( GL_BLEND, 1 ); set->setMode( GL_CLIP_DISTANCE0, 1 ); // set up default options if the caller did not supply them if ( !options().gzdStyle().isSet() ) { options().gzdStyle() = Style(); LineSymbol* line = options().gzdStyle()->getOrCreate<LineSymbol>(); line->stroke()->color() = Color::Gray; line->stroke()->width() = 1.0; line->tessellation() = 20; TextSymbol* text = options().gzdStyle()->getOrCreate<TextSymbol>(); text->fill()->color() = Color(Color::White, 0.3f); text->halo()->color() = Color(Color::Black, 0.2f); text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; } // initialize the UTM sector tables for this profile. _utmData.rebuild(_profile.get()); // now build the lateral tiles for the GZD level. for( UTMData::SectorTable::iterator i = _utmData.sectorTable().begin(); i != _utmData.sectorTable().end(); ++i ) { osg::Node* tile = _utmData.buildGZDTile(i->first, i->second, options().gzdStyle().get(), _featureProfile.get(), map.get()); if ( tile ) _root->addChild( tile ); } }
void UTMGraticule::init() { if ( !_mapNode.valid() ) { OE_WARN << LC << "Illegal NULL map node" << std::endl; return; } if ( !_mapNode->isGeocentric() ) { OE_WARN << LC << "Projected map mode is not yet supported" << std::endl; return; } // safely generate a unique ID for this graticule: _id = Registry::instance()->createUID(); { Threading::ScopedMutexLock lock( s_graticuleMutex ); s_graticuleRegistry[_id] = this; } 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->setMode( GL_LIGHTING, 0 ); set->setMode( GL_BLEND, 1 ); // set up default options if the caller did not supply them if ( !_options.isSet() ) { _options->primaryStyle()= Style(); LineSymbol* line = _options->primaryStyle()->getOrCreate<LineSymbol>(); line->stroke()->color() = Color::Gray; line->stroke()->width() = 1.0; line->tessellation() = 20; AltitudeSymbol* alt = _options->primaryStyle()->getOrCreate<AltitudeSymbol>(); //alt->verticalOffset() = NumericExpression(4900.0); TextSymbol* text = _options->primaryStyle()->getOrCreate<TextSymbol>(); text->fill()->color() = Color(Color::White, 0.3f); text->halo()->color() = Color(Color::Black, 0.2f); text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; } // make the shared depth attr: _depthAttribute = new osg::Depth(osg::Depth::LEQUAL,0,1,false); // this will intialize the graph. rebuild(); }
// // NOTE: run this sample from the repo/tests directory. // int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); if ( arguments.read("--help") ) return usage( argv[0] ); bool useRaster = arguments.read("--rasterize"); bool useOverlay = arguments.read("--overlay"); bool useStencil = arguments.read("--stencil"); bool useMem = arguments.read("--mem"); bool useLabels = arguments.read("--labels"); if ( useStencil ) osg::DisplaySettings::instance()->setMinimumNumStencilBits( 8 ); osgViewer::Viewer viewer(arguments); // Start by creating the map: Map* map = new Map(); // Start with a basemap imagery layer; we'll be using the GDAL driver // to load a local GeoTIFF file: GDALOptions basemapOpt; basemapOpt.url() = "../data/world.tif"; map->addImageLayer( new ImageLayer( ImageLayerOptions("basemap", basemapOpt) ) ); // Next we add a feature layer. OGRFeatureOptions featureOptions; if ( !useMem ) { // Configures the feature driver to load the vectors from a shapefile: featureOptions.url() = "../data/world.shp"; } else { // the --mem options tells us to just make an in-memory geometry: Ring* line = new Ring(); line->push_back( osg::Vec3d(-60, 20, 0) ); line->push_back( osg::Vec3d(-120, 20, 0) ); line->push_back( osg::Vec3d(-120, 60, 0) ); line->push_back( osg::Vec3d(-60, 60, 0) ); featureOptions.geometry() = line; } // 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::Yellow; ls->stroke()->width() = 2.0f; // That's it, the map is ready; now create a MapNode to render the Map: MapNodeOptions mapNodeOptions; mapNodeOptions.enableLighting() = false; MapNode* mapNode = new MapNode( map, mapNodeOptions ); osg::Group* root = new osg::Group(); root->addChild( mapNode ); viewer.setSceneData( root ); viewer.setCameraManipulator( new EarthManipulator() ); // Process cmdline args MapNodeHelper().parse(mapNode, arguments, &viewer, root, new LabelControl("Features Demo")); if (useStencil) { FeatureStencilModelOptions stencilOptions; stencilOptions.featureOptions() = featureOptions; stencilOptions.styles() = new StyleSheet(); stencilOptions.styles()->addStyle( style ); stencilOptions.enableLighting() = false; stencilOptions.depthTestEnabled() = false; ls->stroke()->width() = 0.1f; map->addModelLayer( new ModelLayer("my features", stencilOptions) ); } else if (useRaster) { AGGLiteOptions rasterOptions; rasterOptions.featureOptions() = featureOptions; rasterOptions.styles() = new StyleSheet(); rasterOptions.styles()->addStyle( style ); map->addImageLayer( new ImageLayer("my features", rasterOptions) ); } else //if (useGeom || useOverlay) { FeatureGeomModelOptions geomOptions; geomOptions.featureOptions() = featureOptions; geomOptions.styles() = new StyleSheet(); geomOptions.styles()->addStyle( style ); geomOptions.enableLighting() = false; ModelLayerOptions layerOptions( "my features", geomOptions ); map->addModelLayer( new ModelLayer(layerOptions) ); } if ( useLabels ) { // set up symbology for drawing labels. We're pulling the label // text from the name attribute, and its draw priority from the // population attribute. Style labelStyle; TextSymbol* text = labelStyle.getOrCreateSymbol<TextSymbol>(); text->content() = StringExpression( "[cntry_name]" ); text->priority() = NumericExpression( "[pop_cntry]" ); text->removeDuplicateLabels() = true; text->size() = 16.0f; text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; text->fill()->color() = Color::White; text->halo()->color() = Color::DarkGray; // and configure a model layer: FeatureGeomModelOptions geomOptions; geomOptions.featureOptions() = featureOptions; geomOptions.styles() = new StyleSheet(); geomOptions.styles()->addStyle( labelStyle ); map->addModelLayer( new ModelLayer("labels", geomOptions) ); } if ( !useStencil ) viewer.getCamera()->addCullCallback( new osgEarth::Util::AutoClipPlaneCullCallback(mapNode) ); // add some stock OSG handlers: viewer.addEventHandler(new osgViewer::StatsHandler()); viewer.addEventHandler(new osgViewer::WindowSizeHandler()); viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet())); return viewer.run(); }
void MapInspectorUI::addTerrainLayer(TerrainLayer* layer, MapNode* mapNode) { const Color colors[6] = { Color::White, Color::Yellow, Color::Cyan, Color::Lime, Color::Red, Color::Magenta }; Color color = colors[(int)layer->getUID()%6]; osg::ref_ptr<MultiGeometry> collection = new MultiGeometry(); const DataExtentList& exlist = layer->getDataExtents(); if (!exlist.empty()) { for(DataExtentList::const_iterator i = exlist.begin(); i != exlist.end(); ++i) { const DataExtent& e = *i; Polygon* p = new Polygon(); p->push_back( e.xMin(), e.yMin() ); p->push_back( e.xMax(), e.yMin() ); p->push_back( e.xMax(), e.yMax() ); p->push_back( e.xMin(), e.yMax() ); collection->add( p ); } // poly: { Style style; style.getOrCreate<LineSymbol>()->stroke()->color() = color; style.getOrCreate<LineSymbol>()->stroke()->width() = 2; style.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; style.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_DRAPE; style.getOrCreate<RenderSymbol>()->lighting() = false; Feature* feature = new Feature(collection.get(), layer->getProfile()->getSRS(), style); FeatureNode* node = new FeatureNode( mapNode, feature ); _annos->addChild( node ); } // label: std::string text = !layer->getName().empty()? layer->getName() : Stringify() << "Layer " << layer->getUID(); { Style style; TextSymbol* ts = style.getOrCreate<TextSymbol>(); ts->halo()->color().set(0,0,0,1); ts->declutter() = true; ts->alignment() = TextSymbol::ALIGN_CENTER_CENTER; osg::Vec2d center = collection->getBounds().center2d(); GeoPoint position(layer->getProfile()->getSRS(), center.x(), center.y(), 0.0, ALTMODE_ABSOLUTE); LabelNode* label = new LabelNode(mapNode, position, text, style); _annos->addChild( label ); } unsigned r = this->getNumRows(); setControl(0, r, new ui::LabelControl(text, color)); } }
void PlaceNode::init() { Decluttering::setEnabled( this->getOrCreateStateSet(), true ); //reset. //this->clearDecoration(); getPositionAttitudeTransform()->removeChildren(0, getPositionAttitudeTransform()->getNumChildren()); _geode = new osg::Geode(); // ensure that (0,0,0) is the bounding sphere control/center point. // useful for things like horizon culling. _geode->setComputeBoundingSphereCallback(new ControlPointCallback()); osg::Drawable* text = 0L; // If there's no explicit text, look to the text symbol for content. if ( _text.empty() && _style.has<TextSymbol>() ) { _text = _style.get<TextSymbol>()->content()->eval(); } osg::ref_ptr<const InstanceSymbol> instance = _style.get<InstanceSymbol>(); // backwards compability, support for deprecated MarkerSymbol if ( !instance.valid() && _style.has<MarkerSymbol>() ) { instance = _style.get<MarkerSymbol>()->convertToInstanceSymbol(); } const IconSymbol* icon = instance->asIcon(); if ( !_image.valid() ) { URI imageURI; if ( icon ) { if ( icon->url().isSet() ) { imageURI = icon->url()->evalURI(); } else if (icon->getImage()) { _image = icon->getImage(); } } if ( !imageURI.empty() ) { _image = imageURI.getImage( _dbOptions.get() ); } } osg::BoundingBox imageBox(0,0,0,0,0,0); // found an image; now format it: if ( _image.get() ) { // Scale the icon if necessary double scale = 1.0; if ( icon && icon->scale().isSet() ) { scale = icon->scale()->eval(); } double s = scale * _image->s(); double t = scale * _image->t(); // this offset anchors the image at the bottom osg::Vec2s offset; if ( !icon || !icon->alignment().isSet() ) { // default to bottom center offset.set(0.0, t / 2.0); } else { // default to bottom center switch (icon->alignment().value()) { case IconSymbol::ALIGN_LEFT_TOP: offset.set((s / 2.0), -(t / 2.0)); break; case IconSymbol::ALIGN_LEFT_CENTER: offset.set((s / 2.0), 0.0); break; case IconSymbol::ALIGN_LEFT_BOTTOM: offset.set((s / 2.0), (t / 2.0)); break; case IconSymbol::ALIGN_CENTER_TOP: offset.set(0.0, -(t / 2.0)); break; case IconSymbol::ALIGN_CENTER_CENTER: offset.set(0.0, 0.0); break; case IconSymbol::ALIGN_CENTER_BOTTOM: default: offset.set(0.0, (t / 2.0)); break; case IconSymbol::ALIGN_RIGHT_TOP: offset.set(-(s / 2.0), -(t / 2.0)); break; case IconSymbol::ALIGN_RIGHT_CENTER: offset.set(-(s / 2.0), 0.0); break; case IconSymbol::ALIGN_RIGHT_BOTTOM: offset.set(-(s / 2.0), (t / 2.0)); break; } } // Apply a rotation to the marker if requested: double heading = 0.0; if ( icon && icon->heading().isSet() ) { heading = osg::DegreesToRadians( icon->heading()->eval() ); } //We must actually rotate the geometry itself and not use a MatrixTransform b/c the //decluttering doesn't respect Transforms above the drawable. osg::Geometry* imageGeom = AnnotationUtils::createImageGeometry( _image.get(), offset, 0, heading, scale ); if ( imageGeom ) { _geode->addDrawable( imageGeom ); imageBox = imageGeom->getBoundingBox(); } } if ( _image.valid() ) { TextSymbol* textSymbol = _style.getOrCreate<TextSymbol>(); if ( !textSymbol->alignment().isSet() ) textSymbol->alignment() = textSymbol->ALIGN_LEFT_CENTER; } text = AnnotationUtils::createTextDrawable( _text, _style.get<TextSymbol>(), imageBox ); if ( text ) _geode->addDrawable( text ); osg::StateSet* stateSet = _geode->getOrCreateStateSet(); stateSet->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS, 0, 1, false), 1 ); getPositionAttitudeTransform()->addChild( _geode ); // for clamping and occlusion culling //OE_WARN << LC << "PlaceNode::applyStyle: " << _style.getConfig().toJSON(true) << std::endl; applyStyle( _style ); setLightingIfNotSet( false ); // generate shaders: Registry::shaderGenerator().run( this, "osgEarth.PlaceNode", Registry::stateSetCache() ); setPriority(getPriority()); if ( _dynamic ) setDynamic( _dynamic ); }
void UTMGraticule::rebuild() { // clear everything out this->removeChildren( 0, this->getNumChildren() ); // requires a map node if ( !getMapNode() ) { return; } // requires a geocentric map if ( !getMapNode()->isGeocentric() ) { OE_WARN << LC << "Projected map mode is not yet supported" << std::endl; return; } const Profile* mapProfile = getMapNode()->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->setMode( GL_LIGHTING, 0 ); set->setMode( GL_BLEND, 1 ); // set up default options if the caller did not supply them if ( !_options.isSet() ) { _options->primaryStyle() = Style(); LineSymbol* line = _options->primaryStyle()->getOrCreate<LineSymbol>(); line->stroke()->color() = Color::Gray; line->stroke()->width() = 1.0; line->tessellation() = 20; AltitudeSymbol* alt = _options->primaryStyle()->getOrCreate<AltitudeSymbol>(); TextSymbol* text = _options->primaryStyle()->getOrCreate<TextSymbol>(); text->fill()->color() = Color(Color::White, 0.3f); text->halo()->color() = Color(Color::Black, 0.2f); text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; } // rebuild the graph: _root = new DrapeableNode( getMapNode(), false ); this->addChild( _root ); #if 0 // set up depth offsetting. osg::StateSet* s = _root->getOrCreateStateSet(); s->setAttributeAndModes( DepthOffsetUtils::getOrCreateProgram(), 1 ); s->addUniform( DepthOffsetUtils::getIsNotTextUniform() ); osg::Uniform* u = DepthOffsetUtils::createMinOffsetUniform(); u->set( 10000.0f ); s->addUniform( u ); #endif // build the base Grid Zone Designator (GZD) loolup table. This is a table // that maps the GZD string to its extent. static std::string s_gzdRows( "CDEFGHJKLMNPQRSTUVWX" ); const SpatialReference* geosrs = _profile->getSRS()->getGeographicSRS(); // build the lateral zones: for( unsigned zone = 0; zone < 60; ++zone ) { for( unsigned row = 0; row < s_gzdRows.size(); ++row ) { double yMaxExtra = row == s_gzdRows.size()-1 ? 4.0 : 0.0; // extra 4 deg for row X GeoExtent cellExtent( geosrs, -180.0 + double(zone)*6.0, -80.0 + row*8.0, -180.0 + double(zone+1)*6.0, -80.0 + double(row+1)*8.0 + yMaxExtra ); _gzd[ Stringify() << (zone+1) << s_gzdRows[row] ] = cellExtent; } } // the polar zones (UPS): _gzd["1Y"] = GeoExtent( geosrs, -180.0, 84.0, 0.0, 90.0 ); _gzd["1Z"] = GeoExtent( geosrs, 0.0, 84.0, 180.0, 90.0 ); _gzd["1A"] = GeoExtent( geosrs, -180.0, -90.0, 0.0, -80.0 ); _gzd["1B"] = GeoExtent( geosrs, 0.0, -90.0, 180.0, -80.0 ); // replace the "exception" zones in Norway and Svalbard _gzd["31V"] = GeoExtent( geosrs, 0.0, 56.0, 3.0, 64.0 ); _gzd["32V"] = GeoExtent( geosrs, 3.0, 56.0, 12.0, 64.0 ); _gzd["31X"] = GeoExtent( geosrs, 0.0, 72.0, 9.0, 84.0 ); _gzd["33X"] = GeoExtent( geosrs, 9.0, 72.0, 21.0, 84.0 ); _gzd["35X"] = GeoExtent( geosrs, 21.0, 72.0, 33.0, 84.0 ); _gzd["37X"] = GeoExtent( geosrs, 33.0, 72.0, 42.0, 84.0 ); // ..and remove the non-existant zones: _gzd.erase( "32X" ); _gzd.erase( "34X" ); _gzd.erase( "36X" ); // now build the lateral tiles for the GZD level. for( SectorTable::iterator i = _gzd.begin(); i != _gzd.end(); ++i ) { osg::Node* tile = buildGZDTile( i->first, i->second ); if ( tile ) _root->addChild( tile ); } DepthOffsetUtils::prepareGraph( _root ); }
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 ); } } }