void TileModelFactory::createTileModel(const TileKey& key, const MapFrame& frame, bool accumulate, osg::ref_ptr<TileModel>& out_model, ProgressCallback* progress) { osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() ); model->_useParentData = _terrainReqs->parentTexturesRequired(); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo()); OE_START_TIMER(fetch_imagery); // Fetch the image data and make color layers. unsigned index = 0; unsigned order = 0; for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() && layer->isKeyInRange(key) ) { BuildColorData build; build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, _liveTiles.get(), model.get() ); bool addedToModel = build.execute(progress); if ( addedToModel ) { // only bump the order if we added something to the data model. order++; } } } if (progress) progress->stats()["fetch_imagery_time"] += OE_STOP_TIMER(fetch_imagery); // make an elevation layer. OE_START_TIMER(fetch_elevation); buildElevation(key, frame, accumulate, _terrainReqs->elevationTexturesRequired(), model.get(), progress); if (progress) progress->stats()["fetch_elevation_time"] += OE_STOP_TIMER(fetch_elevation); // make a normal map layer (if necessary) if ( _terrainReqs->normalTexturesRequired() ) { OE_START_TIMER(fetch_normalmap); buildNormalMap(key, frame, accumulate, model.get(), progress); if (progress) progress->stats()["fetch_normalmap_time"] += OE_STOP_TIMER(fetch_normalmap); } // If nothing was added, not even a fallback heightfield, something went // horribly wrong. Leave without a tile model. Chances are that a parent tile // not not found in the live-tile registry. if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it // as fallback data of course) if ( !model->_elevationData.getHeightField() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 ); model->_elevationData = TileModel::ElevationData( hf, GeoLocator::createForKey(key, frame.getMapInfo()), true ); } // look up the parent model and cache it. osg::ref_ptr<TileNode> parentTile; if ( _liveTiles->get(key.createParentKey(), parentTile) ) { model->_parentModel = parentTile->getTileModel(); } out_model = model.release(); }
void TileModelFactory::createTileModel(const TileKey& key, const MapFrame& frame, osg::ref_ptr<TileModel>& out_model) //, //bool& out_hasRealData) { osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() ); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo()); // Fetch the image data and make color layers. unsigned order = 0; for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() ) { BuildColorData build; build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, model.get() ); bool addedToModel = build.execute(); if ( addedToModel ) { // only bump the order if we added something to the data model. order++; } } } // make an elevation layer. BuildElevationData build; build.init( key, frame, _terrainOptions, model.get(), _hfCache ); build.execute(); // Bail out now if there's no data to be had. if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it // as fallback data of course) if ( !model->_elevationData.getHeightField() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 ); model->_elevationData = TileModel::ElevationData( hf, GeoLocator::createForKey(key, frame.getMapInfo()), true ); } // look up the parent model and cache it. osg::ref_ptr<TileNode> parentTile; if ( _liveTiles->get(key.createParentKey(), parentTile) ) model->_parentModel = parentTile->getTileModel(); out_model = model.release(); }
bool HeightFieldCache::getOrCreateHeightField(const MapFrame& frame, const TileKey& key, //bool cummulative, const osg::HeightField* parent_hf, osg::ref_ptr<osg::HeightField>& out_hf, bool& out_isFallback, ElevationSamplePolicy samplePolicy, ElevationInterpolation interp, ProgressCallback* progress ) { // default out_isFallback = false; // check the quick cache. HFKey cachekey; cachekey._key = key; cachekey._revision = frame.getRevision(); cachekey._samplePolicy = samplePolicy; if (progress) progress->stats()["hfcache_try_count"] += 1; bool hit = false; LRUCache<HFKey,HFValue>::Record rec; if ( _cache.get(cachekey, rec) ) { out_hf = rec.value()._hf.get(); out_isFallback = rec.value()._isFallback; if (progress) { progress->stats()["hfcache_hit_count"] += 1; progress->stats()["hfcache_hit_rate"] = progress->stats()["hfcache_hit_count"]/progress->stats()["hfcache_try_count"]; } return true; } // Find the parent tile and start with its heightfield. if ( parent_hf ) { TileKey parentKey = key.createParentKey(); out_hf = HeightFieldUtils::createSubSample( parent_hf, parentKey.getExtent(), key.getExtent(), interp ); if ( !out_hf.valid() && ((int)key.getLOD())-1 > _firstLOD ) { // This most likely means that a parent tile expired while we were building the child. // No harm done in that case as this tile will soo be discarded as well. OE_DEBUG << "MP HFC: Unable to find tile " << key.str() << " in the live tile registry" << std::endl; return false; } } if ( !out_hf.valid() ) { //TODO. // This sets the elevation tile size; query size for all tiles. out_hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), _tileSize, _tileSize, true ); } bool populated = frame.populateHeightField( out_hf, key, true, // convertToHAE samplePolicy, progress ); // Treat Plate Carre specially by scaling the height values. (There is no need // to do this with an empty heightfield) const MapInfo& mapInfo = frame.getMapInfo(); if ( mapInfo.isPlateCarre() ) { HeightFieldUtils::scaleHeightFieldToDegrees( out_hf.get() ); } // cache it. HFValue cacheval; cacheval._hf = out_hf.get(); cacheval._isFallback = !populated; _cache.insert( cachekey, cacheval ); out_isFallback = !populated; return true; }
bool HeightFieldCache::getOrCreateHeightField(const MapFrame& frame, const TileKey& key, const osg::HeightField* parent_hf, osg::ref_ptr<osg::HeightField>& out_hf, bool& out_isFallback, ElevationSamplePolicy samplePolicy, ElevationInterpolation interp, ProgressCallback* progress ) { // default out_isFallback = false; // check the quick cache. HFKey cachekey; cachekey._key = key; cachekey._revision = frame.getRevision(); cachekey._samplePolicy = samplePolicy; if (progress) progress->stats()["hfcache_try_count"] += 1; LRUCache<HFKey,HFValue>::Record rec; if ( _enabled && _cache.get(cachekey, rec) ) { // Found it in the cache. out_hf = rec.value()._hf.get(); out_isFallback = rec.value()._isFallback; if (progress) { progress->stats()["hfcache_hit_count"] += 1; progress->stats()["hfcache_hit_rate"] = progress->stats()["hfcache_hit_count"]/progress->stats()["hfcache_try_count"]; } } else { // Not in the cache, so we need to create a HF. TileKey parentKey = key.createParentKey(); // Elevation "smoothing" uses the parent HF as the starting point for building // a new tile. This will cause lower-resolution data to propagate down the tree // and fill in any gaps in higher-resolution data. The result will be an elevation // grid that is "smoother" but not neccessarily as accurate. if ( _useParentAsReferenceHF && parent_hf && parentKey.valid() ) { out_hf = HeightFieldUtils::createSubSample( parent_hf, parentKey.getExtent(), key.getExtent(), interp ); } // If we are not smoothing, or we have no parent data, start with a basic // MSL=0 reference heightfield instead. if ( !out_hf.valid() ) { out_hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), _tileSize, _tileSize, 0u ); } // Next, populate it with data from the Map. The map will overwrite our starting // data with real data from the elevation stack. bool populated = frame.populateHeightField( out_hf, key, true, // convertToHAE progress ); // If the map failed to provide any suitable data sources at all, replace the // heightfield with data from its parent (if available). if ( !populated ) { if ( parentKey.valid() && parent_hf ) { out_hf = HeightFieldUtils::createSubSample( parent_hf, parentKey.getExtent(), key.getExtent(), interp ); } if ( !out_hf.valid() ) { // NOTE: This is probably no longer be possible, but check anyway for completeness. return false; } } // ONLY cache the new heightfield if a parent HF existed. Otherwise the new HF // may contain invalid data. This can happen if this task runs to completion // while the tile's parent expires from the scene graph. In that case the result // of this task will be discarded. Therefore we should not cache the result here. // This was causing intermittent rare "flat tiles" to appear in the terrain. if ( _enabled && parent_hf ) { // cache it. HFValue cacheval; cacheval._hf = out_hf.get(); cacheval._isFallback = !populated; _cache.insert( cachekey, cacheval ); } out_isFallback = !populated; } return true; }