コード例 #1
0
ファイル: TerrainLayer.cpp プロジェクト: dgraves/osgearth
bool
TerrainLayer::isKeyValid(const TileKey& key) const
{
	if (!key.valid()) return false;
    const TerrainLayerOptions& opt = getTerrainLayerOptions();
	
    //Check to see if explicit levels of detail are set
    if ( opt.minLevel().isSet() && (int)key.getLevelOfDetail() < opt.minLevel().value() ) return false;
	if ( opt.maxLevel().isSet() && (int)key.getLevelOfDetail() > opt.maxLevel().value() ) return false;
    
    //Check to see if levels of detail based on resolution are set
    if (opt.minLevelResolution().isSet())
    {        
        unsigned int minLevel = getProfile()->getLevelOfDetailForHorizResolution( opt.minLevelResolution().value(), getTileSize());
        OE_DEBUG << "Computed min level of " << minLevel << std::endl;
        if (key.getLevelOfDetail() < minLevel) return false;
    }

    if (opt.maxLevelResolution().isSet())
    {        
        unsigned int maxLevel = getProfile()->getLevelOfDetailForHorizResolution( opt.maxLevelResolution().value(), getTileSize());
        OE_DEBUG << "Computed max level of " << maxLevel << std::endl;
        if (key.getLevelOfDetail() > maxLevel) return false;
    }

	return true;
}
コード例 #2
0
    FeatureCursor* createFeatureCursor( const Symbology::Query& query )
    {
        TileKey key = *query.tileKey();

        int z = key.getLevelOfDetail();
        int tileX = key.getTileX();
        int tileY = key.getTileY();

        unsigned int numRows, numCols;
        key.getProfile()->getNumTiles(key.getLevelOfDetail(), numCols, numRows);
        tileY  = numRows - tileY - 1;

        //Get the image
        sqlite3_stmt* select = NULL;
        std::string queryStr = "SELECT tile_data from tiles where zoom_level = ? AND tile_column = ? AND tile_row = ?";
        int rc = sqlite3_prepare_v2( _database, queryStr.c_str(), -1, &select, 0L );
        if ( rc != SQLITE_OK )
        {
            OE_WARN << LC << "Failed to prepare SQL: " << queryStr << "; " << sqlite3_errmsg(_database) << std::endl;
            return NULL;
        }

        bool valid = true;        

        sqlite3_bind_int( select, 1, z );
        sqlite3_bind_int( select, 2, tileX );
        sqlite3_bind_int( select, 3, tileY );

        rc = sqlite3_step( select );

        FeatureList features;

        if ( rc == SQLITE_ROW)
        {                     
            // the pointer returned from _blob gets freed internally by sqlite, supposedly
            const char* data = (const char*)sqlite3_column_blob( select, 0 );
            int dataLen = sqlite3_column_bytes( select, 0 );
            std::string dataBuffer( data, dataLen );
            std::stringstream in(dataBuffer);
            MVT::read(in, key, features);
        }
        else
        {
            OE_DEBUG << LC << "SQL QUERY failed for " << queryStr << ": " << std::endl;
            valid = false;
        }

        sqlite3_finalize( select );

        // apply filters before returning.
        applyFilters( features );

        if (!features.empty())
        {
            //OE_NOTICE << "Returning " << features.size() << " features" << std::endl;
            return new FeatureListCursor(features);
        }

        return 0;
    }
コード例 #3
0
ファイル: CacheSeed.cpp プロジェクト: ebabyak/osgearth
void
CacheSeed::processKey(const MapFrame& mapf, const TileKey& key ) const
{
    unsigned int x, y, lod;
    key.getTileXY(x, y);
    lod = key.getLevelOfDetail();

    bool gotData = true;

    if ( _minLevel <= lod && _maxLevel >= lod )
    {
        gotData = cacheTile( mapf, key );
        if (gotData)
        {
        incrementCompleted( 1 );
        }

        if ( _progress.valid() && _progress->isCanceled() )
            return; // Task has been cancelled by user

        if ( _progress.valid() && gotData && _progress->reportProgress(_completed, _total, std::string("Cached tile: ") + key.str()) )
            return; // Canceled
    }

    if ( gotData && lod <= _maxLevel )
    {
        TileKey k0 = key.createChildKey(0);
        TileKey k1 = key.createChildKey(1);
        TileKey k2 = key.createChildKey(2);
        TileKey k3 = key.createChildKey(3); 

        bool intersectsKey = false;
        if (_extents.empty()) intersectsKey = true;
        else
        {
            for (unsigned int i = 0; i < _extents.size(); ++i)
            {
                if (_extents[i].intersects( k0.getExtent() ) ||
                    _extents[i].intersects( k1.getExtent() ) ||
                    _extents[i].intersects( k2.getExtent() ) ||
                    _extents[i].intersects( k3.getExtent() ))
                {
                    intersectsKey = true;
                }

            }
        }

        //Check to see if the bounds intersects ANY of the tile's children.  If it does, then process all of the children
        //for this level
        if (intersectsKey)
        {
            processKey(mapf, k0);
            processKey(mapf, k1);
            processKey(mapf, k2);
            processKey(mapf, k3);
        }
    }
}
コード例 #4
0
ファイル: OSGTileFactory.cpp プロジェクト: hulumogu/osgearth
bool
OSGTileFactory::hasMoreLevels( Map* map, const TileKey& key )
{
    //Threading::ScopedReadLock lock( map->getMapDataMutex() );

    bool more_levels = false;

    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );

    for ( ImageLayerVector::const_iterator i = imageLayers.begin(); i != imageLayers.end(); i++ )
    {
        const ImageLayerOptions& opt = i->get()->getImageLayerOptions();

        if ( !opt.maxLevel().isSet() || key.getLevelOfDetail() < (unsigned int)*opt.maxLevel() )
        {
            more_levels = true;
            break;
        }
    }
    if ( !more_levels )
    {
        ElevationLayerVector elevLayers;
        map->getElevationLayers( elevLayers );

        for( ElevationLayerVector::const_iterator j = elevLayers.begin(); j != elevLayers.end(); j++ )
        {
            const ElevationLayerOptions& opt = j->get()->getElevationLayerOptions();

            if ( !opt.maxLevel().isSet() || key.getLevelOfDetail() < (unsigned int)*opt.maxLevel() )
            //if ( !j->get()->maxLevel().isSet() || key.getLevelOfDetail() < j->get()->maxLevel().get() )
            {
                more_levels = true;
                break;
            }
        }
    }

    return more_levels;
}
コード例 #5
0
ファイル: StreamingTile.cpp プロジェクト: JohnDr/osgearth
StreamingTile::StreamingTile(const TileKey& key,
                             GeoLocator*    keyLocator, 
                             bool           quickReleaseGLObjects ) :

Tile( key, keyLocator, quickReleaseGLObjects ),

_requestsInstalled     ( false ),
_elevationLayerDirty   ( false ),
_colorLayersDirty      ( false ),
_elevationLayerUpToDate( true ),
_elevationLOD          ( key.getLevelOfDetail() ),
_useTileGenRequest     ( true )
{
    // because the lowest LOD (1) is always loaded fully:
    _elevationLayerUpToDate = _key.getLevelOfDetail() <= 1;
}
コード例 #6
0
    std::string createURL( const TileKey& key ) const
    {
        unsigned int x, y;
        key.getTileXY(x, y);

        unsigned int lod = key.getLevelOfDetail()+1;

        //http://s0.tileservice.worldwindcentral.com/getTile?interface=map&version=1&dataset=bmng.topo.bathy.200401&level=0&x=0&y=0
        return Stringify() 
            << _options.url()->full() << "interface=map&version=1"
            << "&dataset=" << _options.dataset().value()
            << "&level=" << lod
            << "&x=" << x
            << "&y=" << y
            << "&." << _formatToUse; //Add this to trick osg into using the correct loader.
    }
コード例 #7
0
ファイル: TileVisitor.cpp プロジェクト: energonQuest/dtEarth
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 );
        }                                
    }       
}
コード例 #8
0
ファイル: Caching.cpp プロジェクト: hulumogu/osgearth
std::string
TMSCache::getFilename( const TileKey& key,const CacheSpec& spec ) const
{
	unsigned int x,y;
    key.getTileXY(x, y);

    unsigned int lod = key.getLevelOfDetail();
    
    unsigned int numCols, numRows;
    key.getProfile()->getNumTiles(lod, numCols, numRows);
    if ( _options.invertY() == false )
    {
        y = numRows - y - 1;
    }

    std::stringstream buf;
    buf << getPath() << "/" << spec.cacheId() << "/" << lod << "/" << x << "/" << y << "." << spec.format();
	std::string bufStr;
	bufStr = buf.str();
    return bufStr;
}
コード例 #9
0
ファイル: BingTileSource.cpp プロジェクト: Sylla/osgearth
    std::string getQuadKey(const TileKey& key)
    {
        unsigned int tile_x, tile_y;
        key.getTileXY(tile_x, tile_y);
        unsigned int lod = key.getLevelOfDetail();

        std::stringstream ss;
        for( unsigned i = (int)lod+1; i > 0; i-- )
        {
            char digit = '0';
            unsigned mask = 1 << (i-1);
            if ( (tile_x & mask) != 0 )
            {
                digit++;
            }
            if ( (tile_y & mask) != 0 )
            {
                digit += 2;
            }
            ss << digit;
        }
        return ss.str();
    }
コード例 #10
0
ファイル: Cube.cpp プロジェクト: emminizer/osgearth
int
UnifiedCubeProfile::getFace( const TileKey& key )
{
    return key.getTileX() >> key.getLevelOfDetail();
}
コード例 #11
0
bool 
MBTilesTileSource::storeImage(const TileKey&    key,
                              osg::Image*       image,
                              ProgressCallback* progress)
{
    if ( (getMode() & MODE_WRITE) == 0 )
        return false;

    Threading::ScopedMutexLock exclusiveLock(_mutex);

    // encode the data stream:
    std::stringstream buf;
    osgDB::ReaderWriter::WriteResult wr;
    if ( _forceRGB && ImageUtils::hasAlphaChannel(image) )
    {
        osg::ref_ptr<osg::Image> rgb = ImageUtils::convertToRGB8(image);
        wr = _rw->writeImage(*(rgb.get()), buf, _dbOptions.get());
    }
    else
    {
        wr = _rw->writeImage(*image, buf, _dbOptions.get());
    }

    if ( wr.error() )
    {
        OE_WARN << LC << "Image encoding failed: " << wr.message() << std::endl;
        return false;
    }

    std::string value = buf.str();
    
    // compress if necessary:
    if ( _compressor.valid() )
    {
        std::ostringstream output;
        if ( !_compressor->compress(output, value) )
        {
            OE_WARN << LC << "Compressor failed" << std::endl;
            return false;
        }
        value = output.str();
    }

    int z = key.getLOD();
    int x = key.getTileX();
    int y = key.getTileY();

    // flip Y axis
    unsigned int numRows, numCols;
    key.getProfile()->getNumTiles(key.getLevelOfDetail(), numCols, numRows);
    y  = numRows - y - 1;

    // Prep the insert statement:
    sqlite3_stmt* insert = NULL;
    std::string query = "INSERT OR REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES (?, ?, ?, ?)";
    int rc = sqlite3_prepare_v2( _database, query.c_str(), -1, &insert, 0L );
    if ( rc != SQLITE_OK )
    {
        OE_WARN << LC << "Failed to prepare SQL: " << query << "; " << sqlite3_errmsg(_database) << std::endl;
        return false;
    }

    // bind parameters:
    sqlite3_bind_int( insert, 1, z );
    sqlite3_bind_int( insert, 2, x );
    sqlite3_bind_int( insert, 3, y );

    // bind the data blob:
    sqlite3_bind_blob( insert, 4, value.c_str(), value.length(), SQLITE_STATIC );

    // run the sql.
    bool ok = true;
    int tries = 0;
    do {
        rc = sqlite3_step(insert);
    }
    while (++tries < 100 && (rc == SQLITE_BUSY || rc == SQLITE_LOCKED));

    if (SQLITE_OK != rc && SQLITE_DONE != rc)
    {
#if SQLITE_VERSION_NUMBER >= 3007015
        OE_WARN << LC << "Failed query: " << query << "(" << rc << ")" << sqlite3_errstr(rc) << "; " << sqlite3_errmsg(_database) << std::endl;
#else
        OE_WARN << LC << "Failed query: " << query << "(" << rc << ")" << rc << "; " << sqlite3_errmsg(_database) << std::endl;
#endif        
        ok = false;
    }

    sqlite3_finalize( insert );

    return ok;
}
コード例 #12
0
    FeatureCursor* createFeatureCursor( const Symbology::Query& query )
    {
        TileKey key = *query.tileKey();

        int z = key.getLevelOfDetail();
        int tileX = key.getTileX();
        int tileY = key.getTileY();

        unsigned int numRows, numCols;
        key.getProfile()->getNumTiles(key.getLevelOfDetail(), numCols, numRows);
        tileY  = numRows - tileY - 1;

        //Get the image
        sqlite3_stmt* select = NULL;
        std::string queryStr = "SELECT tile_data from tiles where zoom_level = ? AND tile_column = ? AND tile_row = ?";
        int rc = sqlite3_prepare_v2( _database, queryStr.c_str(), -1, &select, 0L );
        if ( rc != SQLITE_OK )
        {
            OE_WARN << LC << "Failed to prepare SQL: " << queryStr << "; " << sqlite3_errmsg(_database) << std::endl;
            return NULL;
        }

        bool valid = true;        

        sqlite3_bind_int( select, 1, z );
        sqlite3_bind_int( select, 2, tileX );
        sqlite3_bind_int( select, 3, tileY );

        rc = sqlite3_step( select );

        FeatureList features;

        if ( rc == SQLITE_ROW)
        {                     
            // the pointer returned from _blob gets freed internally by sqlite, supposedly
            const char* data = (const char*)sqlite3_column_blob( select, 0 );
            int dataLen = sqlite3_column_bytes( select, 0 );

            std::string dataBuffer( data, dataLen );

            // decompress if necessary:
            if ( _compressor.valid() )
            {
                std::istringstream inputStream(dataBuffer);
                std::string value;
                if ( !_compressor->decompress(inputStream, value) )
                {
                    OE_WARN << LC << "Decompression failed" << std::endl;
                    valid = false;
                }
                else
                {
                    dataBuffer = value;
                }
            }

            
            
            mapnik::vector::tile tile;

            if (tile.ParseFromString(dataBuffer))
            {
                // Get the layer in question
                for (unsigned int i = 0; i < tile.layers().size(); i++)
                {
                    const mapnik::vector::tile_layer &layer = tile.layers().Get(i);

                    //OE_NOTICE << layer.name() << std::endl;
                    //if (layer.name() != "road") continue;
                    //if (layer.name() != "building") continue;

                    for (unsigned int j = 0; j < layer.features().size(); j++)
                    {
                        const mapnik::vector::tile_feature &feature = layer.features().Get(j);

                        osg::ref_ptr< osgEarth::Symbology::Geometry > geometry; 

                        eGeomType geomType = static_cast<eGeomType>(feature.type());
                        if (geomType == ::Polygon)
                        {
                            //OE_NOTICE << "Polygon " << std::endl;
                            geometry = new osgEarth::Symbology::Polygon();
                        }
                        else if (geomType == ::LineString)
                        {
                            //OE_NOTICE << "LineString" << std::endl;
                            geometry = new osgEarth::Symbology::LineString();
                        }
                        else if (geomType == ::Point)
                        {
                            //OE_NOTICE << "Point" << std::endl;
                            geometry = new osgEarth::Symbology::PointSet();
                        }
                        else
                        {
                            //OE_NOTICE << "uknown" << std::endl;
                            geometry = new osgEarth::Symbology::LineString();
                        }

                        osg::ref_ptr< Feature > oeFeature = new Feature(geometry, key.getProfile()->getSRS());
                        features.push_back(oeFeature.get());                    

                        // Read attributes
                        for (unsigned int k = 0; k < feature.tags().size(); k+=2)
                        {
                            std::string key = layer.keys().Get(feature.tags().Get(k));
                            mapnik::vector::tile_value value = layer.values().Get(feature.tags().Get(k+1));

                            if (value.has_bool_value())
                            {
                                oeFeature->set(key, value.bool_value());
                            }
                            else if (value.has_double_value())
                            {
                                oeFeature->set(key, value.double_value());
                            }
                            else if (value.has_float_value())
                            {
                                oeFeature->set(key, value.float_value());
                            }
                            else if (value.has_int_value())
                            {
                                oeFeature->set(key, (int)value.int_value());
                            }
                            else if (value.has_sint_value())
                            {
                                oeFeature->set(key, (int)value.sint_value());
                            }
                            else if (value.has_string_value())
                            {
                                oeFeature->set(key, value.string_value());
                            }
                            else if (value.has_uint_value())
                            {
                                oeFeature->set(key, (int)value.uint_value());
                            }

                            // Special path for getting heights from our test dataset.
                            if (key == "other_tags")
                            {
                                std::string other_tags = value.string_value();
                                
                                StringTokenizer tok("=>");
                                StringVector tized;
                                tok.tokenize(other_tags, tized);            
                                if (tized.size() == 3)
                                {
                                    if (tized[0] == "height")
                                    {
                                        std::string value = tized[2];
                                        // Remove quotes from the height
                                        float height = as<float>(value, FLT_MAX);
                                        if (height != FLT_MAX)
                                        {
                                            oeFeature->set("height", height);                                            
                                        }
                                    }
                                }
                            }
                        }
                        
                        
                        unsigned int length = 0;
                        int cmd = -1;
                        const int cmd_bits = 3;

                        unsigned int tileres = layer.extent();

                        int x = 0;
                        int y = 0;

                        for (int k = 0; k < feature.geometry_size();)
                        {
                            if (!length)
                            {
                                unsigned int cmd_length = feature.geometry(k++);
                                cmd = cmd_length & ((1 << cmd_bits) - 1);
                                length = cmd_length >> cmd_bits;
                            } 
                            if (length > 0)
                            {
                                length--;
                                if (cmd == SEG_MOVETO || cmd == SEG_LINETO)
                                {
                                    int px = feature.geometry(k++);
                                    int py = feature.geometry(k++);
                                    px = zig_zag_decode(px);
                                    py = zig_zag_decode(py);

                                    x += px;
                                    y += py;

                                    double width = key.getExtent().width();
                                    double height = key.getExtent().height();

                                    double geoX = key.getExtent().xMin() + (width/(double)tileres) * (double)x;
                                    double geoY = key.getExtent().yMax() - (height/(double)tileres) * (double)y;
                                    geometry->push_back(geoX, geoY, 0);
                                }
                                else if (cmd == (SEG_CLOSE & ((1 << cmd_bits) - 1)))
                                {
                                    geometry->push_back(geometry->front());
                                }
                            }
                        }

                        if (geometry->getType() == Geometry::TYPE_POLYGON)
                        {
                            geometry->rewind(osgEarth::Symbology::Geometry::ORIENTATION_CCW);                                               
                        }
                    }
                }
            }
            else
            {
コード例 #13
0
ファイル: ImageLayer.cpp プロジェクト: APerennec/osgearth
GeoImage
ImageLayer::createImageFromTileSource(const TileKey&    key,
                                      ProgressCallback* progress,
                                      bool              forceFallback,
                                      bool&             out_isFallback)
{
    // Results:
    // 
    // * return an osg::Image matching the key extent is all goes well;
    //
    // * return NULL to indicate that the key exceeds the maximum LOD of the source data,
    //   and that the engine may need to generate a "fallback" tile if necessary;
    //
    // deprecated:
    // * return an "empty image" if the LOD is valid BUT the key does not intersect the
    //   source's data extents.

    out_isFallback = false;

    TileSource* source = getTileSource();
    if ( !source )
        return GeoImage::INVALID;

    // If the profiles are different, use a compositing method to assemble the tile.
    if ( !key.getProfile()->isEquivalentTo( getProfile() ) )
    {
        return assembleImageFromTileSource( key, progress, out_isFallback );
    }

    // Good to go, ask the tile source for an image:
    osg::ref_ptr<TileSource::ImageOperation> op = _preCacheOp;

    osg::ref_ptr<osg::Image> result;

    if ( forceFallback )
    {
        // check if the tile source has any data coverage for the requested key.
        // the LOD is ignore here and checked later
        if ( !source->hasDataInExtent( key.getExtent() ) )
        {
            OE_DEBUG << LC << "createImageFromTileSource: hasDataInExtent(" << key.str() << ") == false" << std::endl;
            return GeoImage::INVALID;
        }

        TileKey finalKey = key;
        while( !result.valid() && finalKey.valid() )
        {
            if ( !source->getBlacklist()->contains( finalKey.getTileId() ) &&
                source->hasDataForFallback(finalKey))
            {
                result = source->createImage( finalKey, op.get(), progress );
                if ( result.valid() )
                {
                    if ( finalKey.getLevelOfDetail() != key.getLevelOfDetail() )
                    {
                        // crop the fallback image to match the input key, and ensure that it remains the
                        // same pixel size; because chances are if we're requesting a fallback that we're
                        // planning to mosaic it later, and the mosaicer requires same-size images.
                        GeoImage raw( result.get(), finalKey.getExtent() );
                        GeoImage cropped = raw.crop( key.getExtent(), true, raw.getImage()->s(), raw.getImage()->t(), *_runtimeOptions.driver()->bilinearReprojection() );
                        result = cropped.takeImage();
                    }
                }
            }
            if ( !result.valid() )
            {
                finalKey = finalKey.createParentKey();
                out_isFallback = true;
            }
        }

        if ( !result.valid() )
        {
            result = 0L;
            //result = _emptyImage.get();
            finalKey = key;
        }
    }
    else
    {
        // Fail is the image is blacklisted.
        if ( source->getBlacklist()->contains( key.getTileId() ) )
        {
            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;
        }
        result = source->createImage( key, op.get(), progress );
    }

    // Process images with full alpha to properly support MP blending.    
    if ( result != 0L && *_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.getTileId() );
    }

    return GeoImage(result.get(), key.getExtent());
}
コード例 #14
0
ファイル: ImageLayer.cpp プロジェクト: APerennec/osgearth
GeoImage
ImageLayer::createImageInNativeProfile( const TileKey& key, ProgressCallback* progress, bool forceFallback, bool& out_isFallback)
{
    out_isFallback = false;

    const Profile* nativeProfile = getProfile();
    if ( !nativeProfile )
    {
        OE_WARN << LC << "Could not establish the profile" << std::endl;
        return GeoImage::INVALID;
    }

    if ( key.getProfile()->isEquivalentTo(nativeProfile) )
    {
        // requested profile matches native profile, move along.
        return createImageInKeyProfile( key, progress, forceFallback, out_isFallback );
    }
    else
    {
        // find the intersection of keys.
        std::vector<TileKey> nativeKeys;
        nativeProfile->getIntersectingTiles(key.getExtent(), nativeKeys);


        //OE_INFO << "KEY = " << key.str() << ":" << std::endl;
        //for(int i=0; i<nativeKeys.size(); ++i)
        //    OE_INFO << "    " << nativeKeys[i].str() << std::endl;
        
        // build a mosaic of the images from the native profile keys:
        bool foundAtLeastOneRealTile = false;

        ImageMosaic mosaic;
        for( std::vector<TileKey>::iterator k = nativeKeys.begin(); k != nativeKeys.end(); ++k )
        {
            bool isFallback = false;
            GeoImage image = createImageInKeyProfile( *k, progress, true, isFallback );
            if ( image.valid() )
            {
                mosaic.getImages().push_back( TileImage(image.getImage(), *k) );
                if ( !isFallback )
                    foundAtLeastOneRealTile = true;
            }
            else
            {
                // if we get EVEN ONE invalid tile, we have to abort because there will be
                // empty spots in the mosaic. (By "invalid" we mean a tile that could not
                // even be resolved through the fallback procedure.)
                return GeoImage::INVALID;
            }
        }

        // bail out if we got nothing.
        if ( mosaic.getImages().size() == 0 )
            return GeoImage::INVALID;

        // if the mosaic is ALL fallback data, this tile is fallback data.
        if ( foundAtLeastOneRealTile )
        {
            // assemble new GeoImage from the mosaic.
            double rxmin, rymin, rxmax, rymax;
            mosaic.getExtents( rxmin, rymin, rxmax, rymax );

            GeoImage result( 
                mosaic.createImage(), 
                GeoExtent( nativeProfile->getSRS(), rxmin, rymin, rxmax, rymax ) );

#if 1
            return result;

#else // let's try this. why crop? Just leave it. Faster and more compatible with NPOT
      // systems (like iOS)

            // calculate a tigher extent that matches the original input key:
            GeoExtent tightExtent = nativeProfile->clampAndTransformExtent( key.getExtent() );

            // a non-exact crop is critical here to avoid resampling the data
            return result.crop( tightExtent, false, 0, 0, *_runtimeOptions.driver()->bilinearReprojection() );
#endif
        }

        else // all fallback data
        {
            GeoImage result;

            if ( forceFallback && key.getLevelOfDetail() > 0 )
            {
                result = createImageInNativeProfile(
                    key.createParentKey(),
                    progress,
                    forceFallback,
                    out_isFallback );
            }

            out_isFallback = true;
            return result;
        }

        //if ( !foundAtLeastOneRealTile )
        //    out_isFallback = true;

    }
}
コード例 #15
0
ファイル: ElevationLayer.cpp プロジェクト: JohnDr/osgearth
bool
ElevationLayerVector::createHeightField(const TileKey&                  key,
                                        bool                            fallback,
                                        const Profile*                  haeProfile,
                                        ElevationInterpolation          interpolation,
                                        ElevationSamplePolicy           samplePolicy,
                                        osg::ref_ptr<osg::HeightField>& out_result,
                                        bool*                           out_isFallback,
                                        ProgressCallback*               progress )  const
{        
    unsigned lowestLOD = key.getLevelOfDetail();
    bool hfInitialized = false;

    //Get a HeightField for each of the enabled layers
    GeoHeightFieldVector heightFields;

    //The number of fallback heightfields we have
    int numFallbacks = 0;

    //Default to being fallback data.
    if ( out_isFallback )
    {
        *out_isFallback = true;
    }

    // if the caller provided an "HAE map profile", he wants an HAE elevation grid even if
    // the map profile has a vertical datum. This is the usual case when building the 3D
    // terrain, for example. Construct a temporary key that doesn't have the vertical
    // datum info and use that to query the elevation data.
    TileKey keyToUse = key;
    if ( haeProfile )
    {
        keyToUse = TileKey(key.getLevelOfDetail(), key.getTileX(), key.getTileY(), haeProfile );
    }

    // Generate a heightfield for each elevation layer.

    unsigned defElevSize = 8;

    for( ElevationLayerVector::const_iterator i = this->begin(); i != this->end(); i++ )
    {
        ElevationLayer* layer = i->get();
        if ( layer->getVisible() )
        {
            GeoHeightField geoHF = layer->createHeightField( keyToUse, progress );

            // if "fallback" is set, try to fall back on lower LODs.
            if ( !geoHF.valid() && fallback )
            {
                TileKey hf_key = keyToUse.createParentKey();

                while ( hf_key.valid() && !geoHF.valid() )
                {
                    geoHF = layer->createHeightField( hf_key, progress );
                    if ( !geoHF.valid() )
                        hf_key = hf_key.createParentKey();
                }

                if ( geoHF.valid() )
                {
                    if ( hf_key.getLevelOfDetail() < lowestLOD )
                        lowestLOD = hf_key.getLevelOfDetail();

                    //This HeightField is fallback data, so increment the count.
                    numFallbacks++;
                }
            }

            if ( geoHF.valid() )
            {
                heightFields.push_back( geoHF );
            }
        }
    }

    //If any of the layers produced valid data then it's not considered a fallback
    if ( out_isFallback )
    {
        *out_isFallback = (numFallbacks == heightFields.size());
        //OE_NOTICE << "Num fallbacks=" << numFallbacks << " numHeightFields=" << heightFields.size() << " is fallback " << *out_isFallback << std::endl;
    }   

    if ( heightFields.size() == 0 )
    {            
        //If we got no heightfields but were requested to fallback, create an empty heightfield.
        if ( fallback )
        {
            out_result = HeightFieldUtils::createReferenceHeightField( keyToUse.getExtent(), defElevSize, defElevSize );                
            return true;
        }
        else
        {
            //We weren't requested to fallback so just return.
            return false;
        }
    }

    else if (heightFields.size() == 1)
    {
        if ( lowestLOD == key.getLevelOfDetail() )
        {
            //If we only have on heightfield, just return it.
            out_result = heightFields[0].takeHeightField();
        }
        else
        {
            GeoHeightField geoHF = heightFields[0].createSubSample( key.getExtent(), interpolation);
            out_result = geoHF.takeHeightField();
            hfInitialized = true;
        }
    }

    else
    {
        //If we have multiple heightfields, we need to composite them together.
        unsigned int width = 0;
        unsigned int height = 0;

        for (GeoHeightFieldVector::const_iterator i = heightFields.begin(); i < heightFields.end(); ++i)
        {
            if (i->getHeightField()->getNumColumns() > width) 
                width = i->getHeightField()->getNumColumns();
            if (i->getHeightField()->getNumRows() > height) 
                height = i->getHeightField()->getNumRows();
        }
        out_result = new osg::HeightField();
        out_result->allocate( width, height );

        //Go ahead and set up the heightfield so we don't have to worry about it later
        double minx, miny, maxx, maxy;
        key.getExtent().getBounds(minx, miny, maxx, maxy);
        double dx = (maxx - minx)/(double)(out_result->getNumColumns()-1);
        double dy = (maxy - miny)/(double)(out_result->getNumRows()-1);

        const SpatialReference* keySRS = keyToUse.getProfile()->getSRS();

        //Create the new heightfield by sampling all of them.
        for (unsigned int c = 0; c < width; ++c)
        {
            double x = minx + (dx * (double)c);
            for (unsigned r = 0; r < height; ++r)
            {
                double y = miny + (dy * (double)r);

                //Collect elevations from all of the layers. Iterate BACKWARDS because the last layer
                // is the highest priority.
                std::vector<float> elevations;
                for( GeoHeightFieldVector::reverse_iterator itr = heightFields.rbegin(); itr != heightFields.rend(); ++itr )
                {
                    const GeoHeightField& geoHF = *itr;

                    float elevation = 0.0f;
                    if ( geoHF.getElevation(keySRS, x, y, interpolation, keySRS, elevation) )
                    {
                        if (elevation != NO_DATA_VALUE)
                        {
                            elevations.push_back(elevation);
                        }
                    }
                }

                float elevation = NO_DATA_VALUE;

                //The list of elevations only contains valid values
                if (elevations.size() > 0)
                {
                    if (samplePolicy == SAMPLE_FIRST_VALID)
                    {
                        elevation = elevations[0];
                    }
                    else if (samplePolicy == SAMPLE_HIGHEST)
                    {
                        elevation = -FLT_MAX;
                        for (unsigned int i = 0; i < elevations.size(); ++i)
                        {
                            if (elevation < elevations[i]) elevation = elevations[i];
                        }
                    }
                    else if (samplePolicy == SAMPLE_LOWEST)
                    {
                        elevation = FLT_MAX;
                        for (unsigned i = 0; i < elevations.size(); ++i)
                        {
                            if (elevation > elevations[i]) elevation = elevations[i];
                        }
                    }
                    else if (samplePolicy == SAMPLE_AVERAGE)
                    {
                        elevation = 0.0;
                        for (unsigned i = 0; i < elevations.size(); ++i)
                        {
                            elevation += elevations[i];
                        }
                        elevation /= (float)elevations.size();
                    }
                }
                out_result->setHeight(c, r, elevation);
            }
        }
    }

    // Replace any NoData areas with the reference value. This is zero for HAE datums,
    // and some geoid height for orthometric datums.
    if (out_result.valid())
    {
        const Geoid*         geoid = 0L;
        const VerticalDatum* vdatum = key.getProfile()->getSRS()->getVerticalDatum();

        if ( haeProfile && vdatum )
        {
            geoid = vdatum->getGeoid();
        }

        HeightFieldUtils::resolveInvalidHeights(
            out_result.get(),
            key.getExtent(),
            NO_DATA_VALUE,
            geoid );

        //ReplaceInvalidDataOperator o;
        //o.setValidDataOperator(new osgTerrain::NoDataValue(NO_DATA_VALUE));
        //o( out_result.get() );
    }

    //Initialize the HF values for osgTerrain
    if (out_result.valid() && !hfInitialized )
    {   
        //Go ahead and set up the heightfield so we don't have to worry about it later
        double minx, miny, maxx, maxy;
        key.getExtent().getBounds(minx, miny, maxx, maxy);
        out_result->setOrigin( osg::Vec3d( minx, miny, 0.0 ) );
        double dx = (maxx - minx)/(double)(out_result->getNumColumns()-1);
        double dy = (maxy - miny)/(double)(out_result->getNumRows()-1);
        out_result->setXInterval( dx );
        out_result->setYInterval( dy );
        out_result->setBorderWidth( 0 );
    }

    return out_result.valid();
}
コード例 #16
0
ファイル: TileModelFactory.cpp プロジェクト: JohnDr/osgearth
void
TileModelFactory::createTileModel(const TileKey&           key, 
                                  osg::ref_ptr<TileModel>& out_model,
                                  bool&                    out_hasRealData,
                                  bool&                    out_hasLodBlendedLayers )
{
    MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS );
    
    const MapInfo& mapInfo = mapf.getMapInfo();

    osg::ref_ptr<TileModel> model = new TileModel();
    model->_tileKey = key;
    model->_tileLocator = GeoLocator::createForKey(key, mapInfo);

    // init this to false, then search for real data. "Real data" is data corresponding
    // directly to the key, as opposed to fallback data, which is derived from a lower
    // LOD key.
    out_hasRealData = false;
    out_hasLodBlendedLayers = false;
    
    // Fetch the image data and make color layers.
    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() )
        {
            BuildColorData build;
            build.init( key, layer, mapInfo, _terrainOptions, model.get() );
            build.execute();

            if ( layer->getImageLayerOptions().lodBlending() == true )
            {
                out_hasLodBlendedLayers = true;
            }
        }
    }

    // make an elevation layer.
    BuildElevationData build;
    build.init( key, mapf, _terrainOptions, model.get(), _hfCache );
    build.execute();


    // Bail out now if there's no data to be had.
    if ( model->_colorData.size() == 0 && !model->_elevationData.getHFLayer() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !model->_elevationData.getHFLayer() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 );
        osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf );
        hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) );
        model->_elevationData = TileModel::ElevationData( hfLayer, true );
    }

    // Now, if there are any color layers that did not get built, create them with an empty
    // image so the shaders have something to draw.
    osg::ref_ptr<osg::Image> emptyImage;
    osgTerrain::Locator* locator = model->_elevationData.getHFLayer()->getLocator();

    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() && !layer->isKeyValid(key) )
        {
            if ( !emptyImage.valid() )
                emptyImage = ImageUtils::createEmptyImage();

            model->_colorData[i->get()->getUID()] = TileModel::ColorData(
                layer,
                emptyImage.get(),
                locator,
                key.getLevelOfDetail(),
                key,
                true );
        }
    }

    // Ready to create the actual tile.
    //AssembleTile assemble;
    //assemble.init( key, mapInfo, _terrainOptions, model.get(), mapf.terrainMaskLayers() );
    //assemble.execute();

    // if we're using LOD blending, find and add the parent's state set.
    if ( out_hasLodBlendedLayers && key.getLevelOfDetail() > 0 && _liveTiles.valid() )
    {
        osg::ref_ptr<TileNode> parent;
        if ( _liveTiles->get( key.createParentKey(), parent ) )
        {
            model->_parentStateSet = parent->getPublicStateSet();
        }
    }

    if (!out_hasRealData)
    {
        // Check the results and see if we have any real data.
        for( TileModel::ColorDataByUID::const_iterator i = model->_colorData.begin(); i != model->_colorData.end(); ++i )
        {
            if ( !i->second.isFallbackData() ) 
            {
                out_hasRealData = true;
                break;
            }
        }
    }

    if ( !out_hasRealData && !model->_elevationData.isFallbackData() )
    {
        out_hasRealData = true;
    }

    out_model = model.release();
    //out_tile = assemble._node;
}
コード例 #17
0
bool
ElevationProxyImageLayer::isKeyInRange( const TileKey& key ) const
{
    return key.getLevelOfDetail() <= *_runtimeOptions.maxLevel();
}
コード例 #18
0
ファイル: TileBuilder.cpp プロジェクト: 2php/osgearth
void
TileBuilder::createTile(const TileKey&      key, 
                        bool                parallelize, 
                        osg::ref_ptr<Tile>& out_tile, 
                        bool&               out_hasRealData,
                        bool&               out_hasLodBlendedLayers )
{
    MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS );

    SourceRepo repo;

    // init this to false, then search for real data. "Real data" is data corresponding
    // directly to the key, as opposed to fallback data, which is derived from a lower
    // LOD key.
    out_hasRealData = false;
    out_hasLodBlendedLayers = false;

    const MapInfo& mapInfo = mapf.getMapInfo();

    // If we need more than one layer, fetch them in parallel.
    // TODO: change the test based on isKeyValid total.
    if ( parallelize && (mapf.imageLayers().size() + mapf.elevationLayers().size() > 1) )
    {
        // count the valid layers.
        int jobCount = 0;

        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            if ( i->get()->isKeyValid( key ) )
                ++jobCount;

            if ( i->get()->getImageLayerOptions().lodBlending() == true )
                out_hasLodBlendedLayers = true;
        }

        if ( mapf.elevationLayers().size() > 0 )
            ++jobCount;

        // A thread job monitoring event:
        Threading::MultiEvent semaphore( jobCount );

        // Start the image layer jobs:
        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            ImageLayer* layer = i->get();
            if ( layer->isKeyValid(key) )
            {
                ParallelTask<BuildColorLayer>* j = new ParallelTask<BuildColorLayer>( &semaphore );
                j->init( key, layer, mapInfo, _terrainOptions, repo );
                j->setPriority( -(float)key.getLevelOfDetail() );
                _service->add( j );
            }
        }

        // If we have elevation layers, start an elevation job as well. Otherwise just create an
        // empty one while we're waiting for the images to load.
        if ( mapf.elevationLayers().size() > 0 )
        {
            ParallelTask<BuildElevLayer>* ej = new ParallelTask<BuildElevLayer>( &semaphore );
            ej->init( key, mapf, _terrainOptions, repo );
            ej->setPriority( -(float)key.getLevelOfDetail() );
            _service->add( ej );
        }
        else
        {
            BuildElevLayer build;
            build.init( key, mapf, _terrainOptions, repo );
            build.execute();
        }

        // Wait for all the jobs to finish.
        semaphore.wait();
    }
    
    // Fetch the image data serially:
    else
    {
        // gather all the image layers serially.
        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            ImageLayer* layer = i->get();
            //if ( layer->isKeyValid(key) )  // Wrong. no guarantee key is in the same profile.

            if ( layer->getEnabled() )
            {
                BuildColorLayer build;
                build.init( key, layer, mapInfo, _terrainOptions, repo );
                build.execute();

                if ( layer->getImageLayerOptions().lodBlending() == true )
                    out_hasLodBlendedLayers = true;
            }
        }
        
        // make an elevation layer.
        BuildElevLayer build;
        build.init( key, mapf, _terrainOptions, repo );
        build.execute();
    }

    // Bail out now if there's no data to be had.
    if ( repo._colorLayers.size() == 0 && !repo._elevLayer.getHFLayer() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !repo._elevLayer.getHFLayer() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 );
        //osg::HeightField* hf = key.getProfile()->getVerticalSRS()->createReferenceHeightField( key.getExtent(), 8, 8 );
        osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf );
        hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) );
        repo._elevLayer = CustomElevLayer( hfLayer, true );
    }

    // Now, if there are any color layers that did not get built, create them with an empty
    // image so the shaders have something to draw.
    osg::ref_ptr<osg::Image> emptyImage;
    osgTerrain::Locator* locator = repo._elevLayer.getHFLayer()->getLocator();

    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() && !layer->isKeyValid(key) )
        {
            if ( !emptyImage.valid() )
                emptyImage = ImageUtils::createEmptyImage();

            repo.add( CustomColorLayer(
                layer,
                emptyImage.get(),
                locator,
                key.getLevelOfDetail(),
                key,
                true ) );
        }
    }

    //osg::Vec3dArray* maskBounds = 0L;
    //osgEarth::MaskLayer* mask = mapf.getTerrainMaskLayer();
    //if (mask)
    //  maskBounds = mask->getOrCreateBoundary();

    // Ready to create the actual tile.
    AssembleTile assemble;
    assemble.init( key, mapInfo, _terrainOptions, repo, mapf.terrainMaskLayers() );
    assemble.execute();

    if (!out_hasRealData)
    {
        // Check the results and see if we have any real data.
        for( ColorLayersByUID::const_iterator i = repo._colorLayers.begin(); i != repo._colorLayers.end(); ++i )
        {
            if ( !i->second.isFallbackData() ) 
            {
                out_hasRealData = true;
                break;
            }
        }
    }

    if ( !out_hasRealData && !repo._elevLayer.isFallbackData() )
    {
        out_hasRealData = true;
    }

    out_tile = assemble._tile;
}