bool TileSource::hasData(const osgEarth::TileKey& key) const { //sematics: "might have data" if ( !key.valid() ) return false; // If no data extents are provided, and there's no data level override, // return true because there might be data but there's no way to tell. if (_dataExtents.size() == 0 && !_options.maxDataLevel().isSet()) { return true; } unsigned int lod = key.getLevelOfDetail(); // Remap the lod to an appropriate lod if it's not in the same SRS if (!key.getProfile()->isHorizEquivalentTo( getProfile() ) ) { lod = getProfile()->getEquivalentLOD( key.getProfile(), key.getLevelOfDetail() ); } // If there's an explicit LOD override and we've exceeded it, no data. if (_options.maxDataLevel().isSet() && lod > _options.maxDataLevel().value()) { return false; } // If there are no extents to check, there might be data. if (_dataExtents.size() == 0) { return true; } bool intersectsData = false; const osgEarth::GeoExtent& keyExtent = key.getExtent(); for (DataExtentList::const_iterator itr = _dataExtents.begin(); itr != _dataExtents.end(); ++itr) { if ((keyExtent.intersects( *itr )) && (!itr->minLevel().isSet() || itr->minLevel() <= lod ) && (!itr->maxLevel().isSet() || itr->maxLevel() >= lod )) { intersectsData = true; break; } } return intersectsData; }
std::string DiskCache::getFilename(const osgEarth::TileKey& key, const CacheSpec& spec ) const { unsigned int level, x, y; level = key.getLevelOfDetail() +1; key.getTileXY( x, y ); unsigned int numCols, numRows; key.getProfile()->getNumTiles(level, numCols, numRows); // need to invert the y-tile index y = numRows - y - 1; char buf[2048]; sprintf( buf, "%s/%s/%02d/%03d/%03d/%03d/%03d/%03d/%03d.%s", getPath().c_str(), spec.cacheId().c_str(), level, (x / 1000000), (x / 1000) % 1000, (x % 1000), (y / 1000000), (y / 1000) % 1000, (y % 1000), spec.format().c_str()); return buf; }
std::string TileMap::getURL(const osgEarth::TileKey& tilekey, bool invertY) { if (!intersectsKey(tilekey)) { //OE_NOTICE << LC << "No key intersection for tile key " << tilekey.str() << std::endl; return ""; } unsigned int zoom = tilekey.getLevelOfDetail(); unsigned int x, y; tilekey.getTileXY(x, y); //Some TMS like services swap the Y coordinate so 0,0 is the upper left rather than the lower left. The normal TMS //specification has 0,0 at the bottom left, so inverting Y will make 0,0 in the upper left. //http://code.google.com/apis/maps/documentation/overlays.html#Google_Maps_Coordinates if (!invertY) { unsigned int numRows, numCols; tilekey.getProfile()->getNumTiles(tilekey.getLevelOfDetail(), numCols, numRows); y = numRows - y - 1; } //OE_NOTICE << LC << "KEY: " << tilekey.str() << " level " << zoom << " ( " << x << ", " << y << ")" << std::endl; //Select the correct TileSet if ( _tileSets.size() > 0 ) { for (TileSetList::iterator itr = _tileSets.begin(); itr != _tileSets.end(); ++itr) { if (itr->getOrder() == zoom) { std::stringstream ss; std::string path = osgDB::getFilePath(_filename); ss << path << "/" << zoom << "/" << x << "/" << y << "." << _format.getExtension(); //OE_NOTICE << LC << "Returning URL " << ss.str() << std::endl; std::string ssStr; ssStr = ss.str(); return ssStr; } } } else // Just go with it. No way of knowing the max level. { std::stringstream ss; std::string path = osgDB::getFilePath(_filename); ss << path << "/" << zoom << "/" << x << "/" << y << "." << _format.getExtension(); std::string ssStr; ssStr = ss.str(); return ssStr; } return ""; }
virtual void onTileAdded(const osgEarth::TileKey& tileKey, osg::Node* terrain, TerrainCallbackContext&) { if ((int)tileKey.getLevelOfDetail() > _minLevel && _maxLevel < (int)tileKey.getLevelOfDetail()) { osg::Vec3d position = _locator->getLocator()->getPosition(); if (tileKey.getExtent().contains(position.x(), position.y())) { //Compute our location in geocentric const osg::EllipsoidModel* ellipsoid = tileKey.getProfile()->getSRS()->getEllipsoid(); double x, y, z; ellipsoid->convertLatLongHeightToXYZ( osg::DegreesToRadians(position.y()), osg::DegreesToRadians(position.x()), 0, x, y, z); //Compute the up vector osg::Vec3d up = ellipsoid->computeLocalUpVector(x, y, z ); up.normalize(); osg::Vec3d world(x, y, z); double segOffset = 50000; osg::Vec3d start = world + (up * segOffset); osg::Vec3d end = world - (up * segOffset); osgUtil::LineSegmentIntersector* i = new osgUtil::LineSegmentIntersector( start, end ); osgUtil::IntersectionVisitor iv; iv.setIntersector( i ); terrain->accept( iv ); osgUtil::LineSegmentIntersector::Intersections& results = i->getIntersections(); if ( !results.empty() ) { const osgUtil::LineSegmentIntersector::Intersection& result = *results.begin(); osg::Vec3d hit = result.getWorldIntersectPoint(); double lat, lon, height; ellipsoid->convertXYZToLatLongHeight(hit.x(), hit.y(), hit.z(), lat, lon, height); position.z() = height; //OE_NOTICE << "Got hit, setting new height to " << height << std::endl; _maxLevel = tileKey.getLevelOfDetail(); _locator->getLocator()->setPosition( position ); } } } }
bool TileSource::getBestAvailableTileKey(const osgEarth::TileKey& key, osgEarth::TileKey& output) const { // trivial reject if ( !key.valid() ) return false; // trivial accept: no data extents = not enough info. if (_dataExtents.size() == 0) { output = key; return true; } // trivial reject: key doesn't intersect the union of data extents at all. if ( !getDataExtentsUnion().intersects(key.getExtent()) ) { return false; } bool intersects = false; unsigned highestLOD = 0; // We must use the equivalent lod b/c the key can be in any profile. int layerLOD = getProfile()->getEquivalentLOD( key.getProfile(), key.getLOD() ); for (DataExtentList::const_iterator itr = _dataExtents.begin(); itr != _dataExtents.end(); ++itr) { // check for 2D intersection: if (key.getExtent().intersects( *itr )) { // check that the extent isn't higher-resolution than our key: if ( !itr->minLevel().isSet() || layerLOD >= itr->minLevel().get() ) { // Got an intersetion; now test the LODs: intersects = true; // Is the high-LOD set? If not, there's not enough information // so just assume our key might be good. if ( itr->maxLevel().isSet() == false ) { output = key; return true; } // Is our key at a lower or equal LOD than the max key in this extent? // If so, our key is good. else if ( layerLOD <= itr->maxLevel().get() ) { output = key; return true; } // otherwise, record the highest encountered LOD that // intersects our key. else if ( itr->maxLevel().get() > highestLOD ) { highestLOD = itr->maxLevel().get(); } } } } if ( intersects ) { output = key.createAncestorKey( highestLOD ); return true; } else { return false; } }