基于GeoTools使用JavaFx进行矢量数据可视化实战

CSDN 2024-08-14 10:05:02 阅读 86

目录

前言

一、JavaFx展示原理说明

二、GeoTools的Maven依赖问题

三、引入Geotools相关的资源包

四、创建JavaFx的Canvas实例

五、JavaFx的Scene和Node的绑定

六、总结


前言

        众所周知,JavaFx是Java继Swing之后的又一款用于桌面应用的开发利器。当然,现在已经是Web的时代,很多以前需要用桌面软件来支撑的软件,现在都可以使用Web的工具来完成。Web是一个大的趋势,同时现在在这里谈论JavaFx,也并不是说要深入研究。首先还是要根据市场需求来,作为Java开发人员,有可能在实际工作过程中,我们的需求方想要开发一个简单的工具。尤其是面向GIS这样的工具,首先不想像Arcgis那么大,甚至像SuperMap或者MapGIS这样的桌面端软件都不要,需求也是非常简单的,只是进行空间数据的简单可视化,或者做简单的空间分析。同时要求我们的软件是可以在跨平台的环境下运行的。当然除了Java,跨平台的可选择性还有许多。不是说跨平台只有Java能做。

        本文以全球各个国家的矢量数据的展示为例,重点讲解如何在JavaFx中进行展示,结合GeoTools来进行展示为需求背景。大家知道,geotools自身的组件框架中,gt_swing是实现桌面应用的一个可视化展示层,虽然在JavaFx中可以将Swing的一些控件进行集成,把Swing的按钮或者表格等放在JavaFx中进行渲染。但是很少把底图放在JavaFx中进行渲染的。当然,哪些使用JavaFx中的WebView嵌入了本地浏览器的不算在内。通过本文,会讲解如何将Geotools的地图在JavaFx中进行展示,大家在实际应用建设过程当中有这个需求的,可以看看博文。

一、JavaFx展示原理说明

        本节将对如何使用JavaFx进行空间数据的可视化进行说明,与Swing组件的机制不同。这里将重点讲解这两者是如何结合在一起,最终实现空间数据的可视化的。

        上图是一张JavaFx的组件架构图,最下面的是JavaFx的两个基石,Jvm和Java的相关API,这些其实都是它的底层依赖基础。 然后构建在JVM和JDK API基础之上的是相关的组件和开发工具包。这是对不同实现需求的组件封装。最上层是JavaFx的展示层,通过JavaAPI和Scene进行展示,其中Scene场景是JavaFx中一个很重要的对象。因此本文的重点也是围绕Scene来进行,通过Scene的构建和展示,帮助我们来实现空间数据的可视化展示。在实现可视化的过程中,还有一个很重要的对象,就是Canvas画布,我们在JavaFx当中实现可视化的基础,是中间渲染的桥梁。

二、GeoTools的Maven依赖问题

        关于GeoTools的Maven依赖问题,由于GeoTools工程项目的相关包不是都在Maven的中央仓库中的,因此我们在配置它的Maven依赖来就跟普通的工程是不一样的。关于GeoTools的maven依赖,其它的很多博主也有相应的文章进行介绍。这里就不再进行赘述。需要申明的是,博客编写过程中,我们的JDK使用的1.8的版本,而对应的Geotools我使用的是28.2的版本。现在Geotools的最新版本应该到31了,大家感兴趣可以到Github中查看一下GeoTools的官方仓库的信息传送门。

        应该是31.x的版本是最新的版本。不过为了兼容我们的Jdk的版本,大家用1.8的Jdk,还是可以使用28.x的版本。因此博客提供的案例都是使用28.x版本。

        如果我们的maven仓库引用的是阿里云的maven私服的话,那么在仓库的定义上要设置好,否则可能导致geotools的依赖包不能下下来。来看下项目工程的Pom.xml配置。

<code><repositories>

<!--从22.x后geotools由OSGeo管理-->

<repository>

<id>osgeo</id>

<name>OSGeo Release Repository</name>

<url>https://repo.osgeo.org/repository/release/</url>

<snapshots><enabled>false</enabled></snapshots>

<releases><enabled>true</enabled></releases>

</repository>

<repository>

<id>osgeo-snapshot</id>

<name>OSGeo Snapshot Repository</name>

<url>https://repo.osgeo.org/repository/snapshot/</url>

<snapshots><enabled>true</enabled></snapshots>

<releases><enabled>false</enabled></releases>

</repository>

<repository>

<id>GeoSolutions</id>

<url>http://maven.geo-solutions.it/</url>

</repository>

</repositories>

三、引入Geotools相关的资源包

        在pom.xml中定义了Geotools的依赖仓库地址后,我们来正式引入Geotools的相关依赖。这里为了简化,只提供其具体的配置代码,具体的每个组件的功能,在后面的博客中会进行逐一介绍。

<dependencies>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.11</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.geotools</groupId>

<artifactId>gt-shapefile</artifactId>

<version>${geotools.version}</version>

</dependency>

<dependency>

<groupId>org.geotools</groupId>

<artifactId>gt-swing</artifactId>

<version>${geotools.version}</version>

</dependency>

<dependency>

<groupId>org.geotools</groupId>

<artifactId>gt-main</artifactId>

<version>${geotools.version}</version>

</dependency>

<dependency>

<groupId>org.geotools.xsd</groupId>

<artifactId>gt-xsd-sld</artifactId>

<version>${geotools.version}</version>

</dependency>

<dependency>

<groupId>org.geotools.xsd</groupId>

<artifactId>gt-xsd-core</artifactId>

<version>${geotools.version}</version>

</dependency>

<dependency>

<groupId>org.geotools</groupId>

<artifactId>gt-xml</artifactId>

<version>${geotools.version}</version>

</dependency>

<dependency>

<groupId>org.jfree</groupId>

<artifactId>fxgraphics2d</artifactId>

<version>1.3</version>

</dependency>

</dependencies>

        经过上面的步骤,我们基本完成了Geotools官方仓库的定义以及相关依赖包的引用申明,在正常有网络的情况下,系统在后台就会自动帮助我们下载依赖的包。接下来我们来进行具体的功能开发即可。

四、创建JavaFx的Canvas实例

        由于在Jdk1.8当中,Javafx还是绑定在一起的,因此我们不需要单独针对JavaFx来进行配置,但是在1.8后面的版本中,jdk就将javaFx和jdk进行了分离,因此要单独进行配置。在引用相应的geotools的资源包之后,我们就可以来创建最重要的Canvas对象,这个Canvas对象是JavaFx的Canvas对象。通过Canvas对象,实现将Map和画布的融合,从而让数据显示处理。因此这里我们定义Canvas对象,并进行地图的初始化等操作。

        首先我们创建一个Node对象,这个Node对象包括Canvas、Map和GraphicsContext。同时我们提供两个方法,第一个是进行地图初始化的方法,第二个是进行地图数据绘制的方法。下面是定义Node类的属性和方法。

package tutorial1;

import java.awt.Rectangle;

import java.io.IOException;

import org.geotools.data.FileDataStore;

import org.geotools.data.FileDataStoreFinder;

import org.geotools.data.simple.SimpleFeatureSource;

import org.geotools.map.FeatureLayer;

import org.geotools.map.MapContent;

import org.geotools.renderer.lite.StreamingRenderer;

import org.geotools.styling.SLD;

import org.geotools.styling.Style;

import org.jfree.fx.FXGraphics2D;

import javafx.scene.Node;

import javafx.scene.canvas.Canvas;

import javafx.scene.canvas.GraphicsContext;

public class MapCanvas {

private Canvas canvas;

private MapContent map;

private GraphicsContext gc;

public MapCanvas(int width, int height) {

canvas = new Canvas(width, height);

gc = canvas.getGraphicsContext2D();

initMap();

drawMap(gc);

}

public Node getCanvas() {

return canvas;

}

private void initMap() {

}

private void drawMap(GraphicsContext gc) {

}

}

        Canvas负责进行展示,而Map对象负责提供显示的数据源。在上述的方法中,我们要先创建一个Canvas对象,在进行对象构造时,指定Canvas对象的高和宽,按照这个尺寸要求来创建。下面我们来看一下如何进行地图的初始化,也就是上面的initMap这个方法。

private void initMap() {

try {

FileDataStore store = FileDataStoreFinder

.getDataStore(this.getClass().getClassLoader().getResource("maps/countries.shp"));

SimpleFeatureSource featureSource = store.getFeatureSource();

map = new MapContent();

map.setTitle("Quickstart");

Style style = SLD.createSimpleStyle(featureSource.getSchema());

FeatureLayer layer = new FeatureLayer(featureSource, style);

map.addLayer(layer);

map.getViewport().setScreenArea(new Rectangle((int) canvas.getWidth(), (int) canvas.getHeight()));

} catch (IOException e) {

e.printStackTrace();

}

}

        在进行空间矢量数据的展示时,首先要告诉可视化渲染器,具体的文件在什么位置。接下来是使用样式,为了简单起见,这里使用默认样式来进行可视化,创建样式的时候,样式构建器会根据数据的类型来进行分别构建,比如不同的点、线、面,它的默认样式都是不一样的。这里的数据是面,因此会勾画出边界的线信息。代码如下:

Style style = SLD.createSimpleStyle(featureSource.getSchema());

        最后将样式和数据源进行绑定,然后将图层对象设置到map当中。MapContent这个对象就承载着双发的一个展示容器,最后通过返回这个node,将node和JavaFx的scene场景进行融合。再来看一下绘制地图的方法:

private void drawMap(GraphicsContext gc) {

StreamingRenderer draw = new StreamingRenderer();

draw.setMapContent(map);

FXGraphics2D graphics = new FXGraphics2D(gc);

graphics.setBackground(java.awt.Color.WHITE);

Rectangle rectangle = new Rectangle((int) canvas.getWidth(), (int) canvas.getHeight());

draw.paint(graphics, rectangle, map.getViewport().getBounds());

}

        在这里,通过JavaFx的Graphics对象就可以实现地图的绘制。

public Node getCanvas() {

return canvas;

}

五、JavaFx的Scene和Node的绑定

        虽然在上面的代码中已经实现了将Node对象进行创建,但是还是没有将Node和JavaFx的容器进行绑定,没有Scene的搭载就像没有舞台的演员,想展示自己的才艺都没有舞台。因此最后我们要将Node对象和Scene进行绑定即可。

package tutorial1;

import javafx.application.Application;

import javafx.scene.Scene;

import javafx.scene.layout.Pane;

import javafx.stage.Stage;

public class MainTutorial1 extends Application {

@Override

public void start(Stage primaryStage) {

MapCanvas canvas = new MapCanvas(1090, 670);

Pane pane = new Pane(canvas.getCanvas());

Scene scene = new Scene(pane);

primaryStage.setScene(scene);

primaryStage.setTitle("JavaFx结合Geotools展示地图");

primaryStage.show();

}

public static void main(String[] args) {

launch(args);

}

}

        上面的代码非常简单,通过创建的Canvas对象,然后设置一个地图展示的高度和宽度。将创建的对象和JavaFx的Scene进行绑定,最后设置好JavaFx的应用窗口的标题后,调用Show方法实现空间数据的可视化展示,最后运行的可视化效果如下:

        经过以上的步骤,我们就实现了在JavaFx中调用Geotools的相关库实现空间矢量数据的快速预览。 当然,这里只展示了空间可视化的效果。这个程序还是有很多进步的空间,比如需要增加鼠标的拖动和缩放、还要支持样式的定制等操作。时间缘故,下次再深入的来将这些设置,本文到此结束。

六、总结

        以上就是本文的主要内容, 本文以全球各个国家的矢量数据的展示为例,重点讲解如何在JavaFx中进行展示,结合GeoTools来进行展示为需求背景。大家知道,geotools自身的组件框架中,gt_swing是实现桌面应用的一个可视化展示层,虽然在JavaFx中可以将Swing的一些控件进行集成,把Swing的按钮或者表格等放在JavaFx中进行渲染。但是很少把底图放在JavaFx中进行渲染的。当然,哪些使用JavaFx中的WebView嵌入了本地浏览器的不算在内。通过本文,会讲解如何将Geotools的地图在JavaFx中进行展示,大家在实际应用建设过程当中有这个需求的,可以看看博文。

        本文行文仓促,难免有许多不足之处,还恳请各位专家和朋友们在阅读本文时在评论区留下宝贵意见,鄙人不胜感激。GeoTools非常值得学习,在Java进行GIS开发,一定要掌握这个组件库,提高我们的GIS技术开发能力。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。