http://blog.csdn.net/giser_whu/article/details/42044599

上一篇博客主要是针对小文件直接导入WW中显示,然而当文件特别大时,这种方式就不太可行。因此要将大文件切片,生成本地缓存,WW可以加载本地缓存文件,保障浏览场景时的流畅性。

1、使用Global Mapper生成WW缓存切片

使用Global Mapper生成WW缓存切片的步骤已上传至使用GlobalMapper生成WW缓存切片,这里不再赘述。生成后的切片可以放在任意文件夹下,目前参考了WWJ自带的例子InstallImageryAndElevationsDemo,暂时将数据放在C:\ProgramData\WorldWindInstalled目录下,如下图所示。
生成的XML文件修改如下:

2、参照InstallImageryAndElevationsDemo示例实现缓存文件的初始化加载

未多做修改,写了一个加载缓存数据的类LoadCacheData,代码如下所示。
  1. /**
  2. * @Copyright 2014-2020 @奔跑的鸡丝
  3. **/
  4. package edu.whu.vge.util;
  5. import edu.whu.vge.util.JavaCheckBoxTree.CheckBoxTreeNode;
  6. import gov.nasa.worldwind.Factory;
  7. import gov.nasa.worldwind.WorldWind;
  8. import gov.nasa.worldwind.avlist.AVKey;
  9. import gov.nasa.worldwind.avlist.AVList;
  10. import gov.nasa.worldwind.avlist.AVListImpl;
  11. import gov.nasa.worldwind.awt.WorldWindowGLCanvas;
  12. import gov.nasa.worldwind.cache.FileStore;
  13. import gov.nasa.worldwind.exception.WWRuntimeException;
  14. import gov.nasa.worldwind.geom.Sector;
  15. import gov.nasa.worldwind.globes.Earth;
  16. import gov.nasa.worldwind.globes.ElevationModel;
  17. import gov.nasa.worldwind.layers.Layer;
  18. import gov.nasa.worldwind.terrain.CompoundElevationModel;
  19. import gov.nasa.worldwind.util.DataConfigurationFilter;
  20. import gov.nasa.worldwind.util.DataConfigurationUtils;
  21. import gov.nasa.worldwind.util.Logging;
  22. import gov.nasa.worldwind.util.WWIO;
  23. import gov.nasa.worldwind.util.WWXML;
  24. import java.awt.Component;
  25. import java.io.File;
  26. import javax.swing.JTree;
  27. import javax.swing.SwingUtilities;
  28. import javax.swing.tree.DefaultMutableTreeNode;
  29. import javax.xml.xpath.XPath;
  30. import org.w3c.dom.Document;
  31. import org.w3c.dom.Element;
  32. /**
  33. * @项目名称:GF_ZHJCYPG
  34. * @类名称:LoadCacheData
  35. * @类描述: 加载缓存数据
  36. * @创建人:奔跑的鸡丝
  37. * @创建时间:2014-12-19 下午4:30:49
  38. * @修改备注:
  39. * @版本:
  40. */
  41. public class LoadCacheData
  42. {
  43. private static WorldWindowGLCanvas worldWindowGLCanvas;
  44. private static JTree layerJTree;
  45. /**
  46. *
  47. * 创建一个新的实例 LoadCacheData.
  48. *
  49. * @param worWindowGLCanvas
  50. */
  51. public LoadCacheData(WorldWindowGLCanvas worWindowGLCanvas, JTree jTree)
  52. {
  53. LoadCacheData.setWorldWindowGLCanvas(worWindowGLCanvas);
  54. LoadCacheData.setLayerJTree(jTree);
  55. }
  56. /**
  57. *
  58. * @方法名称: loadPreviouslyInstalledData ;
  59. * @方法描述: 加载已有的缓存文件 ;
  60. * @参数 :
  61. * @返回类型: void ;
  62. * @创建人:奔跑的鸡丝 ;
  63. * @创建时间:2014-12-19 下午7:06:09;
  64. * @throws
  65. */
  66. public void loadPreviouslyInstalledData()
  67. {
  68. Thread thread = new Thread(new Runnable()
  69. {
  70. @Override
  71. public void run()
  72. {
  73. // TODO Auto-generated method stub
  74. loadInstalledDataFromFileStore(WorldWind.getDataFileStore());
  75. }
  76. });
  77. thread.start();
  78. }
  79. /**
  80. *
  81. * @方法名称: loadInstalledDataFromFileStore ;
  82. * @方法描述: TODO ;
  83. * @参数 :@param fileStore
  84. * @返回类型: void ;
  85. * @创建人:奔跑的鸡丝 ;
  86. * @创建时间:2014-12-19 下午7:06:42;
  87. * @throws
  88. */
  89. protected void loadInstalledDataFromFileStore(FileStore fileStore)
  90. {
  91. // 便利已有的缓存文件
  92. for (File file : fileStore.getLocations())
  93. {
  94. // 文件存在并且是缓存文件目录
  95. if (file.exists() && fileStore.isInstallLocation(file.getPath()))
  96. {
  97. System.out.println(file.getPath());
  98. loadInstalledDataFromDirectory(file);
  99. }
  100. }
  101. }
  102. /**
  103. *
  104. * @方法名称: loadInstalledDataFromDirectory ;
  105. * @方法描述: 从文件目录加载缓存数据 ;
  106. * @参数 :@param dir
  107. * @返回类型: void ;
  108. * @创建人:奔跑的鸡丝 ;
  109. * @创建时间:2014-12-19 下午7:43:36;
  110. * @throws
  111. */
  112. private void loadInstalledDataFromDirectory(File dir)
  113. {
  114. /**
  115. * 获取缓存文件xml配置文件的在缓存文件目录的相对目录,如Landsat\Landsat.xml
  116. */
  117. String[] names = WWIO.listDescendantFilenames(dir,
  118. new DataConfigurationFilter(), false);
  119. if (names == null || names.length == 0)
  120. return;
  121. for (String filename : names)
  122. {
  123. Document doc = null;
  124. try
  125. {
  126. // 根据缓存文件XML描述文件创建Document对象
  127. File dataConfigFile = new File(dir, filename);
  128. doc = WWXML.openDocument(dataConfigFile);
  129. doc = DataConfigurationUtils.convertToStandardDataConfigDocument(doc);
  130. }
  131. catch (WWRuntimeException e)
  132. {
  133. e.printStackTrace();
  134. }
  135. if (doc == null)
  136. continue;
  137. // 由于数据配置文件来自于已有的文件,因此不能保证它是由当前版本WW's Installer
  138. // 产生的。可能是由之前版本或其他应用程序产生的,因此要为可能缺失的参数设置备用值(这些参数需要用来构建图层或高程模拟)
  139. AVList params = new AVListImpl();
  140. setFallbackParams(doc, filename, params);
  141. // 添加数据
  142. addInstalledData(doc, params);
  143. }
  144. }
  145. /**
  146. *
  147. * @方法名称: setFallbackParams ;
  148. * @方法描述: 设置备用参数值 ;
  149. * @参数 :@param dataConfig :数据配置XML文件
  150. * @参数 :@param filename :文件名
  151. * @参数 :@param params :参数列表
  152. * @返回类型: void ;
  153. * @创建人:奔跑的鸡丝 ;
  154. * @创建时间:2014-12-20 下午12:21:03;
  155. * @throws
  156. */
  157. private void setFallbackParams(Document dataConfig, String filename,
  158. AVList params)
  159. {
  160. XPath xpath = WWXML.makeXPath();
  161. Element domElement = dataConfig.getDocumentElement();
  162. // If the data configuration document doesn't define a cache name, then
  163. // compute one using the file's path
  164. // relative to its file cache directory.
  165. String s = WWXML.getText(domElement, "DataCacheName", xpath);
  166. if (s == null || s.length() == 0)
  167. DataConfigurationUtils.getDataConfigCacheName(filename, params);
  168. // If the data configuration document doesn't define the data's extreme
  169. // elevations, provide default values using
  170. // the minimum and maximum elevations of Earth.
  171. String type = DataConfigurationUtils.getDataConfigType(domElement);
  172. if (type.equalsIgnoreCase("ElevationModel"))
  173. {
  174. if (WWXML.getDouble(domElement, "ExtremeElevations/@min", xpath) == null)
  175. params.setValue(AVKey.ELEVATION_MIN, Earth.ELEVATION_MIN);
  176. if (WWXML.getDouble(domElement, "ExtremeElevations/@max", xpath) == null)
  177. params.setValue(AVKey.ELEVATION_MAX, Earth.ELEVATION_MAX);
  178. }
  179. }
  180. /**
  181. *
  182. * @方法名称: addInstalledData ;
  183. * @方法描述: 添加缓存数据 ;
  184. * @参数 :@param dataConfig
  185. * @参数 :@param params
  186. * @返回类型: void ;
  187. * @创建人:奔跑的鸡丝 ;
  188. * @创建时间:2014-12-20 下午12:22:29;
  189. * @throws
  190. */
  191. private void addInstalledData(final Document dataConfig, final AVList params)
  192. {
  193. if (!SwingUtilities.isEventDispatchThread())
  194. {
  195. SwingUtilities.invokeLater(new Runnable()
  196. {
  197. public void run()
  198. {
  199. addInstalledData(dataConfig, params);
  200. }
  201. });
  202. }
  203. else
  204. {
  205. addInstalledCacheData(dataConfig.getDocumentElement(), params);
  206. }
  207. }
  208. /**
  209. *
  210. * @方法名称: addInstalledCacheData ;
  211. * @方法描述: 添加已有缓存数据 ;
  212. * @参数 :@param domElement :数据XML描述文件
  213. * @参数 :@param params :参数列表
  214. * @返回类型: void ;
  215. * @创建人:奔跑的鸡丝 ;
  216. * @创建时间:2014-12-19 下午8:02:21;
  217. * @throws
  218. */
  219. public void addInstalledCacheData(final Element domElement,
  220. final AVList params)
  221. {
  222. if (domElement == null)
  223. {
  224. String message = Logging.getMessage("nullValue.DocumentIsNull");
  225. Logging.logger().severe(message);
  226. throw new IllegalArgumentException(message);
  227. }
  228. String description = getDescription(domElement); // 图层名称
  229. Sector sector = getSector(domElement); // 图层范围
  230. System.out.println(description);
  231. System.out.println(sector);
  232. addToWorldWindow(domElement, params);
  233. }
  234. /**
  235. *
  236. * @方法名称: addToWorldWindow ;
  237. * @方法描述: 将缓存文件加入WW ;
  238. * @参数 :@param domElement
  239. * @参数 :@param params
  240. * @返回类型: void ;
  241. * @创建人:奔跑的鸡丝 ;
  242. * @创建时间:2014-12-19 下午4:44:08;
  243. * @throws
  244. */
  245. private void addToWorldWindow(Element domElement, AVList params)
  246. {
  247. String type = DataConfigurationUtils.getDataConfigType(domElement);
  248. if (type == null)
  249. return;
  250. if (type.equalsIgnoreCase("Layer"))
  251. {
  252. addLayerToWorldWindow(domElement, params);
  253. }
  254. else if (type.equalsIgnoreCase("ElevationModel"))
  255. {
  256. addElevationModelToWorldWindow(domElement, params);
  257. }
  258. }
  259. /**
  260. *
  261. * @方法名称: addLayerToWorldWindow ;
  262. * @方法描述: 向WW中添加图层 ;
  263. * @参数 :@param domElement
  264. * @参数 :@param params
  265. * @返回类型: void ;
  266. * @创建人:奔跑的鸡丝 ;
  267. * @创建时间:2014-12-19 下午4:45:06;
  268. * @throws
  269. */
  270. private void addLayerToWorldWindow(Element domElement, AVList params)
  271. {
  272. Layer layer = null;
  273. try
  274. {
  275. // Factory创建的图层默认是不可见的
  276. Factory factory = (Factory) WorldWind.createConfigurationComponent(AVKey.LAYER_FACTORY);
  277. layer = (Layer) factory.createFromConfigSource(domElement, params);
  278. }
  279. catch (Exception e)
  280. {
  281. String message = Logging.getMessage(
  282. "generic.CreationFromConfigurationFailed",
  283. DataConfigurationUtils.getDataConfigDisplayName(domElement));
  284. Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
  285. }
  286. if (layer == null)
  287. return;
  288. layer.setEnabled(true); // 设置图层可见
  289. // 添加至WW
  290. if (!getWorldWindowGLCanvas().getModel().getLayers().contains(layer))
  291. {
  292. getWorldWindowGLCanvas().getModel().getLayers().add(layer);
  293. // System.out.println(pLayerTree.getModel().getRoot().toString());
  294. Object rootObject = layerJTree.getModel().getRoot();
  295. if (!layerJTree.getModel().isLeaf(rootObject))
  296. {
  297. int count = layerJTree.getModel().getChildCount(rootObject);
  298. for (int i = 0; i < count; i++)
  299. {
  300. String childNodeNameString = layerJTree.getModel().getChild(
  301. rootObject, i).toString();
  302. if (childNodeNameString.equals("影像图层"))
  303. {
  304. ((DefaultMutableTreeNode) layerJTree.getModel().getChild(
  305. rootObject, i)).add(new CheckBoxTreeNode(
  306. layer.getName()));
  307. layerJTree.updateUI();
  308. }
  309. }
  310. }
  311. }
  312. }
  313. /**
  314. *
  315. * @方法名称: addElevationModelToWorldWindow ;
  316. * @方法描述: 添加高程图层 ;
  317. * @参数 :@param domElement
  318. * @参数 :@param params
  319. * @返回类型: void ;
  320. * @创建人:奔跑的鸡丝 ;
  321. * @创建时间:2014-12-19 下午4:51:37;
  322. * @throws
  323. */
  324. private void addElevationModelToWorldWindow(Element domElement,
  325. AVList params)
  326. {
  327. ElevationModel em = null;
  328. try
  329. {
  330. Factory factory = (Factory) WorldWind.createConfigurationComponent(AVKey.ELEVATION_MODEL_FACTORY);
  331. em = (ElevationModel) factory.createFromConfigSource(domElement,
  332. params);
  333. }
  334. catch (Exception e)
  335. {
  336. String message = Logging.getMessage(
  337. "generic.CreationFromConfigurationFailed",
  338. DataConfigurationUtils.getDataConfigDisplayName(domElement));
  339. Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
  340. }
  341. if (em == null)
  342. return;
  343. ElevationModel defaultElevationModel = getWorldWindowGLCanvas().getModel().getGlobe().getElevationModel();
  344. if (defaultElevationModel instanceof CompoundElevationModel)
  345. {
  346. if (!((CompoundElevationModel) defaultElevationModel).containsElevationModel(em))
  347. ((CompoundElevationModel) defaultElevationModel).addElevationModel(em);
  348. }
  349. else
  350. {
  351. CompoundElevationModel cm = new CompoundElevationModel();
  352. cm.addElevationModel(defaultElevationModel);
  353. cm.addElevationModel(em);
  354. getWorldWindowGLCanvas().getModel().getGlobe().setElevationModel(cm);
  355. }
  356. }
  357. /**
  358. * 获取缓存文件类型 获取缓存配置文件描述:是Layer或者是Elevation
  359. *
  360. * @方法名称: getDescription ;
  361. * @方法描述: TODO ;
  362. * @参数 :@param domElement
  363. * @参数 :@return
  364. * @返回类型: String ;
  365. * @创建人:奔跑的鸡丝 ;
  366. * @创建时间:2014-12-19 下午4:53:26;
  367. * @throws
  368. */
  369. private String getDescription(Element domElement)
  370. {
  371. String displayName = DataConfigurationUtils.getDataConfigDisplayName(domElement);
  372. String type = DataConfigurationUtils.getDataConfigType(domElement);
  373. StringBuilder sb = new StringBuilder(displayName);
  374. if (type.equalsIgnoreCase("Layer"))
  375. {
  376. sb.append(" (Layer)");
  377. }
  378. else if (type.equalsIgnoreCase("ElevationModel"))
  379. {
  380. sb.append(" (Elevations)");
  381. }
  382. return sb.toString();
  383. }
  384. /**
  385. * 获取图层范围
  386. *
  387. * @方法名称: getSector ;
  388. * @方法描述: TODO ;
  389. * @参数 :@param domElement
  390. * @参数 :@return
  391. * @返回类型: Sector ;
  392. * @创建人:奔跑的鸡丝 ;
  393. * @创建时间:2014-12-19 下午4:54:17;
  394. * @throws
  395. */
  396. protected static Sector getSector(Element domElement)
  397. {
  398. return WWXML.getSector(domElement, "Sector", null);
  399. }
  400. public static WorldWindowGLCanvas getWorldWindowGLCanvas()
  401. {
  402. return worldWindowGLCanvas;
  403. }
  404. public static void setWorldWindowGLCanvas(
  405. WorldWindowGLCanvas worldWindowGLCanvas)
  406. {
  407. LoadCacheData.worldWindowGLCanvas = worldWindowGLCanvas;
  408. }
  409. public JTree getLayerJTree()
  410. {
  411. return layerJTree;
  412. }
  413. public static void setLayerJTree(JTree layerJTree)
  414. {
  415. LoadCacheData.layerJTree = layerJTree;
  416. }
  417. }

3、高程数据的加载

高程数据采用NASA的30m公开DEM数据,使用World Wind Server发布即可,详见前面的搭建本地World wind Severe服务器。最终实现效果图如下图所示。
PS:年末各种忙啊,项目总算结题,明天小组年会,预祝一切顺利!欢迎大家留言交流,共享自己的学习笔记。
World Wind Java的资料实在太少啦,断断续续总算搭建起了三维框架,后面陆续添加功能,计划做一个基于新安江模型的洪涝模拟仿真模块,将之前做的洪涝模拟和参数率定、径流模拟全部整合到自己的这个平台上来。
---------------------------------分割线(2015年1月13日)-----------------------------------
补充:关于LoadCacheData的使用,只需在程序初始化时加入以下两句代码即可:
  1. // 加载缓存数据
  2. LoadCacheData loadCacheData = new LoadCacheData(wGlCanvas,
  3. layerJTree);
  4. loadCacheData.loadPreviouslyInstalledData();

其中layerJTree是图层树,大家可以不要这个参数,修改相应代码即可,另外如何测试自己的切片数据是否加载成功,可以参考示例中的InstallImageryAndElevationsDemo这个。可能有些朋友不知如何运行自带的示例,下面我贴图说明下哈(假设已添加Worldwind.jar文件,并且已使用GlobalMapper切片放置C:\ProgramData\WorldWindInstalled文件夹下)

如果结果如上图所示,说明数据已加载成功。如果还未成功,检查缓存数据xml配置文件是否正确,可以跟一下源代码看下是如何加载缓存数据的。
PS:另外,最近期末考试,再加上其他项目的事情,更新有些慢哈。后面会陆续更新,欢迎大家留言交流!

World Wind Java开发之八——加载本地缓存文件构建大范围三维场景(的更多相关文章

  1. iOS开发-UIWebView加载本地和网络数据

    UIWebView是内置的浏览器控件,可以用它来浏览网页.打开文档,关于浏览网页榜样可以参考UC,手机必备浏览器,至于文档浏览的手机很多图书阅读软件,UIWebView是一个混合体,具体的功能控件内置 ...

  2. iOS - 开发中加载本地word/pdf文档说明

    最近项目中要加载一个本地的word/pdf等文件比如<用户隐私政策><用户注册说明>,有两种方法加载 > 用QLPreviewController控制器实现 步骤 : & ...

  3. [转]World Wind Java开发之四——搭建本地WMS服务器

    在提供地理信息系统客户端时,NASA还为用户提供了开源的WMS Server 服务器应用:World Wind WMS Server.利用这个应用,我们可以架设自己的WMS服务并使用自己的数据(也支持 ...

  4. IOS开发-加载本地音乐

    IOS开发-加载本地音乐 $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text() ...

  5. 微信小程序-工具无法加载本地模拟开发服务的解决办法

    微信小程序开发工具出现如下问题: 因为网络代理软件或者 VPN 影响,工具无法加载本地模拟开发服务  请尝试以下任一解决方案1.关闭相关网络代理软件,重新编译成功后,再启动相关网络代理软件: 2.配置 ...

  6. Android GIS开发系列-- 入门季(5) FeatureLayer加载本地shp文件与要素查询

    FeatureLayer是要素图层,也是Arcgis的主要图层.用这个图层可以加载本地的shp文件.下面我们看怎样加载shp文件到MapView中.查看ArcGis API可知FeatureLayer ...

  7. World Wind Java开发之六——解析shape文件(转)

    http://blog.csdn.net/giser_whu/article/details/41647117 最近一直忙于导师项目的事情了,几天没更新了,昨天和今天研究了下WWJ解析shp文件的源代 ...

  8. jvm系列(一):java类的加载机制

    java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...

  9. Android开发--异步加载

    因为移动端软件开发思维模式或者说是开发的架构其实是不分平台和编程语言的,就拿安卓和IOS来说,他们都是移动前端app开发展示数据和用户交互数据的数据终端,移动架构的几个大模块:UI界面展示.本地数据可 ...

随机推荐

  1. linux---安装ftp并配置用户部分权限

    一.启动vsftpd服务1. 启动VSFTP服务器A:cenos下运行:yum install vsftpdB. 登录Linux主机后,运行命令:”service vsftpd start”C. 要让 ...

  2. 启动windows .net 3.5 功能

    近期给window 2008 版本安装loadrunner ,发现还需要用户自己打开windows 的 .net 3.5 功能,所以在这里记录一下步骤 激活

  3. 一文带你看懂WebSocket 的原理?为什么可以实现持久连接?

    工作之余在知乎上偶然看到一篇回帖,瞬间觉得之前看的那么多资料都不及这一篇让我对 websocket 的认知深刻易懂,之前看总完总觉得一知半解云里雾里.所以与大家共同分享一下一起学习.比较喜欢这种博客理 ...

  4. 【外部节点】json判断@表示正在处理的当前数组项或对象。过滤器还可用于$引用当前对象之外的属性

    $.store.book[?(@.price < $.expensive)] { "category" : "reference", "auth ...

  5. POJ1046 Color Me Less

    题目来源:http://poj.org/problem?id=1046 题目大意: 在RGB颜色空间中,用下面的公式来度量两个颜色值的距离. 现给出16个RGB表示的颜色,和一些用于测试的颜色,求被测 ...

  6. Linux--7

    一.Nginx.conf主配置文件 Nginx主配置文件conf/nginx.conf是一个纯文本类型的文件,整个配置文件是以区块的形式组织的.一般,每个区块以一对大括号{}来表示开始与结束. 核心模 ...

  7. 【手撸一个ORM】第七步、SqlDataReader转实体

    说明 使用Expression(表达式目录树)转Entity的文章在园子里有很多,思路也大致也一样,我在前面有篇文章对解决思路有些说明,有兴趣的小伙伴可以看下 (传送门),刚接触表达式目录树时写的,不 ...

  8. UVALive 5983 二分答案+dp

    想了很久都想不出怎么dp,然后发现有些例子,如果你开始不确定起始值的话,是不能dp的,每种状态都有可能,所以只能二分一个答案,确定开始的val值,来dp了. #include <cstdio&g ...

  9. Sqoop Export HDFS

    Sqoop Export应用场景——直接导出 直接导出 我们先复制一个表,然后将上一篇博文(Sqoop Import HDFS)导入的数据再导出到我们所复制的表里. sqoop export \ -- ...

  10. Practice encryptedblobstore

    C++ BlobStore 使用范例(C++伪代码) 一个可能的接口设计示例(C++) Java BlobStore 使用范例(Java伪代码) 一个可能的接口设计示例(Java) 一个基于Key/V ...