TileMap* TileMapReaderWriter::read( const std::string& location, const osgDB::ReaderWriter::Options* options ) { TileMap* tileMap = NULL; ReadResult r = URI(location).readString(); if ( r.failed() ) { OE_WARN << LC << "Failed to read TMS tile map file from " << location << std::endl; return 0L; } // Read tile map into a Config: Config conf; std::stringstream buf( r.getString() ); conf.fromXML( buf ); // parse that into a tile map: tileMap = TileMapReaderWriter::read( conf ); if (tileMap) { tileMap->setFilename( location ); } return tileMap; }
TileMap* TileMapReaderWriter::read( const std::string& location, const osgDB::ReaderWriter::Options* options ) { TileMap* tileMap = NULL; ReadResult r = URI(location).readString(); if ( r.failed() ) { OE_DEBUG << LC << "Failed to read TMS tile map file from " << location << std::endl; return 0L; } // Read tile map into a Config: Config conf; std::stringstream buf( r.getString() ); conf.fromXML( buf ); // parse that into a tile map: tileMap = TileMapReaderWriter::read( conf ); if (tileMap) { tileMap->setFilename( location ); // record the timestamp (if there is one) in the tilemap. It's not a persistent field // but will help with things like per-session caching. tileMap->setTimeStamp( r.lastModifiedTime() ); } return tileMap; }
FeatureCursor* createFeatureCursor( const Symbology::Query& query ) { FeatureCursor* result = 0L; std::string url = createURL( query ); // check the blacklist: if ( Registry::instance()->isBlacklisted(url) ) return 0L; OE_DEBUG << LC << url << std::endl; URI uri(url); // read the data: ReadResult r = uri.readString( _dbOptions.get() ); const std::string& buffer = r.getString(); const Config& meta = r.metadata(); bool dataOK = false; FeatureList features; if ( !buffer.empty() ) { // Get the mime-type from the metadata record if possible const std::string& mimeType = r.metadata().value( IOMetadata::CONTENT_TYPE ); dataOK = getFeatures( buffer, mimeType, features ); } if ( dataOK ) { OE_DEBUG << LC << "Read " << features.size() << " features" << std::endl; } //If we have any filters, process them here before the cursor is created if (!_options.filters().empty()) { // preprocess the features using the filter list: if ( features.size() > 0 ) { FilterContext cx; cx.setProfile( getFeatureProfile() ); for( FeatureFilterList::const_iterator i = _options.filters().begin(); i != _options.filters().end(); ++i ) { FeatureFilter* filter = i->get(); cx = filter->push( features, cx ); } } } //result = new FeatureListCursor(features); result = dataOK ? new FeatureListCursor( features ) : 0L; if ( !result ) Registry::instance()->blacklist( url ); return result; }
// read the WKT geometry from a URL, then parse into a Geometry. Symbology::Geometry* parseGeometryUrl( const std::string& geomUrl, const osgDB::Options* dbOptions ) { ReadResult r = URI(geomUrl).readString( dbOptions ); if ( r.succeeded() ) { Config conf( "geometry", r.getString() ); return parseGeometry( conf ); } return 0L; }
TileService* TileServiceReader::read( const std::string &location, const osgDB::ReaderWriter::Options* options ) { TileService *tileService = NULL; ReadResult r = URI(location).readString( options ); if ( r.succeeded() ) { std::istringstream buf( r.getString() ); tileService = read( buf ); } return tileService; }
FeatureCursor* createFeatureCursor( const Symbology::Query& query ) { FeatureCursor* result = 0L; std::string url = createURL( query ); if (url.empty()) return 0; // check the blacklist: if ( Registry::instance()->isBlacklisted(url) ) return 0L; OE_DEBUG << LC << url << std::endl; URI uri(url); // read the data: ReadResult r = uri.readString( _dbOptions.get() ); const std::string& buffer = r.getString(); const Config& meta = r.metadata(); bool dataOK = false; FeatureList features; if ( !buffer.empty() ) { // Get the mime-type from the metadata record if possible std::string mimeType = r.metadata().value( IOMetadata::CONTENT_TYPE ); //If the mimetype is empty then try to set it from the format specification if (mimeType.empty()) { if (_options.format().value() == "json") mimeType = "json"; else if (_options.format().value().compare("gml") == 0) mimeType = "text/xml"; } dataOK = getFeatures( buffer, mimeType, features ); } if ( dataOK ) { OE_DEBUG << LC << "Read " << features.size() << " features" << std::endl; } //result = new FeatureListCursor(features); result = dataOK ? new FeatureListCursor( features ) : 0L; if ( !result ) Registry::instance()->blacklist( url ); return result; }
XmlDocument* XmlDocument::load( const URI& uri, const osgDB::Options* dbOptions ) { XmlDocument* result = 0L; ReadResult r = uri.readString( dbOptions ); if ( r.succeeded() ) { std::stringstream buf( r.getString() ); result = load( buf ); if ( result ) result->_sourceURI = uri; } return result; }
bool TileMapServiceReader::read( const std::string &location, const osgDB::ReaderWriter::Options* options, TileMapEntryList& tileMaps ) { ReadResult r = URI(location).readString(); if ( r.failed() ) { OE_WARN << LC << "Failed to read TileMapServices from " << location << std::endl; return 0L; } // Read tile map into a Config: Config conf; std::stringstream buf( r.getString() ); conf.fromXML( buf ); // parse that into a tile map: return read( conf, tileMaps ); }
WMSCapabilities* WMSCapabilitiesReader::read( const std::string &location, const osgDB::ReaderWriter::Options* options ) { WMSCapabilities *caps = NULL; if ( osgDB::containsServerAddress( location ) ) { ReadResult rr = URI(location).readString( options ); if ( rr.succeeded() ) { std::istringstream in( rr.getString() ); caps = read( in ); } } else { if ((osgDB::fileExists(location)) && (osgDB::fileType(location) == osgDB::REGULAR_FILE)) { std::ifstream in( location.c_str() ); caps = read( in ); } } return caps; }
bool ServiceReader::read( const URI& location, const osgDB::Options* options, RESTResponse& response ) { response.setServiceURL( location.full() ); std::string serviceLocation = location.full() + "?f=json&pretty=true"; ReadResult r = URI(serviceLocation, location.context()).readString(); if ( r.failed() ) { OE_WARN << "Failed to read ArcGIS Services tile map file from " << serviceLocation << std::endl; return false; } // Read tile map into a Config: Config conf; std::stringstream buf( r.getString() ); if (!conf.fromJSON( buf.str() )) { return false; } return read( conf, response ); }
bool MapService::init( const URI& _uri, const osgDB::ReaderWriter::Options* options ) { uri = _uri; std::string sep = uri.full().find( "?" ) == std::string::npos ? "?" : "&"; std::string json_url = uri.full() + sep + std::string("f=pjson"); // request the data in JSON format ReadResult r = URI(json_url).readString( options ); if ( r.failed() ) return setError( "Unable to read metadata from ArcGIS service" ); Json::Value doc; Json::Reader reader; // if ( !reader.parse( response.getPartStream(0), doc ) ) if ( !reader.parse( r.getString(), doc ) ) { return setError( "Unable to parse metadata; invalid JSON" ); } // Read the profile. We are using "fullExtent"; perhaps an option to use "initialExtent" instead? double xmin = 0.0; double ymin = 0.0; double xmax = 0.0; double ymax = 0.0; int srs = 0; Json::Value fullExtentValue = doc["fullExtent"]; Json::Value extentValue = doc["extent"]; std::string srsValue; // added a case for "extent" which can be removed if we want to fall back on initialExtent if fullExtent fails if ( !fullExtentValue.empty() ) { // if "fullExtent" exists .. use that xmin = doc["fullExtent"].get("xmin", 0).asDouble(); ymin = doc["fullExtent"].get("ymin", 0).asDouble(); xmax = doc["fullExtent"].get("xmax", 0).asDouble(); ymax = doc["fullExtent"].get("ymax", 0).asDouble(); srs = doc["fullExtent"].get("spatialReference", osgEarth::Json::Value::null).get("wkid", 0).asInt(); srsValue = doc["fullExtent"].get("spatialReference", osgEarth::Json::Value::null).get("wkt", "null").asString(); OE_DEBUG << LC << "fullExtent discovered: xmin: " << xmin << ", ymin: " << ymin << ", xmax: " << xmax << ", ymax: " << ymax << ", srs: " << srs << std::endl; } else if( !extentValue.empty() ) { // else if "extent" exists .. use that xmin = doc["extent"].get("xmin", 0).asDouble(); ymin = doc["extent"].get("ymin", 0).asDouble(); xmax = doc["extent"].get("xmax", 0).asDouble(); ymax = doc["extent"].get("ymax", 0).asDouble(); srs = doc["extent"].get("spatialReference", osgEarth::Json::Value::null).get("wkid", 0).asInt(); srsValue = doc["extent"].get("spatialReference", osgEarth::Json::Value::null).get("wkt", "null").asString(); OE_DEBUG << LC << "extent discovered: xmin: " << xmin << ", ymin: " << ymin << ", xmax: " << xmax << ", ymax: " << ymax << ", srs: " << srs << std::endl; } else { // else "initialExtent" must exist .. xmin = doc["initialExtent"].get("xmin", 0).asDouble(); ymin = doc["initialExtent"].get("ymin", 0).asDouble(); xmax = doc["initialExtent"].get("xmax", 0).asDouble(); ymax = doc["initialExtent"].get("ymax", 0).asDouble(); srs = doc["initialExtent"].get("spatialReference", osgEarth::Json::Value::null).get("wkid", 0).asInt(); srsValue = doc["initialExtent"].get("spatialReference", osgEarth::Json::Value::null).get("wkt", "null").asString(); OE_DEBUG << LC << "initialExtent discovered: xmin: " << xmin << ", ymin: " << ymin << ", xmax: " << xmax << ", ymax: " << ymax << ", srs: " << srs << std::endl; } //Assumes the SRS is going to be an EPSG code std::stringstream ss; ss << "epsg:" << srs; // we can create a valid spatial reference from the WKT/proj4 string .. here just check if x/y/min/max values are set & correct if ( ! (xmax > xmin && ymax > ymin /*&& srs != 0*/ ) ) { return setError( "Map service does not define a full extent" ); } // Check that the layers list is not empty Json::Value j_layers = doc["layers"]; if ( j_layers.empty() ) { return setError( "Map service contains no layers" ); } // not required to initialise a layer .. in any case this code does nothing for( unsigned int i=0; i<j_layers.size(); i++ ) { Json::Value layer = j_layers[i]; int id = i; // layer.get("id", -1).asInt(); std::string name = layer["name"].asString(); if ( id >= 0 && !name.empty() ) { layers.push_back( MapServiceLayer( id, name ) ); } } tiled = false; std::string format = "png"; int tile_rows = 256; int tile_cols = 256; int min_level = 25; int max_level = 0; int num_tiles_wide = 1; int num_tiles_high = 1; // Read the tiling schema Json::Value j_tileinfo = doc["tileInfo"]; if ( !j_tileinfo.empty() ) { tiled = true; // return setError( "Map service does not define a tiling schema" ); // TODO: what do we do if the width <> height? tile_rows = j_tileinfo.get( "rows", 0 ).asInt(); tile_cols = j_tileinfo.get( "cols", 0 ).asInt(); if ( tile_rows <= 0 && tile_cols <= 0 ) { return setError( "Map service tile size not specified" ); } format = j_tileinfo.get( "format", "" ).asString(); if ( format.empty() ) { return setError( "Map service tile schema does not specify an image format" ); } Json::Value j_levels = j_tileinfo["lods"]; if ( j_levels.empty() ) { return setError( "Map service tile schema contains no LODs" ); } min_level = INT_MAX; max_level = 0; for( unsigned int i=0; i<j_levels.size(); i++ ) { int level = j_levels[i].get( "level", -1 ).asInt(); if ( level >= 0 && level < min_level ) { min_level = level; } if ( level >= 0 && level > max_level ) { max_level = level; } } if (j_levels.size() > 0) { int l = j_levels[0u].get("level", -1).asInt(); double res = j_levels[0u].get("resolution", 0.0).asDouble(); num_tiles_wide = (int)osg::round((xmax - xmin) / (res * tile_cols)); num_tiles_high = (int)osg::round((ymax - ymin) / (res * tile_cols)); //In case the first level specified isn't level 0, compute the number of tiles at level 0 for (int i = 0; i < l; i++) { num_tiles_wide /= 2; num_tiles_high /= 2; } //profile.setNumTilesWideAtLod0(num_tiles_wide); //profile.setNumTilesHighAtLod0(num_tiles_high); } } std::string ssStr; ssStr = ss.str(); osg::ref_ptr< SpatialReference > spatialReference; // if srs is in a non integer form .. find out what form it's in & create .. if(srs == 0) { OE_DEBUG << LC << "srsString: " << srsValue << std::endl; // create spatial reference from WKT string spatialReference = SpatialReference::create( srsValue ); } else { // create spatial reference from epsg string (WKID) spatialReference = SpatialReference::create( ssStr ); } // if spatial reference is valid .. create a profile if( spatialReference.valid() ) { // create profile from spatial reference if ( spatialReference->isGeographic() ) { // If we have a geographic SRS, just use the geodetic profile profile = Registry::instance()->getGlobalGeodeticProfile(); } else if ( spatialReference->isMercator() ) { // If we have a mercator SRS, just use the mercator profile profile = Registry::instance()->getGlobalMercatorProfile(); } else { //It's not geodetic or mercator, so try to use the full extent profile = Profile::create( spatialReference.get(), xmin, ymin, xmax, ymax, num_tiles_wide, num_tiles_high); } } else { return setError( "Map service Spatial Reference INVALID" ); } if( !profile.valid() ) { return setError( "Map service could not create a valid profile" ); } // now we're good. tile_info = TileInfo( tile_rows, format, min_level, max_level, num_tiles_wide, num_tiles_high); is_valid = true; return is_valid; }
/** * Create and return an image for the given TileKey. */ osg::Image* createImage( const TileKey& key, ProgressCallback* progress ) { if (_debugDirect) { //osg::Image* image = new osg::Image; //image->allocateImage(256,256,1, GL_RGB, GL_UNSIGNED_BYTE); //return image; return osgDB::readImageFile( getDirectURI(key) ); //return URI(getDirectURI(key)).getImage(_dbOptions.get(), progress); } // center point of the tile (will be in spherical mercator) double x, y; key.getExtent().getCentroid(x, y); // transform it to lat/long: GeoPoint geo; GeoPoint( getProfile()->getSRS(), x, y ).transform( getProfile()->getSRS()->getGeographicSRS(), geo ); // contact the REST API. Docs are here: // http://msdn.microsoft.com/en-us/library/ff701716.aspx // construct the request URI: std::string request = Stringify() << std::setprecision(12) << _options.imageryMetadataAPI().get() // base REST API << "/" << _options.imagerySet().get() // imagery set to use << "/" << geo.y() << "," << geo.x() // center point in lat/long << "?zl=" << key.getLOD() + 1 // zoom level << "&o=json" // response format << "&key=" << _options.key().get(); // API key // check the URI cache. URI location; TileURICache::Record rec; if ( _tileURICache.get(request, rec) ) { location = URI(rec.value()); //CacheStats stats = _tileURICache.getStats(); //OE_INFO << "Ratio = " << (stats._hitRatio*100) << "%" << std::endl; } else { unsigned c = ++_apiCount; if ( c % 25 == 0 ) OE_INFO << LC << "API calls = " << c << std::endl; // fetch it: ReadResult metadataResult = URI(request).readString(_dbOptions, progress); if ( metadataResult.failed() ) { // check for a REST error: if ( metadataResult.code() == ReadResult::RESULT_SERVER_ERROR ) { OE_WARN << LC << "REST API request error!" << std::endl; Config metadata; std::string content = metadataResult.getString(); metadata.fromJSON( content ); ConfigSet errors = metadata.child("errorDetails").children(); for(ConfigSet::const_iterator i = errors.begin(); i != errors.end(); ++i ) { OE_WARN << LC << "REST API: " << i->value() << std::endl; } return 0L; } else { OE_WARN << LC << "Request error: " << metadataResult.getResultCodeString() << std::endl; } return 0L; } // decode it: Config metadata; if ( !metadata.fromJSON(metadataResult.getString()) ) { OE_WARN << LC << "Error decoding REST API response" << std::endl; return 0L; } // check the vintage field. If it's empty, that means we got a "no data" tile. Config* vintageEnd = metadata.find("vintageEnd"); if ( !vintageEnd || vintageEnd->value().empty() ) { OE_DEBUG << LC << "NO data image encountered." << std::endl; return 0L; } // find the tile URI: Config* locationConf= metadata.find("imageUrl"); if ( !locationConf ) { OE_WARN << LC << "REST API JSON parsing error (imageUrl not found)" << std::endl; return 0L; } location = URI( locationConf->value() ); _tileURICache.insert( request, location.full() ); } // request the actual tile //OE_INFO << "key = " << key.str() << ", URL = " << location->value() << std::endl; //osg::Image* image = location.getImage(_dbOptions.get(), progress); osg::Image* image = osgDB::readImageFile( location.full() ); if ( image && _geom.valid() ) { GeometryRasterizer rasterizer( image->s(), image->t() ); rasterizer.draw( _geom.get(), osg::Vec4(1,1,1,1) ); osg::ref_ptr<osg::Image> overlay = rasterizer.finalize(); ImageUtils::PixelVisitor<AlphaBlend> blend; blend.accept( overlay.get(), image ); } return image; }
bool SplatExtension::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.catalogURI().isSet() ) { OE_WARN << LC << "Illegal: catalog URI is required" << std::endl; return false; } if ( !_options.legendURI().isSet() ) { OE_WARN << LC << "Illegal: legend URI is required" << std::endl; return false; } if ( !_options.coverageLayerName().isSet() ) { OE_WARN << LC << "Illegal: coverage layer name is required" << std::endl; return false; } // Locate the coverage layer in the map. const Map* map = mapNode->getMap(); const ImageLayer* coverageLayer = map->getImageLayerByName( _options.coverageLayerName().get() ); if ( !coverageLayer ) { OE_WARN << LC << "Coverage layer \"" << _options.coverageLayerName().get() << "\" not found in map." << std::endl; return false; } // Read in the catalog. osg::ref_ptr<SplatCatalog> catalog = new SplatCatalog(); { ReadResult result = _options.catalogURI()->readString( _dbOptions.get() ); if ( result.succeeded() ) { Config conf; conf.setReferrer(_options.catalogURI()->full()); std::string json = result.getString(); conf.fromJSON( json ); catalog->fromConfig( conf ); OE_INFO << LC << "Catalog: " << catalog->getClasses().size() << " classes\n"; } else { OE_WARN << LC << "Failed to read catalog from \"" << _options.catalogURI()->full() << "\"\n"; return false; } } // Read in the legend. osg::ref_ptr<SplatCoverageLegend> legend = new SplatCoverageLegend(); { ReadResult result = _options.legendURI()->readString( _dbOptions.get() ); if ( result.succeeded() ) { Config conf; conf.setReferrer(_options.legendURI()->full()); conf.fromJSON( result.getString() ); legend->fromConfig( conf ); OE_INFO << LC << "Legend: " << legend->getPredicates().size() << " mappings \n"; } else { OE_WARN << LC << "Failed to read legend from \"" << _options.legendURI()->full() << "\"\n"; return false; } } // Terrain effect that implements splatting. _effect = new SplatTerrainEffect( catalog, legend, _dbOptions.get() ); // set the coverage layer (mandatory) _effect->setCoverageLayer( coverageLayer ); // set the render order (optional) if ( _options.drawAfterImageLayers() == true ) _effect->setRenderOrder( 1.0f ); // set the various rendering options. if ( _options.coverageWarp().isSet() ) _effect->getCoverageWarpUniform()->set( _options.coverageWarp().get() ); if ( _options.coverageBlur().isSet() ) _effect->getCoverageBlurUniform()->set( _options.coverageBlur().get() ); if ( _options.scaleLevelOffset().isSet() ) _effect->getScaleLevelOffsetUniform()->set( (float)_options.scaleLevelOffset().get() ); // add it to the terrain. mapNode->getTerrainEngine()->addEffect( _effect.get() ); if ( ::getenv("OSGEARTH_SPLAT_MODELS") ) { // TEMPORARY. This is just a quick hack to test the tile-based model splatter. // It finds any occurance of a model in the catalog and just installs that in // a single splatter. Doesn't support multiple models, classifications, or // anything interesting quite yet. //const SplatClassVector& classes = catalog->getClasses(); //for(SplatClassVector::const_iterator i = classes.begin(); i != classes.end(); ++i ) //{ osg::ref_ptr<osg::Node> model; //if ( i->_modelURI.isSet() ) //{ model = URI("../data/red_flag.osg").getNode(_dbOptions.get()); //model = i->_modelURI->getNode(_dbOptions.get()); if ( model.valid() ) { if ( !_modelSplatter.valid() ) { _modelSplatter = new ModelSplatter(); } _modelSplatter->setModel( model.get() ); //if ( i->_modelCount.isSet() ) // _modelSplatter->setNumInstances( i->_modelCount.get() ); //if ( i->_modelLevel.isSet() ) // _modelSplatter->setMinLOD( i->_modelLevel.get() ); } else { OE_WARN << LC << "Can't load the tree!\n"; } // } } // Install the model splatter if we made one. if ( _modelSplatter.valid() ) { mapNode->getTerrainEngine()->addTileNodeCallback( _modelSplatter.get() ); } return true; }
FeatureCursor* createFeatureCursor(const Symbology::Query& query, ProgressCallback* progress) { FeatureCursor* result = 0L; std::string url = createURL( query ); // the URL wil lbe empty if it was invalid or outside the level bounds of the layer. if (url.empty()) return 0L; OE_DEBUG << LC << url << std::endl; URI uri(url, _options.url()->context()); // read the data: ReadResult r = uri.readString(_readOptions.get(), progress); const std::string& buffer = r.getString(); const Config& meta = r.metadata(); bool dataOK = false; FeatureList features; if ( !buffer.empty() ) { // Get the mime-type from the metadata record if possible std::string mimeType = r.metadata().value( IOMetadata::CONTENT_TYPE ); //If the mimetype is empty then try to set it from the format specification if (mimeType.empty()) { if (_options.format().value() == "json") mimeType = "json"; else if (_options.format().value().compare("gml") == 0) mimeType = "text/xml"; else if (_options.format().value().compare("pbf") == 0) mimeType = "application/x-protobuf"; } dataOK = getFeatures( buffer, *query.tileKey(), mimeType, features ); } if ( dataOK ) { OE_DEBUG << LC << "Read " << features.size() << " features" << std::endl; } //If we have any filters, process them here before the cursor is created if (getFilters() && !getFilters()->empty() && !features.empty()) { FilterContext cx; cx.setProfile(getFeatureProfile()); cx.extent() = query.tileKey()->getExtent(); for (FeatureFilterChain::const_iterator i = getFilters()->begin(); i != getFilters()->end(); ++i) { FeatureFilter* filter = i->get(); cx = filter->push(features, cx); } } // If we have any features and we have an fid attribute, override the fid of the features if (_options.fidAttribute().isSet()) { for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) { std::string attr = itr->get()->getString(_options.fidAttribute().get()); FeatureID fid = as<long>(attr, 0); itr->get()->setFID( fid ); } } result = new FeatureListCursor(features); return result; }
CacheBin* TerrainLayer::getCacheBin(const Profile* profile) { if ( !_openCalled ) { OE_WARN << LC << "Illegal- called getCacheBin() before layer is open.. did you call open()?\n"; return 0L; } CacheSettings* cacheSettings = getCacheSettings(); if (!cacheSettings) return 0L; if (cacheSettings->cachePolicy()->isCacheDisabled()) return 0L; CacheBin* bin = cacheSettings->getCacheBin(); if (!bin) return 0L; // does the metadata need initializing? std::string metaKey = getMetadataKey(profile); Threading::ScopedMutexLock lock(_mutex); CacheBinMetadataMap::iterator i = _cacheBinMetadata.find(metaKey); if (i == _cacheBinMetadata.end()) { //std::string cacheId = _runtimeOptions->cacheId().get(); // read the metadata record from the cache bin: ReadResult rr = bin->readString(metaKey, _readOptions.get()); osg::ref_ptr<CacheBinMetadata> meta; bool metadataOK = false; if (rr.succeeded()) { // Try to parse the metadata record: Config conf; conf.fromJSON(rr.getString()); meta = new CacheBinMetadata(conf); if (meta->isOK()) { metadataOK = true; // verify that the cache if compatible with the open tile source: if ( getTileSource() && getProfile() ) { //todo: check the profile too if ( meta->_sourceDriver.get() != getTileSource()->getOptions().getDriver() ) { OE_WARN << LC << "Layer \"" << getName() << "\" is requesting a \"" << getTileSource()->getOptions().getDriver() << "\" cache, but a \"" << meta->_sourceDriver.get() << "\" cache exists at the specified location. " << "The cache will ignored for this layer.\n"; cacheSettings->cachePolicy() = CachePolicy::NO_CACHE; return 0L; } } // if not, see if we're in cache-only mode and still need a profile: else if (cacheSettings->cachePolicy()->isCacheOnly() && !_profile.valid()) { // in cacheonly mode, create a profile from the first cache bin accessed // (they SHOULD all be the same...) setProfile( Profile::create(meta->_sourceProfile.get()) ); _tileSize = meta->_sourceTileSize.get(); } bin->setMetadata(meta.get()); } else { OE_WARN << LC << "Metadata appears to be corrupt.\n"; } } if (!metadataOK) { // cache metadata does not exist, so try to create it. if ( getProfile() ) { meta = new CacheBinMetadata(); // no existing metadata; create some. meta->_cacheBinId = _runtimeCacheId; meta->_sourceName = this->getName(); meta->_sourceTileSize = getTileSize(); meta->_sourceProfile = getProfile()->toProfileOptions(); meta->_cacheProfile = profile->toProfileOptions(); meta->_cacheCreateTime = DateTime().asTimeStamp(); meta->_dataExtents = getDataExtents(); if (getTileSource()) { meta->_sourceDriver = getTileSource()->getOptions().getDriver(); } // store it in the cache bin. std::string data = meta->getConfig().toJSON(false); osg::ref_ptr<StringObject> temp = new StringObject(data); bin->write(metaKey, temp.get(), _readOptions.get()); bin->setMetadata(meta.get()); } else if ( cacheSettings->cachePolicy()->isCacheOnly() ) { disable(Stringify() << "Failed to open a cache for layer " "because cache_only policy is in effect and bin [" << _runtimeCacheId << "] " "could not be located."); return 0L; } else { OE_WARN << LC << "Failed to create cache bin [" << _runtimeCacheId << "] " "because there is no valid profile." << std::endl; cacheSettings->cachePolicy() = CachePolicy::NO_CACHE; return 0L; } } // If we loaded a profile from the cache metadata, apply the overrides: applyProfileOverrides(); if (meta.valid()) { _cacheBinMetadata[metaKey] = meta.get(); OE_DEBUG << LC << "Established metadata for cache bin [" << _runtimeCacheId << "]" << std::endl; } } return bin; }
bool SplatExtension::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.catalogURI().isSet() ) { OE_WARN << LC << "Illegal: catalog URI is required" << std::endl; return false; } if ( !_options.legendURI().isSet() ) { OE_WARN << LC << "Illegal: legend URI is required" << std::endl; return false; } if ( !_options.coverageLayerName().isSet() ) { OE_WARN << LC << "Illegal: coverage layer name is required" << std::endl; return false; } // Locate the coverage layer in the map. const Map* map = mapNode->getMap(); const ImageLayer* coverageLayer = map->getImageLayerByName( _options.coverageLayerName().get() ); if ( !coverageLayer ) { OE_WARN << LC << "Coverage layer \"" << _options.coverageLayerName().get() << "\" not found in map." << std::endl; return false; } // Read in the catalog. osg::ref_ptr<SplatCatalog> catalog = new SplatCatalog(); { ReadResult result = _options.catalogURI()->readString( _dbOptions.get() ); if ( result.succeeded() ) { Config conf; conf.setReferrer(_options.catalogURI()->full()); std::string json = result.getString(); conf.fromJSON( json ); catalog->fromConfig( conf ); OE_INFO << LC << "Catalog: " << catalog->getClasses().size() << " classes\n"; } else { OE_WARN << LC << "Failed to read catalog from \"" << _options.catalogURI()->full() << "\"\n"; return false; } } // Read in the legend. osg::ref_ptr<SplatCoverageLegend> legend = new SplatCoverageLegend(); { ReadResult result = _options.legendURI()->readString( _dbOptions.get() ); if ( result.succeeded() ) { Config conf; conf.setReferrer(_options.legendURI()->full()); conf.fromJSON( result.getString() ); legend->fromConfig( conf ); OE_INFO << LC << "Legend: " << legend->getPredicates().size() << " mappings \n"; } else { OE_WARN << LC << "Failed to read legend from \"" << _options.legendURI()->full() << "\"\n"; return false; } } // Install the splatter on the terrain engine. _effect = new SplatTerrainEffect( catalog, legend, _dbOptions.get() ); // set the coverage layer (mandatory) _effect->setCoverageLayer( coverageLayer ); // set the render order (optional) if ( _options.drawAfterImageLayers() == true ) _effect->setRenderOrder( 1.0f ); mapNode->getTerrainEngine()->addEffect( _effect.get() ); return true; }