World Wind Java开发之十四——添加WMS地图服务资源

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

在我们国家常用的还是天地图的地图服务资源,详见:http://blog.3snews.net/space.php?uid=6955280&do=blog&id=67981,这篇博客列举了一些常用的在线地图服务资源,读者可以自行试下。

1、添加天地图地图服务

由于上篇转载的平常心的博客对WMSTiledImageLayer已经讲的非常清楚了,这里不再赘述了,看代码:

	public static WMSTiledImageLayer addTianDiTuImage() throws Exception
	{
		// 请求地图的URL
		String uri = "http://www.scgis.net.cn/imap/iMapServer/defaultRest/services/newtianditudom/WMS";
		// WMS
		WMSCapabilities caps;
		URI serverURI;
		serverURI = new URI(uri);
		// 获得WMSCapabilities对象
		caps = WMSCapabilities.retrieve(serverURI);
		// 解析WMSCapabilities数据
		caps.parse();

		// // 输出wms元数据信息
		// System.out.println(caps.getCapabilityInformation().toString());
		// 获取所有图层(这里只有一个,自己用geoserver发布的则可能有很多)
		final List<WMSLayerCapabilities> namedLayerCaps = caps.getNamedLayers();
		String layerName = null;
		for (WMSLayerCapabilities wmsLayerCapabilities : namedLayerCaps)
		{
			layerName = wmsLayerCapabilities.getName();
		}
		AVList params = new AVListImpl();
		// 图层的名称
		params.setValue(AVKey.LAYER_NAMES, layerName);
		// 地图服务的协议,这里是OGC:WMS
		params.setValue(AVKey.SERVICE_NAME, "OGC:WMS");
		// 获得地图的uri,也就是上面定义的uri
		params.setValue(AVKey.GET_MAP_URL, uri);
		// 在本地缓存文件的名称
		params.setValue(AVKey.DATA_CACHE_NAME, layerName);
		params.setValue(AVKey.TILE_URL_BUILDER,
				new WMSTiledImageLayer.URLBuilder(params));

		WMSTiledImageLayer layer = new WMSTiledImageLayer(caps, params);
		return layer;
	}

这里添加天地图影像作为底图,效果还是不错的,看下效果图:

另外,天地图还提供了在线注记底图服务,只需改动上面的地图请求地址即可,看下效果图:

这里加载的效果要比天地图的在线三维球的效果要好,有兴趣的可以去对比下。另外天地图的在线三维体验还是比较差的,只是单纯的浏览,单是这个体验效果还不是很好,毕竟这是政府的东东,不像Google财大气粗,全球几十万台服务器,天地图的商业化发展之路任重道远啊。

2、添加Geoserver发布的地图服务

这里暂时只发布了世界国界和中国县界数据(面和线),这些数据稍后会打包发到我的CSDN资源,大家有需要的可以去下载。为了方便服务资源的管理,在右边添加了一个简单的WMS服务器管理面板,后面仿照ArcCatalog做一个WMS服务器管理的模块。

3、WMS服务器管理面板

examples中有个WMSLayerManager,这个demo实现了wms服务的基本管理,只需根据自己的需要修改源代码即可。这里说下我自己修改源代码的方法,首先将需要修改的java文件在改目录下copy一份,名字自取,这样做的好处是不破坏源代码的完整性,因为其他的demo也可能用到这个java文件,避免了大量的修改,改完只需将src导出jar包即可。如下图所示:

改动的不多,都加了注释,可以对比原WMSLayersPanel.java文件看下不同,修改后的SmartScopeWMSLayersPanel源码如下:

/*
Copyright (C) 2001, 2006 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
 */
package gov.nasa.worldwindx.examples;

import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.globes.ElevationModel;
import gov.nasa.worldwind.layers.*;
import gov.nasa.worldwind.ogc.wms.*;
import gov.nasa.worldwind.terrain.CompoundElevationModel;
import gov.nasa.worldwind.util.WWUtil;
import gov.nasa.worldwindx.examples.WMSLayersPanel.LayerInfo;

import javax.swing.*;
import javax.swing.border.*;

import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;
import java.util.List;

/**
 *
 * @项目名称:worldwind-1.5.0
 * @类名称:SmartScopeWMSLayersPanel
 * @类描述: WMS服务图层管理面板
 * @创建人:刘硕
 * @创建时间:2015年2月4日 下午5:09:31
 * @修改备注:
 * @版本:
 */
public class SmartScopeWMSLayersPanel extends JPanel
{

	/**
	 * @Fields serialVersionUID : TODO
	 */

	private static final long serialVersionUID = 1L;

	protected static class LayerInfo
	{
		protected WMSCapabilities caps;
		protected AVListImpl params = new AVListImpl();

		protected String getTitle()
		{
			return params.getStringValue(AVKey.DISPLAY_NAME);
		}

		protected String getName()
		{
			return params.getStringValue(AVKey.LAYER_NAMES);
		}

		protected String getAbstract()
		{
			return params.getStringValue(AVKey.LAYER_ABSTRACT);
		}
	}

	// 所有图层元数据信息
	protected String[] servers;
	protected List<WMSLayerCapabilities> namedLayerCaps;
	protected WorldWindow wwd;
	protected URI serverURI;
	protected Dimension size;
	protected Thread loadingThread;
	protected TreeSet<LayerInfo> layerInfos = new TreeSet<LayerInfo>(
			new Comparator<LayerInfo>()
			{
				public int compare(LayerInfo infoA, LayerInfo infoB)
				{
					String nameA = infoA.getName();
					String nameB = infoB.getName();
					return nameA.compareTo(nameB);
				}
			});

	public  SmartScopeWMSLayersPanel(String[] servers)
	{

	}

	/**
	 *
	 * 创建一个新的实例 SmartScopeWMSLayersPanel.
	 *
	 * @param wwd
	 * @param server
	 * @param size
	 * @throws URISyntaxException
	 */
	public SmartScopeWMSLayersPanel(WorldWindow wwd, String[] server,
			Dimension size) throws URISyntaxException
	{
		super(new BorderLayout());

		this.servers = server;
		this.wwd = wwd;
		this.size = size;
		this.setPreferredSize(this.size);

		this.makeProgressPanel();

		// Thread off a retrieval of the server's capabilities document and
		// update of this panel.
		this.loadingThread = new Thread(new Runnable()
		{
			public void run()
			{
				load();
			}
		});
		this.loadingThread.setPriority(Thread.MIN_PRIORITY);
		this.loadingThread.start();
	}

	/**
	 *
	 * @方法名称: load ;
	 * @方法描述: 加载服务 ;
	 * @参数 :
	 * @返回类型: void ;
	 * @创建人:刘硕;
	 * @创建时间:2015年2月5日 上午9:33:23;
	 * @throws
	 */
	protected void load()
	{
		WMSCapabilities caps = null;
		try
		{
			for (int i = 0; i < servers.length; i++)
			{

				this.serverURI = new URI(servers[i].trim());
				caps = WMSCapabilities.retrieve(this.serverURI);
				caps.parse();
				// 获取该服务下的所有图层元数据描述
				namedLayerCaps = caps.getNamedLayers();

				if (namedLayerCaps == null) return;

				try
				{
					for (WMSLayerCapabilities lc : namedLayerCaps)
					{
						Set<WMSLayerStyle> styles = lc.getStyles();
						if (styles == null || styles.size() == 0)
						{
							LayerInfo layerInfo = createLayerInfo(caps, lc,
									null);
							SmartScopeWMSLayersPanel.this.layerInfos
									.add(layerInfo);
						}
						else
						{
							for (WMSLayerStyle style : styles)
							{
								LayerInfo layerInfo = createLayerInfo(caps, lc,
										style);
								SmartScopeWMSLayersPanel.this.layerInfos
										.add(layerInfo);
							}
						}
					}
				}
				catch (Exception e)
				{
					e.printStackTrace();
					return;
				}

				// 在面板上显示所有图层的名称
				EventQueue.invokeLater(new Runnable()
				{
					public void run()
					{
						SmartScopeWMSLayersPanel.this.removeAll();
						makeLayerInfosPanel(layerInfos);
					}
				});

			}

		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		// Gather up all the named layers and make a world wind layer for each.

	}

	public String getServerDisplayString()
	{
		return this.serverURI.getHost();
	}

	protected LayerInfo createLayerInfo(WMSCapabilities caps,
			WMSLayerCapabilities layerCaps, WMSLayerStyle style)
	{
		// Create the layer info specified by the layer's capabilities entry and
		// the selected style.
		LayerInfo linfo = new LayerInfo();
		linfo.caps = caps;
		linfo.params = new AVListImpl();
		linfo.params.setValue(AVKey.LAYER_NAMES, layerCaps.getName());
		if (style != null) linfo.params.setValue(AVKey.STYLE_NAMES,
				style.getName());
		String abs = layerCaps.getLayerAbstract();
		if (!WWUtil.isEmpty(abs)) linfo.params.setValue(AVKey.LAYER_ABSTRACT,
				abs);

		linfo.params.setValue(AVKey.DISPLAY_NAME, makeTitle(caps, linfo));

		return linfo;
	}

	protected void makeLayerInfosPanel(Collection<LayerInfo> layerInfos)
	{
		// JPanel layersPanel = new JPanel(new GridLayout(0, 1, 0, 4));
		// layersPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		JPanel layersPanel = new JPanel();
		BoxLayout layout = new BoxLayout(layersPanel, BoxLayout.Y_AXIS);
		layersPanel.setLayout(layout);
		layersPanel.setFont(new Font("宋体", Font.PLAIN, 10));
		// Add the server's layers to the panel.
		for (LayerInfo layerInfo : layerInfos)
		{
			addLayerInfoPanel(layersPanel, SmartScopeWMSLayersPanel.this.wwd,
					layerInfo);
		}

		// Put the name panel in a scroll bar.
		JScrollPane scrollPane = new JScrollPane(layersPanel);
		scrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
		scrollPane.setPreferredSize(size);

		// Add the scroll bar and name panel to a titled panel that will resize
		// with the main window.
		// JPanel westPanel = new JPanel(new GridLayout(0, 1, 0, 10));
		// westPanel.setBorder(new
		// CompoundBorder(BorderFactory.createEmptyBorder(
		// 9, 9, 9, 9), new TitledBorder("Layers")));
		// westPanel.add(scrollPane);
		this.add(scrollPane, BorderLayout.CENTER);

		this.revalidate();
	}

	protected void addLayerInfoPanel(JPanel layersPanel, WorldWindow wwd,
			LayerInfo linfo)
	{
		// Give a layer a button and label and add it to the layer names panel.

		LayerInfoAction action = new LayerInfoAction(linfo, wwd);
		if (linfo.getAbstract() != null)
		{
			action.putValue(Action.SHORT_DESCRIPTION, linfo.getAbstract());
			JCheckBox jcb = new JCheckBox(action);
			jcb.setFont(new Font("宋体", Font.PLAIN, 14));
			jcb.setSelected(false);
			layersPanel.add(jcb);
		}

	}

	protected class LayerInfoAction extends AbstractAction
	{
		protected WorldWindow wwd;
		protected LayerInfo layerInfo;
		protected Object component;

		public LayerInfoAction(LayerInfo linfo, WorldWindow wwd)
		{
			super(linfo.getTitle());

			// Capture info we'll need later to control the layer.
			this.wwd = wwd;
			this.layerInfo = linfo;
		}

		public void actionPerformed(ActionEvent actionEvent)
		{
			// If the layer is selected, add it to the world window's current
			// model, else remove it from the model.
			if (((JCheckBox) actionEvent.getSource()).isSelected())
			{
				if (this.component == null) this.component = createComponent(
						layerInfo.caps, layerInfo.params);

				updateComponent(this.component, true);
			}
			else
			{
				if (this.component != null) updateComponent(this.component,
						false);
			}

			// Tell the world window to update.
			wwd.redraw();
		}
	}

	protected void updateComponent(Object component, boolean enable)
	{
		if (component instanceof Layer)
		{
			Layer layer = (Layer) component;
			LayerList layers = this.wwd.getModel().getLayers();

			layer.setEnabled(enable);

			if (enable)
			{
				if (!layers.contains(layer))
				{
					ApplicationTemplate.insertBeforePlacenames(this.wwd, layer);
					ApplicationTemplate.insertBeforeLayerName(wwd, layer,
							"Landsat");
					this.firePropertyChange("LayersPanelUpdated", null, layer);
				}
			}
			else
			{
				layers.remove(layer);
				this.firePropertyChange("LayersPanelUpdated", layer, null);
			}
		}
		else if (component instanceof ElevationModel)
		{
			ElevationModel model = (ElevationModel) component;
			CompoundElevationModel compoundModel = (CompoundElevationModel) this.wwd
					.getModel().getGlobe().getElevationModel();

			if (enable)
			{
				if (!compoundModel.getElevationModels().contains(model)) compoundModel
						.addElevationModel(model);
			}
		}
	}

	protected static Object createComponent(WMSCapabilities caps, AVList params)
	{
		AVList configParams = params.copy(); // Copy to insulate changes from
												// the caller.

		// Some wms servers are slow, so increase the timeouts and limits used
		// by world wind's retrievers.
		configParams.setValue(AVKey.URL_CONNECT_TIMEOUT, 30000);
		configParams.setValue(AVKey.URL_READ_TIMEOUT, 30000);
		configParams.setValue(AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT, 60000);

		try
		{
			String factoryKey = getFactoryKeyForCapabilities(caps);
			Factory factory = (Factory) WorldWind
					.createConfigurationComponent(factoryKey);
			return factory.createFromConfigSource(caps, configParams);
		}
		catch (Exception e)
		{
			// Ignore the exception, and just return null.
		}

		return null;
	}

	protected static String getFactoryKeyForCapabilities(WMSCapabilities caps)
	{
		boolean hasApplicationBilFormat = false;

		Set<String> formats = caps.getImageFormats();
		for (String s : formats)
		{
			if (s.contains("application/bil"))
			{
				hasApplicationBilFormat = true;
				break;
			}
		}

		return hasApplicationBilFormat ? AVKey.ELEVATION_MODEL_FACTORY
				: AVKey.LAYER_FACTORY;
	}

	protected static String makeTitle(WMSCapabilities caps, LayerInfo layerInfo)
	{
		String layerNames = layerInfo.params.getStringValue(AVKey.LAYER_NAMES);
		String styleNames = layerInfo.params.getStringValue(AVKey.STYLE_NAMES);
		String[] lNames = layerNames.split(",");
		String[] sNames = styleNames != null ? styleNames.split(",") : null;

		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < lNames.length; i++)
		{
			if (sb.length() > 0) sb.append(", ");

			String layerName = lNames[i];
			WMSLayerCapabilities lc = caps.getLayerByName(layerName);
			String layerTitle = lc.getTitle();
			sb.append(layerTitle != null ? layerTitle : layerName);

			if (sNames == null || sNames.length <= i) continue;

			String styleName = sNames[i];
			WMSLayerStyle style = lc.getStyleByName(styleName);
			if (style == null) continue;

			sb.append(" : ");
			String styleTitle = style.getTitle();
			sb.append(styleTitle != null ? styleTitle : styleName);
		}

		return sb.toString();
	}

	protected void makeProgressPanel()
	{
		// Create the panel holding the progress bar during loading.

		JPanel outerPanel = new JPanel(new BorderLayout());
		outerPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		outerPanel.setPreferredSize(this.size);

		JPanel innerPanel = new JPanel(new BorderLayout());
		innerPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		JProgressBar progressBar = new JProgressBar();
		progressBar.setIndeterminate(true);
		innerPanel.add(progressBar, BorderLayout.CENTER);

		JButton cancelButton = new JButton("Cancel");
		innerPanel.add(cancelButton, BorderLayout.EAST);
		cancelButton.addActionListener(new AbstractAction()
		{
			public void actionPerformed(ActionEvent actionEvent)
			{
				if (loadingThread.isAlive()) loadingThread.interrupt();

				Container c = SmartScopeWMSLayersPanel.this.getParent();
				c.remove(SmartScopeWMSLayersPanel.this);
			}
		});

		outerPanel.add(innerPanel, BorderLayout.NORTH);
		this.add(outerPanel, BorderLayout.CENTER);
		this.revalidate();
	}
}
时间: 2024-10-14 10:54:46

World Wind Java开发之十四——添加WMS地图服务资源的相关文章

World Wind Java开发之十五——加载三维模型

之前的一篇博客是关于加载粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能加载纹理的问题,一直没呢解决.那么WW如何加载常用的三维模型格式(3ds.obj.skp)呢,通过一番搜索,了解到WW可以加载collada的dae格式的三维模型,并且还可以加载kml\kmz文件,那么WW加载三维模型的方法就出来了:首先将其他格式三维模型转换为kmz或kml文件,再加载.这里我是从su的三维模型库中下载的sk

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

http://blog.csdn.net/giser_whu/article/details/43017881 1.AnalyticSurfaceDemo ArcGIS下对栅格的各种分级渲染效果是非常好的,可以做出很漂亮的图,现在在WW下也可以做出同样的效果了,看到这里是不是有点小兴奋呢.先看下WW自带的AnalyticSurfaceDemo的运行效果图: 通过看源代码可以知道给出了三种渲染示例,其中两种是动态的,这里我需要的是对dem数据或者是单波段影像的渲染,也就是左上方的渲染效果. 2.A

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

1.AnalyticSurfaceDemo ArcGIS下对栅格的各种分级渲染效果是非常好的,可以做出很漂亮的图,现在在WW下也可以做出同样的效果了,看到这里是不是有点小兴奋呢.先看下WW自带的AnalyticSurfaceDemo的运行效果图: 通过看源代码可以知道给出了三种渲染示例,其中两种是动态的,这里我需要的是对dem数据或者是单波段影像的渲染,也就是左上方的渲染效果. 2.AnalyticSurface类 下面来看下主要用到的类: 主要用到的方法: // 创建AnalyticSurfa

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

ww可以根据DLG图批量生成假三维模型,这对于小区等特征相似的建筑物模型的构建是非常有用的.下面来看如何一步步实现假三维模型的加载: 1.Shp文件的制作 首先在arcmap下数字化几个建筑物,并新建height字段存储建筑物的高度. 2.代码实现 /** * * @方法名称: init3DModel : * @方法描述: 导入简易三维模型 : * @参数 :@param filePath :shp文件路径 * @返回类型: void : * @创建人:刘硕; * @创建时间:2015年2月3日

从零开始学ios开发(十四):Navigation Controllers and Table Views(上)

这一篇我们将学习一个新的控件Navigation Controller,很多时候Navigation Controller是和Table View紧密结合在一起的,因此在学习Navigation Controller的同时,我们还将继续学习Table View其他一些特性,毕竟Navigation Controller还是相对来说毕竟简单的,没有什么太大的花头,它的主要作用就是一个view的切换,切来切去,而Table View的花头就比较多了,这次我们将这2个控件结合在一起进行学习. 再多说一

QT开发(十四)——QT绘图系统

QT开发(十四)--QT绘图系统 一.QT绘图原理 Qt4中的2D绘图系统称为Arthur绘图系统,可以使用相同的API在屏幕上和绘图设备上进行绘制,主要基于QPainter.QPainterDevice和 QPainterEngine.QPainter执行绘图操作,QPainterDevice提供绘图设备,是一个二维空间的抽象,QPainterEngine提供一些接口.QPainter用来执行具体的绘图相关操作,如画点,画线,填充,变换,alpha通道等.QPaintDevice类是能够进行绘

World Wind Java开发之六——解析shape文件(上)

最近一直忙于导师项目的事情了,几天没更新了,昨天和今天研究了下WWJ解析shp文件的源代码,现在记录下,希望可以帮到更多的人! 上一篇博客:World Wind Java开发之五--读取本地shp文件只讲了如何加载shp文件,没有涉及到shp文件的解析,我们这篇博客紧接上一篇博客,利用WWJ来解析shp文件.首先来看用到的源码包和相关类,如下图所示.解析shp文件主要用到Shapefile(shapefile文件类).ShapefileRecord(shape文件记录类).DBaseRecord

“全栈2019”Java第五十四章:多态详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第五十四章:多态详解 下一章 "全栈2019"Java第五十五章:方法的静态绑定与动态绑定 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组"

“全栈2019”Java第六十四章:接口与静态方法详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第六十四章:接口与静态方法详解 下一章 "全栈2019"Java第六十五章:接口与默认方法详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组&qu