Beispiel #1
0
void CacheSeed::seed( Map* map )
{
    if ( !map->getCache() )
    {
        OE_WARN << LC << "Warning: No cache defined; aborting." << std::endl;
        return;
    }

    std::vector<TileKey> keys;
    map->getProfile()->getRootKeys(keys);

    //Add the map's entire extent if we don't have one specified.
    if (_extents.empty())
    {
        addExtent( map->getProfile()->getExtent() );
    }

    bool hasCaches = false;
    int src_min_level = INT_MAX;
    unsigned int src_max_level = 0;

    MapFrame mapf( map, Map::TERRAIN_LAYERS, "CacheSeed::seed" );

    //Assumes the the TileSource will perform the caching for us when we call createImage
    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); i++ )
    {
        ImageLayer* layer = i->get();
        TileSource* src   = layer->getTileSource();

        const ImageLayerOptions& opt = layer->getImageLayerOptions();

        if ( layer->isCacheOnly() )
        {
            OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl;
        }
        else if ( !src )
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl;
        }
        else if ( src->getCachePolicyHint() == CachePolicy::NO_CACHE )
        {
            OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl;
        }
        else if ( !layer->getCache() )
        {
            OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl;
        }
        else
        {
            hasCaches = true;

            if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level)
                src_min_level = opt.minLevel().get();
            if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level)
                src_max_level = opt.maxLevel().get();
        }
    }

    for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); i++ )
    {
        ElevationLayer* layer = i->get();
        TileSource*     src   = layer->getTileSource();
        const ElevationLayerOptions& opt = layer->getElevationLayerOptions();

        if ( layer->isCacheOnly() )
        {
            OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl;
        }
        else if (!src)
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl;
        }
        else if ( src->getCachePolicyHint() == CachePolicy::NO_CACHE )
        {
            OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl;
        }
        else if ( !layer->getCache() )
        {
            OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl;
        }
        else
        {
            hasCaches = true;

            if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level)
                src_min_level = opt.minLevel().get();
            if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level)
                src_max_level = opt.maxLevel().get();
        }
    }

    if ( !hasCaches )
    {
        OE_WARN << LC << "There are either no caches defined in the map, or no sources to cache; aborting." << std::endl;
        return;
    }

    if ( src_max_level > 0 && src_max_level < _maxLevel )
    {
        _maxLevel = src_max_level;
    }

    OE_NOTICE << LC << "Maximum cache level will be " << _maxLevel << std::endl;

    osg::Timer_t startTime = osg::Timer::instance()->tick();
    //Estimate the number of tiles
    _total = 0;    

    for (unsigned int level = _minLevel; level <= _maxLevel; level++)
    {
        double coverageRatio = 0.0;

        if (_extents.empty())
        {
            unsigned int wide, high;
            map->getProfile()->getNumTiles( level, wide, high );
            _total += (wide * high);
        }
        else
        {
            for (std::vector< GeoExtent >::const_iterator itr = _extents.begin(); itr != _extents.end(); itr++)
            {
                const GeoExtent& extent = *itr;
                double boundsArea = extent.area();

                TileKey ll = map->getProfile()->createTileKey(extent.xMin(), extent.yMin(), level);
                TileKey ur = map->getProfile()->createTileKey(extent.xMax(), extent.yMax(), level);

                int tilesWide = ur.getTileX() - ll.getTileX() + 1;
                int tilesHigh = ll.getTileY() - ur.getTileY() + 1;
                int tilesAtLevel = tilesWide * tilesHigh;
                //OE_NOTICE << "Tiles at level " << level << "=" << tilesAtLevel << std::endl;

                bool hasData = false;

                for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); itr++)
                {
                    TileSource* src = itr->get()->getTileSource();
                    if (src)
                    {
                        if (src->hasDataAtLOD( level ))
                        {
                            //Compute the percent coverage of this dataset on the current extent
                            if (src->getDataExtents().size() > 0)
                            {
                                double cov = 0.0;
                                for (unsigned int j = 0; j < src->getDataExtents().size(); j++)
                                {
                                    GeoExtent b = src->getDataExtents()[j].transform( extent.getSRS());
                                    GeoExtent intersection = b.intersectionSameSRS( extent );
                                    if (intersection.isValid())
                                    {
                                        double coverage = intersection.area() / boundsArea;
                                        cov += coverage; //Assumes the extents aren't overlapping                            
                                    }
                                }
                                if (coverageRatio < cov) coverageRatio = cov;
                            }
                            else
                            {
                                //We have no way of knowing how much coverage we have
                                coverageRatio = 1.0;
                            }
                            hasData = true;
                            break;
                        }
                    }
                }

                for (ElevationLayerVector::const_iterator itr = mapf.elevationLayers().begin(); itr != mapf.elevationLayers().end(); itr++)
                {
                    TileSource* src = itr->get()->getTileSource();
                    if (src)
                    {
                        if (src->hasDataAtLOD( level ))
                        {
                            //Compute the percent coverage of this dataset on the current extent
                            if (src->getDataExtents().size() > 0)
                            {
                                double cov = 0.0;
                                for (unsigned int j = 0; j < src->getDataExtents().size(); j++)
                                {
                                    GeoExtent b = src->getDataExtents()[j].transform( extent.getSRS());
                                    GeoExtent intersection = b.intersectionSameSRS( extent );
                                    if (intersection.isValid())
                                    {
                                        double coverage = intersection.area() / boundsArea;
                                        cov += coverage; //Assumes the extents aren't overlapping                            
                                    }
                                }
                                if (coverageRatio < cov) coverageRatio = cov;
                            }
                            else
                            {
                                //We have no way of knowing how much coverage we have
                                coverageRatio = 1.0;
                            }
                            hasData = true;
                            break;
                        }
                    }
                }

                //Adjust the coverage ratio by a fudge factor to try to keep it from being too small,
                //tiles are either processed or not and the ratio is exact so will cover tiles partially
                //and potentially be too small
                double adjust = 4.0;
                coverageRatio = osg::clampBetween(coverageRatio * adjust, 0.0, 1.0);

                //OE_NOTICE << level <<  " CoverageRatio = " << coverageRatio << std::endl;

                if (hasData)
                {
                    _total += (int)ceil(coverageRatio * (double)tilesAtLevel );
                }
            }
        }
    }

    //Adjust the # of tiles again to be bigger than computed to avoid giving false hope
    _total *= 2;
    osg::Timer_t endTime = osg::Timer::instance()->tick();
    //OE_NOTICE << "Counted tiles in " << osg::Timer::instance()->delta_s(startTime, endTime) << " s" << std::endl;

    OE_INFO << "Processing ~" << _total << " tiles" << std::endl;

    for (unsigned int i = 0; i < keys.size(); ++i)
    {
        processKey( mapf, keys[i] );
    }

    _total = _completed;

    if ( _progress.valid()) _progress->reportProgress(_completed, _total, 0, 1, "Finished");
}
Beispiel #2
0
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 );
    }

    // Fail is the image is blacklisted.
    // ..unless there will be a fallback attempt.
    if ( source->getBlacklist()->contains( key.getTileId() ) && !forceFallback )
    {
        OE_DEBUG << LC << "createImageFromTileSource: blacklisted(" << key.str() << ")" << std::endl;
        return GeoImage::INVALID;
    }

    // Fail if no data is available for this key.
    if ( !source->hasDataAtLOD( key.getLevelOfDetail() ) && !forceFallback )
    {
        OE_DEBUG << LC << "createImageFromTileSource: hasDataAtLOD(" << key.str() << ") == false" << std::endl;
        return GeoImage::INVALID;
    }

    if ( !source->hasDataInExtent( key.getExtent() ) )
    {
        OE_DEBUG << LC << "createImageFromTileSource: hasDataInExtent(" << key.str() << ") == false" << std::endl;
        return GeoImage::INVALID;
    }

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

    osg::ref_ptr<osg::Image> result;
    TileKey finalKey = key;
    bool fellBack = false;

    if ( forceFallback )
    {        
        while( !result.valid() && finalKey.valid() )
        {
            if ( !source->getBlacklist()->contains( finalKey.getTileId() ) )
            {
                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();
                        fellBack = true;
                    }
                }
            }
            if ( !result.valid() )
            {
                finalKey = finalKey.createParentKey();
                out_isFallback = true;
            }
        }

        if ( !result.valid() )
        {
            result = 0L;
            //result = _emptyImage.get();
            finalKey = key;
        }
    }

    else
    {
        result = source->createImage( key, op.get(), progress );
    }

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