osgEarth的Rex引擎原理分析(八十八)osgEarth::MemCache详解

本文详述osgEarth中的MemCache机制,包括其在TerrainLayer中的创建、LRU缓存策略以及在加载高程和影像数据时的角色。探讨了MemCacheBin如何管理缓存数据,并介绍了缓存数据的读取和写入过程。同时列举了一系列与osgEarth及Rex引擎相关的问题,用于进一步理解其工作原理。

目标:(八十二)中的问题163

1、在图层open时创建

具体在TerrainLayer中实现

osgEarth/TerrainLayer.cpp
const Status&
TerrainLayer::open()
{
        if ( l2CacheSize > 0 )
        {
            _memCache = new MemCache( l2CacheSize );
        }
}

默认的缓存大小为16。

2、在首次读取数据时,创建缓存体CacheBin(osgEarth::MemCacheBin具体负责读取和写入缓存数据)

osgEarth/MemCache.cpp
CacheBin*
MemCache::getOrCreateDefaultBin()
{
    if ( !_defaultBin.valid() )
    {
        Threading::ScopedMutexLock lock( s_defaultBinMutex );
        // double check
        if ( !_defaultBin.valid() )
        {
            _defaultBin = new MemCacheBin("__default", _maxBinSize);
        }
    }

    return _defaultBin.get();
}

MemCacheBin中有一个最近最少使用缓存(Least-recently-used).

LRU(Least Recently Used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:

a.新数据插入到链表头部;

b.每当缓存命中(即缓存数据被访问),则将数据移到链表头部;

c.当链表满的时候,将链表尾部的数据丢弃。

osgEarth/MemCache.cpp
typedef LRUCache<std::string, MemCacheEntry> MemCacheLRU;

struct MemCacheBin : public CacheBin
{
    MemCacheLRU _lru;
}
osgEarth/Containers
template<typename K, typename T, typename COMPARE=std::less<K> >
class LRUCache
{
    map_type _map;//用于查找
    lru_type _lru;//用于确定淘汰顺序,尾部是最新的,头部是要淘汰的
}

3、在图层加载高程或影像数据时从里面读取或写入缓存内容

3.1读取过程

osgEarth/ImageLayer.cpp
GeoImage
ImageLayer::createImageInKeyProfile(const TileKey&    key, 
                                    ProgressCallback* progress)
{
    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());
    }
}
osgEarth/MemCache.cpp
        ReadResult readObject(const std::string& key, const osgDB::Options*)
        {
            MemCacheLRU::Record rec;
            _lru.get(key, rec);
            if ( rec.valid() )
            {
                return ReadResult( 
                   osg::clone(rec.value().first.get(), osg::CopyOp::DEEP_COPY_ALL),
                   r
<think>我们正在讨论的是osgEarth中的TMSElevationLayer,特别是setMinLevel和setMaxLevel两个方法。 根据用户的问题,需要说明这两个方法的使用方法、作用以及相关注意事项。 首先,TMSElevationLayer是用于加载TMS(Tile Map Service)格式的高程数据(地形)的图层类。它继承自ElevationLayer,而ElevationLayer又继承自TileLayer。在TileLayer中,有设置最小和最大层级的函数。 作用: 1. setMinLevel(unsigned int level): 设置图层加载的最小瓦片级别(层级)。低于此级别的瓦片不会被加载。 2. setMaxLevel(unsigned int level): 设置图层加载的最大瓦片级别(层级)。高于此级别的瓦片不会被加载。 使用方法: 在代码中,可以通过创建TMSElevationLayer的实例,然后调用这两个方法来设置。 注意事项: 1. 级别(Level)从0开始,0级表示最粗粒度的瓦片(覆盖范围最大,分辨率最低),级别越高,瓦片分辨率越高。 2. 设置合理的层级范围可以避免加载不必要的数据,提高性能。 3. 如果设置的最大层级超过了数据源实际提供的最大层级,则不会加载任何数据(或者只会加载到数据源的最大层级,具体取决于驱动实现)。 4. 同样,如果设置的最小层级高于数据源的最小层级,则最低层级的瓦片将不会被加载(可能会显示空白或使用其他图层的数据)。 下面结合代码示例进行说明: 示例代码: ```cpp #include <osgEarth/TMSElevationLayer> #include <osgEarth/Map> // 创建TMS高程图层 osgEarth::TMSElevationLayer* tmsElevation = new osgEarth::TMSElevationLayer(); // 配置TMS的URL tmsElevation->setURL("http://tileserver/tms.xml"); // 假设的TMS服务地址 // 设置最小层级为3,即从第3级开始加载(0,1,2级不加载) tmsElevation->setMinLevel(3); // 设置最大层级为15,即最多加载到第15级(16级及以上不加载) tmsElevation->setMaxLevel(15); // 将图层添加到地图 osgEarth::Map* map = ...; // 获取地图指针 map->addLayer(tmsElevation); ``` 另外,也可以通过TMSOptions来设置: ```cpp #include <osgEarth/TMS> osgEarth::TMSOptions options; options.url() = "http://tileserver/tms.xml"; options.minLevel() = 3; options.maxLevel() = 15; osgEarth::TMSElevationLayer* tmsElevation = new osgEarth::TMSElevationLayer(options); map->addLayer(tmsElevation); ``` 注意事项补充: 1. 在设置层级时,需要确保数据源在指定的层级范围内有数据,否则可能导致地形显示不完整。 2. 当多个高程图层叠加时,每个图层都可以设置自己的层级范围,osgEarth会进行融合。 3. 如果同时设置了TileSource的DataExtent(数据范围,包括层级范围),那么实际加载的层级范围是两者(setMinLevel/setMaxLevel和DataExtent)的交集。 引用站内资料: 在引用[2]中提到了osgEarth的缓存机制(MemCache),设置层级范围也会影响缓存的数据量[^2]。 关于性能优化: 合理设置最小和最大层级是优化性能的重要手段,避免加载过细或过粗的瓦片,减少内存占用和网络请求。 总结: setMinLevel和setMaxLevel用于控制TMSElevationLayer加载瓦片的层级范围,从而控制数据加载的粒度和性能。 相关问题: 1. 如何根据当前视图动态调整地形瓦片的加载层级? 2. 在osgEarth中如何合并多个高程图层的显示? 3. osgEarth中地形瓦片的缓存机制是如何工作的?[^2] </think> ### OSGEarth::TMSElevationLayer 中 `setMinLevel` 和 `setMaxLevel` 详解 #### 🎯 作用与功能 这两个方法用于控制 TMS 高程瓦片图层的加载范围: 1. **`setMinLevel(level)`** - 设置**最低加载层级**(最粗糙分辨率) - 低于此层级的瓦片不会被加载 - 例如:`setMinLevel(5)` 表示跳过 0-4 级瓦片 2. **`setMaxLevel(level)`** - 设置**最高加载层级**(最精细分辨率) - 高于此层级的瓦片不会被加载 - 例如:`setMaxLevel(18)` 表示停止加载 19 级及以上瓦片 #### 📝 使用方法 ##### 代码示例 ```cpp #include <osgEarth/TMS> #include <osgEarth/ElevationLayer> // 创建 TMS 高程图层 osgEarth::TMSElevationLayer* tmsLayer = new osgEarth::TMSElevationLayer(); // 设置服务地址(示例URL) tmsLayer->setURL("http://tileserver/{z}/{x}/{y}.terrain"); // 设置层级范围:仅加载 5-18 级瓦片 tmsLayer->setMinLevel(5); // 最低层级 tmsLayer->setMaxLevel(18); // 最高层级 // 添加到地图 osgEarth::Map* map = ...; map->addLayer(tmsLayer); ``` ##### Earth 文件配置 ```xml <elevation name="tms_terrain" driver="tms"> <url>http://tileserver/{z}/{x}/{y}.terrain</url> <min_level>5</min_level> <!-- 最低层级 --> <max_level>18</max_level> <!-- 最高层级 --> </elevation> ``` #### ⚠️ 核心注意事项 1. **层级范围有效性** - 层级值必须满足:$0 \leq \text{minLevel} \leq \text{maxLevel} \leq \text{服务最高层级}$ - 超出实际层级范围会导致空白区域(如 `maxLevel=25` 但服务只支持到 20 级) 2. **性能优化平衡** - **`minLevel` 过高** → 远距离地形粗糙 (示例:`minLevel=10` 时,远山呈块状) - **`maxLevel` 过高** → 内存/显存消耗剧增[^2] (每提升 1 级,瓦片数量增加约 4 倍) 3. **引擎层级限制** osgEarth Rex 引擎默认支持最大 21 级,如需更高层级需修改配置: ```cpp osgEarth::Registry::instance()->setMaxTextureLevel(23); ``` 4. **坐标系一致性** 确保层级定义与 TMS 服务的原始坐标系匹配(如 Web Mercator 的层级定义不同于经纬度坐标系)[^3] 5. **多图层协同** 当多个高程图层叠加时,实际显示层级范围由各图层的 `minLevel/maxLevel` 共同决定 #### 💡 应用场景示例 ```cpp // 根据视点距离动态调整层级 osgEarth::ViewPoint vp = earthManipulator->getViewpoint(); double range = vp.range()->as(osgEarth::Units::METERS); if (range > 10000) { // 远距离:加载粗糙瓦片 tmsLayer->setMinLevel(3); tmsLayer->setMaxLevel(10); } else { // 近距离:加载精细瓦片 tmsLayer->setMinLevel(10); tmsLayer->setMaxLevel(18); } ``` #### 📚 引用说明 - 层级限制影响内存缓存机制[^2] - 与视点距离 (`range`) 协同实现动态加载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值