Profile::Profile(const SpatialReference* srs, double xmin, double ymin, double xmax, double ymax, double geo_xmin, double geo_ymin, double geo_xmax, double geo_ymax, unsigned int numTilesWideAtLod0, unsigned int numTilesHighAtLod0 ) : osg::Referenced( true ) { _extent = GeoExtent( srs, xmin, ymin, xmax, ymax ); _numTilesWideAtLod0 = numTilesWideAtLod0 != 0? numTilesWideAtLod0 : srs->isGeographic()? 2 : 1; _numTilesHighAtLod0 = numTilesHighAtLod0 != 0? numTilesHighAtLod0 : 1; _latlong_extent = GeoExtent( srs->getGeographicSRS(), geo_xmin, geo_ymin, geo_xmax, geo_ymax ); //if ( !_vsrs.valid() ) // _vsrs = Registry::instance()->getDefaultVSRS(); // make a profile sig (sans srs) and an srs sig for quick comparisons. ProfileOptions temp = toProfileOptions(); _fullSignature = Stringify() << std::hex << hashString( temp.getConfig().toJSON() ); temp.vsrsString() = ""; _horizSignature = Stringify() << std::hex << hashString( temp.getConfig().toJSON() ); }
const Profile* TerrainLayer::getProfile() const { // NB: in cache-only mode, there IS NO layer profile. if ( !_profile.valid() && !isCacheOnly() ) { if ( !_tileSourceInitAttempted ) { // Call getTileSource to make sure the TileSource is initialized getTileSource(); } if ( _tileSource.valid() && !_profile.valid() && !_tileSourceInitFailed ) { const_cast<TerrainLayer*>(this)->_profile = _tileSource->getProfile(); // check for a vertical datum override: if ( _profile.valid() && _runtimeOptions->verticalDatum().isSet() ) { std::string vdatum = toLower( *_runtimeOptions->verticalDatum() ); if ( _profile->getSRS()->getVertInitString() != vdatum ) { ProfileOptions po = _profile->toProfileOptions(); po.vsrsString() = vdatum; const_cast<TerrainLayer*>(this)->_profile = Profile::create(po); } } } } return _profile.get(); }
Profile::Profile(const SpatialReference* srs, double xmin, double ymin, double xmax, double ymax, unsigned int numTilesWideAtLod0, unsigned int numTilesHighAtLod0) : osg::Referenced( true ) { _extent = GeoExtent( srs, xmin, ymin, xmax, ymax ); _numTilesWideAtLod0 = numTilesWideAtLod0 != 0? numTilesWideAtLod0 : srs->isGeographic()? 2 : 1; _numTilesHighAtLod0 = numTilesHighAtLod0 != 0? numTilesHighAtLod0 : 1; // automatically calculate the lat/long extents: _latlong_extent = srs->isGeographic()? _extent : _extent.transform( _extent.getSRS()->getGeographicSRS() ); // make a profile sig (sans srs) and an srs sig for quick comparisons. ProfileOptions temp = toProfileOptions(); _fullSignature = Stringify() << std::hex << hashString( temp.getConfig().toJSON() ); temp.vsrsString() = ""; _horizSignature = Stringify() << std::hex << hashString( temp.getConfig().toJSON() ); }
void TerrainLayer::applyProfileOverrides() { // Check for a vertical datum override. bool changed = false; if ( _profile.valid() && _runtimeOptions->verticalDatum().isSet() ) { std::string vdatum = *_runtimeOptions->verticalDatum(); OE_INFO << "override vdatum = " << vdatum << ", profile vdatum = " << _profile->getSRS()->getVertInitString() << std::endl; if ( !ciEquals(_profile->getSRS()->getVertInitString(), vdatum) ) { ProfileOptions po = _profile->toProfileOptions(); po.vsrsString() = vdatum; _profile = Profile::create(po); changed = true; } } if (changed && _profile.valid()) { OE_INFO << LC << "Override profile: " << _profile->toString() << std::endl; } }
ProfileOptions Profile::toProfileOptions() const { ProfileOptions op; op.srsString() = getSRS()->getHorizInitString(); op.vsrsString() = getSRS()->getVertInitString(); op.bounds()->xMin() = _extent.xMin(); op.bounds()->yMin() = _extent.yMin(); op.bounds()->xMax() = _extent.xMax(); op.bounds()->yMax() = _extent.yMax(); op.numTilesWideAtLod0() = _numTilesWideAtLod0; op.numTilesHighAtLod0() = _numTilesHighAtLod0; return op; }
void TerrainLayer::initTileSource() { _tileSourceInitAttempted = true; OE_DEBUG << LC << "Initializing tile source ..." << std::endl; // Instantiate it from driver options if it has not already been created. // This will also set a manual "override" profile if the user provided one. if ( !_tileSource.valid() ) { if ( _runtimeOptions->driver().isSet() ) { _tileSource = TileSourceFactory::create(*_runtimeOptions->driver()); } } // Initialize the profile with the context information: if ( _tileSource.valid() ) { // set up the URI options. if ( !_dbOptions.valid() ) { _dbOptions = Registry::instance()->cloneOrCreateOptions(); if ( _cache.valid() ) _cache->apply( _dbOptions.get() ); _initOptions.cachePolicy()->apply( _dbOptions.get() ); URIContext( _runtimeOptions->referrer() ).apply( _dbOptions.get() ); } // report on a manual override profile: if ( _tileSource->getProfile() ) { OE_INFO << LC << "set profile to: " << _tileSource->getProfile()->toString() << std::endl; } // Open the tile source (if it hasn't already been started) TileSource::Status status = _tileSource->getStatus(); if ( status != TileSource::STATUS_OK ) { status = _tileSource->open(TileSource::MODE_READ, _dbOptions.get()); } if ( status == TileSource::STATUS_OK ) { _tileSize = _tileSource->getPixelsPerTile(); #if 0 //debugging // dump out data extents: if ( _tileSource->getDataExtents().size() > 0 ) { OE_INFO << LC << "Data extents reported:" << std::endl; for(DataExtentList::const_iterator i = _tileSource->getDataExtents().begin(); i != _tileSource->getDataExtents().end(); ++i) { const DataExtent& de = *i; OE_INFO << " " << "X(" << i->xMin() << ", " << i->xMax() << ") " << "Y(" << i->yMin() << ", " << i->yMax() << ") " << "Z(" << i->minLevel().get() << ", " << i->maxLevel().get() << ")" << std::endl; } } #endif } else { OE_WARN << LC << "Could not initialize driver" << std::endl; _tileSource = NULL; _tileSourceInitFailed = true; _runtimeOptions->enabled() = true; } } // Set the profile from the TileSource if possible: if ( _tileSource.valid() ) { if ( !_profile.valid() && !_tileSourceInitFailed ) { _profile = _tileSource->getProfile(); } // check for a vertical datum override: if ( _profile.valid() && _runtimeOptions->verticalDatum().isSet() ) { std::string vdatum = *_runtimeOptions->verticalDatum(); if ( !ciEquals(_profile->getSRS()->getVertInitString(), vdatum) ) { OE_INFO << LC << "Overriding vdatum with: " << vdatum << std::endl; ProfileOptions po = _profile->toProfileOptions(); po.vsrsString() = vdatum; _profile = Profile::create(po); } } if ( _profile.valid() ) { OE_INFO << LC << "Profile=" << _profile->toString() << std::endl; } } // Otherwise, force cache-only mode (since there is no tilesource). The layer will try to // establish a profile from the metadata in the cache instead. else if (_cache.valid()) { OE_NOTICE << LC << "Could not initialize TileSource " << _name << ", but a cache exists. Setting layer to cache-only mode." << std::endl; setCachePolicy( CachePolicy::CACHE_ONLY ); } }
/** * Command-line tool that copies the contents of one TileSource * to another. All arguments are Config name/value pairs, so you need * to look in the header file for each driver's Options structure for * options :) * * Example: copy a GDAL file to an MBTiles repo: * * osgearth_conv * --in driver gdal * --in url world.tif * --out driver mbtiles * --out filename world.db * * The "in" properties come from the GDALOptions getConfig method. The * "out" properties come from the MBTilesOptions getConfig method. * * Other arguments: * * --elevation : convert as elevation data (instead of image data) * --profile [profile] : reproject to the target profile, e.g. "wgs84" * --min-level [int] : min level of detail to copy * --max-level [int] : max level of detail to copy * --threads [n] : threads to use (may crash. Careful.) * * --extents [minLat] [minLong] [maxLat] [maxLong] : Lat/Long extends to copy (*) * * Of course, the output driver must support writing (by implementing * the ReadWriteTileSource interface). */ int main(int argc, char** argv) { osg::ArgumentParser args(&argc,argv); if ( argc == 1 ) return usage(argv); typedef std::map<std::string,std::string> KeyValue; std::string key, value; // collect input configuration: Config inConf; while( args.read("--in", key, value) ) inConf.set(key, value); TileSourceOptions inOptions(inConf); osg::ref_ptr<TileSource> input = TileSourceFactory::create(inOptions); if ( !input.valid() ) { OE_WARN << LC << "Failed to open input" << std::endl; return -1; } TileSource::Status inputStatus = input->open(); if ( inputStatus.isError() ) { OE_WARN << LC << "Error initializing input" << std::endl; return -1; } // collect output configuration: Config outConf; while( args.read("--out", key, value) ) outConf.set(key, value); // heightfields? bool heightFields = args.read("--heightfield") || args.read("--hf") || args.read("--elevation"); if ( heightFields ) OE_INFO << LC << "Converting heightfield tiles" << std::endl; else OE_INFO << LC << "Converting image tiles" << std::endl; // are we changing profiles? osg::ref_ptr<const Profile> outputProfile = input->getProfile(); std::string profileString; bool isSameProfile = true; if ( args.read("--profile", profileString) ) { outputProfile = Profile::create(profileString); if ( !outputProfile.valid() || !outputProfile->isOK() ) { OE_WARN << LC << "Output profile is not recognized" << std::endl; return -1; } isSameProfile = outputProfile->isHorizEquivalentTo(input->getProfile()); } // set the output profile. ProfileOptions profileOptions = outputProfile->toProfileOptions(); outConf.add("profile", profileOptions.getConfig()); // open the output tile source: TileSourceOptions outOptions(outConf); osg::ref_ptr<TileSource> output = TileSourceFactory::create(outOptions); if ( !output.valid() ) { OE_WARN << LC << "Failed to open output" << std::endl; return -1; } TileSource::Status outputStatus = output->open(TileSource::MODE_WRITE | TileSource::MODE_CREATE); if ( outputStatus.isError() ) { OE_WARN << LC << "Error initializing output" << std::endl; return -1; } // Dump out some stuff... OE_NOTICE << LC << "FROM:\n" << inConf.toJSON(true) << std::endl; OE_NOTICE << LC << "TO:\n" << outConf.toJSON(true) << std::endl; // create the visitor. osg::ref_ptr<TileVisitor> visitor; unsigned numThreads = 1; if (args.read("--threads", numThreads)) { MultithreadedTileVisitor* mtv = new MultithreadedTileVisitor(); mtv->setNumThreads( numThreads < 1 ? 1 : numThreads ); visitor = mtv; } else { visitor = new TileVisitor(); } // If the profiles are identical, just use a tile copier. if ( isSameProfile ) { OE_NOTICE << LC << "Profiles match - initiating simple tile copy" << std::endl; visitor->setTileHandler( new TileSourceToTileSource(input.get(), output.get(), heightFields) ); } else { OE_NOTICE << LC << "Profiles differ - initiating tile transformation" << std::endl; if (heightFields) { ElevationLayer* layer = new ElevationLayer(ElevationLayerOptions(), input.get()); if ( !layer->getProfile() || !layer->getProfile()->isOK() ) { OE_WARN << LC << "Input profile is not valid" << std::endl; return -1; } visitor->setTileHandler( new ElevationLayerToTileSource(layer, output.get()) ); } else { ImageLayer* layer = new ImageLayer(ImageLayerOptions(), input.get()); if ( !layer->getProfile() || !layer->getProfile()->isOK() ) { OE_WARN << LC << "Input profile is not valid" << std::endl; return -1; } visitor->setTileHandler( new ImageLayerToTileSource(layer, output.get()) ); } } // Set the level limits: unsigned minLevel = ~0; bool minLevelSet = args.read("--min-level", minLevel); unsigned maxLevel = 0; bool maxLevelSet = args.read("--max-level", maxLevel); // figure out the max source level: if ( !minLevelSet || !maxLevelSet ) { for(DataExtentList::const_iterator i = input->getDataExtents().begin(); i != input->getDataExtents().end(); ++i) { if ( !maxLevelSet && i->maxLevel().isSet() && i->maxLevel().value() > maxLevel ) maxLevel = i->maxLevel().value(); if ( !minLevelSet && i->minLevel().isSet() && i->minLevel().value() < minLevel ) minLevel = i->minLevel().value(); } } if ( minLevel < ~0 ) { visitor->setMinLevel( minLevel ); } if ( maxLevel > 0 ) { maxLevel = outputProfile->getEquivalentLOD( input->getProfile(), maxLevel ); visitor->setMaxLevel( maxLevel ); OE_NOTICE << LC << "Calculated max level = " << maxLevel << std::endl; } // set the extents: double minlat, minlon, maxlat, maxlon; while( args.read("--extents", minlat, minlon, maxlat, maxlon) ) { GeoExtent extent(SpatialReference::get("wgs84"), minlon, minlat, maxlon, maxlat); visitor->addExtent( extent ); } // Ready!!! std::cout << "Working..." << std::endl; visitor->setProgressCallback( new ProgressReporter() ); osg::Timer_t t0 = osg::Timer::instance()->tick(); visitor->run( outputProfile.get() ); osg::Timer_t t1 = osg::Timer::instance()->tick(); std::cout << "Time = " << std::fixed << std::setprecision(1) << osg::Timer::instance()->delta_s(t0, t1) << " seconds." << std::endl; return 0; }
void Map::calculateProfile() { if ( !_profile.valid() ) { osg::ref_ptr<const Profile> userProfile; if ( _mapOptions.profile().isSet() ) { userProfile = Profile::create( _mapOptions.profile().value() ); } if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC ) { if ( userProfile.valid() ) { if ( userProfile->isOK() && userProfile->getSRS()->isGeographic() ) { _profile = userProfile.get(); } else { OE_WARN << LC << "Map is geocentric, but the configured profile SRS (" << userProfile->getSRS()->getName() << ") is not geographic; " << "it will be ignored." << std::endl; } } if ( !_profile.valid() ) { // by default, set a geocentric map to use global-geodetic WGS84. _profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile(); } } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE ) { //If the map type is a Geocentric Cube, set the profile to the cube profile. _profile = osgEarth::Registry::instance()->getCubeProfile(); } else // CSTYPE_PROJECTED { if ( userProfile.valid() ) { _profile = userProfile.get(); } } // At this point, if we don't have a profile we need to search tile sources until we find one. if ( !_profile.valid() ) { Threading::ScopedReadLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end() && !_profile.valid(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end() && !_profile.valid(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } } // convert the profile to Plate Carre if necessary. if (_profile.valid() && _profile->getSRS()->isGeographic() && getMapOptions().coordSysType() == MapOptions::CSTYPE_PROJECTED ) { OE_INFO << LC << "Projected display with geographic SRS; activating Plate Carre mode" << std::endl; _profile = _profile->overrideSRS( _profile->getSRS()->createPlateCarreGeographicSRS() ); } // finally, fire an event if the profile has been set. if ( _profile.valid() ) { OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl; for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapInfoEstablished( MapInfo(this) ); } } else { OE_WARN << LC << "Warning, not yet able to establish a map profile!" << std::endl; } } if ( _profile.valid() ) { // tell all the loaded layers what the profile is, as a hint { Threading::ScopedWriteLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() == true ) { layer->setTargetProfileHint( _profile.get() ); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getEnabled() ) { layer->setTargetProfileHint( _profile.get() ); } } } // create a "proxy" profile to use when querying elevation layers with a vertical datum if ( _profile->getSRS()->getVerticalDatum() != 0L ) { ProfileOptions po = _profile->toProfileOptions(); po.vsrsString().unset(); _profileNoVDatum = Profile::create(po); } else { _profileNoVDatum = _profile; } } }