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

1、AnalyticSurfaceDemo

ArcGIS下对栅格的各种分级渲染效果是非常好的,可以做出很漂亮的图,现在在WW下也可以做出同样的效果了,看到这里是不是有点小兴奋呢。先看下WW自带的AnalyticSurfaceDemo的运行效果图:

通过看源代码可以知道给出了三种渲染示例,其中两种是动态的,这里我需要的是对dem数据或者是单波段影像的渲染,也就是左上方的渲染效果。

2、AnalyticSurface类

下面来看下主要用到的类:

主要用到的方法:

  1. // 创建AnalyticSurface并设置其属性
  2. final AnalyticSurface surface = new AnalyticSurface();
  3. surface.setSector(raster.getSector());
  4. surface.setDimensions(raster.getWidth(), raster.getHeight());
  5. surface.setValues(AnalyticSurface.createColorGradientValues(
  6. raster.getBuffer(), raster.getTransparentValue(), extremes[0],
  7. extremes[1], minHue, maxHue));
  8. // surface.setVerticalScale(5e3);
  9. // 设置表面渲染方式为 CLAMP_TO_GROUND
  10. surface.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);

根据自己的需要可以查阅开发文档设置其他属性。

3、DEM渲染实例

将demo中的代码稍加修改封装为AnalyticSurfaceUtil类以供后面所有栅格数据的渲染使用,目前比较简单,后面陆续扩充该类。
WW下渲染效果:
ArcMap下渲染效果:

可以看到WW下渲染的效果丝毫不逊色,图是不是很漂亮呢。

4、洪涝模拟渲染

这是对之前洪涝模拟的改进,对洪涝模拟输出的范围图和深度图进行渲染。
(1)范围图
(2)深度图
这幅渲染的深度图是不是有种火山喷发的感觉,很有艺术美感,非常喜欢这个渲染的效果。改一下配色再看下另一种渲染效果:

5、源码。

下面是自己封装的AnalyticSurfaceUtil类,供大家参考:
  1. /**
  2. * @Copyright 2014-2020 @刘硕
  3. **/
  4. package edu.whu.vge.util;
  5. import gov.nasa.worldwind.WorldWind;
  6. import gov.nasa.worldwind.avlist.AVKey;
  7. import gov.nasa.worldwind.avlist.AVList;
  8. import gov.nasa.worldwind.data.BufferWrapperRaster;
  9. import gov.nasa.worldwind.data.DataRaster;
  10. import gov.nasa.worldwind.data.DataRasterReader;
  11. import gov.nasa.worldwind.data.DataRasterReaderFactory;
  12. import gov.nasa.worldwind.exception.WWRuntimeException;
  13. import gov.nasa.worldwind.geom.Extent;
  14. import gov.nasa.worldwind.geom.Sector;
  15. import gov.nasa.worldwind.layers.RenderableLayer;
  16. import gov.nasa.worldwind.render.DrawContext;
  17. import gov.nasa.worldwind.render.Renderable;
  18. import gov.nasa.worldwind.util.Logging;
  19. import gov.nasa.worldwind.util.WWBufferUtil;
  20. import gov.nasa.worldwind.util.WWIO;
  21. import gov.nasa.worldwind.util.WWMath;
  22. import gov.nasa.worldwindx.examples.analytics.AnalyticSurface;
  23. import gov.nasa.worldwindx.examples.analytics.AnalyticSurfaceAttributes;
  24. import gov.nasa.worldwindx.examples.analytics.AnalyticSurfaceLegend;
  25. import gov.nasa.worldwindx.examples.util.ExampleUtil;
  26. import java.awt.Point;
  27. import java.io.File;
  28. import java.text.DecimalFormat;
  29. import java.text.FieldPosition;
  30. import java.text.Format;
  31. import javax.swing.SwingUtilities;
  32. /**
  33. * @项目名称:SmartScope
  34. * @类名称:AnalyticSurfaceUtil
  35. * @类描述:
  36. * @创建人:刘硕
  37. * @创建时间:2015-1-21 下午3:40:54
  38. * @修改备注:
  39. * @版本:
  40. */
  41. public class AnalyticSurfaceUtil
  42. {
  43. /**
  44. * 创建一个新的实例 AnalyticSurfaceUtil.
  45. *
  46. */
  47. public AnalyticSurfaceUtil()
  48. {
  49. // TODO Auto-generated constructor stub
  50. }
  51. public static void createPrecipitationSurface(double minHue, double maxHue,
  52. final RenderableLayer outLayer)
  53. {
  54. String DATA_PATH = "J:/data/wwj/FloodDepth.tif";
  55. BufferWrapperRaster raster = loadRasterElevations(DATA_PATH);
  56. if (raster == null)
  57. return;
  58. // 获取像元最大值与最小值
  59. double[] extremes = WWBufferUtil.computeExtremeValues(
  60. raster.getBuffer(), raster.getTransparentValue());
  61. if (extremes == null)
  62. return;
  63. // 创建AnalyticSurface并设置其属性
  64. final AnalyticSurface surface = new AnalyticSurface();
  65. surface.setSector(raster.getSector());
  66. surface.setDimensions(raster.getWidth(), raster.getHeight());
  67. surface.setValues(AnalyticSurface.createColorGradientValues(
  68. raster.getBuffer(), raster.getTransparentValue(), extremes[0],
  69. extremes[1], minHue, maxHue));
  70. // surface.setVerticalScale(5e3);
  71. // 设置表面渲染方式为 CLAMP_TO_GROUND
  72. surface.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);
  73. AnalyticSurfaceAttributes attr = new AnalyticSurfaceAttributes();
  74. attr.setDrawOutline(false);
  75. attr.setDrawShadow(false);
  76. attr.setInteriorOpacity(0.6);
  77. surface.setSurfaceAttributes(attr);
  78. // 设置图例样式
  79. Format legendLabelFormat = new DecimalFormat("# m")
  80. {
  81. public StringBuffer format(double number, StringBuffer result,
  82. FieldPosition fieldPosition)
  83. {
  84. double valueInFeet = number;
  85. return super.format(valueInFeet, result, fieldPosition);
  86. }
  87. };
  88. // 创建图例
  89. final AnalyticSurfaceLegend legend = AnalyticSurfaceLegend.fromColorGradient(
  90. extremes[0], extremes[1], minHue, maxHue,
  91. AnalyticSurfaceLegend.createDefaultColorGradientLabels(
  92. extremes[0], extremes[1], legendLabelFormat),
  93. AnalyticSurfaceLegend.createDefaultTitle("Legend"));
  94. legend.setOpacity(0.8);
  95. legend.setScreenLocation(new Point(100, 300));
  96. SwingUtilities.invokeLater(new Runnable()
  97. {
  98. public void run()
  99. {
  100. surface.setClientLayer(outLayer);
  101. outLayer.addRenderable(surface);
  102. outLayer.addRenderable(createLegendRenderable(surface, 600,
  103. legend));
  104. }
  105. });
  106. }
  107. /**
  108. *
  109. * @方法名称: loadRasterElevations ;
  110. * @方法描述: 读取数据(单波段) ;
  111. * @参数 :@param path
  112. * @参数 :@return
  113. * @返回类型: BufferWrapperRaster ;
  114. * @创建人:刘硕;
  115. * @创建时间:2015-1-22 上午11:25:40;
  116. * @throws
  117. */
  118. public static BufferWrapperRaster loadRasterElevations(String path)
  119. {
  120. // Download the data and save it in a temp file.
  121. File file = ExampleUtil.saveResourceToTempFile(path,
  122. "." + WWIO.getSuffix(path));
  123. // Create a raster reader for the file type.
  124. DataRasterReaderFactory readerFactory = (DataRasterReaderFactory) WorldWind.createConfigurationComponent(AVKey.DATA_RASTER_READER_FACTORY_CLASS_NAME);
  125. DataRasterReader reader = readerFactory.findReaderFor(file, null);
  126. try
  127. {
  128. // Before reading the raster, verify that the file contains
  129. // elevations.
  130. AVList metadata = reader.readMetadata(file, null);
  131. if (metadata == null
  132. || !AVKey.ELEVATION.equals(metadata.getStringValue(AVKey.PIXEL_FORMAT)))
  133. {
  134. String msg = Logging.getMessage(
  135. "ElevationModel.SourceNotElevations",
  136. file.getAbsolutePath());
  137. Logging.logger().severe(msg);
  138. throw new IllegalArgumentException(msg);
  139. }
  140. // Read the file into the raster.
  141. DataRaster[] rasters = reader.read(file, null);
  142. if (rasters == null || rasters.length == 0)
  143. {
  144. String msg = Logging.getMessage(
  145. "ElevationModel.CannotReadElevations",
  146. file.getAbsolutePath());
  147. Logging.logger().severe(msg);
  148. throw new WWRuntimeException(msg);
  149. }
  150. // Determine the sector covered by the elevations. This
  151. // information
  152. // is in the GeoTIFF file or auxiliary
  153. // files associated with the elevations file.
  154. Sector sector = (Sector) rasters[0].getValue(AVKey.SECTOR);
  155. if (sector == null)
  156. {
  157. String msg = Logging.getMessage("DataRaster.MissingMetadata",
  158. AVKey.SECTOR);
  159. Logging.logger().severe(msg);
  160. throw new IllegalArgumentException(msg);
  161. }
  162. // Request a sub-raster that contains the whole file. This step
  163. // is
  164. // necessary because only sub-rasters
  165. // are reprojected (if necessary); primary rasters are not.
  166. int width = rasters[0].getWidth();
  167. int height = rasters[0].getHeight();
  168. DataRaster subRaster = rasters[0].getSubRaster(width, height,
  169. sector, rasters[0]);
  170. // Verify that the sub-raster can create a ByteBuffer, then
  171. // create
  172. // one.
  173. if (!(subRaster instanceof BufferWrapperRaster))
  174. {
  175. String msg = Logging.getMessage(
  176. "ElevationModel.CannotCreateElevationBuffer", path);
  177. Logging.logger().severe(msg);
  178. throw new WWRuntimeException(msg);
  179. }
  180. return (BufferWrapperRaster) subRaster;
  181. }
  182. catch (Exception e)
  183. {
  184. e.printStackTrace();
  185. return null;
  186. }
  187. }
  188. /**
  189. *
  190. * @方法名称: createLegendRenderable ;
  191. * @方法描述: 创建图例 ;
  192. * @参数 :@param surface
  193. * @参数 :@param surfaceMinScreenSize
  194. * @参数 :@param legend
  195. * @参数 :@return
  196. * @返回类型: Renderable ;
  197. * @创建人:刘硕;
  198. * @创建时间:2015-1-22 上午11:26:07;
  199. * @throws
  200. */
  201. protected static Renderable createLegendRenderable(
  202. final AnalyticSurface surface, final double surfaceMinScreenSize,
  203. final AnalyticSurfaceLegend legend)
  204. {
  205. return new Renderable()
  206. {
  207. public void render(DrawContext dc)
  208. {
  209. Extent extent = surface.getExtent(dc);
  210. if (!extent.intersects(dc.getView().getFrustumInModelCoordinates()))
  211. return;
  212. if (WWMath.computeSizeInWindowCoordinates(dc, extent) < surfaceMinScreenSize)
  213. return;
  214. legend.render(dc);
  215. }
  216. };
  217. }
  218. }

目前还很不完善,后面有需要的话打算做一个类似于ArcGIS的分级渲染工具,对于降雨量蒸散发量等数据都可以很方便的进行渲染。

 
 

World Wind Java开发之十——AnalyticSurface栅格渲染(转)的更多相关文章

  1. World Wind Java开发之十五——载入三维模型

    之前的一篇博客是关于载入粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能载入纹理的问题,一直没呢解决 ...

  2. World Wind Java开发之十五——加载三维模型(转)

    之前的一篇博客是关于加载粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能加载纹理的问题,一直没呢解决 ...

  3. World Wind Java开发之十四——添加WMS地图服务资源(转)

    数据是GIS的核心,没有数据一切无从谈起,Internet上有很多在线WMS地图服务资源,我们可以好好利用这些数据资源,比如天地图.必应地图.NASA.OGC数据服务等等. 在我们国家常用的还是天地图 ...

  4. World Wind Java开发之七——读取本地栅格文件(影像+高程)构建三维场景(转)

    http://blog.csdn.net/giser_whu/article/details/41679515 首先,看下本篇博客要达到的效果图: 下面逐步分析如何加载影像及高程文件. 1.World ...

  5. World Wind Java开发之十二——加载粗制三维模型(ExtrudedPolygon)(转)

    ww可以根据DLG图批量生成假三维模型,这对于小区等特征相似的建筑物模型的构建是非常有用的.下面来看如何一步步实现假三维模型的加载: 1.Shp文件的制作 首先在arcmap下数字化几个建筑物,并新建 ...

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

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

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

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

  8. World Wind Java开发之一(转)

    http://blog.csdn.net/giser_whu/article/details/40477235 参照<World wind Java三维地理信息系统开发指南随书光盘>以及官 ...

  9. [转]World Wind Java开发之五——读取本地shp文件

    World Wind Java 使用IconLayer图层类表现点和多点数据,使用RenderableLayer图层表现线和面数据,一个图层只能对应一组shape文件.World Wind Java首 ...

随机推荐

  1. Boost Python学习笔记(二)

    你将学到什么 如何在Python中调用C++代码 如何在C++中调用Python代码 在Python中调用C++代码 首先定义一个动物类(include/animal.h) #pragma once ...

  2. luogu1975 排队(分块)

    luogu1975 排队(分块) 给你一个长度为n的序列,每次交换给定的两个数,输出每次操作后的逆序对个数. 首先考虑求出刚开始的逆序对.接着相当于带修改的求区间中比x大的数. 可以用分块,每个块内排 ...

  3. 清北刷题冲刺 10-31 a.m

    集合 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; ], ...

  4. Spring MVC 简述:从MVC框架普遍关注的问题说起

    任何一个完备的MVC框架都需要解决Web开发过程中的一些共性的问题,比如请求的收集与分发.数据前后台流转与转换,当前最流行的SpringMVC和Struts2也不例外.本文首先概述MVC模式的分层思想 ...

  5. AT2689 Prime Flip

    传送门 这个题是真的巧妙 首先一个很巧妙的思路,差分 考虑假如\(a_i!=a_{i-1}\),则\(b_i=1\),否则\(b_i=0\) 这样一来,一个区间的翻转就变成了对于两个数的取反了 然后我 ...

  6. thinkphp5使用第三方没有使用命名空间的类库

    特别注意的是,如果你需要调用PHP内置的类库,或者第三方没有使用命名空间的类库,记得在实例化类库的时候加上 \ // 错误的用法 $class = new stdClass(); $xml = new ...

  7. thinkphp5加密解密

    thinkphp5目前没有提供加密解密类,但是tp3.2中提供了好几种加密解密方法,我们可以吧3.2的这些类拿来使用. 1.将tp3.2中ThinkPHP\Library\Think的Crypt文件夹 ...

  8. Python爬取天气预报

    实现爬取一天的天气预报 非常简单的一个小爬虫,利用的也是基本的request.BeautifulSoup.re库,算是简单的上手一个小测试吧 from urllib.request import ur ...

  9. angularJs1.x 版本中 uib-tabset 如何默认激活不同的标签页

     <uib-tabset> 默认有个active属性,根据官方文档,active的默认值是0,也就是说,默认显示索引为0的标签页,可以通过修改这个值来默认显示不同的索引的标签页. 示例: ...

  10. Helvetic Coding Contest 2016 online mirror F1

    Description Heidi has finally found the mythical Tree of Life – a legendary combinatorial structure ...