liyihongcug 发表于 2020-3-11 15:34:36

API加载earth文件的解析

转文章API加载earth文件的解析。最后一个问题下午解决。
通过\src\osgEarthDrivers\earth\ReaderWriterOsgEarth.cpp文件
ReaderWriterEarth类,用来解析“earth”文件
在文件225行的readNode函数virtual ReadResult readNode(std::istream& in, const osgDB::Options* readOptions) const
      {
            // pull the URI context from the options structure (since we're reading
            // from an "anonymous" stream here)
            URIContext uriContext( readOptions );

            osg::ref_ptr<XmlDocument> doc = XmlDocument::load( in, uriContext );
            if ( !doc.valid() )
                return ReadResult::ERROR_IN_READING_FILE;

            Config docConf = doc->getConfig();

            // support both "map" and "earth" tag names at the top level
            Config conf;
            if ( docConf.hasChild( "map" ) )
                conf = docConf.child( "map" );
            else if ( docConf.hasChild( "earth" ) )
                conf = docConf.child( "earth" );

            osg::ref_ptr<osg::Node> node;

            if ( !conf.empty() )
            {
                // see if we were given a reference URI to use:
                std::string refURI = uriContext.referrer();

                if ( conf.value("version") == "1" )
                {
                  OE_INFO << LC << "Detected a version 1.x earth file" << std::endl;
                  EarthFileSerializer1 ser;
                  node = ser.deserialize( conf, refURI );
                }

                else
                {
                  if ( conf.value("version") != "2" )
                        OE_DEBUG << LC << "No valid earth file version; assuming version='2'" << std::endl;

                  // attempt to parse a "default options" JSON string:
                  std::string defaultConfStr;
                  if ( readOptions )
                  {
                        defaultConfStr = readOptions->getPluginStringData("osgEarth.defaultOptions");
                        if ( !defaultConfStr.empty() )
                        {
                            Config optionsConf("options");
                            if (optionsConf.fromJSON(defaultConfStr))
                            {
                              //OE_NOTICE << "\n\nOriginal = \n" << conf.toJSON(true) << "\n";
                              Config* original = conf.mutable_child("options");
                              if ( original )
                              {
                                    recursiveUniqueKeyMerge(optionsConf, *original);
                              }
                              if ( !optionsConf.empty() )
                              {
                                    conf.set("options", optionsConf);
                              }
                              //OE_NOTICE << "\n\nMerged = \n" << conf.toJSON(true) << "\n";
                            }
                        }
                  }

                  EarthFileSerializer2 ser;
                  node = ser.deserialize( conf, refURI );
                }
            }

            MapNode* mapNode = MapNode::get(node.get());
            if (mapNode)
            {
                // If the user passed in a cache object, apply it to the map now
                CacheSettings* cacheSettings = CacheSettings::get(readOptions);
                if (cacheSettings && cacheSettings->getCache())
                {
                  mapNode->getMap()->setCache( cacheSettings->getCache() );
                  OE_INFO << LC << "Applied user-supplied cache to the Map\n";
                }
            }

            return ReadResult(node.get());
      }
};看到65行的读取调用
进入\src\osgEarthDrivers\earth\EarthFileSerializer2.cpp文件
EarthFileSerializer2类的deserialize函数
void addImageLayer(const Config& conf, Map* map)
    {
      ImageLayerOptions options( conf );
      options.name() = conf.value("name");
      ImageLayer* layer = new ImageLayer(options);
      map->addLayer(layer);
      if (layer->getStatus().isError())
            OE_WARN << LC << "Layer \"" << layer->getName() << "\" : " << layer->getStatus().toString() << std::endl;
    }

    void addElevationLayer(const Config& conf, Map* map)
    {
      ElevationLayerOptions options( conf );
      options.name() = conf.value( "name" );
      ElevationLayer* layer = new ElevationLayer(options);
      map->addLayer(layer);
      if (layer->getStatus().isError())
            OE_WARN << LC << "Layer \"" << layer->getName() << "\" : " << layer->getStatus().toString() << std::endl;
    }

    void addModelLayer(const Config& conf, Map* map)
    {
      ModelLayerOptions options( conf );
      options.name() = conf.value( "name" );
      options.driver() = ModelSourceOptions( conf );
      ModelLayer* layer = new ModelLayer(options);
      map->addLayer(layer);
      if (layer->getStatus().isError())
            OE_WARN << LC << "Layer \"" << layer->getName() << "\" : " << layer->getStatus().toString() << std::endl;
    }

    void addMaskLayer(const Config& conf, Map* map)
    {
      MaskLayerOptions options(conf);
      options.name() = conf.value( "name" );
      options.driver() = MaskSourceOptions(options);
      MaskLayer* layer = new MaskLayer(options);
      map->addLayer(layer);
      if (layer->getStatus().isError())
            OE_WARN << LC << "Layer \"" << layer->getName() << "\" : " << layer->getStatus().toString() << std::endl;
    }

    // support for "special" extension names (convenience and backwards compat)
    Extension* createSpecialExtension(const Config& conf)
    {
      // special support for the default sky extension:
      if (conf.key() == "sky" && !conf.hasValue("driver"))
            return Extension::create("sky_simple", conf);

      if (conf.key() == "ocean" && !conf.hasValue("driver"))
            return Extension::create("ocean_simple", conf);

      return 0L;
    }

    bool addLayer(const Config& conf, Map* map)
    {
      std::string name = conf.key();
      Layer* layer = Layer::create(name, conf);
      if (layer)
      {
            map->addLayer(layer);
            if (layer->getStatus().isError())
                OE_WARN << LC << "Layer \"" << layer->getName() << "\" : " << layer->getStatus().toString() << std::endl;
      }
      return layer != 0L;
    }

osg::Node*
EarthFileSerializer2::deserialize( const Config& conf, const std::string& referrer ) const
{
    // First, pre-load any extension DLLs.
    preloadExtensionLibs(conf);
    preloadExtensionLibs(conf.child("extensions"));
    preloadExtensionLibs(conf.child("external"));

    MapOptions mapOptions( conf.child( "options" ) );

    // legacy: check for name/type in top-level attrs:
    if ( conf.hasValue( "name" ) || conf.hasValue( "type" ) )
    {
      Config legacy;
      if ( conf.hasValue("name") ) legacy.add( "name", conf.value("name") );
      if ( conf.hasValue("type") ) legacy.add( "type", conf.value("type") );
      mapOptions.mergeConfig( legacy );
    }

    Map* map = new Map( mapOptions );

    // Start a batch update of the map:
    map->beginUpdate();

    // Read all the elevation layers in FIRST so other layers can access them for things like clamping.
    for(ConfigSet::const_iterator i = conf.children().begin(); i != conf.children().end(); ++i)
    {
      if ( i->key() == "elevation" || i->key() == "heightfield" )
      {
            addElevationLayer( *i, map );
      }
    }

    Config externalConfig;
    std::vector<osg::ref_ptr<Extension> > extensions;

    // Read the layers in LAST (otherwise they will not benefit from the cache/profile configuration)
    for(ConfigSet::const_iterator i = conf.children().begin(); i != conf.children().end(); ++i)
    {
      if (i->key() == "options" || i->key() == "name" || i->key() == "type" || i->key() == "version")
      {
            // nop - handled earlier
      }

      else if ( i->key() == "image" )
      {
            addImageLayer( *i, map );
      }

      else if ( i->key() == "model" )
      {
            addModelLayer( *i, map );
      }

      else if ( i->key() == "mask" )
      {
            addMaskLayer( *i, map );
      }

      else if ( i->key() == "external" || i->key() == "extensions" )
      {
            externalConfig = *i;
            
            for(ConfigSet::const_iterator e = i->children().begin(); e != i->children().end(); ++e)
            {
                Extension* extension = loadExtension(*e);
                if (extension)
                  extensions.push_back(extension);
                //addExtension( *e, mapNode.get() );
            }
      }

      else if ( !isReservedWord(i->key()) ) // plugins/extensions.
      {
            bool addedLayer = addLayer(*i, map); //mapNode.get());

            if ( !addedLayer )
            {
                Extension* extension = loadExtension(*i);
                if (extension)
                  extensions.push_back(extension);
                //OE_INFO << LC << "Tried to load \"" << i->key() << "\" as a layer; now trying extension\n";
                //addExtension( *i, mapNode.get() );
            }
      }
    }

    // Complete the batch update of the map
    map->endUpdate();

    // Yes, MapOptions and MapNodeOptions share the same Config node. Weird but true.
    MapNodeOptions mapNodeOptions( conf.child("options") );

    // Create a map node.
    osg::ref_ptr<MapNode> mapNode = new MapNode( map, mapNodeOptions );

    // Apply the external conf if there is one.
    if (!externalConfig.empty())
    {
      mapNode->externalConfig() = externalConfig;
    }

    // Install the extensions
    for (unsigned i = 0; i < extensions.size(); ++i)
    {
      mapNode->addExtension(extensions.at(i).get());
    }

    // return the topmost parent of the mapnode. It's possible that
    // an extension added parents!
    osg::Node* top = mapNode.release();

    while( top->getNumParents() > 0 )
      top = top->getParent(0);

    return top;
}
从上面可以看到
1 earth插件 map 统筹OE中所有"层"的概念,支持多层影像,高程,模型,镂空层(mask)等
2各个层相应配置的属性由指定的Option类从Config中获取,如果对应Config中有Option类指定元素相应值的配置Option将其写入
为了统筹OE各个层的属性配置,OE提供了ConfigOptions类,ConfigOptions类就是对某个Config类的封装,提供了到Config层次上的调用,例如Config赋值,拼接等

为不同层的属性配置提供了存储载体,结合上文map包含的图层有以下关系
通过这些类,可以很方便的将特定的XML节点下属性配置生成Config归类到某一个图层中,以下列出部分图层的属性(仅供参考)

MapOptions:XML<<options>>节点下配置的信息,主要是配置地形渲染时的属性;包括如下
<elevation_interploation> 插值,nearset 最近点插值average 最近点平均值 bilinear 线性插值,triangulate 三角面片插值
<elevation_tile_size> 瓦片大小
<elevation_texture_size> 纹理大小
<overlay_wapring> 纹理装载
<overlay_blending>混合
<overlay_minmapping>纹理映射
<overlay_texture_size>
<overlay_attach_stencil>模板


ImageLayerOptions: XML<<image>>节点下配置的信息,很明显,影像属性配置,部分属性值




<nodata_image> 无数据显示的url
<opacity>    透明度
<min_range> 最小可视范围
<max_range> 最大可视范围
<min_level>最小显示细节层级
<max_level>最大显示细节层级
<min_resolution> 数据的最小分辨率,单位的像素
<max_resolution>数据的最大分辨率,单位的像素
<enable> 是否包含进map层
<visible> 可视
ElevationLayerOptions: XML<<elevation>>or<<heightfield>>节点下配置的信息,高程层

<min_level>最小显示细节层级
<max_level>最大显示细节层级
<min_resolution> 数据的最小分辨率,单位的像素
<max_resolution>数据的最大分辨率,单位的像素
<enable> 是否包含进map层
ModelLayerOptions: XML<<Model>>节点下配置的信息 模型层装载 矢量数据,模型,几何体等
<name>
<driver>
<enable><span style="font-family:Arial, Helvetica, sans-serif;">是否包含进map层</span>
<visible>是否可见
<overLay>
MaskLayerOptions: XML<<mask>>节点配置下的信息,镂空层

一个比较特殊的节点 ext(Config); 暂且叫他功能层,XML <<external>>,它由mapNode直接读取配置信息,实现一些经常用到的功能点,例如 视点定位 <<<viewpoint>> 星空时刻设置<<sky>>

最后的masklayer
<mask driver="feature" name="mask">
      <features driver="ogr">
            <geometry>
                POLYGON(( -111.0466 42.0015 0, -111.0467 40.9979 0, -109.0501 41.0007 0, -109.0452 36.9991 0, -114.0506 37.0004 0, -114.0417 41.9937 0))
            </geometry>
      </features>
      <profile>global-geodetic</profile>
    </mask>

liyihongcug 发表于 2020-3-11 15:37:09

api开发的方式   char *driver = Tcl_GetString(objv);
2001                char *format = Tcl_GetString(objv);
2002                if (format && strlen(format) > 0 &&
2003                    strcmp(format, "json") != 0 && strcmp(format, "gml") != 0) {
2004                    Tcl_AppendResult(interp, "unknown format \"", format,
2005                                     "\": should be 'json' or 'gml'", (char*)NULL);
2006                    return TCL_ERROR;
2007                }
2008                char *typeName = Tcl_GetString(objv);
2009                osgEarth::Drivers::FeatureMaskOptions maskOpts;
2010                std::string url;
2011                if (objc > 8) {
2012                    if (driver == 'w' && strcmp(driver, "wkt") == 0) {
2013                      url = Tcl_GetString(objv);
2014                      if (url.empty()) {
2015                            Tcl_AppendResult(interp, "Empty WKT length",
2016                                           (char*)NULL);
2017                            return TCL_ERROR;
2018                      }
2019                    } else {
2020                      char *urlIn = Tcl_GetString(objv);
2021                      url = g_renderer->getCanonicalPath(std::string(urlIn));
2022                      if (url.empty()) {
2023                            Tcl_AppendResult(interp, "file not found: \"",
2024                                           urlIn, "\"", (char*)NULL);
2025                            return TCL_ERROR;
2026                      }
2027                    }
2028                }
2029                if (driver == 'd' && strcmp(driver, "db") == 0) {
2030                    osgEarth::Drivers::OGRFeatureOptions opts;
2031                    opts.name() = name;
2032                    opts.connection() = url;
2033                    opts.layer() = typeName;
2034                    maskOpts.featureOptions() = opts;
2035                } else if (driver == 'o' && strcmp(driver, "ogr") == 0) {
2036                    osgEarth::Drivers::OGRFeatureOptions opts;
2037                    opts.name() = name;
2038                    opts.url() = url;
2039                    maskOpts.featureOptions() = opts;
2040                } else if (driver == 't' && strcmp(driver, "tfs") == 0) {
2041                    osgEarth::Drivers::TFSFeatureOptions opts;
2042                    opts.name() = name;
2043                    opts.url() = url;
2044                    opts.format() = format;
2045                    maskOpts.featureOptions() = opts;
2046                } else if (driver == 'w' && strcmp(driver, "wfs") == 0) {
2047                    osgEarth::Drivers::WFSFeatureOptions opts;
2048                    opts.name() = name;
2049                    opts.url() = url;
2050                    opts.outputFormat() = format;
2051                    opts.typeName() = typeName;
2052                    maskOpts.featureOptions() = opts;
2053                } else if (driver == 'w' && strcmp(driver, "wkt") == 0) {
2054                    // Inline geometry, url is length of following data
2055                    char *ptr;
2056                    long len = strtol(url.c_str(), &ptr, 10);
2057                    if (len <= 0 || *ptr != '\0') {
2058                      Tcl_AppendResult(interp, "Failed to parse WKT length: \"",
2059                                         url.c_str(), "\"", (char*)NULL);
2060                      return TCL_ERROR;
2061                    }
2062                    char *wkt = (char *)malloc((size_t)len);
2063                    if (!SocketRead(wkt, len)) {
2064                      free(wkt);
2065                      Tcl_AppendResult(interp, "Failed to read WKT string",
2066                                         (char*)NULL);
2067                      return TCL_ERROR;
2068                    }
2069                    osgEarth::Drivers::OGRFeatureOptions opts;
2070                    opts.name() = name;
2071                    TRACE("Geometry: \"%s\"", wkt);
2072                    osgEarth::Config conf("geometry", std::string(wkt));
2073                    free(wkt);
2074                    opts.geometryConfig() = conf;
2075                    maskOpts.featureOptions() = opts;
2076                } else if (driver == 'w' && strcmp(driver, "wkt_file") == 0) {
2077                    osgEarth::Drivers::OGRFeatureOptions opts;
2078                    opts.name() = name;
2079                    opts.geometryUrl() = url;
2080                    maskOpts.featureOptions() = opts;
2081                } else {
2082                    Tcl_AppendResult(interp, "unknown mask driver \"", driver,
2083                                     "\": should be 'db', 'ogr', 'tfs', 'wfs', 'wkt', or 'wkt_file'", (char*)NULL);
2084                    return TCL_ERROR;
2085                }
2086                int minLOD = 0;
2087                if (objc > 9) {
2088                    if (Tcl_GetIntFromObj(interp, objv, &minLOD) != TCL_OK) {
2089                      return TCL_ERROR;
2090                    }
2091                }
2092                g_renderer->addTerrainMaskLayer(name, maskOpts, (unsigned)minLOD);

liyihongcug 发表于 2020-3-11 15:57:00

本帖最后由 liyihongcug 于 2020-3-11 16:18 编辑

例如
<options type="geocentric">
    <cache path="d:/test/cache_dir" type="filesystem" />
    <terrain first_lod="0" tile_size="17" />
</options>
<options>
      <lighting>false</lighting>
      <overlay_blending>false</overlay_blending>
      <terrain min_lod="8"/>
    </options>

MapOptions( const ConfigOptions& options =ConfigOptions() )
            : ConfigOptions          ( options ),
            _cachePolicy         ( ),
            _cstype                ( CSTYPE_GEOCENTRIC ),
            _referenceURI          ( "" ),
            _elevationInterpolation( INTERP_BILINEAR )
MapOptions MapOptions.cpp
      optional<std::string>            _name;
      optional<ProfileOptions>         _profileOptions;
      optional<CacheOptions>         _cacheOptions;
      optional<CachePolicy>            _cachePolicy;
      optional<CoordinateSystemType>   _cstype;
      optional<std::string>            _referenceURI;
      optional<ElevationInterpolation> _elevationInterpolation;

terrain的源文件在TerrainOptions.cpp
MapOptions:XML<<options>>节点下配置的信息,主要是配置地形渲染时的属性;包括如下
<elevation_interploation> 插值,nearset 最近点插值average 最近点平均值 bilinear 线性插值,triangulate 三角面片插值
<elevation_tile_size> 瓦片大小
<elevation_texture_size> 纹理大小
<overlay_wapring> 纹理装载
<overlay_blending>混合
<overlay_minmapping>纹理映射
<overlay_texture_size>
<overlay_attach_stencil>模板   2.8里没有这些参数,2.10才有


TerrainOptions::getConfig() const
{
    Config conf = DriverConfigOptions::getConfig();
    conf.key() = "terrain";
   
    conf.updateIfSet( "tile_size", _tileSize );
    conf.updateIfSet( "vertical_scale", _verticalScale );
    conf.updateIfSet( "vertical_offset", _verticalOffset );
    conf.updateIfSet( "min_tile_range_factor", _minTileRangeFactor );
    conf.updateIfSet( "range_factor", _minTileRangeFactor );
    conf.updateIfSet( "max_lod", _maxLOD );
    conf.updateIfSet( "min_lod", _minLOD );
    conf.updateIfSet( "first_lod", _firstLOD );
    conf.updateIfSet( "lighting", _enableLighting );
    conf.updateIfSet( "attenuation_distance", _attenuationDistance );
    conf.updateIfSet( "lod_transition_time", _lodTransitionTimeSeconds );
    conf.updateIfSet( "mipmapping", _enableMipmapping );
    conf.updateIfSet( "cluster_culling", _clusterCulling );
    conf.updateIfSet( "blending", _enableBlending );
    conf.updateIfSet( "mercator_fast_path", _mercatorFastPath );
    conf.updateIfSet( "min_normal_map_lod", _minNormalMapLOD );
    conf.updateIfSet( "gpu_tessellation", _gpuTessellation );
    conf.updateIfSet( "debug", _debug );
    conf.updateIfSet( "bin_number", _binNumber );
    conf.updateIfSet( "min_expiry_time", _minExpiryTime);
    conf.updateIfSet( "min_expiry_frames", _minExpiryFrames);

    //Save the filter settings
        conf.updateIfSet("mag_filter","LINEAR",                _magFilter,osg::Texture::LINEAR);
    conf.updateIfSet("mag_filter","LINEAR_MIPMAP_LINEAR",_magFilter,osg::Texture::LINEAR_MIPMAP_LINEAR);
    conf.updateIfSet("mag_filter","LINEAR_MIPMAP_NEAREST", _magFilter,osg::Texture::LINEAR_MIPMAP_NEAREST);
    conf.updateIfSet("mag_filter","NEAREST",               _magFilter,osg::Texture::NEAREST);
    conf.updateIfSet("mag_filter","NEAREST_MIPMAP_LINEAR", _magFilter,osg::Texture::NEAREST_MIPMAP_LINEAR);
    conf.updateIfSet("mag_filter","NEAREST_MIPMAP_NEAREST",_magFilter,osg::Texture::NEAREST_MIPMAP_NEAREST);
    conf.updateIfSet("min_filter","LINEAR",                _minFilter,osg::Texture::LINEAR);
    conf.updateIfSet("min_filter","LINEAR_MIPMAP_LINEAR",_minFilter,osg::Texture::LINEAR_MIPMAP_LINEAR);
    conf.updateIfSet("min_filter","LINEAR_MIPMAP_NEAREST", _minFilter,osg::Texture::LINEAR_MIPMAP_NEAREST);
    conf.updateIfSet("min_filter","NEAREST",               _minFilter,osg::Texture::NEAREST);
    conf.updateIfSet("min_filter","NEAREST_MIPMAP_LINEAR", _minFilter,osg::Texture::NEAREST_MIPMAP_LINEAR);
    conf.updateIfSet("min_filter","NEAREST_MIPMAP_NEAREST",_minFilter,osg::Texture::NEAREST_MIPMAP_NEAREST);

    return conf;
}
页: [1]
查看完整版本: API加载earth文件的解析