1、AnalyticSurfaceDemo
ArcGIS下对栅格的各种分级渲染效果是非常好的,可以做出很漂亮的图,现在在WW下也可以做出同样的效果了,看到这里是不是有点小兴奋呢。先看下WW自带的AnalyticSurfaceDemo的运行效果图:
通过看源代码可以知道给出了三种渲染示例,其中两种是动态的,这里我需要的是对dem数据或者是单波段影像的渲染,也就是左上方的渲染效果。
2、AnalyticSurface类
下面来看下主要用到的类:
主要用到的方法:
// 创建AnalyticSurface并设置其属性 final AnalyticSurface surface = new AnalyticSurface(); surface.setSector(raster.getSector()); surface.setDimensions(raster.getWidth(), raster.getHeight()); surface.setValues(AnalyticSurface.createColorGradientValues( raster.getBuffer(), raster.getTransparentValue(), extremes[0], extremes[1], minHue, maxHue)); // surface.setVerticalScale(5e3); // 设置表面渲染方式为 CLAMP_TO_GROUND surface.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);
根据自己的需要可以查阅开发文档设置其他属性。
3、DEM渲染实例
将demo中的代码稍加修改封装为AnalyticSurfaceUtil类以供后面所有栅格数据的渲染使用,目前比较简单,后面陆续扩充该类。
WW下渲染效果:
ArcMap下渲染效果:
可以看到WW下渲染的效果丝毫不逊色,图是不是很漂亮呢。
4、洪涝模拟渲染
这是对之前洪涝模拟的改进,对洪涝模拟输出的范围图和深度图进行渲染。
(1)范围图
(2)深度图
这幅渲染的深度图是不是有种火山喷发的感觉,很有艺术美感,非常喜欢这个渲染的效果。改一下配色再看下另一种渲染效果:
5、源码。
下面是自己封装的AnalyticSurfaceUtil类,供大家参考:
/** * @Copyright 2014-2020 @刘硕 **/ package edu.whu.vge.util; import gov.nasa.worldwind.WorldWind; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.avlist.AVList; import gov.nasa.worldwind.data.BufferWrapperRaster; import gov.nasa.worldwind.data.DataRaster; import gov.nasa.worldwind.data.DataRasterReader; import gov.nasa.worldwind.data.DataRasterReaderFactory; import gov.nasa.worldwind.exception.WWRuntimeException; import gov.nasa.worldwind.geom.Extent; import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.layers.RenderableLayer; import gov.nasa.worldwind.render.DrawContext; import gov.nasa.worldwind.render.Renderable; import gov.nasa.worldwind.util.Logging; import gov.nasa.worldwind.util.WWBufferUtil; import gov.nasa.worldwind.util.WWIO; import gov.nasa.worldwind.util.WWMath; import gov.nasa.worldwindx.examples.analytics.AnalyticSurface; import gov.nasa.worldwindx.examples.analytics.AnalyticSurfaceAttributes; import gov.nasa.worldwindx.examples.analytics.AnalyticSurfaceLegend; import gov.nasa.worldwindx.examples.util.ExampleUtil; import java.awt.Point; import java.io.File; import java.text.DecimalFormat; import java.text.FieldPosition; import java.text.Format; import javax.swing.SwingUtilities; /** * @项目名称:SmartScope * @类名称:AnalyticSurfaceUtil * @类描述: * @创建人:刘硕 * @创建时间:2015-1-21 下午3:40:54 * @修改备注: * @版本: */ public class AnalyticSurfaceUtil { /** * 创建一个新的实例 AnalyticSurfaceUtil. * */ public AnalyticSurfaceUtil() { // TODO Auto-generated constructor stub } public static void createPrecipitationSurface(double minHue, double maxHue, final RenderableLayer outLayer) { String DATA_PATH = "J:/data/wwj/FloodDepth.tif"; BufferWrapperRaster raster = loadRasterElevations(DATA_PATH); if (raster == null) return; // 获取像元最大值与最小值 double[] extremes = WWBufferUtil.computeExtremeValues( raster.getBuffer(), raster.getTransparentValue()); if (extremes == null) return; // 创建AnalyticSurface并设置其属性 final AnalyticSurface surface = new AnalyticSurface(); surface.setSector(raster.getSector()); surface.setDimensions(raster.getWidth(), raster.getHeight()); surface.setValues(AnalyticSurface.createColorGradientValues( raster.getBuffer(), raster.getTransparentValue(), extremes[0], extremes[1], minHue, maxHue)); // surface.setVerticalScale(5e3); // 设置表面渲染方式为 CLAMP_TO_GROUND surface.setAltitudeMode(WorldWind.CLAMP_TO_GROUND); AnalyticSurfaceAttributes attr = new AnalyticSurfaceAttributes(); attr.setDrawOutline(false); attr.setDrawShadow(false); attr.setInteriorOpacity(0.6); surface.setSurfaceAttributes(attr); // 设置图例样式 Format legendLabelFormat = new DecimalFormat("# m") { public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) { double valueInFeet = number; return super.format(valueInFeet, result, fieldPosition); } }; // 创建图例 final AnalyticSurfaceLegend legend = AnalyticSurfaceLegend.fromColorGradient( extremes[0], extremes[1], minHue, maxHue, AnalyticSurfaceLegend.createDefaultColorGradientLabels( extremes[0], extremes[1], legendLabelFormat), AnalyticSurfaceLegend.createDefaultTitle("Legend")); legend.setOpacity(0.8); legend.setScreenLocation(new Point(100, 300)); SwingUtilities.invokeLater(new Runnable() { public void run() { surface.setClientLayer(outLayer); outLayer.addRenderable(surface); outLayer.addRenderable(createLegendRenderable(surface, 600, legend)); } }); } /** * * @方法名称: loadRasterElevations ; * @方法描述: 读取数据(单波段) ; * @参数 :@param path * @参数 :@return * @返回类型: BufferWrapperRaster ; * @创建人:刘硕; * @创建时间:2015-1-22 上午11:25:40; * @throws */ public static BufferWrapperRaster loadRasterElevations(String path) { // Download the data and save it in a temp file. File file = ExampleUtil.saveResourceToTempFile(path, "." + WWIO.getSuffix(path)); // Create a raster reader for the file type. DataRasterReaderFactory readerFactory = (DataRasterReaderFactory) WorldWind.createConfigurationComponent(AVKey.DATA_RASTER_READER_FACTORY_CLASS_NAME); DataRasterReader reader = readerFactory.findReaderFor(file, null); try { // Before reading the raster, verify that the file contains // elevations. AVList metadata = reader.readMetadata(file, null); if (metadata == null || !AVKey.ELEVATION.equals(metadata.getStringValue(AVKey.PIXEL_FORMAT))) { String msg = Logging.getMessage( "ElevationModel.SourceNotElevations", file.getAbsolutePath()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } // Read the file into the raster. DataRaster[] rasters = reader.read(file, null); if (rasters == null || rasters.length == 0) { String msg = Logging.getMessage( "ElevationModel.CannotReadElevations", file.getAbsolutePath()); Logging.logger().severe(msg); throw new WWRuntimeException(msg); } // Determine the sector covered by the elevations. This // information // is in the GeoTIFF file or auxiliary // files associated with the elevations file. Sector sector = (Sector) rasters[0].getValue(AVKey.SECTOR); if (sector == null) { String msg = Logging.getMessage("DataRaster.MissingMetadata", AVKey.SECTOR); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } // Request a sub-raster that contains the whole file. This step // is // necessary because only sub-rasters // are reprojected (if necessary); primary rasters are not. int width = rasters[0].getWidth(); int height = rasters[0].getHeight(); DataRaster subRaster = rasters[0].getSubRaster(width, height, sector, rasters[0]); // Verify that the sub-raster can create a ByteBuffer, then // create // one. if (!(subRaster instanceof BufferWrapperRaster)) { String msg = Logging.getMessage( "ElevationModel.CannotCreateElevationBuffer", path); Logging.logger().severe(msg); throw new WWRuntimeException(msg); } return (BufferWrapperRaster) subRaster; } catch (Exception e) { e.printStackTrace(); return null; } } /** * * @方法名称: createLegendRenderable ; * @方法描述: 创建图例 ; * @参数 :@param surface * @参数 :@param surfaceMinScreenSize * @参数 :@param legend * @参数 :@return * @返回类型: Renderable ; * @创建人:刘硕; * @创建时间:2015-1-22 上午11:26:07; * @throws */ protected static Renderable createLegendRenderable( final AnalyticSurface surface, final double surfaceMinScreenSize, final AnalyticSurfaceLegend legend) { return new Renderable() { public void render(DrawContext dc) { Extent extent = surface.getExtent(dc); if (!extent.intersects(dc.getView().getFrustumInModelCoordinates())) return; if (WWMath.computeSizeInWindowCoordinates(dc, extent) < surfaceMinScreenSize) return; legend.render(dc); } }; } }
目前还很不完善,后面有需要的话打算做一个类似于ArcGIS的分级渲染工具,对于降雨量蒸散发量等数据都可以很方便的进行渲染。
时间: 2024-11-05 13:03:56