Beispiel #1
0
static Config
mapToConfig( Map* map, const MapEngineProperties& ep )
{
    Config conf( ELEM_MAP );
    conf.attr( ATTR_NAME ) = map->getName();
    
    conf.add( "engine_properties", ep.toConfig() );

    //Write the coordinate system
    std::string cs;
    if (map->getCoordinateSystemType() == Map::CSTYPE_GEOCENTRIC) cs = "geocentric";
    else if (map->getCoordinateSystemType() == Map::CSTYPE_PROJECTED) cs = "projected";
    else if ( map->getCoordinateSystemType() == Map::CSTYPE_GEOCENTRIC_CUBE) cs = "cube";
    else
    {
        OE_NOTICE << "[osgEarth::EarthFile] Unhandled CoordinateSystemType " << std::endl;
        return Config();
    }
    conf.attr( ATTR_CSTYPE ) = cs;

    //Write all the image sources
    for( MapLayerList::const_iterator i = map->getImageMapLayers().begin(); i != map->getImageMapLayers().end(); i++ )
    {
        conf.add( i->get()->toConfig() );
        //conf.add( writeLayer( i->get() ) );
    }

    //Write all the heightfield sources
    for (MapLayerList::const_iterator i = map->getHeightFieldMapLayers().begin(); i != map->getHeightFieldMapLayers().end(); i++ )
    {
        conf.add( i->get()->toConfig() );
        //conf.add( writeLayer( i->get() ) );
    }

    //Write all the model layers
    for(ModelLayerList::const_iterator i = map->getModelLayers().begin(); i != map->getModelLayers().end(); i++ )
    {
        conf.add( writeLayer( i->get() ) );
    }

    //Terrain mask layer, if necc.
    if ( map->getTerrainMaskLayer() )
    {
        conf.add( writeLayer( map->getTerrainMaskLayer() ) );
    }

	//TODO:  Get this from the getCache call itself, not a CacheConfig.
    if ( map->cacheConfig().isSet() )
    {
        conf.add( map->cacheConfig()->toConfig( ELEM_CACHE ) );
    }

    if ( map->profileConfig().isSet() )
    {
        conf.add( map->profileConfig()->toConfig( ELEM_PROFILE ) );
    }

    return conf;
}
Beispiel #2
0
bool
MapEngine::hasMoreLevels( Map* map, const TileKey* key )
{
    Threading::ScopedReadLock lock( map->getMapDataMutex() );

    bool more_levels = false;
    int max_level = 0;

    for ( MapLayerList::const_iterator i = map->getImageMapLayers().begin(); i != map->getImageMapLayers().end(); i++ )
    {
        if ( !i->get()->maxLevel().isSet() || key->getLevelOfDetail() < i->get()->maxLevel().get() )
        {
            more_levels = true;
            break;
        }
    }
    if ( !more_levels )
    {
        for( MapLayerList::const_iterator j = map->getHeightFieldMapLayers().begin(); j != map->getHeightFieldMapLayers().end(); j++ )
        {
            if ( !j->get()->maxLevel().isSet() || key->getLevelOfDetail() < j->get()->maxLevel().get() )
            {
                more_levels = true;
                break;
            }
        }
    }

    return more_levels;
}
Beispiel #3
0
void CacheSeed::seed( Map* map )
{
    Threading::ScopedReadLock lock( map->getMapDataMutex() );

    if (!map->getCache())
    {
        OE_WARN << "Warning:  Map does not have a cache defined, please define a cache." << std::endl;
        return;
    }

    osg::ref_ptr<MapEngine> engine = new MapEngine(); //map->createMapEngine();

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

    //Set the default bounds to the entire profile if the user didn't override the bounds
    if (_bounds.xMin() == 0 && _bounds.yMin() == 0 &&
        _bounds.xMax() == 0 && _bounds.yMax() == 0)
    {
        const GeoExtent& mapEx =  map->getProfile()->getExtent();
        _bounds = Bounds( mapEx.xMin(), mapEx.yMin(), mapEx.xMax(), mapEx.yMax() );
    }


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

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

        if (layer->cacheOnly().get())
        {
            OE_WARN << "Warning:  Cannot seed b/c Layer \"" << layer->getName() << "\" is cache only." << std::endl;
            return;
        }
        else if (!src)
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource." << std::endl;
        }
        else if ( !src->supportsPersistentCaching() )
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" does not support seeding." << std::endl;
        }
        else if ( !layer->getCache() )
        {
            OE_NOTICE << "Notice: Layer \"" << layer->getName() << "\" has no persistent cache defined; skipping." << std::endl;
        }
        else
        {
            hasCaches = true;

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

    for( MapLayerList::const_iterator i = map->getHeightFieldMapLayers().begin(); i != map->getHeightFieldMapLayers().end(); i++ )
    {
		MapLayer* layer = i->get();
        TileSource* src = i->get()->getTileSource();

        if (layer->cacheOnly().get())
        {
            OE_WARN << "Warning:  Cannot seed b/c Layer \"" << layer->getName() << "\" is cache only." << std::endl;
            return;
        }
        else if (!src)
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource." << std::endl;
        }
        else if ( !src->supportsPersistentCaching() )
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" does not support seeding." << std::endl;
        }
        else if ( !layer->getCache() )
        {
            OE_NOTICE << "Notice: Layer \"" << src->getName() << "\" has no persistent cache defined; skipping." << std::endl;
        }
        else
        {
            hasCaches = true;

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

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

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

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

    for (unsigned int i = 0; i < keys.size(); ++i)
    {
        processKey( map, engine.get(), keys[i].get() );
    }
}
Beispiel #4
0
osg::Node*
MapEngine::createPopulatedTile( Map* map, VersionedTerrain* terrain, const TileKey* key, bool wrapInPagedLOD, bool fallback, bool &validData )
{
    Threading::ScopedReadLock lock( map->getMapDataMutex() );

    bool isProjected = map->getCoordinateSystemType() == Map::CSTYPE_PROJECTED;
    bool isPlateCarre = isProjected && map->getProfile()->getSRS()->isGeographic();
    bool isGeocentric = !isProjected;

    double xmin, ymin, xmax, ymax;
    key->getGeoExtent().getBounds( xmin, ymin, xmax, ymax );

    GeoImageList image_tiles;

    const MapLayerList& imageMapLayers = map->getImageMapLayers();
    const MapLayerList& hfMapLayers = map->getHeightFieldMapLayers();

    // Collect the image layers
    bool empty_map = imageMapLayers.size() == 0 && hfMapLayers.size() == 0;
    
    // Whether to use a special mercator locator instead of reprojecting data to spherical mercator
    bool useMercatorLocator = true;

    // Create the images for the tile
    for( MapLayerList::const_iterator i = imageMapLayers.begin(); i != imageMapLayers.end(); i++ )
    {
        MapLayer* layer = i->get();

        osg::ref_ptr<GeoImage> image;
		//Only create images if the key is valid
        if ( layer->isKeyValid( key ) )
        {
            if ( _L2cache )
                image = _L2cache->createImage( layer, key );
            else
                image = layer->createImage( key );
        }
        image_tiles.push_back(image.get());

        // if any one of the layers explicity disables the merc fast path, disable for the whole thing:
        if ( layer->useMercatorFastPath().isSetTo( false ) )
            useMercatorLocator = false;
    }

    bool hasElevation = false;

    //Create the heightfield for the tile
    osg::ref_ptr<osg::HeightField> hf;
    if ( hfMapLayers.size() > 0 )
    {
        hf = map->createHeightField( key, false, _engineProps.elevationInterpolation().value());     
    }

    //If we are on the first LOD and we couldn't get a heightfield tile, just create an empty one.  Otherwise you can run into the situation
    //where you could have an inset heightfield on one hemisphere and the whole other hemisphere won't show up.
    if (map->isGeocentric() && key->getLevelOfDetail() <= 1 && !hf.valid())
    {
        hf = createEmptyHeightField( key );
    }
    hasElevation = hf.valid();

    //Determine if we've created any images
    unsigned int numValidImages = 0;
    for (unsigned int i = 0; i < image_tiles.size(); ++i)
    {
        if (image_tiles[i].valid()) numValidImages++;
    }


    //If we couldn't create any imagery or heightfields, bail out
    if (!hf.valid() && (numValidImages == 0) && !empty_map)
    {
        OE_DEBUG << LC << "Could not create any imagery or heightfields for " << key->str() <<".  Not building tile" << std::endl;
        validData = false;

        //If we're not asked to fallback on previous LOD's and we have no data, return NULL
        if (!fallback)
        {
            return NULL;
        }
    }
    else
    {
        validData = true;
    }
   
    //Try to interpolate any missing image layers from parent tiles
    for (unsigned int i = 0; i < imageMapLayers.size(); i++ )
    {
        if (!image_tiles[i].valid())
        {
			GeoImage* image = NULL;
            if (imageMapLayers[i]->isKeyValid(key))
            {
				//If the key was valid and we have no image, then something possibly went wrong with the image creation such as a server being busy.
                image = createValidGeoImage(imageMapLayers[i].get(), key);
            }

			//If we still couldn't create an image, either something is really wrong or the key wasn't valid, so just create a transparent placeholder image
			if (!image)
			{
				//If the image is not valid, create an empty texture as a placeholder
                image = new GeoImage(ImageUtils::createEmptyImage(), key->getGeoExtent());
			}

			//Assign the new image to the proper place in the list
			image_tiles[i] = image;
        }
    }

    //Fill in missing heightfield information from parent tiles
    if (!hf.valid())
    {
        //We have no heightfield sources, 
        if ( hfMapLayers.size() == 0 )
        {
            hf = createEmptyHeightField( key );
        }
        else
        {
            //Try to get a heightfield again, but this time fallback on parent tiles
            hf = map->createHeightField( key, true, _engineProps.elevationInterpolation().value());
            if (!hf.valid())
            {
                //We couldn't get any heightfield, so just create an empty one.
                hf = createEmptyHeightField( key );
            }
            else
            {
                hasElevation = true;
            }
        }
    }


    // In a Plate Carre tesselation, scale the heightfield elevations from meters to degrees
    if ( isPlateCarre )
    {
        HeightFieldUtils::scaleHeightFieldToDegrees( hf.get() );
    }

    osg::ref_ptr<GeoLocator> locator = GeoLocator::createForKey( key, map );
    osgTerrain::HeightFieldLayer* hf_layer = new osgTerrain::HeightFieldLayer();
    hf_layer->setLocator( locator.get() );
    hf_layer->setHeightField( hf.get() );

    VersionedTile* tile = new VersionedTile( key, locator.get() );
    tile->setTerrainTechnique( osg::clone(terrain->getTerrainTechniquePrototype(), osg::CopyOp::DEEP_COPY_ALL) );
    tile->setVerticalScale( _engineProps.verticalScale().value() );
    tile->setLocator( locator.get() );
    tile->setElevationLayer( hf_layer );
    tile->setRequiresNormals( true );
    tile->setDataVariance(osg::Object::DYNAMIC);

    //Attach an updatecallback to normalize the edges of TerrainTiles.
    if (hasElevation && _engineProps.normalizeEdges().get() )
    {
        tile->setUpdateCallback(new TerrainTileEdgeNormalizerUpdateCallback());
        tile->setDataVariance(osg::Object::DYNAMIC);
    }

    //Assign the terrain system to the TerrainTile.
    //It is very important the terrain system is set while the MapConfig's sourceMutex is locked.
    //This registers the terrain tile so that adding/removing layers are always in sync.  If you don't do this
    //you can end up with a situation where the database pager is waiting to merge a tile, then a layer is added, then
    //the tile is finally merged and is out of sync.

	double min_units_per_pixel = DBL_MAX;

    int layer = 0;
   // create contour layer:
    if (map->getContourTransferFunction() != NULL)
    {
      osgTerrain::ContourLayer* contourLayer(new osgTerrain::ContourLayer(map->getContourTransferFunction()));

      contourLayer->setMagFilter(_engineProps.getContourMagFilter().value());
      contourLayer->setMinFilter(_engineProps.getContourMinFilter().value());
      tile->setColorLayer(layer,contourLayer);
      ++layer;
    }

    for (unsigned int i = 0; i < image_tiles.size(); ++i)
    {
        if (image_tiles[i].valid())
        {
            double img_xmin, img_ymin, img_xmax, img_ymax;

            //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;
			
            GeoImage* geo_image = image_tiles[i].get();

            // Use a special locator for mercator images (instead of reprojecting)
            if (map->getProfile()->getSRS()->isGeographic() &&
                geo_image->getSRS()->isMercator() && 
                useMercatorLocator )
            {
                GeoExtent geog_ext = image_tiles[i]->getExtent().transform(image_tiles[i]->getExtent().getSRS()->getGeographicSRS());
                geog_ext.getBounds( img_xmin, img_ymin, img_xmax, img_ymax );
                img_locator = key->getProfile()->getSRS()->createLocator( img_xmin, img_ymin, img_xmax, img_ymax );
                img_locator = new MercatorLocator( *img_locator.get(), geo_image->getExtent() );
            }
            else
            {
                image_tiles[i]->getExtent().getBounds( img_xmin, img_ymin, img_xmax, img_ymax );

                img_locator = key->getProfile()->getSRS()->createLocator( 
                    img_xmin, img_ymin, img_xmax, img_ymax, isPlateCarre );
            }

            if ( isGeocentric )
                img_locator->setCoordinateSystemType( osgTerrain::Locator::GEOCENTRIC );

			TransparentLayer* img_layer = new TransparentLayer(geo_image->getImage(), imageMapLayers[i].get());
            img_layer->setLevelOfDetail( key->getLevelOfDetail() );
            img_layer->setName( imageMapLayers[i]->getName() );
            img_layer->setLocator( img_locator.get());
			img_layer->setMinFilter( imageMapLayers[i]->getMinFilter().value());
			img_layer->setMagFilter( imageMapLayers[i]->getMagFilter().value());

			double upp = geo_image->getUnitsPerPixel();

			// Scale the units per pixel to degrees if the image is mercator (and the key is geo)
            if ( geo_image->getSRS()->isMercator() && key->getGeoExtent().getSRS()->isGeographic() )
                upp *= 1.0f/111319.0f;

			min_units_per_pixel = osg::minimum(upp, min_units_per_pixel);

            tile->setColorLayer( layer, img_layer );
            layer++;
        }
    }

    osg::BoundingSphere bs = tile->getBound();
    double max_range = 1e10;
    double radius = bs.radius();

#if 1
    double min_range = radius * _engineProps.minTileRangeFactor().get();
    osg::LOD::RangeMode mode = osg::LOD::DISTANCE_FROM_EYE_POINT;
#else
	double width = key->getGeoExtent().width();	
	if (min_units_per_pixel == DBL_MAX) min_units_per_pixel = width/256.0;
	double min_range = (width / min_units_per_pixel) * _engineProps.getMinTileRangeFactor(); 
    osg::LOD::RangeMode mode = osg::LOD::PIXEL_SIZE_ON_SCREEN;
#endif


    // a skirt hides cracks when transitioning between LODs:
    hf->setSkirtHeight(radius * _engineProps.heightFieldSkirtRatio().get() );

    // for now, cluster culling does not work for CUBE rendering
    bool isCube = map->getCoordinateSystemType() == Map::CSTYPE_GEOCENTRIC_CUBE;
    if ( isGeocentric && !isCube )
    {
        //TODO:  Work on cluster culling computation for cube faces
        osg::ClusterCullingCallback* ccc = createClusterCullingCallback(tile, locator->getEllipsoidModel() );
        tile->setCullCallback( ccc );
    }
    
    // Wait until now, when the tile is fully baked, to assign the terrain to the tile.
    // Placeholder tiles might try to locate this tile as an ancestor, and access its layers
    // and locators...so they must be intact before making this tile available via setTerrain.
    //
    // If there's already a placeholder tile registered, this will be ignored. If there isn't,
    // this will register the new tile.
    tile->setTerrain( terrain );
    terrain->registerTile( tile );

    // Set the tile's revision to the current terrain revision
    tile->setTerrainRevision( static_cast<VersionedTerrain*>(terrain)->getRevision() );

    if ( _engineProps.loadingPolicy()->mode() != LoadingPolicy::MODE_STANDARD && key->getLevelOfDetail())
    {
        tile->setUseLayerRequests( true );
        tile->setHasElevationHint( hasElevation );
    }

    tile->setTerrainRevision( terrain->getRevision() );
    tile->setDataVariance( osg::Object::DYNAMIC );

    osg::Node* result = 0L;

    if (wrapInPagedLOD)
    {
        // create a PLOD so we can keep subdividing:
        osg::PagedLOD* plod = new osg::PagedLOD();
        plod->setCenter( bs.center() );
        plod->addChild( tile, min_range, max_range );

        std::string filename = createURI( map->getId(), key );

        //Only add the next tile if it hasn't been blacklisted
        bool isBlacklisted = osgEarth::Registry::instance()->isBlacklisted( filename );
        if (!isBlacklisted && key->getLevelOfDetail() < this->getEngineProperties().maxLOD().value() && validData )
        {
            plod->setFileName( 1, filename  );
            plod->setRange( 1, 0.0, min_range );
        }
        else
        {
            plod->setRange( 0, 0, FLT_MAX );
        }

#if USE_FILELOCATIONCALLBACK
        osgDB::Options* options = new osgDB::Options;
        options->setFileLocationCallback( new osgEarth::FileLocationCallback);
        plod->setDatabaseOptions( options );
#endif
        result = plod;

        if ( tile->getUseLayerRequests() )
            result->addCullCallback( new TileImageBackfillCallback() );
    }
    else
    {
        result = tile;
    }

    return result;
}
Beispiel #5
0
bool
MapEngine::isCached(Map* map, const osgEarth::TileKey *key)
{
    Threading::ScopedReadLock lock( map->getMapDataMutex() );

    const Profile* mapProfile = key->getProfile();

    //Check the imagery layers
    for( MapLayerList::const_iterator i = map->getImageMapLayers().begin(); i != map->getImageMapLayers().end(); i++ )
    {
        MapLayer* layer = i->get();
	    osg::ref_ptr< Cache > cache = layer->getCache();
    	if (!cache.valid()) return false;

        std::vector< osg::ref_ptr< const TileKey > > keys;

        if ( map->getProfile()->isEquivalentTo( layer->getProfile() ) )
        {
            keys.push_back( key );
        }
        else
        {
            layer->getProfile()->getIntersectingTiles( key, keys );
        }

        for (unsigned int j = 0; j < keys.size(); ++j)
        {
            if ( layer->isKeyValid( keys[j].get() ) )
            {
                if ( !cache->isCached( keys[j].get(), layer->getName(), layer->cacheFormat().value() ) )
                {
                    return false;
                }
            }
        }
    }

    //Check the elevation layers
    for( MapLayerList::const_iterator i = map->getHeightFieldMapLayers().begin(); i != map->getHeightFieldMapLayers().end(); i++ )
    {
        MapLayer* layer = i->get();
		osg::ref_ptr< Cache > cache = layer->getCache();
		if (!cache.valid()) return false;

        std::vector< osg::ref_ptr< const TileKey > > keys;

        if ( map->getProfile()->isEquivalentTo( layer->getProfile() ) )
        {
            keys.push_back( key );
        }
        else
        {
            layer->getProfile()->getIntersectingTiles( key, keys );
        }

        for (unsigned int j = 0; j < keys.size(); ++j)
        {
            if ( layer->isKeyValid( keys[j].get() ) )
            {
                if ( !cache->isCached( keys[j].get(), layer->getName(), layer->cacheFormat().value() ) )
                {
                    return false;
                }
            }
        }
    }
    return true;
}