// override
    // Creates an image.
    osg::Image* createImage(const TileKey&    key,
                            ProgressCallback* progress )
    {
        if ( !_imageLayer.valid() || !_featureSource.valid() )
            return 0L;

        // fetch the image for this key:
        GeoImage image = _imageLayer->createImage(key, progress);
        if ( !image.valid() )
            return 0L;

        // fetch a set of features for this key. The features are in their
        // own SRS, so we need to transform:
        const SpatialReference* featureSRS = _featureSource->getFeatureProfile()->getSRS();
        GeoExtent extentInFeatureSRS = key.getExtent().transform( featureSRS );

        // assemble a spatial query. It helps if your features have a spatial index.
        Query query;
        query.bounds() = extentInFeatureSRS.bounds();
        //query.expression() = ... // SQL expression compatible with data source
        osg::ref_ptr<FeatureCursor> cursor = _featureSource->createFeatureCursor(query);

        // create a new image to return.
        osg::Image* output = new osg::Image();
        //output->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE);

        // do your magic here.

        return output;
    }
/** return the maximum resolution in the list of images */
float
GeoImageList::maxResolution()
{
  if (!minMaxResUptodate_) {
    minRes_ = -1;
    maxRes_ = 500;
    qDebug("GeoImageList::maxResolution");
    QDictIterator < GeoImage > it = QDictIterator < GeoImage > (*this);
    for (; it.current(); ++it) {
      GeoImage *img = it.current();
      qDebug("%s: xres: %f yres: %f",
             (img->filename()).latin1(),
             img->resolutionX(), img->resolutionY());
      float res = it.current()->resolutionX();
      if (res > minRes_)
        minRes_ = res;
      if (res < maxRes_)
        maxRes_ = res;
      res = it.current()->resolutionY();
      if (res > minRes_)
        minRes_ = res;
      if (res < maxRes_)
        maxRes_ = res;
    }
    minMaxResUptodate_ = true;
  }
  return maxRes_;
}
Exemple #3
0
bool CacheTileHandler::handleTile(const TileKey& key, const TileVisitor& tv)
{        
    ImageLayer* imageLayer = dynamic_cast< ImageLayer* >( _layer.get() );
    ElevationLayer* elevationLayer = dynamic_cast< ElevationLayer* >( _layer.get() );    

    // Just call createImage or createHeightField on the layer and the it will be cached!
    if (imageLayer)
    {                
        GeoImage image = imageLayer->createImage( key );
        if (image.valid())
        {                
            return true;
        }            
    }
    else if (elevationLayer )
    {
        GeoHeightField hf = elevationLayer->createHeightField(key, 0L);
        if (hf.valid())
        {                
            return true;
        }            
    }

    // If we didn't produce a result but the key isn't within range then we should continue to 
    // traverse the children b/c a min level was set.
    if (!_layer->isKeyInLegalRange(key))
    {
        return true;
    }

    return false;        
}   
/** Prepare the result image with the given instantiated net and the corresponding label image tiles */
void Analysis::prepareResultImage()
{
  iNodeRoot_->setNewID(1);
  emit message("Preparing result map");
  if (!iNodeRoot_->labelImage()) {
    qDebug("Analysis::prepareResultImage: no labelimage");
    return;
  }
  int size_x =
    int ((geoImageList_->geoEast() -
          geoImageList_->geoWest()) / labelImageList_->maxResolution());
  int size_y =
    int ((geoImageList_->geoNorth() -
          geoImageList_->geoSouth()) / labelImageList_->maxResolution());
  GeoImage *img = new GeoImage("result.plm", "result", size_x, size_y,
                               geoImageList_->geoWest(),
                               geoImageList_->geoNorth(),
                               geoImageList_->geoEast(),
                               geoImageList_->geoSouth());
  if (!img->mergeInto(*(iNodeRoot_->labelImage()), 0,
                      iNodeRoot_->attributeInt("id"),
                      iNodeRoot_->attributeInt("IDStart"))) {
    iNodeRoot_->attribute("status", "deleted");
  }
  iNodeRoot_->mergeResultImage(*img);
  img->write();
  map_ = img;
  emit sigMapView(iNodeRoot_, map_);
#ifdef DEBUGMSG
  qDebug("Analysis::prepareResultImage: image=(%dx%d)", size_x, size_y);
#endif
}
GeoImage
TextureCompositorTexArray::prepareImage( const GeoImage& layerImage, const GeoExtent& tileExtent, unsigned textureSize ) const
{
    const osg::Image* image = layerImage.getImage();
    if (!image)
        return GeoImage::INVALID;

    if (image->getPixelFormat() != GL_RGBA ||
        image->getInternalTextureFormat() != GL_RGBA8 ||
        image->s() != textureSize ||
        image->t() != textureSize )
    {
        // Because all tex2darray layers must be identical in format, let's use RGBA.
        osg::ref_ptr<osg::Image> newImage = ImageUtils::convertToRGBA8( image );
        
        // TODO: revisit. For now let's just settle on 256 (again, all layers must be the same size)
        if ( image->s() != textureSize || image->t() != textureSize )
        {
            osg::ref_ptr<osg::Image> resizedImage;
            if ( ImageUtils::resizeImage( newImage.get(), textureSize, textureSize, resizedImage ) )
                newImage = resizedImage.get();
        }

        return GeoImage( newImage.get(), layerImage.getExtent() );
    }
    else
    {
        return layerImage;
    }
}
Exemple #6
0
bool
CacheSeed::cacheTile(const MapFrame& mapf, const TileKey& key ) const
{
    bool gotData = false;

    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); i++ )
    {
        ImageLayer* layer = i->get();
        if ( layer->isKeyValid( key ) )
        {
            GeoImage image = layer->createImage( key );
            if ( image.valid() )
                gotData = true;
        }
    }

    if ( mapf.elevationLayers().size() > 0 )
    {
        osg::ref_ptr<osg::HeightField> hf;
        mapf.getHeightField( key, false, hf );
        if ( hf.valid() )
            gotData = true;
    }

    return gotData;
}
 bool handleTile(const TileKey& key)
 {
     bool ok = false;
     GeoImage image = _source->createImage(key);
     if ( image.valid() )
         ok = _dest->storeImage(key, image.getImage(), 0L);
     return ok;
 }
Exemple #8
0
    osg::Image*
    createImage( const TileKey& key, ProgressCallback* progress )
    {
        if ( !_image.valid() || key.getLevelOfDetail() > getMaxDataLevel() )
            return NULL;

        GeoImage cropped = _image.crop( key.getExtent(), true, getPixelsPerTile(), getPixelsPerTile() );
        return cropped.valid() ? cropped.takeImage() : 0L;
    }
/** return a list of included images*/
QStringList GeoImageList::list(QString type)
{
    if (type.isEmpty())
        return list_;
    QStringList list;
    QStringList::ConstIterator it;
    for (it = list_.begin(); it != list_.end(); ++it) {
        GeoImage *im = geoImage(*it);
        if (QString::compare(im->type(), type, Qt::CaseInsensitive) == 0)
            list += (*it);
        qDebug("GeoImageList::list(item=%s)", it->toLatin1().constData());
    }
    return list;
}
/** return a list of included images*/
QStringList GeoImageList::list(QString type)
{
  if (type.isEmpty())
    return list_;
  QStringList list;
  QStringList::ConstIterator it;
  for (it = list_.begin(); it != list_.end(); ++it) {
    GeoImage *im = geoImage(*it);
    if (qstricmp(im->type(), type) == 0)
      list += (*it);
    qDebug("GeoImageList::list(item=%s)", (const char *) (*it));
  }
  return list;
}
Exemple #11
0
bool
OSGTileFactory::createValidGeoImage(ImageLayer* layer,
                                    const TileKey& key,
                                    GeoImage& out_image,
                                    TileKey&  out_actualTileKey,
                                    ProgressCallback* progress)
{
    //TODO:  Redo this to just grab images from the parent TerrainTiles
    //Try to create the image with the given key
    out_actualTileKey = key;

    while (out_actualTileKey.valid())
    {
        if ( layer->isKeyValid(out_actualTileKey) )
        {
            out_image = layer->createImage( out_actualTileKey, progress );
            if ( out_image.valid() )
            {
                return true;
            }
        }
        out_actualTileKey = out_actualTileKey.createParentKey();
    }
    return false;
}
void
OceanCompositor::applyLayerUpdate(osg::StateSet*       stateSet,
                                  UID                  layerUID,
                                  const GeoImage&      preparedImage,
                                  const TileKey&       tileKey,
                                  const TextureLayout& layout,
                                  osg::StateSet*       parentStateSet) const
{
    osg::Texture2D* tex = s_getTexture( stateSet, layerUID, layout, parentStateSet);
    if ( tex )
    {
        osg::Image* image = preparedImage.getImage();
        image->dirty(); // required for ensure the texture recognizes the image as new data
        tex->setImage( image );

        // set up proper mipmapping filters:
        if (ImageUtils::isPowerOfTwo( image ) && 
            !(!image->isMipmap() && ImageUtils::isCompressed(image)) )
        {
            if ( tex->getFilter(osg::Texture::MIN_FILTER) != osg::Texture::LINEAR_MIPMAP_LINEAR )
                tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
        }
        else if ( tex->getFilter(osg::Texture::MIN_FILTER) != osg::Texture::LINEAR )
        {
            tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR );
        }
    }
}
void
TextureCompositorMultiTexture::applyLayerUpdate(osg::StateSet*       stateSet,
                                                UID                  layerUID,
                                                const GeoImage&      preparedImage,
                                                const TileKey&       tileKey,
                                                const TextureLayout& layout,
                                                osg::StateSet*       parentStateSet) const
{
    osg::Texture2D* tex = s_getTexture( stateSet, layerUID, layout, parentStateSet, _minFilter, _magFilter);
    if ( tex )
    {
        osg::Image* image = preparedImage.getImage();
        image->dirty(); // required for ensure the texture recognizes the image as new data
        tex->setImage( image );

        // set up proper mipmapping filters:
        if (_enableMipmapping &&
            _enableMipmappingOnUpdatedTextures &&
            ImageUtils::isPowerOfTwo( image ) &&
            !(!image->isMipmap() && ImageUtils::isCompressed(image)) )
        {
            if ( tex->getFilter(osg::Texture::MIN_FILTER) != _minFilter )
                tex->setFilter( osg::Texture::MIN_FILTER, _minFilter );
        }
        else if ( tex->getFilter(osg::Texture::MIN_FILTER) != osg::Texture::LINEAR )
        {
            tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR );
        }

        bool lodBlending = layout.getSlot(layerUID, 1) >= 0;

        if (_enableMipmapping &&
            _enableMipmappingOnUpdatedTextures &&
            lodBlending )
        {
            int slot = layout.getSlot(layerUID, 0);

            // update the timestamp on the image layer to support blending.
            float now = (float)osg::Timer::instance()->delta_s( osg::Timer::instance()->getStartTick(), osg::Timer::instance()->tick() );
            ArrayUniform stampUniform( "osgearth_SlotStamp", osg::Uniform::FLOAT, stateSet, layout.getMaxUsedSlot() + 1 );
            stampUniform.setElement( slot, now );

            // set the texture matrix to properly position the blend (parent) texture
            osg::Matrix mat;
            if ( parentStateSet != 0L )
            {
                unsigned tileX, tileY;
                tileKey.getTileXY(tileX, tileY);

                mat(0,0) = 0.5f;
                mat(1,1) = 0.5f;
                mat(3,0) = (float)(tileX % 2) * 0.5f;
                mat(3,1) = (float)(1 - tileY % 2) * 0.5f;
            }

            ArrayUniform texMatUniform( "osgearth_TexBlendMatrix", osg::Uniform::FLOAT_MAT4, stateSet, layout.getMaxUsedSlot() + 1 );
            texMatUniform.setElement( slot, mat );
        }
    }
}
/** loads the given labelimage fname and returns a pointer to the new image. If the image
was already requested, only a pointer to the image is returned and the reference
counter of the image is incremented. */
GeoImage *GeoImageList::loadLabelImage(QString fname,
                             QString key,
                             float west, float north, float east, float south)
{
  minMaxResUptodate_ = false;
  GeoImage *img = find(fname);
  if (img)
    return img->shallowCopy();
  GeoImage *gi = new GeoImage(fname, key, west, north, east, south);
#ifdef WIN32
  if (gi == 0){
    cout << "Out of Memory..7";
    exit(1);
  }
#endif
  insert(fname, gi);            //insert read geoimage
  list_ += fname;               //fill additional list of image names
  return gi;
}
/** return the maximum resolution in the list of images */
float
GeoImageList::maxResolution()
{
    if (!minMaxResUptodate_) {
        minRes_ = -1;
        maxRes_ = 500;
        qDebug("GeoImageList::maxResolution");
        Iterator it = begin();
        for (; it!=end(); ++it) {
            GeoImage *img = it.value();
            qDebug("%s: xres: %f yres: %f",
                   img->filename().toLatin1().constData(),
                   img->resolutionX(),
                   img->resolutionY());
            float res = img->resolutionX();
            if (res > minRes_)
                minRes_ = res;
            if (res < maxRes_)
                maxRes_ = res;
            res = img->resolutionY();
            if (res > minRes_)
                minRes_ = res;
            if (res < maxRes_)
                maxRes_ = res;
        }
        minMaxResUptodate_ = true;
    }
    return maxRes_;
}
Exemple #16
0
CustomColorLayerRef*
OSGTileFactory::createImageLayer(const MapInfo&    mapInfo,
                                 ImageLayer*       layer,
                                 const TileKey&    key,
                                 ProgressCallback* progress)
{
    if ( !layer )
        return 0L;

    GeoImage geoImage;

    //If the key is valid, try to get the image from the MapLayer
    bool keyValid = layer->isKeyValid( key );
    if ( keyValid )
    {
        geoImage = layer->createImage(key, progress);
    }
    else
    {
        //If the key is not valid, simply make a transparent tile
        geoImage = GeoImage(ImageUtils::createEmptyImage(), key.getExtent());
    }

    if (geoImage.valid())
    {
        osg::ref_ptr<GeoLocator> imgLocator = GeoLocator::createForKey( key, mapInfo );

        if ( mapInfo.isGeocentric() )
            imgLocator->setCoordinateSystemType( osgTerrain::Locator::GEOCENTRIC );

        return new CustomColorLayerRef( CustomColorLayer(
            layer,
            geoImage.getImage(),
            imgLocator.get(),
            key.getLevelOfDetail(),
            key) );
    }

    return NULL;
}
Exemple #17
0
bool CacheTileHandler::handleTile( const TileKey& key )
{        
    ImageLayer* imageLayer = dynamic_cast< ImageLayer* >( _layer.get() );
    ElevationLayer* elevationLayer = dynamic_cast< ElevationLayer* >( _layer.get() );    

    // Just call createImage or createHeightField on the layer and the it will be cached!
    if (imageLayer)
    {                
        GeoImage image = imageLayer->createImage( key );
        if (image.valid())
        {                
            return true;
        }            
    }
    else if (elevationLayer )
    {
        GeoHeightField hf = elevationLayer->createHeightField( key );
        if (hf.valid())
        {                
            return true;
        }            
    }
    return false;        
}   
Exemple #18
0
/** merge inodes labelimage into the result image */
void INode::mergeResultImage(GeoImage & resultImg, RunLengthLabelImage &rlelabelimage)
{
  qDebug("INode::mergeResultImage: name=%s", name_.latin1());
  QListIterator < INode > it = QListIterator < INode > (children());
  for (; it.current(); ++it)
  {
    INode *node = it.current();
    
    if (node->status() == TRASH)
      continue;
    
    RunLengthLabelImage copylabelimage = rlelabelimage;
    
    if (node->labelImage() && node->attributeInt("id"))
    {
      // id==0 is background and should not be merged into the result image
      if (!resultImg.mergeInto(*(node->labelImage()), attributeInt("IDStart"),
                                node->attributeInt("id"), node->attributeInt("IDStart"), copylabelimage))
        node->attribute("status", "deleted");
    }
    else
    {
      node->attribute("status", "no labelimage");
      qDebug("INode::mergeResultImage: %s ommitted", (const char *) node->name());
    }
    
    if (node->attributeInt("id"))
    {
      // id==0 is background and should not be merged into the result image
      node->mergeResultImage(resultImg, copylabelimage);
    }
    else
    {
      qDebug("INode::mergeResultImage: %s ommitted", (const char *) node->name());
    }
  }
}
Exemple #19
0
    void execute()
    {
        GeoImage geoImage;
        bool isFallbackData = false;

        // fetch the image from the layer, falling back on parent keys utils we are 
        // able to find one that works.
        TileKey imageKey( _key );
        while( !geoImage.valid() && imageKey.valid() && _layer->isKeyValid(imageKey) )
        {
            geoImage = _layer->createImage( imageKey, 0L ); // TODO: include a progress callback?
            if ( !geoImage.valid() )
            {
                imageKey = imageKey.createParentKey();
                isFallbackData = true;
            }
        }

        GeoLocator* locator = 0L;

        if ( !geoImage.valid() )
        {
            // no image found, so make an empty one (one pixel alpha).
            geoImage = GeoImage( ImageUtils::createEmptyImage(), _key.getExtent() );
            locator = GeoLocator::createForKey( _key, *_mapInfo );
            isFallbackData = true;
        }
        else
        {
            locator = GeoLocator::createForExtent(geoImage.getExtent(), *_mapInfo);                                                                                       
        }
        // add the color layer to the repo.
        _repo->add( CustomColorLayer(
            _layer,
            geoImage.getImage(),
            locator,
            _key.getLevelOfDetail(),
            _key,
            isFallbackData ) );
    }
    FeatureCursor* createFeatureCursor( const Symbology::Query& query )
    {
        TileKey key = *query.tileKey();

#if 0
        // Debug
        Polygon* poly = new Polygon();
        poly->push_back(key.getExtent().xMin(), key.getExtent().yMin());
        poly->push_back(key.getExtent().xMax(), key.getExtent().yMin());
        poly->push_back(key.getExtent().xMax(), key.getExtent().yMax());
        poly->push_back(key.getExtent().xMin(), key.getExtent().yMax());
        FeatureList features;
        Feature* feature = new Feature(poly, SpatialReference::create("wgs84"));
        features.push_back( feature );
        return new FeatureListCursor( features );
#else

        osg::ref_ptr< osgEarth::ImageLayer > layer = query.getMap()->getImageLayerByName(*_options.layer());
        if (layer.valid())
        {
            GeoImage image = layer->createImage( key );
         
            FeatureList features;

            if (image.valid())
            {
                double pixWidth  = key.getExtent().width() / (double)image.getImage()->s();
                double pixHeight = key.getExtent().height() / (double)image.getImage()->t();
                ImageUtils::PixelReader reader(image.getImage());

                for (unsigned int r = 0; r < image.getImage()->t(); r++)
                {
                    double y = key.getExtent().yMin() + (double)r * pixHeight;

                    double minX = 0;
                    double maxX = 0;
                    float value = 0.0;

                    for (unsigned int c = 0; c < image.getImage()->s(); c++)
                    {
                        double x = key.getExtent().xMin() + (double)c * pixWidth;

                        osg::Vec4f color = reader(c, r);

                        // Starting a new row.  Initialize the values.
                        if (c == 0)
                        {
                            minX = x;
                            maxX = x + pixWidth;
                            value = color.r(); 
                        }
                        // Ending a row, finish the polygon.
                        else if (c == image.getImage()->s() -1)
                        {
                            // Increment the maxX to finish the row.
                            maxX = x + pixWidth;
                            Polygon* poly = new Polygon();
                            poly->push_back(minX, y);
                            poly->push_back(maxX, y);
                            poly->push_back(maxX, y+pixHeight);
                            poly->push_back(minX, y+pixHeight);
                            Feature* feature = new Feature(poly, SpatialReference::create("wgs84"));
                            feature->set(*_options.attribute(), value);
                            features.push_back( feature );
                            minX = x;
                            maxX = x + pixWidth;
                            value = color.r();
                        }
                        // The value is different, so complete the polygon and start a new one.
                        else if (color.r() != value)
                        {
                            Polygon* poly = new Polygon();
                            poly->push_back(minX, y);
                            poly->push_back(maxX, y);
                            poly->push_back(maxX, y+pixHeight);
                            poly->push_back(minX, y+pixHeight);
                            Feature* feature = new Feature(poly, SpatialReference::create("wgs84"));
                            feature->set(*_options.attribute(), value);
                            features.push_back( feature );
                            minX = x;
                            maxX = x + pixWidth;
                            value = color.r();
                        }
                        // The value is the same as the previous value, continue the polygon by increasing the maxX.
                        else if (color.r() == value)
                        {
                            maxX = x + pixWidth;
                        }
                    }

                    
                }
               
                if (!features.empty())
                {
                    //OE_NOTICE << LC << "Returning " << features.size() << " features" << std::endl;
                    return new FeatureListCursor( features );
                }
            }
        }
        else
        {
            OE_NOTICE << LC << "Couldn't get layer " << *_options.layer() << std::endl;
        }
        return 0;
#endif
    }
osg::Image*
CompositeTileSource::createImage(const TileKey&    key,
                                 ProgressCallback* progress )
{    
    ImageMixVector images;
    images.reserve(_imageLayers.size());

    // Try to get an image from each of the layers for the given key.
    for (ImageLayerVector::const_iterator itr = _imageLayers.begin(); itr != _imageLayers.end(); ++itr)
    {
        ImageLayer* layer = itr->get();
        ImageInfo imageInfo;
        imageInfo.dataInExtents = layer->getTileSource()->hasDataInExtent( key.getExtent() );
        imageInfo.opacity = layer->getOpacity();

        if (imageInfo.dataInExtents)
        {
            GeoImage image = layer->createImage(key, progress);
            if (image.valid())
            {
                imageInfo.image = image.getImage();
            }

            // If the progress got cancelled or it needs a retry then return NULL to prevent this tile from being built and cached with incomplete or partial data.
            if (progress && (progress->isCanceled() || progress->needsRetry()))
            {
                OE_DEBUG << LC << " createImage was cancelled or needs retry for " << key.str() << std::endl;
                return 0L;
            }
        }

        images.push_back(imageInfo);
    }

    // Determine the output texture size to use based on the image that were creatd.
    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++;        
        }
    } 

    // Create fallback images if we have some valid data but not for all the layers
    if (numValidImages > 0 && numValidImages < images.size())
    {
        for (unsigned int i = 0; i < images.size(); i++)
        {
            ImageInfo& info = images[i];
            ImageLayer* layer = _imageLayers[i].get();
            if (!info.image.valid() && info.dataInExtents)
            {                      
                TileKey parentKey = key.createParentKey();

                GeoImage image;
                while (!image.valid() && parentKey.valid())
                {
                    image = layer->createImage(parentKey, progress);
                    if (image.valid())
                    {
                        break;
                    }

                    // If the progress got cancelled or it needs a retry then return NULL to prevent this tile from being built and cached with incomplete or partial data.
                    if (progress && (progress->isCanceled() || progress->needsRetry()))
                    {
                        OE_DEBUG << LC << " createImage was cancelled or needs retry for " << key.str() << std::endl;
                        return 0L;
                    }

                    parentKey = parentKey.createParentKey();
                }

                if (image.valid())
                {                                        
                    // TODO:  Bilinear options?
                    bool bilinear = layer->isCoverage() ? false : true;
                    GeoImage cropped = image.crop( key.getExtent(), true, textureSize.x(), textureSize.y(), bilinear);
                    info.image = cropped.getImage();
                }                    
            }
        }
    }

    // Now finally create the output image.
    //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.get(), imageInfo.opacity );
                }
            }            
        }        
        return result;
    }



}
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;
    }
}
Exemple #23
0
GeoImage
ImageLayer::createImageInNativeProfile(const TileKey&    key,
                                       ProgressCallback* progress)
{
    if (getStatus().isError())
    {
        return GeoImage::INVALID;
    }

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

    GeoImage result;

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

        // 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 );
            if ( image.valid() )
            {
                mosaic.getImages().push_back( TileImage(image.getImage(), *k) );
            }
            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;
                //TODO: probably need to change this so the mosaic uses alpha.
            }
        }

        // bail out if we got nothing.
        if ( mosaic.getImages().size() > 0 )
        {
            // assemble new GeoImage from the mosaic.
            double rxmin, rymin, rxmax, rymax;
            mosaic.getExtents( rxmin, rymin, rxmax, rymax );

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

    return result;
}
/** read a list of GeoImage and the attributes through parser */
void
GeoImageList::read(MLParser & parser)
{
  minMaxResUptodate_ = false;
  qDebug("GeoImageList::read(parser)");
  list_.clear();
  QString keywords[] = { "geoimage", "geoimagelist", "" };
  const MLTagTable nodeTagTable(keywords);
  const int TOK_GEOIMAGE = 1;
  const int TOK_GEOIMAGE_LIST = 2;
  int tag;
#ifdef WIN32 
  geoNorth_ = -1e38F;
  geoSouth_ = 1e38F;
  geoWest_  = 1e38F;
  geoEast_  = -1e38F;
#else
  geoNorth_ = -1e36;
  geoSouth_ = +1e36;
  geoWest_ = +1e36;
  geoEast_ = -1e36;
#endif
  do {
    tag = parser.tag(nodeTagTable);
    switch (tag) {
    case TOK_GEOIMAGE:{
        GeoImage *gi = new GeoImage(parser);    //parse geoimage
#ifdef WIN32
  if (gi == 0){
    cout << "Out of Memory..6";
    exit(1);
  }
#endif
        if (gi->geoNorth() > geoNorth_)
          geoNorth_ = gi->geoNorth();
        if (gi->geoSouth() < geoSouth_)
          geoSouth_ = gi->geoSouth();
        if (gi->geoEast() > geoEast_)
          geoEast_ = gi->geoEast();
        if (gi->geoWest() < geoWest_)
          geoWest_ = gi->geoWest();
        insert(*((*gi)["key"]), gi);    //insert read geoimage
        list_ += *((*gi)["key"]);       //fill additional list of image names
        break;
      }
    default:{
        ArgDict *args = parser.args();
        delete args;
        break;
      }
    }
  } while ((tag != MLParser::END_OF_FILE) && (tag != -TOK_GEOIMAGE_LIST));

  //test images and create a structure for the images
  QString key;
  for (QStringList::Iterator it = list_.begin(); it != list_.end(); ++it) {
    key = *it;
    GeoImage *img = find(key);
    qDebug("## GeoImageList::read(parser)" + img->filename());
    img->load();
  }
}
void
OSGTerrainEngineNode::addImageLayer( ImageLayer* layerAdded )
{
    if ( !layerAdded )
        return;

    if (!_isStreaming)
    {
        refresh();
    }
    else
    {
        // visit all existing terrain tiles and inform each one of the new image layer:
        TileVector tiles;
        _terrain->getTiles( tiles );

        for( TileVector::iterator itr = tiles.begin(); itr != tiles.end(); ++itr )
        {
            Tile* tile = itr->get();

            StreamingTile* streamingTile = 0L;

            GeoImage geoImage;
            bool needToUpdateImagery = false;
            int imageLOD = -1;

            if ( !_isStreaming || tile->getKey().getLevelOfDetail() == 1 )
            {
                // in standard mode, or at the first LOD in seq/pre mode, fetch the image immediately.
                TileKey geoImageKey = tile->getKey();
                _tileFactory->createValidGeoImage( layerAdded, tile->getKey(), geoImage, geoImageKey );
                imageLOD = tile->getKey().getLevelOfDetail();
            }
            else
            {
                // in seq/pre mode, set up a placeholder and mark the tile as dirty.
                geoImage = GeoImage(ImageUtils::createEmptyImage(), tile->getKey().getExtent() );
                needToUpdateImagery = true;
                streamingTile = static_cast<StreamingTile*>(tile);
            }

            if (geoImage.valid())
            {
                const MapInfo& mapInfo = _update_mapf->getMapInfo();

                double img_min_lon, img_min_lat, img_max_lon, img_max_lat;
                geoImage.getExtent().getBounds(img_min_lon, img_min_lat, img_max_lon, img_max_lat);

                //Specify a new locator for the color with the coordinates of the TileKey that was actually used to create the image
                osg::ref_ptr<GeoLocator> img_locator = tile->getKey().getProfile()->getSRS()->createLocator( 
                    img_min_lon, img_min_lat, img_max_lon, img_max_lat, 
                    !mapInfo.isGeocentric() );

                //Set the CS to geocentric if we are dealing with a geocentric map
                if ( mapInfo.isGeocentric() )
                {
                    img_locator->setCoordinateSystemType( osgTerrain::Locator::GEOCENTRIC );
                }

                tile->setCustomColorLayer( CustomColorLayer(
                    layerAdded,
                    geoImage.getImage(),
                    img_locator.get(), imageLOD,  tile->getKey() ) );

                // if necessary, tell the tile to queue up a new imagery request (since we
                // just installed a placeholder)
                if ( needToUpdateImagery )
                {
                    streamingTile->updateImagery( layerAdded, *_update_mapf, _tileFactory.get() );
                }
            }
            else
            {
                // this can happen if there's no data in the new layer for the given tile.
                // we will rely on the driver to dump out a warning if this is an error.
            }

            tile->applyImmediateTileUpdate( TileUpdate::ADD_IMAGE_LAYER, layerAdded->getUID() );
        }

        updateTextureCombining();
    }
}
Exemple #26
0
GeoImage
ImageLayer::createImageInKeyProfile(const TileKey&    key, 
                                    ProgressCallback* progress)
{
    if (getStatus().isError())
    {
        return GeoImage::INVALID;
    }

    // If the layer is disabled, bail out.
    if ( !getEnabled() )
    {
        return GeoImage::INVALID;
    }

    // Make sure the request is in range.
    if ( !isKeyInRange(key) )
    {
        return GeoImage::INVALID;
    }


    GeoImage result;

    OE_DEBUG << LC << "create image for \"" << key.str() << "\", ext= "
        << key.getExtent().toString() << std::endl;

    // the cache key combines the Key and the horizontal profile.
    std::string cacheKey = Stringify() << key.str() << "_" << key.getProfile()->getHorizSignature();
    const CachePolicy& policy = getCacheSettings()->cachePolicy().get();
    
    // Check the layer L2 cache first
    if ( _memCache.valid() )
    {
        CacheBin* bin = _memCache->getOrCreateDefaultBin();
        ReadResult result = bin->readObject(cacheKey, 0L);
        if ( result.succeeded() )
            return GeoImage(static_cast<osg::Image*>(result.releaseObject()), key.getExtent());
    }

    // locate the cache bin for the target profile for this layer:
    CacheBin* cacheBin = getCacheBin( key.getProfile() );

    // validate that we have either a valid tile source, or we're cache-only.
    if (getTileSource() || (cacheBin && policy.isCacheOnly()))
    {
        //nop = OK.
    }
    else
    {
        disable("Error: layer does not have a valid TileSource, cannot create image");
        return GeoImage::INVALID;
    }

    // validate the existance of a valid layer profile (unless we're in cache-only mode, in which
    // case there is no layer profile)
    if ( !policy.isCacheOnly() && !getProfile() )
    {
        disable("Could not establish a valid profile");
        return GeoImage::INVALID;
    }

    osg::ref_ptr< osg::Image > cachedImage;

    // First, attempt to read from the cache. Since the cached data is stored in the
    // map profile, we can try this first.
    if ( cacheBin && policy.isCacheReadable() )
    {
        ReadResult r = cacheBin->readImage(cacheKey, 0L);
        if ( r.succeeded() )
        {
            cachedImage = r.releaseImage();
            ImageUtils::fixInternalFormat( cachedImage.get() );            
            bool expired = policy.isExpired(r.lastModifiedTime());
            if (!expired)
            {
                OE_DEBUG << "Got cached image for " << key.str() << std::endl;                
                return GeoImage( cachedImage.get(), key.getExtent() );                        
            }
            else
            {
                OE_DEBUG << "Expired image for " << key.str() << std::endl;                
            }
        }
    }
    
    // The data was not in the cache. If we are cache-only, fail sliently
    if ( policy.isCacheOnly() )
    {
        // If it's cache only and we have an expired but cached image, just return it.
        if (cachedImage.valid())
        {
            return GeoImage( cachedImage.get(), key.getExtent() );            
        }
        else
        {
            return GeoImage::INVALID;
        }
    }

    // Get an image from the underlying TileSource.
    result = createImageFromTileSource( key, progress );

    // Normalize the image if necessary
    if ( result.valid() )
    {
        ImageUtils::fixInternalFormat( result.getImage() );
    }

    // memory cache first:
    if ( result.valid() && _memCache.valid() )
    {
        CacheBin* bin = _memCache->getOrCreateDefaultBin();
        bin->write(cacheKey, result.getImage(), 0L);
    }

    // If we got a result, the cache is valid and we are caching in the map profile,
    // write to the map cache.
    if (result.valid()  &&
        cacheBin        && 
        policy.isCacheWriteable())
    {
        if ( key.getExtent() != result.getExtent() )
        {
            OE_INFO << LC << "WARNING! mismatched extents." << std::endl;
        }

        cacheBin->write(cacheKey, result.getImage(), 0L);
    }

    if ( result.valid() )
    {
        OE_DEBUG << LC << key.str() << " result OK" << std::endl;
    }
    else
    {
        OE_DEBUG << LC << key.str() << "result INVALID" << std::endl;        
        // We couldn't get an image from the source.  So see if we have an expired cached image
        if (cachedImage.valid())
        {
            OE_DEBUG << LC << "Using cached but expired image for " << key.str() << std::endl;
            result = GeoImage( cachedImage.get(), key.getExtent());
        }
    }

    return result;
}
Exemple #27
0
GeoImage
ImageLayer::assembleImageFromTileSource(const TileKey&    key,
                                        ProgressCallback* progress)
{
    GeoImage mosaicedImage, result;

    // Scale the extent if necessary to apply an "edge buffer"
    GeoExtent ext = key.getExtent();
    if ( _runtimeOptions.edgeBufferRatio().isSet() )
    {
        double ratio = _runtimeOptions.edgeBufferRatio().get();
        ext.scale(ratio, ratio);
    }

    // Get a set of layer tiles that intersect the requested extent.
    std::vector<TileKey> intersectingKeys;
    getProfile()->getIntersectingTiles( key, intersectingKeys );

    if ( intersectingKeys.size() > 0 )
    {
        double dst_minx, dst_miny, dst_maxx, dst_maxy;
        key.getExtent().getBounds(dst_minx, dst_miny, dst_maxx, dst_maxy);

        // if we find at least one "real" tile in the mosaic, then the whole result tile is
        // "real" (i.e. not a fallback tile)
        bool retry = false;
        ImageMosaic mosaic;

        // keep track of failed tiles.
        std::vector<TileKey> failedKeys;

        for( std::vector<TileKey>::iterator k = intersectingKeys.begin(); k != intersectingKeys.end(); ++k )
        {
            GeoImage image = createImageFromTileSource( *k, progress );

            if ( image.valid() )
            {
                if ( !isCoverage() )
                {
                    ImageUtils::fixInternalFormat(image.getImage());

                    // Make sure all images in mosaic are based on "RGBA - unsigned byte" pixels.
                    // This is not the smarter choice (in some case RGB would be sufficient) but
                    // it ensure consistency between all images / layers.
                    //
                    // The main drawback is probably the CPU memory foot-print which would be reduced by allocating RGB instead of RGBA images.
                    // On GPU side, this should not change anything because of data alignements : often RGB and RGBA textures have the same memory footprint
                    //
                    if (   (image.getImage()->getDataType() != GL_UNSIGNED_BYTE)
                        || (image.getImage()->getPixelFormat() != GL_RGBA) )
                    {
                        osg::ref_ptr<osg::Image> convertedImg = ImageUtils::convertToRGBA8(image.getImage());
                        if (convertedImg.valid())
                        {
                            image = GeoImage(convertedImg, image.getExtent());
                        }
                    }
                }

                mosaic.getImages().push_back( TileImage(image.getImage(), *k) );
            }
            else
            {
                // the tile source did not return a tile, so make a note of it.
                failedKeys.push_back( *k );

                if (progress && (progress->isCanceled() || progress->needsRetry()))
                {
                    retry = true;
                    break;
                }
            }
        }

        if ( mosaic.getImages().empty() || retry )
        {
            // if we didn't get any data, fail.
            OE_DEBUG << LC << "Couldn't create image for ImageMosaic " << std::endl;
            return GeoImage::INVALID;
        }

        // We got at least one good tile, so go through the bad ones and try to fall back on
        // lower resolution data to fill in the gaps. The entire mosaic must be populated or
        // this qualifies as a bad tile.
        for(std::vector<TileKey>::iterator k = failedKeys.begin(); k != failedKeys.end(); ++k)
        {
            GeoImage image;

            for(TileKey parentKey = k->createParentKey();
                parentKey.valid() && !image.valid();
                parentKey = parentKey.createParentKey())
            {
                image = createImageFromTileSource( parentKey, progress );
                if ( image.valid() )
                {
                    GeoImage cropped;

                    if ( !isCoverage() )
                    {
                        ImageUtils::fixInternalFormat(image.getImage());
                        if (   (image.getImage()->getDataType() != GL_UNSIGNED_BYTE)
                            || (image.getImage()->getPixelFormat() != GL_RGBA) )
                        {
                            osg::ref_ptr<osg::Image> convertedImg = ImageUtils::convertToRGBA8(image.getImage());
                            if (convertedImg.valid())
                            {
                                image = GeoImage(convertedImg, image.getExtent());
                            }
                        }

                        cropped = image.crop( k->getExtent(), false, image.getImage()->s(), image.getImage()->t() );
                    }

                    else
                    {
                        // TODO: may not work.... test; tilekey extent will <> cropped extent
                        cropped = image.crop( k->getExtent(), true, image.getImage()->s(), image.getImage()->t(), false );
                    }

                    // and queue it.
                    mosaic.getImages().push_back( TileImage(cropped.getImage(), *k) );       

                }
            }

            if ( !image.valid() )
            {
                // a tile completely failed, even with fallback. Eject.
                OE_DEBUG << LC << "Couldn't fallback on tiles for ImageMosaic" << std::endl;
                // let it go. The empty areas will be filled with alpha by ImageMosaic.
            }
        }

        // all set. Mosaic all the images together.
        double rxmin, rymin, rxmax, rymax;
        mosaic.getExtents( rxmin, rymin, rxmax, rymax );

        mosaicedImage = GeoImage(
            mosaic.createImage(),
            GeoExtent( getProfile()->getSRS(), rxmin, rymin, rxmax, rymax ) );
    }
    else
    {
        OE_DEBUG << LC << "assembleImageFromTileSource: no intersections (" << key.str() << ")" << std::endl;
    }

    // Final step: transform the mosaic into the requesting key's extent.
    if ( mosaicedImage.valid() )
    {
        // GeoImage::reproject() will automatically crop the image to the correct extents.
        // so there is no need to crop after reprojection. Also note that if the SRS's are the 
        // same (even though extents are different), then this operation is technically not a
        // reprojection but merely a resampling.

        result = mosaicedImage.reproject( 
            key.getProfile()->getSRS(),
            &key.getExtent(), 
            *_runtimeOptions.reprojectedTileSize(),
            *_runtimeOptions.reprojectedTileSize(),
            *_runtimeOptions.driver()->bilinearReprojection() );
    }

    // Process images with full alpha to properly support MP blending.
    if ( result.valid() && *_runtimeOptions.featherPixels() && !isCoverage() )
    {
        ImageUtils::featherAlphaRegions( result.getImage() );
    }

    return result;
}
void
TerrainTileModelFactory::addColorLayers(TerrainTileModel* model,
                                        const Map* map,
                                        const TerrainEngineRequirements* reqs,
                                        const TileKey&    key,
                                        const CreateTileModelFilter& filter,
                                        ProgressCallback* progress)
{
    OE_START_TIMER(fetch_image_layers);

    int order = 0;

    LayerVector layers;
    map->getLayers(layers);

    for (LayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i)
    {
        Layer* layer = i->get();

        if (layer->getRenderType() != layer->RENDERTYPE_TERRAIN_SURFACE)
            continue;

        if (!layer->getEnabled())
            continue;

        if (!filter.accept(layer))
            continue;

        ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(layer);
        if (imageLayer)
        {
            osg::Texture* tex = 0L;
            osg::Matrixf textureMatrix;

            if (imageLayer->isKeyInLegalRange(key) && imageLayer->mayHaveDataInExtent(key.getExtent()))
            {
                if (imageLayer->createTextureSupported())
                {
                    tex = imageLayer->createTexture( key, progress, textureMatrix );
                }

                else
                {
                    GeoImage geoImage = imageLayer->createImage( key, progress );
           
                    if ( geoImage.valid() )
                    {
                        if ( imageLayer->isCoverage() )
                            tex = createCoverageTexture(geoImage.getImage(), imageLayer);
                        else
                            tex = createImageTexture(geoImage.getImage(), imageLayer);
                    }
                }
            }
        
            // if this is the first LOD, and the engine requires that the first LOD
            // be populated, make an empty texture if we didn't get one.
            if (tex == 0L &&
                _options.firstLOD() == key.getLOD() &&
                reqs && reqs->fullDataAtFirstLodRequired())
            {
                tex = _emptyTexture.get();
            }
         
            if (tex)
            {
                tex->setName(model->getKey().str());

                TerrainTileImageLayerModel* layerModel = new TerrainTileImageLayerModel();

                layerModel->setImageLayer(imageLayer);

                layerModel->setTexture(tex);
                layerModel->setMatrix(new osg::RefMatrixf(textureMatrix));

                model->colorLayers().push_back(layerModel);

                if (imageLayer->isShared())
                {
                    model->sharedLayers().push_back(layerModel);
                }

                if (imageLayer->isDynamic())
                {
                    model->setRequiresUpdateTraverse(true);
                }
            }
        }

        else // non-image kind of TILE layer:
        {
            TerrainTileColorLayerModel* colorModel = new TerrainTileColorLayerModel();
            colorModel->setLayer(layer);
            model->colorLayers().push_back(colorModel);
        }
    }

    if (progress)
        progress->stats()["fetch_imagery_time"] += OE_STOP_TIMER(fetch_image_layers);
}
Exemple #29
0
    void execute()
    {
        GeoImage geoImage;
        bool isFallbackData = false;

        bool useMercatorFastPath =
            _opt->enableMercatorFastPath() != false &&
            _mapInfo->isGeocentric()                &&
            _layer->getProfile()                    &&
            _layer->getProfile()->getSRS()->isSphericalMercator();

        // fetch the image from the layer, falling back on parent keys utils we are 
        // able to find one that works.

        bool autoFallback = _key.getLevelOfDetail() <= 1;

        TileKey imageKey( _key );
        TileSource* tileSource = _layer->getTileSource();
        const Profile* layerProfile = _layer->getProfile();

        //Only try to get data from the source if it actually intersects the key extent
        bool hasDataInExtent = true;
        if (tileSource && layerProfile)
        {
            GeoExtent ext = _key.getExtent();
            if (!layerProfile->getSRS()->isEquivalentTo( ext.getSRS()))
            {
                ext = layerProfile->clampAndTransformExtent( ext );
            }
            hasDataInExtent = ext.isValid() && tileSource->hasDataInExtent( ext );
        }        
        
        if (hasDataInExtent)
        {
            while( !geoImage.valid() && imageKey.valid() && _layer->isKeyValid(imageKey) )
            {
                if ( useMercatorFastPath )
                {
                    bool mercFallbackData = false;
                    geoImage = _layer->createImageInNativeProfile( imageKey, 0L, autoFallback, mercFallbackData );
                    if ( geoImage.valid() && mercFallbackData )
                    {
                        isFallbackData = true;
                    }
                }
                else
                {
                    geoImage = _layer->createImage( imageKey, 0L, autoFallback );
                }

                if ( !geoImage.valid() )
                {
                    imageKey = imageKey.createParentKey();
                    isFallbackData = true;
                }
            }
        }

        GeoLocator* locator = 0L;

        if ( !geoImage.valid() )
        {
            // no image found, so make an empty one (one pixel alpha).
            geoImage = GeoImage( ImageUtils::createEmptyImage(), _key.getExtent() );
            locator = GeoLocator::createForKey( _key, *_mapInfo );
            isFallbackData = true;
        }
        else
        {
            if ( useMercatorFastPath )
                locator = new MercatorLocator(geoImage.getExtent());
            else
                locator = GeoLocator::createForExtent(geoImage.getExtent(), *_mapInfo);
        }

        bool isStreaming = _opt->loadingPolicy()->mode() == LoadingPolicy::MODE_PREEMPTIVE || _opt->loadingPolicy()->mode() == LoadingPolicy::MODE_SEQUENTIAL;

        if (geoImage.getImage() && isStreaming)
        {
            // protected against multi threaded access. This is a requirement in sequential/preemptive mode, 
            // for example. This used to be in TextureCompositorTexArray::prepareImage.
            // TODO: review whether this affects performance.    
            geoImage.getImage()->setDataVariance( osg::Object::DYNAMIC );
        }

        // add the color layer to the repo.
        _repo->add( CustomColorLayer(
            _layer,
            geoImage.getImage(),
            locator,
            _key.getLevelOfDetail(),
            _key,
            isFallbackData ) );
    }
void
TextureCompositorTexArray::applyLayerUpdate(osg::StateSet*       stateSet,
                                            UID                  layerUID,
                                            const GeoImage&      preparedImage,
                                            const TileKey&       tileKey,
                                            const TextureLayout& layout,
                                            osg::StateSet*       parentStateSet) const
{
    GeoExtent tileExtent(tileKey.getExtent());
    int slot = layout.getSlot( layerUID );
    if ( slot < 0 )
        return; // means the layer no longer exists

    // access the texture array, creating or growing it if necessary:
    osg::Texture2DArray* texture = s_getTexture( stateSet, layout, 0,
                                                 textureSize() );
    ensureSampler( stateSet, 0 );
    // assign the new image at the proper position in the texture array.
    osg::Image* image = preparedImage.getImage();
    assignImage(texture, slot, image);
    
    // update the region uniform to reflect the geo extent of the image:
    const GeoExtent& imageExtent = preparedImage.getExtent();
    osg::Vec4 tileTransform;
    getImageTransform(tileExtent, imageExtent, tileTransform);

    // access the region uniform, creating or growing it if necessary:
    ArrayUniform regionUni( "region", osg::Uniform::FLOAT, stateSet, layout.getMaxUsedSlot()+1 );
    if ( regionUni.isValid() )
    {
        int layerOffset = slot * 8;
        for (int i = 0; i < 4; ++i)
            regionUni.setElement( layerOffset + i, tileTransform[i]);
        //region->dirty();
    }
    
    if ( layout.isBlendingEnabled( layerUID ) && regionUni.isValid() )
    {
        osg::Uniform* secondarySampler = ensureSampler( stateSet, 1 );
        osg::Texture2DArray* parentTexture = 0;
        const unsigned parentLayerOffset = slot * 8 + 4;
        if ( parentStateSet )
        {
            ArrayUniform parentRegion( "region", osg::Uniform::FLOAT, parentStateSet, layout.getMaxUsedSlot()+1 );

            //osg::Uniform* parentRegion = s_getRegionUniform( parentStateSet,
            //                                                 layout );
            GeoExtent parentExtent(tileKey.createParentKey().getExtent());
            float widthRatio, heightRatio;
            parentRegion.getElement(slot * 8 + 2, widthRatio);
            parentRegion.getElement(slot * 8 + 3, heightRatio);
            float parentImageWidth =  parentExtent.width() / widthRatio;
            float parentImageHeight = parentExtent.height() / heightRatio;
            float xRatio, yRatio;
            parentRegion.getElement(slot * 8, xRatio);
            parentRegion.getElement(slot * 8 + 1, yRatio);
            float ParentImageXmin = parentExtent.xMin() - xRatio * parentImageWidth;
            float ParentImageYmin = parentExtent.yMin() - yRatio * parentImageHeight;
            regionUni.setElement(parentLayerOffset,
                               static_cast<float>((tileExtent.xMin() - ParentImageXmin) / parentImageWidth));
            regionUni.setElement(parentLayerOffset + 1,
                               static_cast<float>((tileExtent.yMin() - ParentImageYmin) / parentImageHeight));
            regionUni.setElement(parentLayerOffset + 2,
                               static_cast<float>(tileExtent.width() / parentImageWidth));
            regionUni.setElement(parentLayerOffset + 3,
                               static_cast<float>(tileExtent.height() / parentImageHeight));
            //regionUni.dirty();
            parentTexture = static_cast<osg::Texture2DArray*>(parentStateSet->getTextureAttribute(0, osg::StateAttribute::TEXTURE));
        }
        else
        {
            // setting the parent transform values to -1 disabled blending for this layer. #hack -gw
            for (int i = 0; i < 4; ++i)
                regionUni.setElement(parentLayerOffset + i, tileTransform[i]);
        }

        if (parentTexture)
            stateSet->setTextureAttribute(1, parentTexture, osg::StateAttribute::ON);
        else
            secondarySampler->set(0);

        // update the timestamp on the image layer to support fade-in blending.
        float now = (float)osg::Timer::instance()->delta_s( osg::Timer::instance()->getStartTick(), osg::Timer::instance()->tick() );
        ArrayUniform stampUniform( "osgearth_SlotStamp", osg::Uniform::FLOAT, stateSet, layout.getMaxUsedSlot()+1 );
        stampUniform.setElement( slot, now );
    }
}