首页 > 代码库 > World Wind Java开发之十——AnalyticSurface栅格渲染(转)

World Wind Java开发之十——AnalyticSurface栅格渲染(转)

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

1、AnalyticSurfaceDemo

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

技术分享

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

2、AnalyticSurface类

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

技术分享

主要用到的方法:

 

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

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

World Wind Java开发之十——AnalyticSurface栅格渲染(转)