bool AddPointHandler::addPoint( float x, float y, osgViewer::View* view ) { osg::Vec3d world; MapNode* mapNode = _featureNode->getMapNode(); if ( mapNode->getTerrain()->getWorldCoordsUnderMouse( view, x, y, world ) ) { // Get the map point from the world GeoPoint mapPoint; mapPoint.fromWorld( mapNode->getMapSRS(), world ); Feature* feature = _featureNode->getFeature(); if ( feature ) { // Convert the map point to the feature's SRS GeoPoint featurePoint = mapPoint.transform( feature->getSRS() ); feature->getGeometry()->push_back( featurePoint.vec3d() ); _featureNode->init(); return true; } } return false; }
bool LocalizedNode::setPosition( const GeoPoint& pos ) { if ( _initComplete ) { if ( getMapNode() ) { // first transform the point to the map's SRS: const SpatialReference* mapSRS = getMapNode()->getMapSRS(); GeoPoint mapPos = mapSRS ? pos.transform(mapSRS) : pos; if ( !mapPos.isValid() ) return false; _mapPosition = mapPos; } else { _mapPosition = pos; } // make sure the node is set up for auto-z-update if necessary: configureForAltitudeMode( _mapPosition.altitudeMode() ); // update the node. return updateTransform( _mapPosition ); } else { _mapPosition = pos; return true; } }
bool OrthoNode::setPosition( const GeoPoint& position ) { MapNode* mapNode = getMapNode(); if ( mapNode ) { // first transform the point to the map's SRS: const SpatialReference* mapSRS = mapNode->getMapSRS(); GeoPoint mapPos = mapSRS ? position.transform(mapSRS) : position; if ( !mapPos.isValid() ) return false; _mapPosition = mapPos; } else { _mapPosition = position; } // make sure the node is set up for auto-z-update if necessary: configureForAltitudeMode( _mapPosition.altitudeMode() ); // and update the node. if ( !updateTransforms(_mapPosition) ) return false; return true; }
bool LocalizedNode::setPosition( const GeoPoint& pos ) { if ( _mapSRS.valid() ) { // first transform the point to the map's SRS: GeoPoint mapPos = _mapSRS.get() ? pos.transform(_mapSRS.get()) : pos; if ( !mapPos.isValid() ) return false; _mapPosition = mapPos; } else { _mapPosition = pos; } // make sure the node is set up for auto-z-update if necessary: configureForAltitudeMode( _mapPosition.altitudeMode() ); // update the node. if ( !updateTransforms( _mapPosition ) ) return false; return true; }
void GLSkyNode::onSetDateTime() { if ( !getSunLight() ) return; CelestialBody sun = getEphemeris()->getSunPosition(getDateTime()); // If the user set a projected-map reference point, assume we are using // a projected map and set the sun position acordingly. if (getReferencePoint().isValid()) { // pull the ref point: GeoPoint refpoint = getReferencePoint(); // convert to lat/long: GeoPoint refLatLong; osg::ref_ptr<const SpatialReference> wgs84 = SpatialReference::get("wgs84"); refpoint.transform(wgs84.get(), refLatLong); // Matrix to convert the ECEF sun position to the local tangent plane // centered on our reference point: osg::Matrixd world2local; refLatLong.createWorldToLocal(world2local); // convert the sun position: osg::Vec3d sunPosLocal = sun.geocentric * world2local; sunPosLocal.normalize(); getSunLight()->setPosition( osg::Vec4(sunPosLocal, 0.0) ); } else if (_options.coordinateSystem() == SkyOptions::COORDSYS_ECEF) { osg::Vec3d pos = sun.geocentric; pos.normalize(); _light->setPosition(osg::Vec4(pos, 0.0)); // directional light } else if (_options.coordinateSystem() == SkyOptions::COORDSYS_ECI) { osg::Vec3d pos = sun.eci; pos.normalize(); _light->setPosition(osg::Vec4(pos, 0.0)); // directional light } }
bool OrthoNode::setPosition( const GeoPoint& position ) { MapNode* mapNode = getMapNode(); if ( mapNode ) { // first transform the point to the map's SRS: const SpatialReference* mapSRS = mapNode->getMapSRS(); //$$$注释 //GeoPoint mapPos = mapSRS ? position.transform(mapSRS) : position; //if ( !mapPos.isValid() ) // return false; //_mapPosition = mapPos; //$$$修改 if ( mapSRS && position.isValid() )//position原来SRS信息不为空 { position.transform( mapSRS ); _mapPosition = position; } else if ( mapSRS ) { _mapPosition = GeoPoint( mapSRS, position.x(), position.y(), position.z() );//position原来SRS信息为空 } else { _mapPosition = position; } } else { _mapPosition = position; } // make sure the node is set up for auto-z-update if necessary: configureForAltitudeMode( _mapPosition.altitudeMode() ); // and update the node. if ( !updateTransforms(_mapPosition) ) return false; return true; }
void GLSkyNode::onSetDateTime() { if ( !getSunLight() || !_profile.valid() ) return; const DateTime& dt = getDateTime(); osg::Vec3d sunPosECEF = getEphemeris()->getSunPositionECEF( dt ); if ( _profile->getSRS()->isGeographic() ) { sunPosECEF.normalize(); getSunLight()->setPosition( osg::Vec4(sunPosECEF, 0.0) ); } else { // pull the ref point: GeoPoint refpoint = getReferencePoint(); if ( !refpoint.isValid() ) { // not found; use the center of the profile: _profile->getExtent().getCentroid(refpoint); } // convert to lat/long: GeoPoint refLatLong; refpoint.transform(_profile->getSRS()->getGeographicSRS(), refLatLong); // Matrix to convert the ECEF sun position to the local tangent plane // centered on our reference point: osg::Matrixd world2local; refLatLong.createWorldToLocal(world2local); // convert the sun position: osg::Vec3d sunPosLocal = sunPosECEF * world2local; sunPosLocal.normalize(); getSunLight()->setPosition( osg::Vec4(sunPosLocal, 0.0) ); } }
int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); if ( arguments.read("--stencil") ) osg::DisplaySettings::instance()->setMinimumNumStencilBits( 8 ); //Setup a CompositeViewer osgViewer::CompositeViewer viewer(arguments); //Setup our main view that will show the loaded earth file. osgViewer::View* mainView = new osgViewer::View(); mainView->getCamera()->setNearFarRatio(0.00002); mainView->setCameraManipulator( new EarthManipulator() ); mainView->setUpViewInWindow( 50, 50, 800, 800 ); viewer.addView( mainView ); //Setup a MiniMap View that will be embedded in the main view int miniMapWidth = 400; int miniMapHeight = 200; osgViewer::View* miniMapView = new osgViewer::View(); miniMapView->getCamera()->setNearFarRatio(0.00002); miniMapView->getCamera()->setViewport( 0, 0, miniMapWidth, miniMapHeight); miniMapView->setCameraManipulator( new EarthManipulator() ); miniMapView->getCamera()->setClearColor( osg::Vec4(0,0,0,0)); miniMapView->getCamera()->setProjectionResizePolicy( osg::Camera::FIXED ); miniMapView->getCamera()->setProjectionMatrixAsPerspective(30.0, double(miniMapWidth) / double(miniMapHeight), 1.0, 1000.0); //Share a graphics context with the main view miniMapView->getCamera()->setGraphicsContext( mainView->getCamera()->getGraphicsContext()); viewer.addView( miniMapView ); // load an earth file, and support all or our example command-line options // and earth file <external> tags osg::Node* node = MapNodeHelper().load( arguments, mainView ); if ( node ) { MapNode* mapNode = MapNode::findMapNode(node); //Set the main view's scene data to the loaded earth file mainView->setSceneData( node ); //Setup a group to hold the contents of the MiniMap osg::Group* miniMapGroup = new osg::Group; MapNode* miniMapNode = makeMiniMapNode(); miniMapGroup->addChild( miniMapNode ); //Get the main MapNode so we can do tranformations between it and our minimap MapNode* mainMapNode = MapNode::findMapNode( node ); //Set the scene data for the minimap miniMapView->setSceneData( miniMapGroup ); //Add a marker we can move around with the main view's eye point Style markerStyle; markerStyle.getOrCreate<IconSymbol>()->url()->setLiteral( "../data/placemark32.png" ); PlaceNode* eyeMarker = new PlaceNode(miniMapNode, GeoPoint(miniMapNode->getMapSRS(), 0, 0), "", markerStyle); miniMapGroup->addChild( eyeMarker ); miniMapGroup->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin"); osg::Node* bounds = 0; while (!viewer.done()) { //Reset the viewport so that the camera's viewport is static and doesn't resize with window resizes miniMapView->getCamera()->setViewport( 0, 0, miniMapWidth, miniMapHeight); //Get the eye point of the main view osg::Vec3d eye, up, center; mainView->getCamera()->getViewMatrixAsLookAt( eye, center, up ); //Turn the eye into a geopoint and transform it to the minimap's SRS GeoPoint eyeGeo; eyeGeo.fromWorld( mainMapNode->getMapSRS(), eye ); eyeGeo.transform( miniMapNode->getMapSRS()); //We want the marker to be positioned at elevation 0, so zero out any elevation in the eye point eyeGeo.z() = 0; //Set the position of the marker eyeMarker->setPosition( eyeGeo ); if (bounds) { miniMapGroup->removeChild( bounds ); } GeoExtent extent = getExtent( mainView ); bounds = drawBounds( miniMapNode, extent ); miniMapGroup->addChild( bounds ); viewer.frame(); } } else { OE_NOTICE << "\nUsage: " << argv[0] << " file.earth" << std::endl << MapNodeHelper().usage() << std::endl; } return 0; }
bool BillboardExtension::connect(MapNode* mapNode) { if ( !mapNode ) { OE_WARN << LC << "Illegal: MapNode cannot be null." << std::endl; return false; } OE_INFO << LC << "Connecting to MapNode.\n"; if ( !_options.imageURI().isSet() ) { OE_WARN << LC << "Illegal: image URI is required" << std::endl; return false; } if ( !_options.featureOptions().isSet() ) { OE_WARN << LC << "Illegal: feature source is required" << std::endl; return false; } _features = FeatureSourceFactory::create( _options.featureOptions().value() ); if ( !_features.valid() ) { OE_WARN << LC << "Illegal: no valid feature source provided" << std::endl; return false; } //if ( _features->getGeometryType() != osgEarth::Symbology::Geometry::TYPE_POINTSET ) //{ // OE_WARN << LC << "Illegal: only points currently supported" << std::endl; // return false; //} _features->initialize( _dbOptions ); osg::Vec3dArray* verts; if ( _features->getFeatureProfile() ) { verts = new osg::Vec3dArray(); OE_NOTICE << "Reading features...\n"; osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor(); while ( cursor.valid() && cursor->hasMore() ) { Feature* f = cursor->nextFeature(); if ( f && f->getGeometry() ) { if ( f->getGeometry()->getComponentType() == Geometry::TYPE_POLYGON ) { FilterContext cx; cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) ); ScatterFilter scatter; scatter.setDensity( _options.density().get() ); scatter.setRandom( true ); FeatureList featureList; featureList.push_back(f); scatter.push( featureList, cx ); } // Init a filter to tranform feature in desired SRS if (!mapNode->getMapSRS()->isEquivalentTo(_features->getFeatureProfile()->getSRS())) { FilterContext cx; cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) ); TransformFilter xform( mapNode->getMapSRS() ); FeatureList featureList; featureList.push_back(f); cx = xform.push(featureList, cx); } GeometryIterator iter(f->getGeometry()); while(iter.hasMore()) { const Geometry* geom = iter.next(); osg::ref_ptr<osg::Vec3dArray> fVerts = geom->createVec3dArray(); verts->insert(verts->end(), fVerts->begin(), fVerts->end()); } } } } else { OE_WARN << LC << "Illegal: feature source has no SRS" << std::endl; return false; } if ( verts && verts->size() > 0 ) { OE_NOTICE << LC << "Read " << verts->size() << " points.\n"; //localize all the verts GeoPoint centroid; _features->getFeatureProfile()->getExtent().getCentroid(centroid); centroid = centroid.transform(mapNode->getMapSRS()); OE_NOTICE << "Centroid = " << centroid.x() << ", " << centroid.y() << "\n"; osg::Matrixd l2w, w2l; centroid.createLocalToWorld(l2w); w2l.invert(l2w); osg::MatrixTransform* mt = new osg::MatrixTransform; mt->setMatrix(l2w); OE_NOTICE << "Clamping elevations...\n"; osgEarth::ElevationQuery eq(mapNode->getMap()); eq.setFallBackOnNoData( true ); eq.getElevations(verts->asVector(), mapNode->getMapSRS(), true, 0.005); OE_NOTICE << "Building geometry...\n"; osg::Vec3Array* normals = new osg::Vec3Array(verts->size()); osg::Vec4Array* colors = new osg::Vec4Array(verts->size()); Random rng; for (int i=0; i < verts->size(); i++) { GeoPoint vert(mapNode->getMapSRS(), (*verts)[i], osgEarth::ALTMODE_ABSOLUTE); osg::Vec3d world; vert.toWorld(world); (*verts)[i] = world * w2l; osg::Vec3 normal = world; normal.normalize(); (*normals)[i] = osg::Matrix::transform3x3(normal, w2l); double n = rng.next(); (*colors)[i].set( n, n, n, 1 ); } //create geom and primitive sets osg::Geometry* geometry = new osg::Geometry(); geometry->setVertexArray( verts ); geometry->setNormalArray( normals ); geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX ); geometry->setColorArray(colors); geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX ); geometry->addPrimitiveSet( new osg::DrawArrays( GL_POINTS, 0, verts->size() ) ); //create image and texture to render to osg::Texture2D* tex = new osg::Texture2D(_options.imageURI()->getImage(_dbOptions)); tex->setResizeNonPowerOfTwoHint(false); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); geometry->setName("BillboardPoints"); osg::Geode* geode = new osg::Geode; geode->addDrawable(geometry); //osg::ref_ptr<StateSetCache> cache = new StateSetCache(); //Registry::shaderGenerator().run(geode, cache.get()); //set the texture related uniforms osg::StateSet* geode_ss = geode->getOrCreateStateSet(); geode_ss->setTextureAttributeAndModes( 2, tex, 1 ); geode_ss->getOrCreateUniform("billboard_tex", osg::Uniform::SAMPLER_2D)->set( 2 ); float bbWidth = (float)tex->getImage()->s() / 2.0f; float bbHeight = (float)tex->getImage()->t(); float aspect = (float)tex->getImage()->s() / (float)tex->getImage()->t(); if (_options.height().isSet()) { bbHeight = _options.height().get(); if (!_options.width().isSet()) { bbWidth = bbHeight * aspect / 2.0f; } } if (_options.width().isSet()) { bbWidth = _options.width().get() / 2.0f; if (!_options.height().isSet()) { bbHeight = _options.width().get() / aspect; } } geode_ss->getOrCreateUniform("billboard_width", osg::Uniform::FLOAT)->set( bbWidth ); geode_ss->getOrCreateUniform("billboard_height", osg::Uniform::FLOAT)->set( bbHeight ); geode_ss->setMode(GL_BLEND, osg::StateAttribute::ON); //for now just using an osg::Program //TODO: need to add GeometryShader support to the shader comp setup VirtualProgram* vp = VirtualProgram::getOrCreate(geode_ss); vp->setName( "osgEarth Billboard Extension" ); ShaderPackage shaders; shaders.add( "Billboard geometry shader", billboardGeomShader ); shaders.add( "Billboard fragment shader", billboardFragShader ); shaders.loadAll( vp ); geode_ss->setMode( GL_CULL_FACE, osg::StateAttribute::OFF ); geode->setCullingActive(false); mt->addChild(geode); mapNode->getModelLayerGroup()->addChild(mt); return true; } return false; }
bool ElevationQuery::getElevationImpl(const GeoPoint& point, double& out_elevation, double desiredResolution, double* out_actualResolution) { osg::Timer_t start = osg::Timer::instance()->tick(); if ( _maxDataLevel == 0 || _tileSize == 0 ) { // this means there are no heightfields. out_elevation = 0.0; return true; } //This is the max resolution that we actually have data at this point unsigned int bestAvailLevel = getMaxLevel( point.x(), point.y(), point.getSRS(), _mapf.getProfile()); if (desiredResolution > 0.0) { unsigned int desiredLevel = _mapf.getProfile()->getLevelOfDetailForHorizResolution( desiredResolution, _tileSize ); if (desiredLevel < bestAvailLevel) bestAvailLevel = desiredLevel; } OE_DEBUG << "Best available data level " << point.x() << ", " << point.y() << " = " << bestAvailLevel << std::endl; // transform the input coords to map coords: GeoPoint mapPoint = point; if ( point.isValid() && !point.getSRS()->isEquivalentTo( _mapf.getProfile()->getSRS() ) ) { mapPoint = point.transform(_mapf.getProfile()->getSRS()); if ( !mapPoint.isValid() ) { OE_WARN << LC << "Fail: coord transform failed" << std::endl; return false; } } osg::ref_ptr<osg::HeightField> tile; // get the tilekey corresponding to the tile we need: TileKey key = _mapf.getProfile()->createTileKey( mapPoint.x(), mapPoint.y(), bestAvailLevel ); if ( !key.valid() ) { OE_WARN << LC << "Fail: coords fall outside map" << std::endl; return false; } // Check the tile cache. Note that the TileSource already likely has a MemCache // attached to it. We employ a secondary cache here for a couple reasons. One, this // cache will store not only the heightfield, but also the tesselated tile in the event // that we're using GEOMETRIC mode. Second, since the call the getHeightField can // fallback on a lower resolution, this cache will hold the final resolution heightfield // instead of trying to fetch the higher resolution one each item. TileCache::Record record; if ( _tileCache.get(key, record) ) { tile = record.value().get(); } // if we didn't find it, build it. if ( !tile.valid() ) { // generate the heightfield corresponding to the tile key, automatically falling back // on lower resolution if necessary: _mapf.getHeightField( key, true, tile, 0L ); // bail out if we could not make a heightfield a all. if ( !tile.valid() ) { OE_WARN << LC << "Unable to create heightfield for key " << key.str() << std::endl; return false; } _tileCache.insert(key, tile.get()); } OE_DEBUG << LC << "LRU Cache, hit ratio = " << _tileCache.getStats()._hitRatio << std::endl; // see what the actual resolution of the heightfield is. if ( out_actualResolution ) *out_actualResolution = (double)tile->getXInterval(); bool result = true; const GeoExtent& extent = key.getExtent(); double xInterval = extent.width() / (double)(tile->getNumColumns()-1); double yInterval = extent.height() / (double)(tile->getNumRows()-1); out_elevation = (double) HeightFieldUtils::getHeightAtLocation( tile.get(), mapPoint.x(), mapPoint.y(), extent.xMin(), extent.yMin(), xInterval, yInterval, _mapf.getMapInfo().getElevationInterpolation() ); osg::Timer_t end = osg::Timer::instance()->tick(); _queries++; _totalTime += osg::Timer::instance()->delta_s( start, end ); return result; }
bool GeoTransform::setPosition(const GeoPoint& position) { if ( !position.isValid() ) return false; _position = position; // relative Z or reprojection require a terrain: osg::ref_ptr<Terrain> terrain; _terrain.lock(terrain); // relative Z requires a terrain: if (position.altitudeMode() == ALTMODE_RELATIVE && !terrain.valid()) { OE_TEST << LC << "setPosition failed condition 1\n"; return false; } GeoPoint p; // transform into terrain SRS if neccesary: if (terrain.valid() && !terrain->getSRS()->isEquivalentTo(position.getSRS())) p = position.transform(terrain->getSRS()); else p = position; // bail if the transformation failed: if ( !p.isValid() ) { OE_TEST << LC << "setPosition failed condition 2\n"; return false; } // convert to absolute height: if ( !p.makeAbsolute(_terrain.get()) ) { OE_TEST << LC << "setPosition failed condition 3\n"; return false; } // assemble the matrix: osg::Matrixd local2world; p.createLocalToWorld( local2world ); this->setMatrix( local2world ); // install auto-recompute? if (_autoRecompute && _position.altitudeMode() == ALTMODE_RELATIVE && !_autoRecomputeReady) { // by using the adapter, there's no need to remove // the callback then this object destructs. terrain->addTerrainCallback( new TerrainCallbackAdapter<GeoTransform>(this) ); _autoRecomputeReady = true; } return true; }
bool ElevationQuery::getElevationImpl(const GeoPoint& point, double& out_elevation, double desiredResolution, double* out_actualResolution) { osg::Timer_t start = osg::Timer::instance()->tick(); if ( _mapf.elevationLayers().empty() ) { // this means there are no heightfields. out_elevation = 0.0; return true; } // tile size (resolution of elevation tiles) unsigned tileSize = std::max(_mapf.getMapOptions().elevationTileSize().get(), 2u); //This is the max resolution that we actually have data at this point unsigned int bestAvailLevel = getMaxLevel( point.x(), point.y(), point.getSRS(), _mapf.getProfile()); if (desiredResolution > 0.0) { unsigned int desiredLevel = _mapf.getProfile()->getLevelOfDetailForHorizResolution( desiredResolution, tileSize ); if (desiredLevel < bestAvailLevel) bestAvailLevel = desiredLevel; } OE_DEBUG << LC << "Best available data level " << point.x() << ", " << point.y() << " = " << bestAvailLevel << std::endl; // transform the input coords to map coords: GeoPoint mapPoint = point; if ( point.isValid() && !point.getSRS()->isHorizEquivalentTo( _mapf.getProfile()->getSRS() ) ) { mapPoint = point.transform(_mapf.getProfile()->getSRS()); if ( !mapPoint.isValid() ) { OE_WARN << LC << "Fail: coord transform failed" << std::endl; return false; } } // get the tilekey corresponding to the tile we need: TileKey key = _mapf.getProfile()->createTileKey( mapPoint.x(), mapPoint.y(), bestAvailLevel ); if ( !key.valid() ) { OE_WARN << LC << "Fail: coords fall outside map" << std::endl; return false; } bool result = false; while (!result) { GeoHeightField geoHF; TileCache::Record record; // Try to get the hf from the cache if ( _cache.get( key, record ) ) { geoHF = record.value(); } else { // Create it osg::ref_ptr<osg::HeightField> hf = new osg::HeightField(); hf->allocate( tileSize, tileSize ); // Initialize the heightfield to nodata for (unsigned int i = 0; i < hf->getFloatArray()->size(); i++) { hf->getFloatArray()->at( i ) = NO_DATA_VALUE; } if (_mapf.populateHeightField( hf, key ) ) { geoHF = GeoHeightField( hf.get(), key.getExtent() ); _cache.insert( key, geoHF ); } } if (geoHF.valid()) { float elevation = 0.0f; result = geoHF.getElevation( mapPoint.getSRS(), mapPoint.x(), mapPoint.y(), _mapf.getMapInfo().getElevationInterpolation(), mapPoint.getSRS(), elevation); if (result && elevation != NO_DATA_VALUE) { // see what the actual resolution of the heightfield is. if ( out_actualResolution ) *out_actualResolution = geoHF.getXInterval(); out_elevation = (double)elevation; break; } else { result = false; } } if (!result) { key = key.createParentKey(); if (!key.valid()) { break; } } } osg::Timer_t end = osg::Timer::instance()->tick(); _queries++; _totalTime += osg::Timer::instance()->delta_s( start, end ); return result; }
bool MapInfo::toMapPoint( const GeoPoint& input, GeoPoint& output ) const { return input.isValid() ? input.transform(_profile->getSRS(), output) : false; }
bool ElevationQuery::getElevationImpl(const GeoPoint& point, /* abs */ double& out_elevation, double desiredResolution, double* out_actualResolution) { // assertion. if ( !point.isAbsolute() ) { OE_WARN << LC << "Assertion failure; input must be absolute" << std::endl; return false; } osg::Timer_t begin = osg::Timer::instance()->tick(); // first try the terrain patches. if ( _patchLayers.size() > 0 ) { osgUtil::IntersectionVisitor iv; for(std::vector<ModelLayer*>::iterator i = _patchLayers.begin(); i != _patchLayers.end(); ++i) { // find the scene graph for this layer: osg::Node* node = (*i)->getSceneGraph( _mapf.getUID() ); if ( node ) { // configure for intersection: osg::Vec3d surface; point.toWorld( surface ); // trivial bounds check: if ( node->getBound().contains(surface) ) { osg::Vec3d nvector; point.createWorldUpVector(nvector); osg::Vec3d start( surface + nvector*5e5 ); osg::Vec3d end ( surface - nvector*5e5 ); // first time through, set up the intersector on demand if ( !_patchLayersLSI.valid() ) { _patchLayersLSI = new DPLineSegmentIntersector(start, end); _patchLayersLSI->setIntersectionLimit( _patchLayersLSI->LIMIT_NEAREST ); } else { _patchLayersLSI->reset(); _patchLayersLSI->setStart( start ); _patchLayersLSI->setEnd ( end ); } // try it. iv.setIntersector( _patchLayersLSI.get() ); node->accept( iv ); // check for a result!! if ( _patchLayersLSI->containsIntersections() ) { osg::Vec3d isect = _patchLayersLSI->getIntersections().begin()->getWorldIntersectPoint(); // transform back to input SRS: GeoPoint output; output.fromWorld( point.getSRS(), isect ); out_elevation = output.z(); if ( out_actualResolution ) *out_actualResolution = 0.0; return true; } } else { //OE_INFO << LC << "Trivial rejection (bounds check)" << std::endl; } } } } if ( _mapf.elevationLayers().empty() ) { // this means there are no heightfields. out_elevation = 0.0; return true; } // tile size (resolution of elevation tiles) unsigned tileSize = std::max(_mapf.getMapOptions().elevationTileSize().get(), 2u); //This is the max resolution that we actually have data at this point unsigned int bestAvailLevel = getMaxLevel( point.x(), point.y(), point.getSRS(), _mapf.getProfile()); if (desiredResolution > 0.0) { unsigned int desiredLevel = _mapf.getProfile()->getLevelOfDetailForHorizResolution( desiredResolution, tileSize ); if (desiredLevel < bestAvailLevel) bestAvailLevel = desiredLevel; } OE_DEBUG << LC << "Best available data level " << point.x() << ", " << point.y() << " = " << bestAvailLevel << std::endl; // transform the input coords to map coords: GeoPoint mapPoint = point; if ( point.isValid() && !point.getSRS()->isHorizEquivalentTo( _mapf.getProfile()->getSRS() ) ) { mapPoint = point.transform(_mapf.getProfile()->getSRS()); if ( !mapPoint.isValid() ) { OE_WARN << LC << "Fail: coord transform failed" << std::endl; return false; } } // get the tilekey corresponding to the tile we need: TileKey key = _mapf.getProfile()->createTileKey( mapPoint.x(), mapPoint.y(), bestAvailLevel ); if ( !key.valid() ) { OE_WARN << LC << "Fail: coords fall outside map" << std::endl; return false; } bool result = false; while (!result) { GeoHeightField geoHF; TileCache::Record record; // Try to get the hf from the cache if ( _cache.get( key, record ) ) { geoHF = record.value(); } else { // Create it osg::ref_ptr<osg::HeightField> hf = new osg::HeightField(); hf->allocate( tileSize, tileSize ); // Initialize the heightfield to nodata for (unsigned int i = 0; i < hf->getFloatArray()->size(); i++) { hf->getFloatArray()->at( i ) = NO_DATA_VALUE; } if (_mapf.populateHeightField(hf, key, false)) { geoHF = GeoHeightField( hf.get(), key.getExtent() ); _cache.insert( key, geoHF ); } } if (geoHF.valid()) { float elevation = 0.0f; result = geoHF.getElevation( mapPoint.getSRS(), mapPoint.x(), mapPoint.y(), _mapf.getMapInfo().getElevationInterpolation(), mapPoint.getSRS(), elevation); if (result && elevation != NO_DATA_VALUE) { // see what the actual resolution of the heightfield is. if ( out_actualResolution ) *out_actualResolution = geoHF.getXInterval(); out_elevation = (double)elevation; break; } else { result = false; } } if (!result) { key = key.createParentKey(); if (!key.valid()) { break; } } } osg::Timer_t end = osg::Timer::instance()->tick(); _queries++; _totalTime += osg::Timer::instance()->delta_s( begin, end ); return result; }