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的三维模型库中下载的skp文件,在su中可以直接转换为kmz文件,通过测试,这个方法是可行的。先来看下效果图:

1.效果图

第一幅是德国标志性建筑——柏林奥林匹克体育场,可以看到效果还是可以的,不过没有使用lod技术,一旦模型数量增多,会卡顿。

第二幅是也是德国地标性建筑——柏林电视塔。

第三幅是3D City DB上的德国柏林一些collada三维模型,需要的可以去下载做下测试

2.实现方法

开头已经明确了WW加载三维模型的路线,WW又提供了加载kml/kmz文件的demo(KMLViewer),所以要实现这个是很简单的了,只需根据自己的需要改动原demo,整合到自己的工程下即可,这里我改动原demo,编写了SmartScopeKMLViewer,方法参见之前的博客。所用到的数据,整理完上传到CSDN资源,需要的可以去下载。下载地址:http://download.csdn.net/detail/liushuo_whu/8512739

3.源代码

/*
Copyright (C) 2001, 2010 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
 */

package gov.nasa.worldwindx.examples.kml;

import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.awt.WorldWindowGLCanvas;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.ogc.kml.KMLAbstractFeature;
import gov.nasa.worldwind.ogc.kml.KMLRoot;
import gov.nasa.worldwind.ogc.kml.impl.KMLController;
import gov.nasa.worldwind.render.Offset;
import gov.nasa.worldwind.retrieve.RetrievalService;
import gov.nasa.worldwind.util.WWIO;
import gov.nasa.worldwind.util.WWUtil;
import gov.nasa.worldwind.util.layertree.KMLLayerTreeNode;
import gov.nasa.worldwind.util.layertree.KMLNetworkLinkTreeNode;
import gov.nasa.worldwind.util.layertree.LayerTree;
import gov.nasa.worldwindx.examples.util.BalloonController;
import gov.nasa.worldwindx.examples.util.HotSpotController;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.swing.SwingUtilities;
import javax.xml.stream.XMLStreamException;

/**
 * 导入KML或KMZ文件,以图层形式查看,KML或KMZ文件的内容显示为一个要素树。在要素树上点击KML要素可以查看该要素
 * ,在球上点击要素可以弹出要素的描述信息框
 */
public class SmartScopeKMLViewer
{
	public static class KMLUtil
	{
		protected LayerTree layerTree; // 图层树
		protected RenderableLayer hiddenLayer; // 渲染图层(图层树)

		protected HotSpotController hotSpotController; // 热点controller
		protected KMLApplicationController kmlAppController; // KMLcontroller
		protected BalloonController balloonController; // BalloonController
		protected WorldWindowGLCanvas wwd; // ww

		public KMLUtil(WorldWindowGLCanvas worldWindowGLCanvas)
		{
			this.wwd = worldWindowGLCanvas;
			// 初始化图层树
			this.layerTree = new LayerTree(new Offset(20d, 160d, AVKey.PIXELS,
					AVKey.INSET_PIXELS));
			// this.layerTree.getModel().refresh(this.wwd.getModel().getLayers());

			// 图层树渲染图层
			this.hiddenLayer = new RenderableLayer();
			this.hiddenLayer.addRenderable(this.layerTree);
			this.wwd.getModel().getLayers().add(this.hiddenLayer);

			// 注册图层选择和气球热点选择事件监听
			this.hotSpotController = new HotSpotController(this.wwd);
			// 注册kml事件监听
			this.kmlAppController = new KMLApplicationController(this.wwd);

			this.balloonController = new BalloonController(this.wwd)
			{
				@Override
				protected void addDocumentLayer(KMLRoot document)
				{
					addKMLLayer(document);
				}
			};

			// 关联kml管理器和balloon管理器
			this.kmlAppController.setBalloonController(balloonController);

			// Set up to receive SSLHandshakeExceptions that occur during
			// resource retrieval.
			WorldWind.getRetrievalService().setSSLExceptionListener(
					new RetrievalService.SSLExceptionListener()
					{
						public void onException(Throwable e, String path)
						{
							System.out.println(path);
							System.out.println(e);
						}
					});
		}

		/**
		 *
		 * @方法名称: addKMLLayer ;
		 * @方法描述: 添加KML图层: ;
		 * @参数 :@param kmlRoot
		 * @返回类型: void ;
		 * @创建人:刘硕 ;
		 * @创建时间:2015年3月17日 下午7:54:40;
		 * @throws
		 */
		protected void addKMLLayer(KMLRoot kmlRoot)
		{
			// Create a KMLController to adapt the KMLRoot to the World Wind
			KMLController kmlController = new KMLController(kmlRoot);

			// 添加kml图层
			RenderableLayer layer = new RenderableLayer();
			layer.setName((String) kmlRoot.getField(AVKey.DISPLAY_NAME));
			layer.addRenderable(kmlController);
			this.wwd.getModel().getLayers().add(layer);

			// 添加kml图层树节点
			KMLLayerTreeNode layerNode = new KMLLayerTreeNode(layer, kmlRoot);
			this.layerTree.getModel().addLayer(layerNode);
			this.layerTree.makeVisible(layerNode.getPath());
			layerNode.expandOpenContainers(this.layerTree);

			// Listens to refresh property change events from KML network link
			// nodes. Upon receiving such an event this
			// expands any tree paths that represent open KML containers. When a
			// KML network link refreshes, its tree
			// node replaces its children with new nodes created from the
			// refreshed content, then sends a refresh
			// property change event through the layer tree. By expanding open
			// containers after a network link refresh,
			// we ensure that the network link tree view appearance is
			// consistent with the KML specification.
			layerNode.addPropertyChangeListener(
					AVKey.RETRIEVAL_STATE_SUCCESSFUL,
					new PropertyChangeListener()
					{
						public void propertyChange(
								final PropertyChangeEvent event)
						{
							if (event.getSource() instanceof KMLNetworkLinkTreeNode)
							{
								// Manipulate the tree on the EDT.
								SwingUtilities.invokeLater(new Runnable()
								{
									public void run()
									{
										((KMLNetworkLinkTreeNode) event
												.getSource())
												.expandOpenContainers(layerTree);
										wwd.redraw();
									}
								});
							}
						}
					});
		}
	}

	/**
	 *
	 * @项目名称:worldwind-1.5.0
	 * @类名称:WorkerThread
	 * @类描述:加载KML文件线程类
	 * @创建人:刘硕
	 * @创建时间:2015年3月17日 下午7:58:38
	 * @修改备注:
	 * @版本:
	 */
	public static class WorkerThread extends Thread
	{
		/**
		 * 待加载kml文件,在构造函数中初始化
		 */
		protected Object kmlSource;
		/**
		 * kmlapp
		 */
		protected KMLUtil KMLUtil;

		public WorkerThread(Object kmlSource, KMLUtil KMLUtil)
		{
			this.kmlSource = kmlSource;
			this.KMLUtil = KMLUtil;
		}

		/**
		 * Loads this worker thread's KML source into a new
		 * <code>{@link gov.nasa.worldwind.ogc.kml.KMLRoot}</code>, then adds
		 * the new <code>KMLRoot</code> to this worker thread's
		 * <code>AppFrame</code>. The <code>KMLRoot</code>'s
		 * <code>AVKey.DISPLAY_NAME</code> field contains a display name created
		 * from either the KML source or the KML root feature name.
		 * <p/>
		 * If loading the KML source fails, this prints the exception and its
		 * stack trace to the standard error stream, but otherwise does nothing.
		 */
		public void run()
		{
			try
			{
				KMLRoot kmlRoot = this.parse();
				// 设置文档的显示名称
				kmlRoot.setField(AVKey.DISPLAY_NAME,
						formName(this.kmlSource, kmlRoot));

				// 启动一个任务进程加载解析的kml文件
				final KMLRoot finalKMLRoot = kmlRoot;
				SwingUtilities.invokeLater(new Runnable()
				{
					public void run()
					{
						KMLUtil.addKMLLayer(finalKMLRoot);
					}
				});
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}

		/**
		 *
		 * @方法名称: parse ;
		 * @方法描述: 解析KML文档 ;
		 * @参数 :@return 返回KMLRoot
		 * @参数 :@throws IOException:文档不可读
		 * @参数 :@throws XMLStreamException :文档解析出现错误
		 * @返回类型: KMLRoot ;
		 * @创建人:刘硕 ;
		 * @创建时间:2015年3月17日 下午8:02:59;
		 * @throws
		 */
		protected KMLRoot parse() throws IOException, XMLStreamException
		{
			// KMLRoot.createAndParse will attempt to parse the document using a
			// namespace aware parser, but if that
			// fails due to a parsing error it will try again using a namespace
			// unaware parser. Note that this second
			// step may require the document to be read from the network again
			// if the kmlSource is a stream.
			return KMLRoot.createAndParse(this.kmlSource);
		}
	}

	protected static String formName(Object kmlSource, KMLRoot kmlRoot)
	{
		KMLAbstractFeature rootFeature = kmlRoot.getFeature();

		if (rootFeature != null && !WWUtil.isEmpty(rootFeature.getName()))
			return rootFeature.getName();

		if (kmlSource instanceof File)
			return ((File) kmlSource).getName();

		if (kmlSource instanceof URL)
			return ((URL) kmlSource).getPath();

		if (kmlSource instanceof String
				&& WWIO.makeURL((String) kmlSource) != null)
			return WWIO.makeURL((String) kmlSource).getPath();

		return "KML Layer";
	}

}
时间: 2024-10-27 13:53:05

World Wind Java开发之十五——加载三维模型的相关文章

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

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

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

数据是GIS的核心,没有数据一切无从谈起,Internet上有很多在线WMS地图服务资源,我们可以好好利用这些数据资源,比如天地图.必应地图.NASA.OGC数据服务等等. 在我们国家常用的还是天地图的地图服务资源,详见:http://blog.3snews.net/space.php?uid=6955280&do=blog&id=67981,这篇博客列举了一些常用的在线地图服务资源,读者可以自行试下. 1.添加天地图地图服务 由于上篇转载的平常心的博客对WMSTiledImageLaye

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

嵌入式Linux裸机开发(十五)——LCD

嵌入式Linux裸机开发(十五)--LCD 一.LCD简介 LCD(Liquid Crystal Display)是液晶显示器简称.LCD的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的. 1.LCD类型 按照背光源的不同,LCD可以分为CCFL和LED两种. A.CCFL 指用CCFL(冷阴极荧光灯管)作为背光光源的液晶显示器(L

Java进阶(二十五)Java连接mysql数据库(底层实现)

Java进阶(二十五)Java连接mysql数据库(底层实现) 前言 很长时间没有系统的使用java做项目了.现在需要使用java完成一个实验,其中涉及到java连接数据库.让自己来写,记忆中已无从搜索.特将之前使用的方法做一简单的总结.也能够在底层理解一下连接数据库的具体步骤. 实现 首先需要导入相关的jar包,我使用的为:mysql-connector-java-5.1.7-bin.jar. 下面来看一下我所使用的数据库连接方法类: MysqlUtil.java package cn.edu

S3C2416裸机开发系列十五_GCC下uCOS的移植(1)

S3C2416裸机开发系列十五 GCC下uCOS的移植(1) 象棋小子    1048272975 操作系统是用来管理系统硬件.软件及数据资源,控制程序运行,并为其它应用软件提供支持的一种系统软件.根据不同的种类,又可分为实时操作系统.桌面操作系统.服务器操作系统等.对于一些小型的应用,对系统实时性要求高,硬件资源有限等的情况下,应尽量避免使用复杂庞大的操作系统(如Linux),使用小型的实时操作系统(如uCOS)更能满足应用的需求.笔者此处就uCOS-II的移植作一个简单的介绍. 1. 代码准

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

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

马凯军201771010116《面向对象与程序设计Java》第十五周学习知识总结

实验十五  GUI编程练习与应用程序部署 一.知识学习部分 清单文件 每个JAR文件中包含一个用于描述归档特征的清单文件(manifest).清单文件被命名为MANIFEST.MF,它位于JAR文件的一个特殊的META-INF子目录中. 最小的符合标准的清单文件是很简单的:Manifest-Version:1.0复杂的清单文件包含多个条目,这些条目被分成多个节.第一节被称为主节,作用于整个JAR文件.随后的条目用来指定已命名条目的属性,可以是文件.包或者URL. 清单文件的节与节之间用空行分开,