之前介绍了在WorldWind Java版中加载WMS服务图层,想学习的小伙伴,可以翻看上一篇文章。WorldWind是实现了三维效果的展示,当然少不了加载三维模型,我翻看WorldWind的源码,发现WorldWind支持加载KMZ格式的三维模型。这就比较精细了。如果有需要加载KMZ格式模型的需求,可以在下方留言,后续发加载KMZ格式的代码发出来。今天就记录下加载shape文件,实现三维效果。由于模型所致,就比较粗糙。
首先看一下加载后的效果:
1.shape文件
这里的shape文件是带有高度的矢量文件,可以使用ArcMap制作。如下图:
如图这个是一个机场的shape文件。这个文件属性表中有一列表明了每个像素的高度。如下图。
可以看到属性表中包含许多信息,这里只需看“hhh”列表即可,这里表示每个像素的高程。这个值就是形成三维效果的关键。准备好这个文件后就可以开始编码之路。
2.编写代码
直接贴代码:
/*
* 加载带有高度的shape文件,并将高度进行拉伸,形成三维效果
* 2021年11月24日14:14:17
* */
public class ModelLayer {
private static RenderableLayer layer; //三维模型的渲染图层
//加载三维模型的方法
public static void init3DModel(WorldWindowGLCanvas wwd, String filePath){
Shapefile shapefile = new Shapefile(filePath);
layer = new RenderableLayer();
layer.setName("model"); //图层命名为“model”,这个可以自定义
layer.setPickEnabled(true);
try {
while (shapefile.hasNext()) {
ShapefileRecord record = shapefile.nextRecord();
layer.addRenderable(makeShape(record));
}
wwd.getModel().getLayers().add(layer);
} finally {
shapefile.close();
}
}
private static ExtrudedPolygon makeShape(ShapefileRecord record) {
String IMAGE_PATH = "images/ic_wall.jpg"; //这个是贴图纹理的路径
Double height = null; //每个像素的高度值
/*
* 这里需要注意一下,获取到的高度值必须大于0,当有小于等于0的高度值时,
* 需要将高度值设为0.1即可。且所有值不能忽略,否则会报错
* */
Object o = record.getAttributes().getValue("hhh"); //hhh为shape文件中表示高度的字段值。也就是在第一步中提到的表示高程的字段。
if (o != null) {
Double h = Double.parseDouble(o.toString());
if (h<=0){ //如果有小于等于0的值,设为0.1,只要大于0即可。
h=0.1;
}
height=h*20; //将高度值拉高20倍,否则原始的高度值,三维效果不明显
}
// 顶部属性
ShapeAttributes capAttrs = new BasicShapeAttributes();
capAttrs.setOutlineMaterial(Material.GRAY);
capAttrs.setInteriorMaterial(Material.LIGHT_GRAY);
// 边属性
ShapeAttributes sideAttributes = new BasicShapeAttributes();
sideAttributes.setInteriorMaterial(Material.LIGHT_GRAY);
sideAttributes.setOutlineMaterial(Material.DARK_GRAY);
sideAttributes.setImageSource(IMAGE_PATH);
// 创建拉伸多边形
VecBuffer vb = record.getPointBuffer(0);
gov.nasa.worldwind.render.airspaces.Polygon pgonAirspace = new Polygon(vb.getLocations()); //根据点串构建多边形
//纹理
ArrayList<String> textures = new ArrayList<String>();
for (int i = 0; i < pgonAirspace.getLocations().size()-1; i++) {
textures.add(IMAGE_PATH);
}
//给多边形添加上高度和纹理。
ExtrudedPolygon polygon = new ExtrudedPolygon(pgonAirspace.getLocations(), height, textures); //有纹理
//ExtrudedPolygon polygon = new ExtrudedPolygon(pgonAirspace.getLocations(), height, null); //纹理设为null,即可设为无纹理。
polygon.setCapAttributes(capAttrs);
polygon.setSideAttributes(sideAttributes);
polygon.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);
return polygon;
}
/*
* 移除指定名字的三维模型
* */
public static void removeModel(WorldWindowGLCanvas wwd,String name){
if (wwd.getModel().getLayers().getLayerByName(name)!=null){
wwd.getModel().getLayers().remove(wwd.getModel().getLayers().getLayerByName(name));
wwd.redrawNow();
}
}
}
代码就是这些,是不是很简单。使用的时候,直接调用即可。参数有两个,一个是三维球,一个是shape文件的路径。