首页 > 代码库 > World Wind Java开发之八——加载本地缓存文件构建大范围三维场景
World Wind Java开发之八——加载本地缓存文件构建大范围三维场景
上一篇博客主要是针对小文件直接导入WW中显示,然而当文件特别大时,这种方式就不太可行。因此要将大文件切片,生成本地缓存,WW可以加载本地缓存文件,保障浏览场景时的流畅性。
1、使用Global Mapper生成WW缓存切片
使用Global Mapper生成WW缓存切片的步骤已上传至使用GlobalMapper生成WW缓存切片,这里不再赘述。生成后的切片可以放在任意文件夹下,目前参考了WWJ自带的例子InstallImageryAndElevationsDemo,暂时将数据放在C:\ProgramData\WorldWindInstalled目录下,如下图所示。
生成的XML文件修改如下:
2、参照InstallImageryAndElevationsDemo示例实现缓存文件的初始化加载
未多做修改,写了一个加载缓存数据的类LoadCacheData,代码如下所示。
/** * @Copyright 2014-2020 @奔跑的鸡丝 **/ package edu.whu.vge.util; import edu.whu.vge.util.JavaCheckBoxTree.CheckBoxTreeNode; import gov.nasa.worldwind.Factory; import gov.nasa.worldwind.WorldWind; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.avlist.AVList; import gov.nasa.worldwind.avlist.AVListImpl; import gov.nasa.worldwind.awt.WorldWindowGLCanvas; import gov.nasa.worldwind.cache.FileStore; import gov.nasa.worldwind.exception.WWRuntimeException; import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.globes.Earth; import gov.nasa.worldwind.globes.ElevationModel; import gov.nasa.worldwind.layers.Layer; import gov.nasa.worldwind.terrain.CompoundElevationModel; import gov.nasa.worldwind.util.DataConfigurationFilter; import gov.nasa.worldwind.util.DataConfigurationUtils; import gov.nasa.worldwind.util.Logging; import gov.nasa.worldwind.util.WWIO; import gov.nasa.worldwind.util.WWXML; import java.awt.Component; import java.io.File; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; import javax.xml.xpath.XPath; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * @项目名称:GF_ZHJCYPG * @类名称:LoadCacheData * @类描述: 加载缓存数据 * @创建人:奔跑的鸡丝 * @创建时间:2014-12-19 下午4:30:49 * @修改备注: * @版本: */ public class LoadCacheData { private static WorldWindowGLCanvas worldWindowGLCanvas; private static JTree layerJTree; /** * * 创建一个新的实例 LoadCacheData. * * @param worWindowGLCanvas */ public LoadCacheData(WorldWindowGLCanvas worWindowGLCanvas, JTree jTree) { LoadCacheData.setWorldWindowGLCanvas(worWindowGLCanvas); LoadCacheData.setLayerJTree(jTree); } /** * * @方法名称: loadPreviouslyInstalledData ; * @方法描述: 加载已有的缓存文件 ; * @参数 : * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午7:06:09; * @throws */ public void loadPreviouslyInstalledData() { Thread thread = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub loadInstalledDataFromFileStore(WorldWind.getDataFileStore()); } }); thread.start(); } /** * * @方法名称: loadInstalledDataFromFileStore ; * @方法描述: TODO ; * @参数 :@param fileStore * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午7:06:42; * @throws */ protected void loadInstalledDataFromFileStore(FileStore fileStore) { // 便利已有的缓存文件 for (File file : fileStore.getLocations()) { // 文件存在并且是缓存文件目录 if (file.exists() && fileStore.isInstallLocation(file.getPath())) { System.out.println(file.getPath()); loadInstalledDataFromDirectory(file); } } } /** * * @方法名称: loadInstalledDataFromDirectory ; * @方法描述: 从文件目录加载缓存数据 ; * @参数 :@param dir * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午7:43:36; * @throws */ private void loadInstalledDataFromDirectory(File dir) { /** * 获取缓存文件xml配置文件的在缓存文件目录的相对目录,如Landsat\Landsat.xml */ String[] names = WWIO.listDescendantFilenames(dir, new DataConfigurationFilter(), false); if (names == null || names.length == 0) return; for (String filename : names) { Document doc = null; try { // 根据缓存文件XML描述文件创建Document对象 File dataConfigFile = new File(dir, filename); doc = WWXML.openDocument(dataConfigFile); doc = DataConfigurationUtils.convertToStandardDataConfigDocument(doc); } catch (WWRuntimeException e) { e.printStackTrace(); } if (doc == null) continue; // 由于数据配置文件来自于已有的文件,因此不能保证它是由当前版本WW's Installer // 产生的。可能是由之前版本或其他应用程序产生的,因此要为可能缺失的参数设置备用值(这些参数需要用来构建图层或高程模拟) AVList params = new AVListImpl(); setFallbackParams(doc, filename, params); // 添加数据 addInstalledData(doc, params); } } /** * * @方法名称: setFallbackParams ; * @方法描述: 设置备用参数值 ; * @参数 :@param dataConfig :数据配置XML文件 * @参数 :@param filename :文件名 * @参数 :@param params :参数列表 * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-20 下午12:21:03; * @throws */ private void setFallbackParams(Document dataConfig, String filename, AVList params) { XPath xpath = WWXML.makeXPath(); Element domElement = dataConfig.getDocumentElement(); // If the data configuration document doesn't define a cache name, then // compute one using the file's path // relative to its file cache directory. String s = WWXML.getText(domElement, "DataCacheName", xpath); if (s == null || s.length() == 0) DataConfigurationUtils.getDataConfigCacheName(filename, params); // If the data configuration document doesn't define the data's extreme // elevations, provide default values using // the minimum and maximum elevations of Earth. String type = DataConfigurationUtils.getDataConfigType(domElement); if (type.equalsIgnoreCase("ElevationModel")) { if (WWXML.getDouble(domElement, "ExtremeElevations/@min", xpath) == null) params.setValue(AVKey.ELEVATION_MIN, Earth.ELEVATION_MIN); if (WWXML.getDouble(domElement, "ExtremeElevations/@max", xpath) == null) params.setValue(AVKey.ELEVATION_MAX, Earth.ELEVATION_MAX); } } /** * * @方法名称: addInstalledData ; * @方法描述: 添加缓存数据 ; * @参数 :@param dataConfig * @参数 :@param params * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-20 下午12:22:29; * @throws */ private void addInstalledData(final Document dataConfig, final AVList params) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater(new Runnable() { public void run() { addInstalledData(dataConfig, params); } }); } else { addInstalledCacheData(dataConfig.getDocumentElement(), params); } } /** * * @方法名称: addInstalledCacheData ; * @方法描述: 添加已有缓存数据 ; * @参数 :@param domElement :数据XML描述文件 * @参数 :@param params :参数列表 * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午8:02:21; * @throws */ public void addInstalledCacheData(final Element domElement, final AVList params) { if (domElement == null) { String message = Logging.getMessage("nullValue.DocumentIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } String description = getDescription(domElement); // 图层名称 Sector sector = getSector(domElement); // 图层范围 System.out.println(description); System.out.println(sector); addToWorldWindow(domElement, params); } /** * * @方法名称: addToWorldWindow ; * @方法描述: 将缓存文件加入WW ; * @参数 :@param domElement * @参数 :@param params * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午4:44:08; * @throws */ private void addToWorldWindow(Element domElement, AVList params) { String type = DataConfigurationUtils.getDataConfigType(domElement); if (type == null) return; if (type.equalsIgnoreCase("Layer")) { addLayerToWorldWindow(domElement, params); } else if (type.equalsIgnoreCase("ElevationModel")) { addElevationModelToWorldWindow(domElement, params); } } /** * * @方法名称: addLayerToWorldWindow ; * @方法描述: 向WW中添加图层 ; * @参数 :@param domElement * @参数 :@param params * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午4:45:06; * @throws */ private void addLayerToWorldWindow(Element domElement, AVList params) { Layer layer = null; try { // Factory创建的图层默认是不可见的 Factory factory = (Factory) WorldWind.createConfigurationComponent(AVKey.LAYER_FACTORY); layer = (Layer) factory.createFromConfigSource(domElement, params); } catch (Exception e) { String message = Logging.getMessage( "generic.CreationFromConfigurationFailed", DataConfigurationUtils.getDataConfigDisplayName(domElement)); Logging.logger().log(java.util.logging.Level.SEVERE, message, e); } if (layer == null) return; layer.setEnabled(true); // 设置图层可见 // 添加至WW if (!getWorldWindowGLCanvas().getModel().getLayers().contains(layer)) { getWorldWindowGLCanvas().getModel().getLayers().add(layer); // System.out.println(pLayerTree.getModel().getRoot().toString()); Object rootObject = layerJTree.getModel().getRoot(); if (!layerJTree.getModel().isLeaf(rootObject)) { int count = layerJTree.getModel().getChildCount(rootObject); for (int i = 0; i < count; i++) { String childNodeNameString = layerJTree.getModel().getChild( rootObject, i).toString(); if (childNodeNameString.equals("影像图层")) { ((DefaultMutableTreeNode) layerJTree.getModel().getChild( rootObject, i)).add(new CheckBoxTreeNode( layer.getName())); layerJTree.updateUI(); } } } } } /** * * @方法名称: addElevationModelToWorldWindow ; * @方法描述: 添加高程图层 ; * @参数 :@param domElement * @参数 :@param params * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午4:51:37; * @throws */ private void addElevationModelToWorldWindow(Element domElement, AVList params) { ElevationModel em = null; try { Factory factory = (Factory) WorldWind.createConfigurationComponent(AVKey.ELEVATION_MODEL_FACTORY); em = (ElevationModel) factory.createFromConfigSource(domElement, params); } catch (Exception e) { String message = Logging.getMessage( "generic.CreationFromConfigurationFailed", DataConfigurationUtils.getDataConfigDisplayName(domElement)); Logging.logger().log(java.util.logging.Level.SEVERE, message, e); } if (em == null) return; ElevationModel defaultElevationModel = getWorldWindowGLCanvas().getModel().getGlobe().getElevationModel(); if (defaultElevationModel instanceof CompoundElevationModel) { if (!((CompoundElevationModel) defaultElevationModel).containsElevationModel(em)) ((CompoundElevationModel) defaultElevationModel).addElevationModel(em); } else { CompoundElevationModel cm = new CompoundElevationModel(); cm.addElevationModel(defaultElevationModel); cm.addElevationModel(em); getWorldWindowGLCanvas().getModel().getGlobe().setElevationModel(cm); } } /** * 获取缓存文件类型 获取缓存配置文件描述:是Layer或者是Elevation * * @方法名称: getDescription ; * @方法描述: TODO ; * @参数 :@param domElement * @参数 :@return * @返回类型: String ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午4:53:26; * @throws */ private String getDescription(Element domElement) { String displayName = DataConfigurationUtils.getDataConfigDisplayName(domElement); String type = DataConfigurationUtils.getDataConfigType(domElement); StringBuilder sb = new StringBuilder(displayName); if (type.equalsIgnoreCase("Layer")) { sb.append(" (Layer)"); } else if (type.equalsIgnoreCase("ElevationModel")) { sb.append(" (Elevations)"); } return sb.toString(); } /** * 获取图层范围 * * @方法名称: getSector ; * @方法描述: TODO ; * @参数 :@param domElement * @参数 :@return * @返回类型: Sector ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-19 下午4:54:17; * @throws */ protected static Sector getSector(Element domElement) { return WWXML.getSector(domElement, "Sector", null); } public static WorldWindowGLCanvas getWorldWindowGLCanvas() { return worldWindowGLCanvas; } public static void setWorldWindowGLCanvas( WorldWindowGLCanvas worldWindowGLCanvas) { LoadCacheData.worldWindowGLCanvas = worldWindowGLCanvas; } public JTree getLayerJTree() { return layerJTree; } public static void setLayerJTree(JTree layerJTree) { LoadCacheData.layerJTree = layerJTree; } }
3、高程数据的加载
高程数据采用NASA的30m公开DEM数据,使用World Wind Server发布即可,详见前面的搭建本地World wind Severe服务器。最终实现效果图如下图所示。
PS:年末各种忙啊,项目总算结题,明天小组年会,预祝一切顺利!欢迎大家留言交流,共享自己的学习笔记。
World Wind Java的资料实在太少啦,断断续续总算搭建起了三维框架,后面陆续添加功能,计划做一个基于新安江模型的洪涝模拟仿真模块,将之前做的洪涝模拟和参数率定、径流模拟全部整合到自己的这个平台上来。
World Wind Java开发之八——加载本地缓存文件构建大范围三维场景
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。