GeoImage ElevationProxyImageLayer::createImage(const TileKey& key, ProgressCallback* progress) { if ( _mapf.needsSync() ) { Threading::ScopedMutexLock lock(_mapfMutex); if ( _mapf.needsSync() ) { _mapf.sync(); } } osg::ref_ptr<osg::HeightField> hf = HeightFieldUtils::createReferenceHeightField(key.getExtent(), 257,257, true ); if ( _mapf.populateHeightField(hf, key, true, 0L) ) { // encode the heightfield as a 16-bit normalized LUNIMANCE image osg::Image* image = new osg::Image(); image->allocateImage(hf->getNumColumns(), hf->getNumRows(), 1, GL_LUMINANCE, GL_UNSIGNED_SHORT); image->setInternalTextureFormat( GL_LUMINANCE16 ); const osg::FloatArray* floats = hf->getFloatArray(); for( unsigned int i = 0; i < floats->size(); ++i ) { int col = i % hf->getNumColumns(); int row = i / hf->getNumColumns(); *(unsigned short*)image->data( col, row ) = (unsigned short)(32768 + (short)floats->at(i)); } return GeoImage( image, key.getExtent() ); } else { return GeoImage::INVALID; } }
void OSGTileFactory::addPlaceholderHeightfieldLayer(StreamingTile* tile, StreamingTile* ancestorTile, GeoLocator* defaultLocator, const TileKey& key, const TileKey& ancestorKey) { osgTerrain::HeightFieldLayer* newHFLayer = 0L; if ( ancestorTile && ancestorKey.valid() ) { osg::ref_ptr<osgTerrain::HeightFieldLayer> ancestorLayer; { Threading::ScopedReadLock sharedLock( ancestorTile->getTileLayersMutex() ); ancestorLayer = dynamic_cast<osgTerrain::HeightFieldLayer*>(ancestorTile->getElevationLayer()); } if ( ancestorLayer.valid() ) { osg::ref_ptr<osg::HeightField> ancestorHF = ancestorLayer->getHeightField(); if ( ancestorHF.valid() ) { osg::HeightField* newHF = HeightFieldUtils::createSubSample( ancestorHF.get(), ancestorKey.getExtent(), key.getExtent()); newHFLayer = new osgTerrain::HeightFieldLayer( newHF ); newHFLayer->setLocator( defaultLocator ); // lock to set the elevation layerdata: { Threading::ScopedWriteLock exclusiveLock( tile->getTileLayersMutex() ); tile->setElevationLayer( newHFLayer ); tile->setElevationLOD( ancestorTile->getElevationLOD() ); } } } } // lock the tile to write the elevation data. { Threading::ScopedWriteLock exclusiveLock( tile->getTileLayersMutex() ); if ( !newHFLayer ) { newHFLayer = new osgTerrain::HeightFieldLayer(); newHFLayer->setHeightField( createEmptyHeightField( key, 8, 8 ) ); newHFLayer->setLocator( defaultLocator ); tile->setElevationLOD( -1 ); } if ( newHFLayer ) { tile->setElevationLayer( newHFLayer ); } } }
void Dragger::reclamp( const TileKey& key, osg::Node* tile, const Terrain* terrain ) { GeoPoint p; _position.transform( key.getExtent().getSRS(), p ); // first verify that the control position intersects the tile: if ( key.getExtent().contains( p.x(), p.y() ) ) { updateTransform( tile ); } }
bool TileMap::intersectsKey(const TileKey& tilekey) { osg::Vec3d keyMin, keyMax; //double keyMinX, keyMinY, keyMaxX, keyMaxY; //Check to see if the key overlaps the bounding box using lat/lon. This is necessary to check even in //Mercator situations in case the BoundingBox is described using lat/lon coordinates such as those produced by GDAL2Tiles //This should be considered a bug on the TMS production side, but we can work around it for now... tilekey.getExtent().getBounds(keyMin.x(), keyMin.y(), keyMax.x(), keyMax.y()); //tilekey.getExtent().getBounds(keyMinX, keyMinY, keyMaxX, keyMaxY); bool inter = intersects(_minX, _minY, _maxX, _maxY, keyMin.x(), keyMin.y(), keyMax.x(), keyMax.y() ); //keyMinX, keyMinY, keyMaxX, keyMaxY); if (!inter && tilekey.getProfile()->getSRS()->isSphericalMercator()) { tilekey.getProfile()->getSRS()->transform(keyMin, tilekey.getProfile()->getSRS()->getGeographicSRS(), keyMin ); tilekey.getProfile()->getSRS()->transform(keyMax, tilekey.getProfile()->getSRS()->getGeographicSRS(), keyMax ); inter = intersects(_minX, _minY, _maxX, _maxY, keyMin.x(), keyMin.y(), keyMax.x(), keyMax.y() ); //tilekey.getProfile()->getSRS()->transform2D(keyMinX, keyMinY, tilekey.getProfile()->getSRS()->getGeographicSRS(), keyMinX, keyMinY); //tilekey.getProfile()->getSRS()->transform2D(keyMaxX, keyMaxY, tilekey.getProfile()->getSRS()->getGeographicSRS(), keyMaxX, keyMaxY); //inter = intersects(_minX, _minY, _maxX, _maxY, keyMinX, keyMinY, keyMaxX, keyMaxY); } return inter; }
GeoImage ElevationProxyImageLayer::createImage(const TileKey& key, ProgressCallback* progress, bool forceFallback) { osg::ref_ptr<Map> map = _sourceMap.get(); if ( map.valid() ) { osg::ref_ptr<osg::HeightField> hf; if ( map->getHeightField( key, true, hf ) ) { // encode the heightfield as a 16-bit normalized LUNIMANCE image osg::Image* image = new osg::Image(); image->allocateImage(hf->getNumColumns(), hf->getNumRows(), 1, GL_LUMINANCE, GL_UNSIGNED_SHORT); image->setInternalTextureFormat( GL_LUMINANCE16 ); const osg::FloatArray* floats = hf->getFloatArray(); for( unsigned int i = 0; i < floats->size(); ++i ) { int col = i % hf->getNumColumns(); int row = i / hf->getNumColumns(); *(unsigned short*)image->data( col, row ) = (unsigned short)(32768 + (short)floats->at(i)); } return GeoImage( image, key.getExtent() ); } } return GeoImage::INVALID; }
SurfaceNode::SurfaceNode(const TileKey& tilekey, const MapInfo& mapinfo, const RenderBindings& bindings, TileDrawable* drawable) { _tileKey = tilekey; _drawable = drawable; _surfaceGeode = new osg::Geode(); _surfaceGeode->addDrawable( drawable ); // Create the final node. addChild( _surfaceGeode.get() ); // Establish a local reference frame for the tile: GeoPoint centroid; tilekey.getExtent().getCentroid(centroid); osg::Matrix local2world; centroid.createLocalToWorld( local2world ); setMatrix( local2world ); _matrix = new osg::RefMatrix( local2world ); // Initialize the cached bounding box. setElevationRaster( 0L, osg::Matrixf::identity() ); }
void LocalGeometryNode::onTileAdded(const TileKey& key, osg::Node* graph, TerrainCallbackContext& context) { bool needsClamp; // This was faster, but less precise and resulted in a lot of unnecessary clamp attempts: //if ( _boundingPT.contains(patch->getBound()) ) // Does the tile key's polytope intersect the world bounds or this object? // (taking getParent(0) gives the world-tranformed bounds vs. local bounds) if (key.valid()) { osg::Polytope tope; key.getExtent().createPolytope(tope); needsClamp = tope.contains(this->getParent(0)->getBound()); } else { // with no key, must clamp no matter what needsClamp = true; } if (needsClamp) { clamp(graph, context.getTerrain()); } }
SurfaceNode::SurfaceNode(const TileKey& tilekey, const MapInfo& mapinfo, const RenderBindings& bindings, TileDrawable* drawable) : _debugNodeVisible(false) { _tileKey = tilekey; _drawable = drawable; _surfaceGeode = new osg::Geode(); _surfaceGeode->addDrawable( drawable ); // Create the final node. addChild( _surfaceGeode.get() ); // Establish a local reference frame for the tile: osg::Vec3d centerWorld; GeoPoint centroid; tilekey.getExtent().getCentroid(centroid); centroid.toWorld(centerWorld); osg::Matrix local2world; centroid.createLocalToWorld( local2world ); setMatrix( local2world ); _worldCorners.resize(8); _childrenCorners.resize(4); for(size_t i = 0; i < _childrenCorners.size(); ++i) { _childrenCorners[i].resize(8); } // Initialize the cached bounding box. setElevationExtrema(osg::Vec2f(0, 0)); }
// This will be called by AnnotationNode when a new terrain tile comes in. void FeatureNode::onTileAdded(const TileKey& key, osg::Node* graph, TerrainCallbackContext& context) { if (!_clampDirty) { bool needsClamp; if (key.valid()) { osg::Polytope tope; key.getExtent().createPolytope(tope); needsClamp = tope.contains(this->getBound()); } else { // without a valid tilekey we don't know the extent of the change, // so clamping is required. needsClamp = true; } if (needsClamp) { _clampDirty = true; ADJUST_UPDATE_TRAV_COUNT(this, +1); //clamp(graph, context.getTerrain()); } } }
osg::BoundingSphere SimplePager::getBounds(const TileKey& key) const { int samples = 6; GeoExtent extent = key.getExtent(); double xSample = extent.width() / (double)samples; double ySample = extent.height() / (double)samples; osg::BoundingSphere bs; for (int c = 0; c < samples+1; c++) { double x = extent.xMin() + (double)c * xSample; for (int r = 0; r < samples+1; r++) { double y = extent.yMin() + (double)r * ySample; osg::Vec3d world; GeoPoint samplePoint(extent.getSRS(), x, y, 0, ALTMODE_ABSOLUTE); GeoPoint wgs84 = samplePoint.transform(osgEarth::SpatialReference::create("epsg:4326")); wgs84.toWorld(world); bs.expandBy(world); } } return bs; }
GeoImage ImageLayer::createImageFromTileSource(const TileKey& key, ProgressCallback* progress) { TileSource* source = getTileSource(); if ( !source ) return GeoImage::INVALID; // If the profiles are different, use a compositing method to assemble the tile. if ( !key.getProfile()->isHorizEquivalentTo( getProfile() ) ) { return assembleImage( key, progress ); } // Good to go, ask the tile source for an image: osg::ref_ptr<TileSource::ImageOperation> op = getOrCreatePreCacheOp(); // Fail is the image is blacklisted. if ( source->getBlacklist()->contains(key) ) { OE_DEBUG << LC << "createImageFromTileSource: blacklisted(" << key.str() << ")" << std::endl; return GeoImage::INVALID; } if (!mayHaveData(key)) { OE_DEBUG << LC << "createImageFromTileSource: mayHaveData(" << key.str() << ") == false" << std::endl; return GeoImage::INVALID; } //if ( !source->hasData( key ) ) //{ // OE_DEBUG << LC << "createImageFromTileSource: hasData(" << key.str() << ") == false" << std::endl; // return GeoImage::INVALID; //} // create an image from the tile source. osg::ref_ptr<osg::Image> result = source->createImage( key, op.get(), progress ); // Process images with full alpha to properly support MP blending. if (result.valid() && options().featherPixels() == true) { ImageUtils::featherAlphaRegions( result.get() ); } // If image creation failed (but was not intentionally canceled and // didn't time out or end for any other recoverable reason), then // blacklist this tile for future requests. if (result == 0L) { if ( progress == 0L || ( !progress->isCanceled() && !progress->needsRetry() ) ) { source->getBlacklist()->add( key ); } } return GeoImage(result.get(), key.getExtent()); }
void OrthoNode::reclamp( const TileKey& key, osg::Node* tile, const Terrain* terrain ) { // first verify that the label position intersects the tile: if ( key.getExtent().contains( _mapPosition.x(), _mapPosition.y() ) ) { updateTransforms( _mapPosition, tile ); } }
static void applyBlast(GeoPoint& center, double radius, double offset, const TileKey& key, osg::HeightField* heightField) { //Get the extents of the tile double xmin, ymin, xmax, ymax; key.getExtent().getBounds(xmin, ymin, xmax, ymax); int tileSize = heightField->getNumColumns(); // Iterate over the output heightfield and sample the data that was read into it. double dx = (xmax - xmin) / (tileSize-1); double dy = (ymax - ymin) / (tileSize-1); const SpatialReference* srs = SpatialReference::create("wgs84"); for (int c = 0; c < tileSize; ++c) { double geoX = xmin + (dx * (double)c); for (int r = 0; r < tileSize; ++r) { double geoY = ymin + (dy * (double)r); GeoPoint geo(srs, geoX, geoY, center.z(), ALTMODE_ABSOLUTE); double distance = geo.distanceTo( center ); double ratio = distance / radius; if (ratio <= 1.0) { double weight = 1.0 - osg::clampBetween(ratio, 0.0, 1.0); if (weight > 0) { float h = center.z() + offset * weight; heightField->setHeight(c, r, h); } } /* if ( boundary->contains2D(geo.x(), geo.y()) ) { float h = heightField->getHeight( c, r ); if (h == NO_DATA_VALUE) { //h = deformation._offset; } else { //h += deformation._offset; h = deformation._offset; } heightField->setHeight(c, r, h); } */ } } }
void GeometryPool::createKeyForTileKey(const TileKey& tileKey, unsigned size, const MapInfo& mapInfo, GeometryPool::GeometryKey& out) const { out.lod = tileKey.getLOD(); out.yMin = mapInfo.isGeocentric()? tileKey.getExtent().yMin() : 0.0; out.size = size; }
osg::Node* RexTerrainEngineNode::createTile( const TileKey& key ) { // Compute the sample size to use for the key's level of detail that will line up exactly with the tile size of the highest level of subdivision of the rex engine. unsigned int sampleSize = computeSampleSize( key.getLevelOfDetail() ); OE_INFO << LC << "Computed a sample size of " << sampleSize << " for lod " << key.getLevelOfDetail() << std::endl; TileKey sampleKey = key; // ALWAYS use 257x257 b/c that is what rex always uses. osg::ref_ptr< osg::HeightField > out_hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 257, 257, 0u, true ); sampleKey = key; bool populated = false; while (!populated) { populated = _update_mapf->populateHeightField( out_hf, sampleKey, true, // convertToHAE 0 ); if (!populated) { // Fallback on the parent sampleKey = sampleKey.createParentKey(); if (!sampleKey.valid()) { return 0; } } } // cannot happen (says coverity; see loop above), so commenting this out -gw #if 0 if (!populated) { // We have no heightfield so just create a reference heightfield. out_hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 257, 257, 0u); sampleKey = key; } #endif GeoHeightField geoHF( out_hf.get(), sampleKey.getExtent() ); if (sampleKey != key) { geoHF = geoHF.createSubSample( key.getExtent(), sampleSize, sampleSize, osgEarth::INTERP_BILINEAR); } // We should now have a heightfield that matches up exactly with the requested key at the appropriate resolution. // Turn it into triangles. return renderHeightField( geoHF ); }
bool TerrainLayer::isKeyInLegalRange(const TileKey& key) const { if ( !key.valid() ) { return false; } // We must use the equivalent lod b/c the input key can be in any profile. unsigned localLOD = getProfile() ? getProfile()->getEquivalentLOD(key.getProfile(), key.getLOD()) : key.getLOD(); // First check the key against the min/max level limits, it they are set. if ((options().maxLevel().isSet() && localLOD > options().maxLevel().value()) || (options().minLevel().isSet() && localLOD < options().minLevel().value())) { return false; } // Next check the maxDataLevel if that is set. if (options().maxDataLevel().isSet() && localLOD > options().maxDataLevel().get()) { return false; } // Next, check against resolution limits (based on the source tile size). if (options().minResolution().isSet() || options().maxResolution().isSet()) { const Profile* profile = getProfile(); if ( profile ) { // calculate the resolution in the layer's profile, which can // be different that the key's profile. double resKey = key.getExtent().width() / (double)getTileSize(); double resLayer = key.getProfile()->getSRS()->transformUnits(resKey, profile->getSRS()); if (options().maxResolution().isSet() && options().maxResolution().value() > resLayer) { return false; } if (options().minResolution().isSet() && options().minResolution().value() < resLayer) { return false; } } } return true; }
bool ElevationPool::fetchTileFromMap(const TileKey& key, MapFrame& frame, Tile* tile) { tile->_loadTime = osg::Timer::instance()->tick(); osg::ref_ptr<osg::HeightField> hf = new osg::HeightField(); hf->allocate( _tileSize, _tileSize ); // Initialize the heightfield to nodata hf->getFloatArray()->assign( hf->getFloatArray()->size(), NO_DATA_VALUE ); TileKey keyToUse = key; while( !tile->_hf.valid() && keyToUse.valid() ) { bool ok; if (_layers.empty()) { OE_TEST << LC << "Populating from FULL MAP (" << keyToUse.str() << ")\n"; ok = frame.populateHeightField(hf, keyToUse, false /*heightsAsHAE*/, 0L); } else { OE_TEST << LC << "Populating from layers (" << keyToUse.str() << ")\n"; ok = _layers.populateHeightFieldAndNormalMap(hf.get(), 0L, keyToUse, 0L, INTERP_BILINEAR, 0L); } if (ok) { tile->_hf = GeoHeightField( hf.get(), keyToUse.getExtent() ); tile->_bounds = keyToUse.getExtent().bounds(); } else { keyToUse = keyToUse.createParentKey(); } } return tile->_hf.valid(); }
GeoImage ImageLayer::createImageFromTileSource(const TileKey& key, ProgressCallback* progress) { TileSource* source = getTileSource(); if ( !source ) return GeoImage::INVALID; // If the profiles are different, use a compositing method to assemble the tile. if ( !key.getProfile()->isHorizEquivalentTo( getProfile() ) ) { return assembleImageFromTileSource( key, progress ); } // Good to go, ask the tile source for an image: osg::ref_ptr<TileSource::ImageOperation> op = _preCacheOp; // Fail is the image is blacklisted. if ( source->getBlacklist()->contains(key) ) { OE_DEBUG << LC << "createImageFromTileSource: blacklisted(" << key.str() << ")" << std::endl; return GeoImage::INVALID; } if ( !source->hasData( key ) ) { OE_DEBUG << LC << "createImageFromTileSource: hasData(" << key.str() << ") == false" << std::endl; return GeoImage::INVALID; } // create an image from the tile source. osg::ref_ptr<osg::Image> result = source->createImage( key, op.get(), progress ); // Process images with full alpha to properly support MP blending. if ( result.valid() && *_runtimeOptions.featherPixels()) { ImageUtils::featherAlphaRegions( result.get() ); } // If image creation failed (but was not intentionally canceled), // blacklist this tile for future requests. if ( result == 0L && (!progress || !progress->isCanceled()) ) { source->getBlacklist()->add( key ); } return GeoImage(result.get(), key.getExtent()); }
void Profile::getIntersectingTiles(const TileKey& key, std::vector<TileKey>& out_intersectingKeys) const { OE_DEBUG << "GET ISECTING TILES for key " << key.str() << " -----------------" << std::endl; //If the profiles are exactly equal, just add the given tile key. if ( isEquivalentTo( key.getProfile() ) ) { //Clear the incoming list out_intersectingKeys.clear(); out_intersectingKeys.push_back(key); return; } return getIntersectingTiles(key.getExtent(), out_intersectingKeys); }
std::string createURI( const TileKey& key ) const { double minx, miny, maxx, maxy; key.getExtent().getBounds( minx, miny, maxx, maxy); char buf[2048]; sprintf(buf, _prototype.c_str(), minx, miny, maxx, maxy); std::string uri(buf); // url-ize the uri before returning it if ( osgDB::containsServerAddress( uri ) ) uri = replaceIn(uri, " ", "%20"); return uri; }
void TileVisitor::processKey( const TileKey& key ) { // If we've been cancelled then just return. if (_progress && _progress->isCanceled()) { return; } unsigned int x, y, lod; key.getTileXY(x, y); lod = key.getLevelOfDetail(); // Only process this key if it has a chance of succeeding. if (_tileHandler && !_tileHandler->hasData(key)) { return; } bool traverseChildren = false; // If the key intersects the extent attempt to traverse if (intersects( key.getExtent() )) { // If the lod is less than the min level don't do anything but do traverse the children. if (lod < _minLevel) { traverseChildren = true; } else { // Process the key traverseChildren = handleTile( key ); } } // Traverse the children if (traverseChildren && lod < _maxLevel) { for (unsigned int i = 0; i < 4; i++) { TileKey k = key.createChildKey(i); processKey( k ); } } }
bool TerrainLayer::isKeyInRange(const TileKey& key) const { if ( !key.valid() ) { return false; } // First check the key against the min/max level limits, it they are set. if ((_runtimeOptions->maxLevel().isSet() && key.getLOD() > _runtimeOptions->maxLevel().value()) || (_runtimeOptions->minLevel().isSet() && key.getLOD() < _runtimeOptions->minLevel().value())) { return false; } // Next, check against resolution limits (based on the source tile size). if (_runtimeOptions->minResolution().isSet() || _runtimeOptions->maxResolution().isSet()) { const Profile* profile = getProfile(); if ( profile ) { // calculate the resolution in the layer's profile, which can // be different that the key's profile. double resKey = key.getExtent().width() / (double)getTileSize(); double resLayer = key.getProfile()->getSRS()->transformUnits(resKey, profile->getSRS()); if (_runtimeOptions->maxResolution().isSet() && _runtimeOptions->maxResolution().value() > resLayer) { return false; } if (_runtimeOptions->minResolution().isSet() && _runtimeOptions->minResolution().value() < resLayer) { return false; } } } return true; }
void GeoTransform::onTileAdded(const TileKey& key, osg::Node* node, TerrainCallbackContext& context) { if (!_position.isValid() || _position.altitudeMode() != ALTMODE_RELATIVE) { OE_TEST << LC << "onTileAdded fail condition 1\n"; return; } if (!key.getExtent().contains(_position)) { OE_DEBUG << LC << "onTileAdded fail condition 2\n"; return; } setPosition(_position); }
bool TerrainLayer::isKeyValid(const TileKey& key) const { if (!key.valid()) return false; // Check to see if an explicity max LOD is set. Do NOT compare against the minLevel, // because we still need to create empty tiles until we get to the data. The ImageLayer // will deal with this. if ( _runtimeOptions->maxLevel().isSet() && key.getLOD() > _runtimeOptions->maxLevel().value() ) { return false; } // Check to see if levels of detail based on resolution are set const Profile* profile = getProfile(); if ( profile ) { if ( !profile->isEquivalentTo( key.getProfile() ) ) { OE_DEBUG << LC << "TerrainLayer::isKeyValid called with key of a different profile" << std::endl; //return true; } if ( _runtimeOptions->maxResolution().isSet() ) { double keyres = key.getExtent().width() / (double)getTileSize(); double keyresInLayerProfile = key.getProfile()->getSRS()->transformUnits(keyres, profile->getSRS()); if ( _runtimeOptions->maxResolution().isSet() && keyresInLayerProfile < _runtimeOptions->maxResolution().value() ) { return false; } } } return true; }
osgEarth::HTTPRequest WCS10Source::createRequest(const TileKey& key) const { std::stringstream buf; double lon_min, lat_min, lon_max, lat_max; key.getExtent().getBounds(lon_min, lat_min, lon_max, lat_max); int lon_samples = _options.tileSize().value(); int lat_samples = _options.tileSize().value(); double lon_interval = (lon_max - lon_min) / (double)(lon_samples - 1); double lat_interval = (lat_max - lat_min) / (double)(lat_samples - 1); HTTPRequest req(_options.url()->full()); req.addParameter("SERVICE", "WCS"); req.addParameter("VERSION", "1.0.0"); req.addParameter("REQUEST", "GetCoverage"); req.addParameter("COVERAGE", _options.identifier().value()); req.addParameter("FORMAT", _covFormat); req.addParameter("CRS", "urn:ogc:def:crs:EPSG::4326"); buf.str(""); buf << lon_min << "," << lat_min << "," << lon_max << "," << lat_max; req.addParameter("BBOX", buf.str()); buf.str(""); buf << lon_samples; req.addParameter("WIDTH", buf.str()); buf.str(""); buf << lat_samples; req.addParameter("HEIGHT", buf.str()); // Not supported in WCS 1.0.0... //if (!_options.rangeSubset()->empty()) // req.addParameter("RangeSubset", _options.rangeSubset().value()); return req; }
void Profile::getIntersectingTiles(const TileKey& key, std::vector<TileKey>& out_intersectingKeys) const { OE_DEBUG << "GET ISECTING TILES for key " << key.str() << " -----------------" << std::endl; //If the profiles are exactly equal, just add the given tile key. if ( isHorizEquivalentTo( key.getProfile() ) ) { //Clear the incoming list out_intersectingKeys.clear(); out_intersectingKeys.push_back(key); } else { // figure out which LOD in the local profile is a best match for the LOD // in the source LOD in terms of resolution. unsigned localLOD = getEquivalentLOD(key.getProfile(), key.getLOD()); getIntersectingTiles(key.getExtent(), localLOD, out_intersectingKeys); OE_DEBUG << LC << "GIT, key="<< key.str() << ", localLOD=" << localLOD << ", resulted in " << out_intersectingKeys.size() << " tiles" << std::endl; } }
/** * Applies the deformation to the heightfield with the given key. */ static void deformHeightField(const Deformation& deformation, const TileKey& key, osg::HeightField* heightField) { osgEarth::Symbology::Polygon* boundary = dynamic_cast<osgEarth::Symbology::Polygon*>(deformation._feature->getGeometry()); if (!boundary) { OE_WARN << "NOT A POLYGON" << std::endl; return; } //Get the extents of the tile double xmin, ymin, xmax, ymax; key.getExtent().getBounds(xmin, ymin, xmax, ymax); int tileSize = heightField->getNumColumns(); // Iterate over the output heightfield and sample the data that was read into it. double dx = (xmax - xmin) / (tileSize-1); double dy = (ymax - ymin) / (tileSize-1); const SpatialReference* srs = SpatialReference::create("wgs84"); for (int c = 0; c < tileSize; ++c) { double geoX = xmin + (dx * (double)c); for (int r = 0; r < tileSize; ++r) { double geoY = ymin + (dy * (double)r); GeoPoint geo(srs, geoX, geoY, 0.0, ALTMODE_ABSOLUTE); if ( boundary->contains2D(geo.x(), geo.y()) ) { heightField->setHeight(c, r, deformation._offset); } } } }
bool intersects(const TileKey& key) { return key.getExtent().intersects( _extents ); }
osg::Image* CompositeTileSource::createImage(const TileKey& key, ProgressCallback* progress ) { ImageMixVector images; images.reserve( _options._components.size() ); for(CompositeTileSourceOptions::ComponentVector::const_iterator i = _options._components.begin(); i != _options._components.end(); ++i ) { if ( progress && progress->isCanceled() ) return 0L; ImageInfo imageInfo; imageInfo.dataInExtents = false; TileSource* source = i->_tileSourceInstance.get(); if ( source ) { //TODO: This duplicates code in ImageLayer::isKeyValid. Maybe should move that to TileSource::isKeyValid instead int minLevel = 0; int maxLevel = INT_MAX; if (i->_imageLayerOptions->minLevel().isSet()) { minLevel = i->_imageLayerOptions->minLevel().value(); } else if (i->_imageLayerOptions->minResolution().isSet()) { minLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->minResolution().value(), source->getPixelsPerTile()); } if (i->_imageLayerOptions->maxLevel().isSet()) { maxLevel = i->_imageLayerOptions->maxLevel().value(); } else if (i->_imageLayerOptions->maxResolution().isSet()) { maxLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->maxResolution().value(), source->getPixelsPerTile()); } // check that this source is within the level bounds: if (minLevel > (int)key.getLevelOfDetail() || maxLevel < (int)key.getLevelOfDetail() ) { continue; } //Only try to get data if the source actually has data if (source->hasDataInExtent( key.getExtent() ) ) { //We have data within these extents imageInfo.dataInExtents = true; if ( !source->getBlacklist()->contains( key.getTileId() ) ) { osg::ref_ptr< ImageLayerPreCacheOperation > preCacheOp; if ( i->_imageLayerOptions.isSet() ) { preCacheOp = new ImageLayerPreCacheOperation(); preCacheOp->_processor.init( i->_imageLayerOptions.value(), _dbOptions.get(), true ); } imageInfo.image = source->createImage( key, preCacheOp.get(), progress ); imageInfo.opacity = 1.0f; //If the image is not valid and the progress was not cancelled, blacklist if (!imageInfo.image.valid() && (!progress || !progress->isCanceled())) { //Add the tile to the blacklist OE_DEBUG << LC << "Adding tile " << key.str() << " to the blacklist" << std::endl; source->getBlacklist()->add( key.getTileId() ); } imageInfo.opacity = i->_imageLayerOptions.isSet() ? i->_imageLayerOptions->opacity().value() : 1.0f; } } else { OE_DEBUG << LC << "Source has no data at " << key.str() << std::endl; } } //Add the ImageInfo to the list images.push_back( imageInfo ); } unsigned numValidImages = 0; osg::Vec2s textureSize; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) { if (numValidImages == 0) { textureSize.set( info.image->s(), info.image->t()); } numValidImages++; } } //Try to fallback on any empty images if we have some valid images but not valid images for ALL layers if (numValidImages > 0 && numValidImages < images.size()) { for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (!info.image.valid() && info.dataInExtents) { TileKey parentKey = key.createParentKey(); TileSource* source = _options._components[i]._tileSourceInstance; if (source) { osg::ref_ptr< ImageLayerPreCacheOperation > preCacheOp; if ( _options._components[i]._imageLayerOptions.isSet() ) { preCacheOp = new ImageLayerPreCacheOperation(); preCacheOp->_processor.init( _options._components[i]._imageLayerOptions.value(), _dbOptions.get(), true ); } osg::ref_ptr< osg::Image > image; while (!image.valid() && parentKey.valid()) { image = source->createImage( parentKey, preCacheOp.get(), progress ); if (image.valid()) { break; } parentKey = parentKey.createParentKey(); } if (image.valid()) { //We got an image, but now we need to crop it to match the incoming key's extents GeoImage geoImage( image.get(), parentKey.getExtent()); GeoImage cropped = geoImage.crop( key.getExtent(), true, textureSize.x(), textureSize.y(), *source->_options.bilinearReprojection()); image = cropped.getImage(); } info.image = image.get(); } } } } //Recompute the number of valid images numValidImages = 0; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) numValidImages++; } if ( progress && progress->isCanceled() ) { return 0L; } else if ( numValidImages == 0 ) { return 0L; } else if ( numValidImages == 1 ) { //We only have one valid image, so just return it and don't bother with compositing for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) return info.image.release(); } return 0L; } else { osg::Image* result = 0; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& imageInfo = images[i]; if (!result) { if (imageInfo.image.valid()) { result = new osg::Image( *imageInfo.image.get()); } } else { if (imageInfo.image.valid()) { ImageUtils::mix( result, imageInfo.image, imageInfo.opacity ); } } } return result; } }
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(); }