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

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

1、添加天地图地图服务

由于上篇转载的平常心的博客对WMSTiledImageLayer已经讲的非常清楚了,这里不再赘述了,看代码:
  1. public static WMSTiledImageLayer addTianDiTuImage() throws Exception
  2. {
  3. // 请求地图的URL
  4. String uri = "http://www.scgis.net.cn/imap/iMapServer/defaultRest/services/newtianditudom/WMS";
  5. // WMS
  6. WMSCapabilities caps;
  7. URI serverURI;
  8. serverURI = new URI(uri);
  9. // 获得WMSCapabilities对象
  10. caps = WMSCapabilities.retrieve(serverURI);
  11. // 解析WMSCapabilities数据
  12. caps.parse();
  13. // // 输出wms元数据信息
  14. // System.out.println(caps.getCapabilityInformation().toString());
  15. // 获取所有图层(这里只有一个,自己用geoserver发布的则可能有很多)
  16. final List<WMSLayerCapabilities> namedLayerCaps = caps.getNamedLayers();
  17. String layerName = null;
  18. for (WMSLayerCapabilities wmsLayerCapabilities : namedLayerCaps)
  19. {
  20. layerName = wmsLayerCapabilities.getName();
  21. }
  22. AVList params = new AVListImpl();
  23. // 图层的名称
  24. params.setValue(AVKey.LAYER_NAMES, layerName);
  25. // 地图服务的协议,这里是OGC:WMS
  26. params.setValue(AVKey.SERVICE_NAME, "OGC:WMS");
  27. // 获得地图的uri,也就是上面定义的uri
  28. params.setValue(AVKey.GET_MAP_URL, uri);
  29. // 在本地缓存文件的名称
  30. params.setValue(AVKey.DATA_CACHE_NAME, layerName);
  31. params.setValue(AVKey.TILE_URL_BUILDER,
  32. new WMSTiledImageLayer.URLBuilder(params));
  33. WMSTiledImageLayer layer = new WMSTiledImageLayer(caps, params);
  34. return layer;
  35. }

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

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

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

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

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

3、WMS服务器管理面板

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

改动的不多,都加了注释,可以对比原WMSLayersPanel.java文件看下不同,修改后的SmartScopeWMSLayersPanel源码如下:
  1. /*
  2. Copyright (C) 2001, 2006 United States Government
  3. as represented by the Administrator of the
  4. National Aeronautics and Space Administration.
  5. All Rights Reserved.
  6. */
  7. package gov.nasa.worldwindx.examples;
  8. import gov.nasa.worldwind.*;
  9. import gov.nasa.worldwind.avlist.*;
  10. import gov.nasa.worldwind.globes.ElevationModel;
  11. import gov.nasa.worldwind.layers.*;
  12. import gov.nasa.worldwind.ogc.wms.*;
  13. import gov.nasa.worldwind.terrain.CompoundElevationModel;
  14. import gov.nasa.worldwind.util.WWUtil;
  15. import gov.nasa.worldwindx.examples.WMSLayersPanel.LayerInfo;
  16. import javax.swing.*;
  17. import javax.swing.border.*;
  18. import java.awt.*;
  19. import java.awt.event.*;
  20. import java.net.*;
  21. import java.util.*;
  22. import java.util.List;
  23. /**
  24. *
  25. * @项目名称:worldwind-1.5.0
  26. * @类名称:SmartScopeWMSLayersPanel
  27. * @类描述: WMS服务图层管理面板
  28. * @创建人:bluce
  29. * @创建时间:2015年2月4日 下午5:09:31
  30. * @修改备注:
  31. * @版本:
  32. */
  33. public class SmartScopeWMSLayersPanel extends JPanel
  34. {
  35. /**
  36. * @Fields serialVersionUID : TODO
  37. */
  38. private static final long serialVersionUID = 1L;
  39. protected static class LayerInfo
  40. {
  41. protected WMSCapabilities caps;
  42. protected AVListImpl params = new AVListImpl();
  43. protected String getTitle()
  44. {
  45. return params.getStringValue(AVKey.DISPLAY_NAME);
  46. }
  47. protected String getName()
  48. {
  49. return params.getStringValue(AVKey.LAYER_NAMES);
  50. }
  51. protected String getAbstract()
  52. {
  53. return params.getStringValue(AVKey.LAYER_ABSTRACT);
  54. }
  55. }
  56. // 所有图层元数据信息
  57. protected String[] servers;
  58. protected List<WMSLayerCapabilities> namedLayerCaps;
  59. protected WorldWindow wwd;
  60. protected URI serverURI;
  61. protected Dimension size;
  62. protected Thread loadingThread;
  63. protected TreeSet<LayerInfo> layerInfos = new TreeSet<LayerInfo>(
  64. new Comparator<LayerInfo>()
  65. {
  66. public int compare(LayerInfo infoA, LayerInfo infoB)
  67. {
  68. String nameA = infoA.getName();
  69. String nameB = infoB.getName();
  70. return nameA.compareTo(nameB);
  71. }
  72. });
  73. public  SmartScopeWMSLayersPanel(String[] servers)
  74. {
  75. }
  76. /**
  77. *
  78. * 创建一个新的实例 SmartScopeWMSLayersPanel.
  79. *
  80. * @param wwd
  81. * @param server
  82. * @param size
  83. * @throws URISyntaxException
  84. */
  85. public SmartScopeWMSLayersPanel(WorldWindow wwd, String[] server,
  86. Dimension size) throws URISyntaxException
  87. {
  88. super(new BorderLayout());
  89. this.servers = server;
  90. this.wwd = wwd;
  91. this.size = size;
  92. this.setPreferredSize(this.size);
  93. this.makeProgressPanel();
  94. // Thread off a retrieval of the server's capabilities document and
  95. // update of this panel.
  96. this.loadingThread = new Thread(new Runnable()
  97. {
  98. public void run()
  99. {
  100. load();
  101. }
  102. });
  103. this.loadingThread.setPriority(Thread.MIN_PRIORITY);
  104. this.loadingThread.start();
  105. }
  106. /**
  107. *
  108. * @方法名称: load ;
  109. * @方法描述: 加载服务 ;
  110. * @参数 :
  111. * @返回类型: void ;
  112. * @创建人:bluce;
  113. * @创建时间:2015年2月5日 上午9:33:23;
  114. * @throws
  115. */
  116. protected void load()
  117. {
  118. WMSCapabilities caps = null;
  119. try
  120. {
  121. for (int i = 0; i < servers.length; i++)
  122. {
  123. this.serverURI = new URI(servers[i].trim());
  124. caps = WMSCapabilities.retrieve(this.serverURI);
  125. caps.parse();
  126. // 获取该服务下的所有图层元数据描述
  127. namedLayerCaps = caps.getNamedLayers();
  128. if (namedLayerCaps == null) return;
  129. try
  130. {
  131. for (WMSLayerCapabilities lc : namedLayerCaps)
  132. {
  133. Set<WMSLayerStyle> styles = lc.getStyles();
  134. if (styles == null || styles.size() == 0)
  135. {
  136. LayerInfo layerInfo = createLayerInfo(caps, lc,
  137. null);
  138. SmartScopeWMSLayersPanel.this.layerInfos
  139. .add(layerInfo);
  140. }
  141. else
  142. {
  143. for (WMSLayerStyle style : styles)
  144. {
  145. LayerInfo layerInfo = createLayerInfo(caps, lc,
  146. style);
  147. SmartScopeWMSLayersPanel.this.layerInfos
  148. .add(layerInfo);
  149. }
  150. }
  151. }
  152. }
  153. catch (Exception e)
  154. {
  155. e.printStackTrace();
  156. return;
  157. }
  158. // 在面板上显示所有图层的名称
  159. EventQueue.invokeLater(new Runnable()
  160. {
  161. public void run()
  162. {
  163. SmartScopeWMSLayersPanel.this.removeAll();
  164. makeLayerInfosPanel(layerInfos);
  165. }
  166. });
  167. }
  168. }
  169. catch (Exception e)
  170. {
  171. e.printStackTrace();
  172. }
  173. // Gather up all the named layers and make a world wind layer for each.
  174. }
  175. public String getServerDisplayString()
  176. {
  177. return this.serverURI.getHost();
  178. }
  179. protected LayerInfo createLayerInfo(WMSCapabilities caps,
  180. WMSLayerCapabilities layerCaps, WMSLayerStyle style)
  181. {
  182. // Create the layer info specified by the layer's capabilities entry and
  183. // the selected style.
  184. LayerInfo linfo = new LayerInfo();
  185. linfo.caps = caps;
  186. linfo.params = new AVListImpl();
  187. linfo.params.setValue(AVKey.LAYER_NAMES, layerCaps.getName());
  188. if (style != null) linfo.params.setValue(AVKey.STYLE_NAMES,
  189. style.getName());
  190. String abs = layerCaps.getLayerAbstract();
  191. if (!WWUtil.isEmpty(abs)) linfo.params.setValue(AVKey.LAYER_ABSTRACT,
  192. abs);
  193. linfo.params.setValue(AVKey.DISPLAY_NAME, makeTitle(caps, linfo));
  194. return linfo;
  195. }
  196. protected void makeLayerInfosPanel(Collection<LayerInfo> layerInfos)
  197. {
  198. // JPanel layersPanel = new JPanel(new GridLayout(0, 1, 0, 4));
  199. // layersPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  200. JPanel layersPanel = new JPanel();
  201. BoxLayout layout = new BoxLayout(layersPanel, BoxLayout.Y_AXIS);
  202. layersPanel.setLayout(layout);
  203. layersPanel.setFont(new Font("宋体", Font.PLAIN, 10));
  204. // Add the server's layers to the panel.
  205. for (LayerInfo layerInfo : layerInfos)
  206. {
  207. addLayerInfoPanel(layersPanel, SmartScopeWMSLayersPanel.this.wwd,
  208. layerInfo);
  209. }
  210. // Put the name panel in a scroll bar.
  211. JScrollPane scrollPane = new JScrollPane(layersPanel);
  212. scrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  213. scrollPane.setPreferredSize(size);
  214. // Add the scroll bar and name panel to a titled panel that will resize
  215. // with the main window.
  216. // JPanel westPanel = new JPanel(new GridLayout(0, 1, 0, 10));
  217. // westPanel.setBorder(new
  218. // CompoundBorder(BorderFactory.createEmptyBorder(
  219. // 9, 9, 9, 9), new TitledBorder("Layers")));
  220. // westPanel.add(scrollPane);
  221. this.add(scrollPane, BorderLayout.CENTER);
  222. this.revalidate();
  223. }
  224. protected void addLayerInfoPanel(JPanel layersPanel, WorldWindow wwd,
  225. LayerInfo linfo)
  226. {
  227. // Give a layer a button and label and add it to the layer names panel.
  228. LayerInfoAction action = new LayerInfoAction(linfo, wwd);
  229. if (linfo.getAbstract() != null)
  230. {
  231. action.putValue(Action.SHORT_DESCRIPTION, linfo.getAbstract());
  232. JCheckBox jcb = new JCheckBox(action);
  233. jcb.setFont(new Font("宋体", Font.PLAIN, 14));
  234. jcb.setSelected(false);
  235. layersPanel.add(jcb);
  236. }
  237. }
  238. protected class LayerInfoAction extends AbstractAction
  239. {
  240. protected WorldWindow wwd;
  241. protected LayerInfo layerInfo;
  242. protected Object component;
  243. public LayerInfoAction(LayerInfo linfo, WorldWindow wwd)
  244. {
  245. super(linfo.getTitle());
  246. // Capture info we'll need later to control the layer.
  247. this.wwd = wwd;
  248. this.layerInfo = linfo;
  249. }
  250. public void actionPerformed(ActionEvent actionEvent)
  251. {
  252. // If the layer is selected, add it to the world window's current
  253. // model, else remove it from the model.
  254. if (((JCheckBox) actionEvent.getSource()).isSelected())
  255. {
  256. if (this.component == null) this.component = createComponent(
  257. layerInfo.caps, layerInfo.params);
  258. updateComponent(this.component, true);
  259. }
  260. else
  261. {
  262. if (this.component != null) updateComponent(this.component,
  263. false);
  264. }
  265. // Tell the world window to update.
  266. wwd.redraw();
  267. }
  268. }
  269. protected void updateComponent(Object component, boolean enable)
  270. {
  271. if (component instanceof Layer)
  272. {
  273. Layer layer = (Layer) component;
  274. LayerList layers = this.wwd.getModel().getLayers();
  275. layer.setEnabled(enable);
  276. if (enable)
  277. {
  278. if (!layers.contains(layer))
  279. {
  280. ApplicationTemplate.insertBeforePlacenames(this.wwd, layer);
  281. ApplicationTemplate.insertBeforeLayerName(wwd, layer,
  282. "Landsat");
  283. this.firePropertyChange("LayersPanelUpdated", null, layer);
  284. }
  285. }
  286. else
  287. {
  288. layers.remove(layer);
  289. this.firePropertyChange("LayersPanelUpdated", layer, null);
  290. }
  291. }
  292. else if (component instanceof ElevationModel)
  293. {
  294. ElevationModel model = (ElevationModel) component;
  295. CompoundElevationModel compoundModel = (CompoundElevationModel) this.wwd
  296. .getModel().getGlobe().getElevationModel();
  297. if (enable)
  298. {
  299. if (!compoundModel.getElevationModels().contains(model)) compoundModel
  300. .addElevationModel(model);
  301. }
  302. }
  303. }
  304. protected static Object createComponent(WMSCapabilities caps, AVList params)
  305. {
  306. AVList configParams = params.copy(); // Copy to insulate changes from
  307. // the caller.
  308. // Some wms servers are slow, so increase the timeouts and limits used
  309. // by world wind's retrievers.
  310. configParams.setValue(AVKey.URL_CONNECT_TIMEOUT, 30000);
  311. configParams.setValue(AVKey.URL_READ_TIMEOUT, 30000);
  312. configParams.setValue(AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT, 60000);
  313. try
  314. {
  315. String factoryKey = getFactoryKeyForCapabilities(caps);
  316. Factory factory = (Factory) WorldWind
  317. .createConfigurationComponent(factoryKey);
  318. return factory.createFromConfigSource(caps, configParams);
  319. }
  320. catch (Exception e)
  321. {
  322. // Ignore the exception, and just return null.
  323. }
  324. return null;
  325. }
  326. protected static String getFactoryKeyForCapabilities(WMSCapabilities caps)
  327. {
  328. boolean hasApplicationBilFormat = false;
  329. Set<String> formats = caps.getImageFormats();
  330. for (String s : formats)
  331. {
  332. if (s.contains("application/bil"))
  333. {
  334. hasApplicationBilFormat = true;
  335. break;
  336. }
  337. }
  338. return hasApplicationBilFormat ? AVKey.ELEVATION_MODEL_FACTORY
  339. : AVKey.LAYER_FACTORY;
  340. }
  341. protected static String makeTitle(WMSCapabilities caps, LayerInfo layerInfo)
  342. {
  343. String layerNames = layerInfo.params.getStringValue(AVKey.LAYER_NAMES);
  344. String styleNames = layerInfo.params.getStringValue(AVKey.STYLE_NAMES);
  345. String[] lNames = layerNames.split(",");
  346. String[] sNames = styleNames != null ? styleNames.split(",") : null;
  347. StringBuilder sb = new StringBuilder();
  348. for (int i = 0; i < lNames.length; i++)
  349. {
  350. if (sb.length() > 0) sb.append(", ");
  351. String layerName = lNames[i];
  352. WMSLayerCapabilities lc = caps.getLayerByName(layerName);
  353. String layerTitle = lc.getTitle();
  354. sb.append(layerTitle != null ? layerTitle : layerName);
  355. if (sNames == null || sNames.length <= i) continue;
  356. String styleName = sNames[i];
  357. WMSLayerStyle style = lc.getStyleByName(styleName);
  358. if (style == null) continue;
  359. sb.append(" : ");
  360. String styleTitle = style.getTitle();
  361. sb.append(styleTitle != null ? styleTitle : styleName);
  362. }
  363. return sb.toString();
  364. }
  365. protected void makeProgressPanel()
  366. {
  367. // Create the panel holding the progress bar during loading.
  368. JPanel outerPanel = new JPanel(new BorderLayout());
  369. outerPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  370. outerPanel.setPreferredSize(this.size);
  371. JPanel innerPanel = new JPanel(new BorderLayout());
  372. innerPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  373. JProgressBar progressBar = new JProgressBar();
  374. progressBar.setIndeterminate(true);
  375. innerPanel.add(progressBar, BorderLayout.CENTER);
  376. JButton cancelButton = new JButton("Cancel");
  377. innerPanel.add(cancelButton, BorderLayout.EAST);
  378. cancelButton.addActionListener(new AbstractAction()
  379. {
  380. public void actionPerformed(ActionEvent actionEvent)
  381. {
  382. if (loadingThread.isAlive()) loadingThread.interrupt();
  383. Container c = SmartScopeWMSLayersPanel.this.getParent();
  384. c.remove(SmartScopeWMSLayersPanel.this);
  385. }
  386. });
  387. outerPanel.add(innerPanel, BorderLayout.NORTH);
  388. this.add(outerPanel, BorderLayout.CENTER);
  389. this.revalidate();
  390. }
  391. }

数据下载地址:http://download.csdn.net/detail/liushuo_whu/8426723

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

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

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

  2. Java开发学习(十四)----Spring整合Mybatis及Junit

    一.Spring整合Mybatis思路分析 1.1 环境准备 步骤1:准备数据库表 Mybatis是来操作数据库表,所以先创建一个数据库及表 create database spring_db cha ...

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

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

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

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

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

    http://blog.csdn.net/giser_whu/article/details/43017881 1.AnalyticSurfaceDemo ArcGIS下对栅格的各种分级渲染效果是非常 ...

  6. “全栈2019”Java多线程第二十四章:等待唤醒机制详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. “全栈2019”Java多线程第十四章:线程与堆栈详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  8. “全栈2019”Java异常第十四章:将异常输出到文本文件中

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  9. “全栈2019”Java第八十四章:接口中嵌套接口详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. C#判断字符串是否是数字最简单的正则表达式

    if (theStr!= null)//注意加非空判断,否则报错 { System.Text.RegularExpressions.Regex rex = new System.Text.Regula ...

  2. 浅谈关于SRAM与DRAM的区别

    在上体系结构这门课之前,我只知道DRAM用作内存比较多,SRAM用作cache比较多.在今天讲到内存技术时,我对于这两个基础概念有了更加完整的认识.这篇文章是我的听课心得,现在分享给各位,仅供参考,若 ...

  3. has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

    https://www.cnblogs.com/caimuqing/p/6733405.html // TODO 支持跨域访问 response.setHeader("Access-Cont ...

  4. jmeter将参数值写入到指定文件(转)

    有时在测试过程中需要将测试过程中生成的参数保存下来,jmeter并没有此类功能,此时,可以 通过beanshell编写代码来实现 思路: 每次请求响应返回后,通过正则表达式获取到需要保存的值,通过Be ...

  5. @RequestBody注解的用法

    以前,一直以为在SpringMVC环境中,@RequestBody接收的是一个Json对象,一直在调试代码都没有成功,后来发现,其实 @RequestBody接收的是一个Json对象的字符串,而不是一 ...

  6. python 用turtle 画小猪佩奇

    from turtle import * def nose(x,y):#鼻子 penup()#提起笔 goto(x,y)#定位 pendown()#落笔,开始画 setheading(-30)#将乌龟 ...

  7. git——解决“fatal: Authentication failed for 'https://github.com/balabala”

    平复一下心情,到底如何在github上将队友和owner的仓库连接?如何push代码到远程仓库???找了巨多教程,终于解决了~ 刚到公司不久,开始学着用git,在提交代码的时候怎么都提不上去! 解决办 ...

  8. ubuntu搭建mediawiki

    1.搭建lamp环境,lamp指的是: Linux+Apache+Mysql/MariaDB+Perl/PHP/Python (我们安装的是Linux+apache2+postgresql+php) ...

  9. Murano Weekly Meeting 2015.07.14

    会议时间: 2015.07.14 主持人: Kirill Zaitsev, core from Mirantis 会议摘要:  1.periodic nightly builds,然后通过mailin ...

  10. Nodejs mysql pool使用实例

    前段时间在写一个版本发布工具,用到express+mysql实现,当站点运行很长一段空白时间后,node进程会自动down掉,提示mysql连接错误,谷歌后发现是mysql自身的特性导致,因此后来改为 ...