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() ); }
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() ); }
/** * 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; }