meface/docs/article/gis/worldwind/WorldWindJavaMarker.md

866 lines
41 KiB
Markdown
Raw Normal View History

2023-11-17 10:54:23 +08:00
---
title: WorldWindJava 学习笔记
date: 2021-09-02
author: ac
tags:
- WorldWindJava
categories:
- GIS
---
> `WorldwindJava`是`NASA`美国国家航空航天局开源的Java服务端的三维类库一般用于客户端应用。
<!-- more -->
![image-20210402094245432](./images/image-20210402094245432.png)
## [WorldWind](https://worldwind.arc.nasa.gov/)
### 1. 简介
WorldWind是一个开放源代码的虚拟地球仪API。WorldWind允许开发人员快速轻松地创建3D地球地图和地理信息的交互式可视化。世界各地的组织都使用WorldWind监视天气模式可视化城市和地形跟踪车辆移动分析地理空间数据并科普教育有关地球的知识。
WorldWind提供了[Web端](https://github.com/NASAWorldWind/WebWorldWind)(JavaScript)、[移动端](https://github.com/NASAWorldWind/WorldWindAndroid)(Android)、[服务端](https://github.com/NASAWorldWind/WorldWindJava)(Java)三个版本的开发库。
### 2. 环境搭建(Java)
本篇使用的是Java版本所以安装好JDK最新版本的WorldWindJava [v2.2.0](https://github.com/NASAWorldWind/WorldWindJava/releases/tag/v2.2.0)使用的是JDK11但为了和项目兼容采用的是jdk8所以WorldWindJava下载[v2.1.0](https://github.com/NASAWorldWind/WorldWindJava/releases/tag/v2.1.0)的版本。
![image-20210402100805611](./images/image-20210402100805611.png)
解压后在当前目录的命令行运行`run-demo.bat`命令,可以查看`World Wind Appliaction`程序窗口。
<img src="./images/image-20210402101231643.png" alt="image-20210402101231643" style="zoom: 50%;" />
<img src="./images/image-20210402101308416.png" alt="image-20210402101308416" style="zoom: 25%;" />
> 如果你使用的是jdk8这上图窗口中地图应该是铺满的随着窗口大小的拖动界面内的布局会成百分比缩放但字体、输入框则不会变大。如果jdk版本是9或以上版本则支持图形、窗口和文本的自动缩放而且提供了处理多分辨率图像的能力适配不同的DPI。
在适配DPI的时候内部的canvas大小`WorldWindowGLCanvas`不能和组件大小一致这是JOGL中的GLCanvas在jdk9或以上版本中存在的显示问题。解决方法
1. 降低jdk版本jdk8可以解决这个问题但程序不会适配DPI
2. 使用`WorldWindowGLJPanel`替代`WorldWindowGLCanvas`
3. 根据[ JOGL用户指南](http://download.java.net/media/jogl/doc/userguide/) 重写`WorldWindowGLCanvas`的getPreferredSize方法。
程序可以在Globe中进行3D(Round)和2D(Flat)的切换2维平面可以选择投影方式选择加载的图层(Layers)。
上述的是运行演示demo的方法。
因为使用的是Swing + JOGL 进行OpenGL开发所以要使用`WorldWind`进行开发需要的依赖有:
- `gdal.jar`
- OpenGL相关的`gluegen-rt.jar`、`jogl.jar`以及四个OpenGL三维程序需要的四个`dll`文件(gluegen-rt.dll、jogl.dll、jogl_awt.dll、jogl_cg.dll)
- `worldwind.jar`
这些都可以在下载下来的worldwind-v2.1.0中找到现在新建一个项目作为学习的示例demo:
<img src="./images/image-20210407152316547.png" alt="image-20210407152316547" style="zoom: 33%;" />
`HelloWorldWind.java`
```java
import gov.nasa.worldwind.BasicModel;
import gov.nasa.worldwind.Configuration;
import gov.nasa.worldwind.awt.WorldWindowGLCanvas;
public class HelloWorldWind
{
private static class AppFrame extends javax.swing.JFrame
{
public AppFrame()
{
WorldWindowGLCanvas wwd = new WorldWindowGLCanvas();
wwd.setPreferredSize(new java.awt.Dimension(1000, 800));
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.getContentPane().add(wwd, java.awt.BorderLayout.CENTER);
this.pack();
wwd.setModel(new BasicModel());
}
}
public static void main(String[] args)
{
if (Configuration.isMacOS())
{
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Hello World Wind");
}
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new AppFrame().setVisible(true);
}
});
}
}
```
<img src="./images/image-20210407152752857.png" alt="image-20210407152752857" style="zoom:50%;" />
### 3. 基本概念
`WorldWind`是一个在Java应用程序中展示可交互的三维地理信息组件的集合。
程序通过在用户界面中放置一个或多个`WorldWindow`对象来使用`WorldWind`。
> `WorldWindow`为应用程序的信息和行为提供了3D地理环境。
`WorldWind`组件是可扩展的。API主要是通过接口定义的面向接口编程多态因此组件可以被替代组件选择性地替换。具体类也可以被替换或扩展。可扩展性是WorldWind的一个基本目标。
除了`WorldWindow`外,`WorldWind`还有以下几个主要接口:
<img src="./images/worldwinddevguideillustrations.png" alt="WorldWind Java Interface Diagram" style="zoom:67%;" />
<div style="text-align:center">图 3-1</div>
- `Globe`代表一个星球的形状和地形。`Globe`有一个`Tessellator`作为地形数据的提供者。
- `Layer`负责在`Globe`上渲染imagery影像、shapes形状以及其它信息。当用户在地理位置上导航时这些渲染的实例都保持它们相对于地球的地理位置。`Layer`还提供相对于屏幕平面的图层,图层内的图形不会随球体移动。
- `Model`用于集成`Globe`和`Layers`,包括`in-screen layers`(相对于屏幕的图层)
- `View`决定用户对`Model`的视图(视野位置和角度等),是由用户通过`InputHandler`的输入事件驱动的。
- `SceneController `控制`Model`的渲染和渲染的时间。它将`Model`和`View`关联起来。
常用步骤流程:
`Application`为其数据创建一个`Globe`和`Layers`,并将它们组合到一个`Model`中。同时创建一个`WorldWindow`并将`Model`传递给它。随后`WorldWindow`的`SceneController `会负责管理`globe`和`layers`的展示,与 用户交互的`View`一起使用。
----
### 4. 核心类
WorldWind是一组组件它们在Java应用程序中交互式地显示3D地理信息。应用程序通过在用户界面中放置一个或多个*`WorldWindow`*组件来使用WorldWind。`WorldWind`组件是可扩展的。API主要是通过接口定义的因此组件可以被替代组件*即接口的多种类型的实现之间相互替换*)选择性地替换。
> WorldWindow是一个接口为Swing/AWT以及将来的SWT-Eclipse提供了特定于工具包的接口实现。
除了*`WorldWindow`*接口外worldwind还有五个主要的接口
1. *[`Globe`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/Globe.html)* — represents a planet's shape and terrain.
2. *[`Layer`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/layers/Layer.html)* — applies imagery or information to a `Globe`.
3. *[`Model`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/Model.html)* — aggregates a `Globe` and the `Layer`s to apply to it.
4. *[`SceneController`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/SceneController.html)* — controls the rendering of a `Model`.
5. *[`View`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/View.html)* — interactively controls the user's view of the model.
#### WorldWindow
从图3-1中可以看出`WorldWindow`是核心组件,所以`WorldWindowJava`提供了*WorldWindow*接口,有很多类型的实现,如`WorldWindowGLJPanel`、`WorldWindowGLCanvas`等。
<img src="./images/image-20210414152221937.png" alt="image-20210414152221937" style="zoom: 67%;" />
- `WorldWindowGLCanvas`是用于显示WorldWind [`Model`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/Model.html)`Globe`和`Layer`)的【**重量级**】AWT组件。它是一个独立的组件旨在用作应用程序的`WorldWindow`。它继承了`GLCanvas`。
- `WorldWindowGLJPanel`:是一个【**轻巧级**】的Swing组件用于显示WorldWind [`Model`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/Model.html)`Globe`和`Layer`),它也是一个独立的组件,旨在用作应用程序的`WorldWindow`。它继承了`GLJPanel`。
> Java SDK for OpenGL (JOGL)对`GLJPanel`的支持一直存在问题。它在某些设备上运行良好,但在其他设备上却不行,并且其性能在各设备上的变化要比重量级同类产品大得多[`WorldWindowGLCanvas`](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/awt/WorldWindowGLCanvas.html)。
>
> 重量级AWT组件可以与轻型Swing组件结合使用。
[ JOGL用户指南](http://download.java.net/media/jogl/doc/userguide/)的*重量级和轻量级问题*部分描述相关bug显示大小、闪烁等问题
> JOGL提供了重量级GLCanvas和轻量级GLJPanel小部件从而能够为需要它的应用程序提供最快的性能并为需要它的应用程序提供100正确的Swing集成。GLCanvas通常提供比GLJPanel更高的性能。
**常用方法**
- **[getCurrentPosition](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/awt/WorldWindowGLJPanel.html#getCurrentPosition--)**()返回当前鼠标位置的当前纬度、经度和高度如果鼠标不在globe上则返回null。
- **[getGpuResourceCache](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/awt/WorldWindowGLJPanel.html#getGpuResourceCache--)**()返回该worldwind上使用的GPU资源
- **[getModel](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/awt/WorldWindowGLJPanel.html#getModel--)**()返回该worldwind中的model
- **[getSceneController](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/awt/WorldWindowGLJPanel.html#getSceneController--)**()返回关联的Scene Controller场景
- **[getView](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/awt/WorldWindowGLJPanel.html#getView--)**()返回worldwind中的view
- **[addPositionListener](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/awt/WorldWindowGLJPanel.html#addPositionListener-gov.nasa.worldwind.event.PositionListener-)**([PositionListener](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/event/PositionListener.html) listener):添加位置变化监听
---
#### Globe
> 在worldwind中*Globe*接口代表一个星球的形状和地形,球体可以与提供地球表面地理位置的高程的(*ElevationModel*)高程模型相关联。
Globe提供了将地理位置(纬度、经度和海拔)与笛卡尔坐标相互转换的方法,其中笛卡尔坐标系的原点和方向由该接口的实现决定。
<font color='red'>地心笛卡尔坐标系、经纬度地理坐标系</font>
**笛卡尔坐标的计算**
Globe提供了在以笛卡尔坐标表示的Globe表面的坐标系统中执行计算的方法这些方法在三维笛卡尔坐标下根据地球的实际形状执行工作。对于椭球这些方法等价于下面的椭球坐标计算。对于Globe2D的一个实例这些方法在由球体的2D投影指定的笛卡尔坐标下工作。
```java
//从纬度、经度和高程计算一个笛卡尔点,即地理坐标-->笛卡尔坐标。
Vec4 computePointFromPosition(Angle latitude, Angle longitude, double metersElevation)
//矢量点转为经纬度的位置,地理坐标。
Position computePositionFromPoint(Vec4 point)
//用经纬度计算垂直于地球表面的笛卡尔坐标。
Vec4 computeSurfaceNormalAtLocation(Angle latitude,Angle longitude)
//返回将模型坐标映射到本地坐标系统(纬度、经度、度量)的笛卡尔变换矩阵。
Matrix computeSurfaceOrientationAtPosition(Angle latitude,Angle longitude,double metersElevation)
```
**在椭球体上的坐标计算**
```java
//返回的点是地球的赤道半径和极半径的函数,并且总是表示在三维笛卡尔坐标中与指定位置相对应的椭球上的一个点。
Vec4 computeEllipsoidalPointFromPosition(Angle latitude,Angle longitude,double metersElevation)
//矢量Vec4x,y,z,w--> position 经纬度高程
Position computePositionFromEllipsoidalPoint(Vec4 ellipsoidalPoint)
```
实现类有[Earth](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/Earth.html), [EarthFlat](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/EarthFlat.html), [EllipsoidalGlobe](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/EllipsoidalGlobe.html), [FlatGlobe](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/FlatGlobe.html) 。
- EllipsoidalGlobe定义一个globe作为椭球的模式。globe使用的是Y轴指向北极的笛卡尔坐标系。
Z轴在赤道面上指向本初子午线和赤道的交点。
X轴是一个右手坐标系它在Z轴以东90度也在赤道平面上。
海平面在z = 0处。默认情况下坐标系统的原点位于球体的中心但可以在构造球体时设置为不同的点。
<img src="./images/dikaer1.jpg" alt="dikaer1" style="zoom: 80%;" />
- FlatGlobe继承EllipsoidalGlobe表示一个投影到平面上的globe默认是墨卡托投影。这个globe使用的是笛卡尔坐标系Y轴指向北极Z轴指向屏幕向上X轴完成了一个右手坐标系指向东原点在经纬度都为0的地方。
- Earth继承EllipsoidalGlobe表示一个地球模式使用的是WGS84坐标系统
- EarthFlat继承FlatGlobe表示一个地球投影到平面上的模式地球的半径采用WGS84中的半径。
对于二维平面的FlatGlobe和EarthFlat可以使用[setProjection](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/FlatGlobe.html#setProjection-gov.nasa.worldwind.globes.GeographicProjection-)方法修改投影。
**投影相关类**
- [AbstractGeographicProjection](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/AbstractGeographicProjection.html)
- [ProjectionEquirectangular](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionEquirectangular.html)
- [ProjectionMercator](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionMercator.html)
- [ProjectionModifiedSinusoidal](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionModifiedSinusoidal.html)
- [ProjectionPolarEquidistant](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionPolarEquidistant.html)
- [ProjectionSinusoidal](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionSinusoidal.html)
- [ProjectionTransverseMercator](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionTransverseMercator.html)
- [ProjectionUPS](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionUPS.html)
- [ProjectionUTM](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/globes/projections/ProjectionUTM.html)
![image-20210415153556778](./images/image-20210415153556778.png)
---
#### Layer
*Layer*接口定义了大部分图层公共的操作:
<img src="./images/image-20210415160956309.png" alt="image-20210415160956309" style="zoom: 80%;" />
如图层的请求超时时间、图层名、透明度、是否加载到View中、当前缩放级别Scale、最大有效经纬度等方法。
*AbstractLayer*实现*Layer*接口,增加一些与配置文件,加载参数相关的规范。具体的实现有:
- AnnotationLayer注记图层
- IconLayer图标图层
- MarkerLayer标注图层
- RenderableLayer渲染图层用于管理可渲染对象的集合
- ScalebarLayer比例尺图层在屏幕一角呈现一个比例尺图形
- SkyColorLayer天空颜色图层
- StarsLayer星星图层
- SurfaceImageLayer表面影像图层
- TerainProfileLayer地形剖面图层在屏幕一角显示地形剖面图。
- ViewControlsLayer这个图层显示在屏幕View控件上。可以控制平移缩放标题俯仰倾斜视野和垂直放大。每个控件都可以单独启用或禁用。这个类的实例依赖于ViewControlsSelectListener的实例来控制它。select监听器必须通过WorldWindow.addSelectListener(gov.nasa. worldwind.com event. selectlistener)注册。
- ViewControlsSelectListener由ViewControlsLayer显示的屏幕上视图控件的控制器。
- WorldMapLayer类似鹰眼的控件图层显示世界地图覆盖与当前位置十字准星在屏幕角落。
WorldWind中加载的图层常常是加载的通过Web请求加载的地图服务瓦片这些服务的地址都在worldwind.jar中的config目录下使用方式是
- 创建`AVKey`接口定义了与配置文件中key相对应的常量
- 使用`Configuration`类来加载WorldWind初始化的参数和注册其内容。
---
#### Configuration
> `Configuration`管理`WorldWind`的初始配置。
它读取WorldWind配置文件并注册其内容。配置文件包含要在运行时创建的类的名称、model配置包括globeelevation model 高程模型和layers以及各种控制量例如缓存大小和数据检索超时等
```java
public class Configuration // Singleton
{
...
private static final String CONFIG_WW_DOCUMENT_NAME = "config/worldwind.xml";
private static final String CONFIG_APP_DOCUMENT_KEY = "gov.nasa.worldwind.app.config.document";
private static Configuration ourInstance = new Configuration();
private static Configuration getInstance(){
return ourInstance;
}
...
}
```
<img src="./images/image-20210414162657853.png" alt="image-20210414162657853" style="zoom:80%;" />
`Configuration`类是一个单例,构造器是私有的。它只能通过该类的静态方法得到实例。它是在首次使用其任何静态方法时构建的。
首次实例化`Configuration`类时它将读取XML文档`config/worldwind.xml`并在其中注册所有信息。随后可以通过类的各种`getValue`方法来检索信息 。许多WorldWind启动对象查询此信息以确定要创建的类。例如应用程序创建的第一个WorldWind对象通常是`WorldWindowGLCanvas`。在构造期间该类使用从Configuration单例该类中提取的那些类的名称来构造WorldWind的内部类。
`Configuration.java`常和`AVKey.java`一起搭配使用,`AVKey`是一个接口,用于配置系统常量,其中包含`config/worldwind.xml`配置文件中的Key。
```xml
<WorldWindConfiguration version="1">
<LayerList href="config/worldwind.layers.xml"/>
<Property name="gov.nasa.worldwind.avkey.ModelClassName" value="gov.nasa.worldwind.BasicModel"/>
<Property name="gov.nasa.worldwind.avkey.GlobeClassName"
value="gov.nasa.worldwind.globes.Earth"/>
<Property name="gov.nasa.worldwind.avkey.EarthElevationModelConfigFile"
value="config/Earth/EarthElevations2.xml"/>
...
</WorldWindConfiguration>
```
```java
...
final String MODEL_CLASS_NAME = "gov.nasa.worldwind.avkey.ModelClassName";
final String GLOBE_CLASS_NAME = "gov.nasa.worldwind.avkey.GlobeClassName";
final String EARTH_ELEVATION_MODEL_CONFIG_FILE = "gov.nasa.worldwind.avkey.EarthElevationModelConfigFile";
...
```
---
#### Model
model接口用于集成一个`Globe`实例和多个`Layer`图层通过globe可以间接包括elevation model 高程模型。默认的Model会在`worldwind.xml`中定义:
```xml
<!--Most configuration information is defined in attribute-value pairs-->
<Property name="gov.nasa.worldwind.avkey.ModelClassName" value="gov.nasa.worldwind.BasicModel"/>
```
AVKey.java中的对应的常量
```java
final String MODEL_CLASS_NAME = "gov.nasa.worldwind.avkey.ModelClassName";
```
![image-20210415171438907](./images/image-20210415171438907.png)
实现类只有[BasicModel](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/BasicModel.html) 。常用方法:
- getExtent返回model在笛卡尔坐标系中的边界范围
- getGlobe/setGlobe
- getLayers/setLayers
---
#### View
<img src="./images/17666341-ef2360f9a503f292.png" alt="img" style="zoom:80%;" />
<div style="text-align:center">Local/Object Spcae转换到Screen space的过程</div>
上图是OpenGL中坐标系中局部坐标系到屏幕坐标系的转换流程。
OpenGL中的五个Space和对应的坐标系
1. LocalObjectSpace每个物体都有他们独立的坐标系
2. World Space为每一个物体定义一个位置从而能在更大的世界当中放置它们
3. Eye Space从Camera相机的视角透视投影的坐标系统
4. Clip Space指定视景体如平截头体Frustum作为坐标范围裁剪被裁剪掉的坐标就会被忽略所以剩下的坐标就将变为屏幕上可见的片段
5. Screen Space左上角为原点
*View*接口提供从Local coordinates 到eye coordinates(原点在视点向下看负Z轴的右手坐标系)的转换方法。
*View*还提供了eye coordinates到 screen coordinates的转变方法遵循OpenGL的约定原点位于屏幕左下角。
View 上的大多数方法都取决于调用时View的状态
以下方法返回最近调用后View的状态值
- `getEyePosition`:返回视点的地理坐标(经纬度)
- `getEyePoint`返回视点在3D笛卡尔坐标系中的坐标xyz
- `getUpVector`
- `getForwardVector`
- `getModelviewMatrix`
- `getViewport`返回视口的边界x,y,width,height
- `getFrustum`返回Eye Coordinates中的视锥体
- `getFrustumInModelCoordinates`
- `getProjectionMatrix`
下列方法的依赖于调用时View的状态值
- `project`
- `unproject`
- `computeRayFromScreenPoint`
- `computePositionFromScreenPoint`
- `computePixelSizeAtDistance`
- `computeHorizonDistance`
![image-20210419135708651](./images/image-20210419135708651.png)
实现类有[BasicFlyView](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/view/firstperson/BasicFlyView.html), [BasicOrbitView](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/view/orbit/BasicOrbitView.html), [BasicView](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/view/BasicView.html) 。
- BasicView是View派生的一个基类BasicFlyView和BasicOrbitView继承了BasicView 它提供了一个从地心视图模型到3D图形模型视图矩阵的映射。BasicView也通过截锥来管理投影矩阵。
> BasicView模型中的view由地理位置position仰角pitch标题title和滚动roll构成。
- BasicFlyView这是一个基本的view实现一个以第一人称风格的 yaw-pitch-roll model偏航-俯仰-滚动)模型的视图应用程序。
> 俯仰角pitch定义为垂直于接地平面而不像大多数机体轴线表示中的那样平行这与WorldWind中的pitch定义一致。程序将需要通过增加90度来校正间距值要获得水平视图请输入90度间距。要向下进行请输入0度
<img src="./images/20151125212621964.jpg" alt="20151125212621964" style="zoom:80%;" />
<img src="./images/yaw_pitch_roll.jpg" alt="img" style="zoom:80%;" />
- BasicOrbitView基本轨道视角
---
#### SceneController
`SceneController ` 是控制 `Model` 的渲染和渲染的时间的,且将`Model`和`View`关联起来。
![image-20210419144039507](./images/image-20210419144039507.png)
实现类 [StereoOptionSceneController](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/StereoOptionSceneController.html) 继承了[BasicSceneController](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/BasicSceneController.html) [BasicSceneController](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/BasicSceneController.html)继承了[AbstractSceneController](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/AbstractSceneController.html))。
要使用设备支持的立体声WorldWindow实例必须支持立体声。在创建立体声WorldWindow之前通过指定上面描述的Java VM属性来选择它。
---
### 5. 几何对象
在`gov.nasa.worldwind.geom`包下可以了解到`WorldWind`的几何对象有:
- [Angle](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Angle.html) 表示一个几角度。其实例是不可变的final修饰可以通过静态的工厂方法 `fromDegrees(double)`和`fromRadians(double)` 获得。
- [BarycentricQuadrilateral](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/BarycentricQuadrilateral.html)
- [BarycentricTriangle](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/BarycentricTriangle.html)
- [BilinearInterpolator](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/BilinearInterpolator.html)
- [Box](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Box.html) :一个任意方向的盒子,通常用作点或形状集合的`bounding volume`。一个Box由三个正交的轴和每个轴上的两个位置定义。每个positions 都指定了box 沿各自轴的位置这三个轴按惯例命名为“R”、“S”和“T”并按长度递减顺序排列——R是最长的轴其次是S然后是T。
- [Cylinder](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Cylinder.html) :代表一个圆柱,最常用作为`bounding volume`Cylinder也是不可变的。
- [Frustum](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Frustum.html) 表示view中由六个平面组成的平截头体 left, right, bottom, top, near ,far
- [Frustum.Corners](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Frustum.Corners.html)
- [GeoQuad](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/GeoQuad.html)
- [Intersection](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Intersection.html)
- [LatLon](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/LatLon.html) :表示 globe 二维表面上的一个点。纬度是指北纬,范围在[- 90,90]之间,经度是指东经,范围在(- 180,180]之间。实例也是不可变的。
```java
LatLon(Angle latitude, Angle longitude)
```
- [Line](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Line.html) 表示线使用两个Vec4点构造一条线
- [Matrix](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Matrix.html) :矩阵
- [PickPointFrustum](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/PickPointFrustum.html) 一个视口对齐的截锥它还存储截锥所包含的2D屏幕矩形。
- [Plane](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Plane.html) :表示笛卡尔坐标下的平面,由平面的法向量和与平面到原点的距离成比例的带符号标量值定义。值的符号是相对于平面法线方向的。
```java
Plane(double nx, double ny, double nz, double d)
Plane(Vec4 vec)
```
- [PolarPoint](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/PolarPoint.html) 表示空间中由纬度、经度和到原点的距离定义的点lat, long, r
- [Position](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Position.html) 带有高程的位置点lat,long,elev
```java
Position(Angle latitude, Angle longitude, double elevation)
Position(LatLon latLon, double elevation)
```
- [Position.PositionList](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Position.PositionList.html)
- [Quaternion](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Quaternion.html) 四元数x,y,z,w
- [Sector](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Sector.html) :扇区,表示经纬度的矩形区域。区域由四个角度定义:最小和最大纬度,最小和最大经度。假设角度归一化为+/- 90度纬度和+/- 180度经度。最小值和最大值是相对于这些范围的例如-80小于20。
```java
Sector(Angle minLatitude, Angle maxLatitude, Angle minLongitude, Angle maxLongitude)
```
- [Sphere](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Sphere.html) :表示三维空间中的球体。
```java
//中点加半径
Sphere(Vec4 center, double radius)
```
- [Triangle](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Triangle.html) :提供对三角形的操作。
```java
//用三个逆时针顺序的顶点构造一个三角形。
Triangle(Vec4 a, Vec4 b, Vec4 c)
```
- [Triangle.TriangleIntersection](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Triangle.TriangleIntersection.html)
- [Vec4](https://nasaworldwind.github.io/WorldWindJava/gov/nasa/worldwind/geom/Vec4.html) 四个维度的矢量点x,y,z,w
```java
Vec4(double value)
Vec4(double x, double y)
Vec4(double x, double y, double z)
Vec4(double x, double y, double z, double w)
```
### 6. 图层配置与控件
#### WorldWind中的控件
<img src="./images/widgets.png" alt="image-20210419170903498" style="zoom: 67%;" />
`WorldWindJava`中控件是以Layer图层的形式进行添加的。
在官方实例的`HelloWorldWind.java`中可以看到`WorldWindow`使用的是`BasicModel`对象:
```java
wwd.setModel(new BasicModel());
```
而在`BasicModel.java`中,优先查找`worldwind.xml`配置文件中的*gov.nasa.worldwind.avkey.LayerClassNames*
```java
public BasicModel()
{
String globeName = Configuration.getStringValue(AVKey.GLOBE_CLASS_NAME);
if (globeName == null)
return;
this.setGlobe((Globe) WorldWind.createComponent(globeName));
// Look for the old-style, property-based layer configuration first.
// If not found then use the new-style
// configuration.
LayerList layers = null;
String layerNames = Configuration.getStringValue(AVKey.LAYERS_CLASS_NAMES);
if (layerNames != null)
{
// Usage of this deprecated method is intentional.
// It provides backwards compatibility for deprecated functionality.
//noinspection deprecation
layers = this.createLayersFromProperties(layerNames);
}
else
{
Element el = Configuration.getElement("./LayerList");
if (el != null)
layers = this.createLayersFromElement(el);
}
// an empty list is ok
this.setLayers(layers != null ? layers : new LayerList(/*empty list*/));
}
```
但默认的`worldwind.xml`没有该属性,所以读取的是该文件下的`LayerList`节点:
```xml
<WorldWindConfiguration version="1">
<LayerList href="config/worldwind.layers.xml"/>
...
</WorldWindConfiguration>
```
`worldwind.layers.xml`中配置这默认的18个图层包含默认的三个控件图层
```xml
<LayerList>
<Layer className="gov.nasa.worldwind.layers.StarsLayer">
<!--Individual properties can be specified within Layer entries, like this:-->
<Property name="Name" value="Stars"/>
</Layer>
<Layer className="gov.nasa.worldwind.layers.SkyGradientLayer"/>
<Layer className="gov.nasa.worldwind.layers.Earth.BMNGOneImage">
<Property name="MinActiveAltitude" value="3e6"/>
</Layer>
<Layer href="config/Earth/BMNGWMSLayer2.xml" actuate="onLoad"/>
<Layer href="config/Earth/LandsatI3WMSLayer2.xml" actuate="onLoad"/>
<!--<Layer href="config/Earth/USDANAIPWMSImageLayer.xml" actuate="onRequest"/>-->
<Layer href="config/Earth/USGSNAIPPlusLayer.xml" actuate="onRequest"/>
<!--<Layer href="config/Earth/MSVirtualEarthAerialLayer.xml" actuate="onRequest"/>-->
<Layer href="config/Earth/BingImagery.xml" actuate="onRequest"/>
<Layer href="config/Earth/USGSTNMTopoLayer.xml" actuate="onRequest"/>
<Layer href="config/Earth/USGSTNMTopoLargeLayer.xml" actuate="onRequest"/>
<Layer href="config/Earth/USGSTopoLowResLayer.xml" actuate="onRequest"/>
<Layer href="config/Earth/USGSTopoMedResLayer.xml" actuate="onRequest"/>
<Layer href="config/Earth/USGSTopoHighResLayer.xml" actuate="onRequest"/>
<!--<Layer className="gov.nasa.worldwind.layers.Earth.OSMMapnikLayer" actuate="onRequest"/>-->
<!--<Layer className="gov.nasa.worldwind.layers.Earth.OSMCycleMapLayer" actuate="onRequest"/>-->
<Layer className="gov.nasa.worldwind.layers.Earth.CountryBoundariesLayer" actuate="onRequest"/>
<!--<Layer href="config/Earth/OpenStreetMap.xml" actuate="onRequest"/>-->
<!--<Layer href="config/Earth/WorldBordersShapefile.xml" actuate="onRequest"/>-->
<Layer href="config/Earth/EarthAtNightLayer.xml" actuate="onRequest"/>
<Layer className="gov.nasa.worldwind.layers.Earth.NASAWFSPlaceNameLayer"/>
<Layer className="gov.nasa.worldwind.layers.WorldMapLayer"/>
<Layer className="gov.nasa.worldwind.layers.ScalebarLayer"/>
<Layer className="gov.nasa.worldwind.layers.CompassLayer"/>
</LayerList>
```
#### 重新指定配置文件
项目中可以通过设置Java系统属性的方式修改配置文件的路径让系统读取自定义的配置。如
1. 先将`worldwind.jar`包中的config目录中的Earth目录、worldwind.xml和worldwind.layers.xml拷贝到项目中
<img src="./images/image-20210420113704804.png" alt="image-20210420113704804" style="zoom: 67%;" />
2. 修改worldwind.xml 中LayerList节点图层配置文件的路径
```xml
<LayerList href="com/mgcsat/orbit/config/worldwind.layers.xml"/>
```
3. 修改图层配置文件worldwind.layers.xml。这里只加载星空、地球轮廓光晕、夜光三个图层。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<LayerList>
<Layer className="gov.nasa.worldwind.layers.StarsLayer">
<Property name="Name" value="Stars"/>
</Layer>
<Layer className="gov.nasa.worldwind.layers.SkyGradientLayer"/>
<Layer href="config/Earth/EarthAtNightLayer.xml" actuate="onLoad"/>
</LayerList>
```
4. 在项目的入口main方法里面指定配置文件路径
```java
public class HelloWorldWind {
private static class AppFrame extends javax.swing.JFrame{
public AppFrame(){
WorldWindowGLJPanel wwd = new WorldWindowGLJPanel();
wwd.setPreferredSize(new java.awt.Dimension(1000, 800));
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.getContentPane().add(wwd, java.awt.BorderLayout.CENTER);
this.pack();
wwd.setModel(new BasicModel());
}
}
public static void main(String[] args){
//修改默认配置文件
System.setProperty("gov.nasa.worldwind.config.document", "com/mgcsat/orbit/config/worldwind.xml");
if (Configuration.isMacOS()){
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Hello WorldWind");
}
java.awt.EventQueue.invokeLater(new Runnable(){
public void run(){
new AppFrame().setVisible(true);
}
});
}
}
```
效果:
<img src="./images/image-20210420114319665.png" alt="image-20210420114319665" style="zoom: 33%;" />
---
#### ViewControllerLayer
在上述的例子中添加以下代码添加ViewControllerLayer图层。
```java
//添加ViewController图层
ViewControlsLayer vc = new ViewControlsLayer();
wwd.getModel().getLayers().add(vc);
//将ViewController实例和worldwind关联一个VC实例不能在多个worldwind中共享
ViewControlsSelectListener vcsl = new ViewControlsSelectListener(wwd, vc);
wwd.addSelectListener(vcsl);
```
<img src="./images/image-20210420135700776.png" alt="image-20210420135700776" style="zoom:33%;" />
完整的ViewControllerLayer功能提供Pan、Look、Zoom、Heading、Pitch、Field of view、View Elevation
<img src="./images/image-20210420142012066.png" alt="image-20210420142012066" style="zoom: 80%;" />
```java
vc.setShowPanControls(true);
vc.setShowLookControls(true);
vc.setShowZoomControls(true);
vc.setShowHeadingControls(true);
vc.setShowPitchControls(true);
vc.setShowFovControls(true);//Field of view
vc.setShowVeControls(false);//View Elevation
```
常用方法:
```java
//1.设置vc在左下角的布局有水平AVKey.HORIZONTAL和垂直两种AVKey.VERTICAL
vc.setLayout(AVKey.VERTICAL);
//2.设置vc整个大小比例
vc.setScale(0.8);
```
> 如果在应用中需要隐藏或显示已经绘制了的控件图层如要隐藏ViewController中的Look调用setShowLookControls(false)后worldwind中控件还在这需要worldwind实例调用redraw方法重新绘制。
---
#### WorldMapLayer
WorldMapLayer用于显示2D的地图类似于WebGIS中的鹰眼效果一样。其中十字中心为View中心点所在位置还有一条于View一起联动的视野范围的边界线。WorldMapLayer加入到WorldWindow中后图层会随View一起联动但点击WorldMapLayer图层View是不会移动的是单向的联动。
<img src="./images/image-20210420151939176.png" alt="image-20210420151939176" style="zoom: 80%;" />
实现双向的联动可以使用`ClickAndGoSelectListener`类的实例,来监听和处理`WorldMapLayer`图层的点击事件。
```java
//创建WorldMapLayer
WorldMapLayer worldMapLayer = new WorldMapLayer();
wwd.getModel().getLayers().add(worldMapLayer);
//添加事件监听
wwd.addSelectListener(new ClickAndGoSelectListener(wwd, WorldMapLayer.class));
```
<img src="./images/worldMapLayer07.gif" alt="worldMapLayer07" style="zoom:80%;" />
常用方法:
```java
//设置图层所在位置AVKey.NORTHEAST、AVKey.NORTHWEST(默认)、 AVKey.SOUTHEAST、SOUTHWEST.
worldMapLayer.setPosition(AVKey.NORTHEAST);
```
### 7. 绘制几何对象
```java
//自定义图形图层
RenderableLayer layer = new RenderableLayer();
//将自定义图层添加wwd中因为没有配置地名图层所以不用担心遮挡问题
wwd.getModel().getLayers().add(layer);
//创建几何对象
LatLon dongguan = new LatLon(Angle.fromDegrees(23.04), Angle.fromDegrees(113.75));
LatLon chongqing = new LatLon(Angle.fromDegrees(29.59), Angle.fromDegrees(106.54));
LatLon chengdu = new LatLon(Angle.fromDegrees(30.67), Angle.fromDegrees(104.06));
LatLon wuhan = new LatLon(Angle.fromDegrees(30.52), Angle.fromDegrees(114.31));
LatLon changsha = new LatLon(Angle.fromDegrees(28.21), Angle.fromDegrees(113));
LatLon shenyang = new LatLon(Angle.fromDegrees(41.8), Angle.fromDegrees(123.38));
ArrayList<LatLon> surfaceLinePositions = new ArrayList<>();
surfaceLinePositions.add(shenyang);
surfaceLinePositions.add(LatLon.fromDegrees(42, 125));
surfaceLinePositions.add(LatLon.fromDegrees(41, 124));
surfaceLinePositions.add(shenyang);
SurfaceCircle circle = new SurfaceCircle(dongguan, 100e3);
SurfaceEllipse ellipse = new SurfaceEllipse(chongqing, 100e3, 90e3, Angle.ZERO);
SurfaceSquare square = new SurfaceSquare(chengdu, 100e3);
SurfaceQuad quad = new SurfaceQuad(changsha, 100e3, 60e3, Angle.ZERO);
SurfaceSector sector = new SurfaceSector(Sector.fromDegrees(36.07, 40, 120.33, 123));
SurfacePolygon polygon = new SurfacePolygon(surfaceLinePositions);
BasicShapeAttributes attr = new BasicShapeAttributes();
//设置图形边界
attr.setDrawOutline(true);
attr.setOutlineMaterial(new Material(new Color(0f,0f,1f)));
attr.setOutlineOpacity(1);
attr.setOutlineWidth(1);
//设置图形内部颜色(填充色)和不透明度
attr.setInteriorMaterial(new Material(new Color(1f,0f,0f,1)));
attr.setInteriorOpacity(1);
attr.setDrawInterior(true);
circle.setAttributes(attr);
layer.addRenderable(circle);
ellipse.setAttributes(attr);
layer.addRenderable(ellipse);
square.setAttributes(attr);
layer.addRenderable(square);
quad.setAttributes(attr);
layer.addRenderable(quad);
sector.setAttributes(attr);
layer.addRenderable(sector);
polygon.setAttributes(attr);
layer.addRenderable(polygon);
wwd.redraw();
```
<img src="./images/image-20210422174722864.png" alt="image-20210422174722864" style="zoom: 33%;" />
### 8. 数据检索
`WorldWind`处理大量的数据和信息,这些数据和信息主要存在于远程数据服务器上。`WorldWind`支持缓存远程请求的数据和信息,检索本地数据的功能。检索到远程数据后,它会存储在本地磁盘缓存中,然后从检索使用。缓存没有固定大小。可以通过应用程序以编程方式将其删除。
> 所有数据检索,甚至从磁盘检索,都在后台线程上执行。
### Tip:
---
**日期时间**
**儒略日**(Julian day,JD)是指由公元前4713年1月1日协调世界时中午12时开始所经过的天数多为天文学家采用,用以作为天文学的单一历法,把不同历法的年表统一起来。
[世界时](https://baike.baidu.com/item/世界时)[UT](https://baike.baidu.com/item/UT/4044923) 即[格林尼治](https://baike.baidu.com/item/格林尼治/3065623) 平太阳时间,是指格林尼治所在地的标准时间,也是表示地球自转速率的一种形式。
CST中央标准时间CST可视为美国、澳大利亚、古巴或中国的标准时间。
UTC协调世界时即格林威治平太阳时间是指格林威治所在地的标准时间也是表示地球自转速率的一种形式UTC基于国际原子时间。
GMT被视为世界时UT 即格林尼治平太阳时间指格林尼治所在地的标准时间。GMTGreenwish Mean Time 格林威治平时这是UTC的民间名称。GMT=UTC。
![img](./images/cc11728b4710b9122a8b1b14cdfdfc0393452296.png)