纯Java实现Google地图的KMZ和KML文件的解析

目录

前言

一、关于KMZ和KML

1、KMZ是什么

2、KML是什么

二、Java解析实例

1、POM.xml引用

2、KML 基类定义

3、空间对象的定义

4、Kml解析工具类

三、KML文件的解析

1、KML解析测试

2、KMZ解析测试

四、总结


前言

        今天是六.一儿童节,在这里祝各位大朋友们儿童节快乐,同时祝祖国的所有花朵们更加快乐。童年的欢乐可以治愈一切。不知道各位的儿童节是怎么度过的呀,是在陪孩子呢,还在在享受自己的欢乐时光,只愿大家都欢乐就好。这是写在最前面祝福的话,愿我们都开心快乐。

        最近碰到有朋友咨询,大致的问题是,他在项目中要实现KMZ数据的解析和WebGIS的可视化。刚好他用的技术栈是Java,同时KMZ的解析在各个网站上的相关解析代码不多。有很多代码是解析KML的,但是解析KMZ的相对比较少。一时没有参考的例子,希望能结合JAVA讲一下如何进行KMZ数据的解析。其实话说回来,虽然大致了解KMZ是什么数据,但是在之前的项目过程中,接触的空间数据也基本都是shp、gdb等等,至于google的KMZ还真的是第一回接触。

        本文主要讲解如何用JAVA语言,直接解析KMZ数据。文章首先介绍google地图中的KMZ和KML数据,然后使用代码的方式实现数据的解析,最后展示解析成果以及如何将数据转换成空间WKT数据。关于JAVA解析KML的博客和资料有不少,但是KMZ文件的还是比较稀少的,供各位朋友在工作中解析KMZ文件有一个参考。

一、关于KMZ和KML

        在进行相关文件的解析之前,首先我们来看一下KMZ和KML这两种文件,先了解这两种文件是什么?用来做什么的,具体的文件内容是什么样的。本节主要提供这些基础知识的讲解。

1、KMZ是什么

        KMZ 文件包含主 KML 文件以及0个或多个用 ZIP 格式打包成一个单元的支持文件(称为归档)。然后,KMZ 文件就可以作为单个实体进行存储和通过电子邮件发送。NetworkLink 可从网络服务器提取 KMZ 文件。将 KMZ 文件解压缩后,主 .kml 文件及其支持文件便分离成其各自的原始格式和目录结构,以及原始文件名和扩展名。除了变成归档格式外,ZIP 格式也会受到压缩,因此归档只能包含一个大型 KML 文件。根据 KML 文件的内容,此过程通常会产生10:1的压缩。10千字节的 KML 文件可以用1千字节的 KMZ 文件来提供。

        KMZ是Google Earth默认的输出文件格式,是一个经过ZIP格式压缩过的KML文件,当我们从网站上下载KMZ文件的时候,Windows会把KMZ文件认成ZIP文件,所以另存的时候文件后缀会被改成.ZIP,因此需要手动将文件后缀改成.KMZ。   KMZ文件用ZIP工具软件打开,然后解压缩即可得到原始KML文件。当然,KMZ文件也有自己的好处,就是KMZ文件的自身可以包含影像,这样就可以不依赖引用网络上的截图。   一般情况下,双击KMZ/KML文件即可从Google Earth中打开地标文件,但是需要注意的是,KMZ/KML地标文件名不能包含中文字符,文件存放的路径也不能有中文字符,否则将无法在Google Earth中打开。

        这里我们以漂亮国的全球基地为说明,验证一下上述的内容。把KMZ文件的后缀名修改为zip,然后用压缩文件打开。可以看到以下的文件:

        总结一下,KMZ就是把KML文件,进行了一个打包。这个很重要,在后面的解析过程中,会用到这个知识点。讲完了KMZ,下面介绍一下KML。

2、KML是什么

        KML 代表 钥匙孔标记语言。此 GIS 格式基于 XML,主要用于 Google 地球。KML由Keyhole Inc开发,后来被Google收购.KMZ(KML-Zipped)取代KML成为默认的Google地球地理空间格式,因为它是文件的压缩版本。KML/KMZ于2008年成为开放地理空间联盟的国际标准。经度和纬度分量(十进制度)由 1984 年世界大地测量系统 (WGS84) 定义。垂直分量(高度)以米为单位从 WGS84 EGM96 大地水准面垂直基准面开始测量。

        KML (keyhole markup language)是以XML语言为基础开发的一种文件格式,用来描述和存储地理信息数据(点、线、面、图片等),是纯粹的xml文本格式,可用记事本打开编辑,所以kml文件很小。KML跟XML文件最大的不同就是KML描述的是地理信息数据。最早开发KML的是keyhole公司,2004年Goole收购keyhole并用KML开发GooleEarth。KML是原先的Keyhole客户端进行读写的文件格式,是一种XML描述语言,并且是文本格式,这种格式的文件对于Google Earth程序设计来说有极大的好处,程序员可以通过简单的几行代码读取出地标文件的内部信息,并且还可以通过程序自动生成KML文件,因此,使用KML格式的地标文件非常利于Google Earth应用程序的开发。

        这里我们还是以上面的kml文件为说明,将打开的示例xml文件内容展示如下:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
<Document><!-- Begin Style Definitions --><Folder><name>Point Features</name><description>Point Features</description><Placemark><description>Airport</description><name><![CDATA[CHARLESTON AFB/INTL 查尔斯顿空军基地/国际机场]]></name><Point><coordinates>-80.0408900000,32.8985600000,0</coordinates></Point></Placemark><Placemark><description>Airport</description><name><![CDATA[DAVIS-MONTHAN AFB 戴维斯-蒙森空军基地]]></name><Point><coordinates>-110.8822600000,32.1652200000,0</coordinates></Point></Placemark></Folder>
</Document>
</kml>

        以上就是一个KML文件的示例,其主体内容就是一个XML。它以XML为主体,用来存储地理空间数据。因此对KML数据的解析,其本质就是对XML文件的解析。

二、Java解析实例

        本节主要以代码实战的方式介绍使用Java编程语言实现对KML语言和KMZ语言的解析。由于涉及到xml的解析,这里不采用最原始的dom解析方式。对于KML语言,有成熟的组件de.micromata.jak.JavaAPIforKml对KML的解析。这里对相关的解析组件进行介绍:

序号组件名称作用
1de.micromata.jak.JavaAPIforKmlKML文件解析
2org.apache.commons.commons-compress压缩包解压
3com.vividsolutions.jtsJTS wkt字符串构建

1、POM.xml引用

<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.yelang</groupId><artifactId>gdal_demo1</artifactId><version>0.0.1-SNAPSHOT</version><name>gdal_demo1</name><description>试验</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><!-- https://mvnrepository.com/artifact/de.micromata.jak/JavaAPIforKml --><dependency><groupId>de.micromata.jak</groupId><artifactId>JavaAPIforKml</artifactId><version>2.2.1</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.21</version></dependency><dependency><groupId>com.vividsolutions</groupId><artifactId>jts</artifactId><version>1.13</version></dependency></dependencies>
</project>

2、KML 基类定义

        这里进行kml 基类定义,将name、description、List<Coordinate>进行统一封装。针对Point、Polygon、Polyline对象,在自己的对象属性中扩展额外的属性。这里采用OOP的实现方式。网上很多的代码没有将父级类抽象出来,同时其代码只解析了name。没有解析description属性。这里我们将描述信息同样解析出来。关键代码如下:

package com.yelang.kmzcase;
import java.util.List;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
/*** kml 基类,将name、description、List<Coordinate>进行统一封装* @author 夜郎king*/
public class KmlBaseEntity {private List<Coordinate> points;private String name;private String description;public List<Coordinate> getPoints() {return points;}public void setPoints(List<Coordinate> points) {this.points = points;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public KmlBaseEntity(List<Coordinate> points, String name, String description) {super();this.points = points;this.name = name;this.description = description;}public KmlBaseEntity() {super();}
}

3、空间对象的定义

        空间对象常见的类型包括点(Point)、线(Polyline)、面(Polygon)三种类型。这里我们将根据需要定义不同的空间对象。下面分别给出实例代码:

KmlPoint.java

package com.yelang.kmzcase;
import java.util.List;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
public class KmlPoint extends KmlBaseEntity{private String color;public String getColor() {return color;}public void setColor(String color) {this.color = color;}public KmlPoint(List<Coordinate> points,String name,String description,String color){super(points, name, description);this.color = color;}public KmlPoint() {super();}
}

KmlLine.java 

package com.yelang.kmzcase;
public class KmlLine extends KmlBaseEntity {private String color;private long width;public String getColor() {return color;}public void setColor(String color) {this.color = color;}public long getWidth() {return width;}public void setWidth(long width) {this.width = width;}
}

KmlPolygon.java

package com.yelang.kmzcase;
/*** @program: 面状实体**/
public class KmlPolygon extends KmlBaseEntity {private String color;public String getColor() {return color;}public void setColor(String color) {this.color = color;}
}

4、Kml解析工具类

        这里定义Kml的解析工具类,主要负责解析KML,然后根据不同的图层,将属性和空间坐标点信息赋值给不同的空间数据集合。网上有一些解析的代码,仅解析name属性。这里扩展了其它的属性,包括描述属性。详细代码如下:

package com.yelang.kmzcase;import de.micromata.opengis.kml.v_2_2_0.*;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/*** @description: KML文件解析**/
public class ParsingKmlUtil {/***	 解析kml文件*/public KmlData parseKmlByFile(File file) {Kml kml = Kml.unmarshal(file);return getByKml(kml);}/*** 	解析kml文件流* * @param inputstream* @return*/public KmlData parseKmlByInputstream(InputStream inputstream) {Kml kml = Kml.unmarshal(inputstream);return getByKml(kml);}/*** Kml对象转自定义存储对象* * @param kml* @return*/public KmlData getByKml(Kml kml) {KmlData kmlData = new KmlData();kmlData.setKmlPoints(new ArrayList<>());kmlData.setKmlLines(new ArrayList<>());kmlData.setKmlPolygons(new ArrayList<>());Feature feature = kml.getFeature();parseFeature(feature, kmlData);return kmlData;}/*** 	解析kml节点* @param feature* @param kmlData*/private void parseFeature(Feature feature, KmlData kmlData) {if (feature != null) {if (feature instanceof Document) {List<Feature> featureList = ((Document) feature).getFeature();featureList.forEach(documentFeature -> {if (documentFeature instanceof Placemark) {getPlaceMark((Placemark) documentFeature, kmlData);} else {parseFeature(documentFeature, kmlData);}});} else if (feature instanceof Folder) {List<Feature> featureList = ((Folder) feature).getFeature();featureList.forEach(documentFeature -> {if (documentFeature instanceof Placemark) {getPlaceMark((Placemark) documentFeature, kmlData);} else {parseFeature(documentFeature, kmlData);}});}}}private void getPlaceMark(Placemark placemark, KmlData kmlData) {Geometry geometry = placemark.getGeometry();/*String name = placemark.getName();placemark.getDescription();System.out.println(placemark.getDescription());if (name == null) {name = placemark.getDescription();}parseGeometry(name, geometry, kmlData);*/parseGeometry(placemark,geometry,kmlData);}/***	 解析点线面形状的数据分别放入存储对象* @param placemark placemark对象* @param geometry 形状类型* @param kmlData  存储对象*/private void parseGeometry(Placemark placemark, Geometry geometry, KmlData kmlData) {if (geometry != null) {if (geometry instanceof Polygon) {Polygon polygon = (Polygon) geometry;Boundary outerBoundaryIs = polygon.getOuterBoundaryIs();if (outerBoundaryIs != null) {LinearRing linearRing = outerBoundaryIs.getLinearRing();if (linearRing != null) {List<Coordinate> coordinates = linearRing.getCoordinates();if (coordinates != null) {outerBoundaryIs = ((Polygon) geometry).getOuterBoundaryIs();addPolygonToList(kmlData.getKmlPolygons(), placemark, outerBoundaryIs);}}}} else if (geometry instanceof LineString) {LineString lineString = (LineString) geometry;List<Coordinate> coordinates = lineString.getCoordinates();if (coordinates != null) {coordinates = ((LineString) geometry).getCoordinates();addLineStringToList(kmlData.getKmlLines(), coordinates, placemark);}} else if (geometry instanceof Point) {Point point = (Point) geometry;List<Coordinate> coordinates = point.getCoordinates();if (coordinates != null) {coordinates = ((Point) geometry).getCoordinates();addPointToList(kmlData.getKmlPoints(), coordinates, placemark);}} else if (geometry instanceof MultiGeometry) {List<Geometry> geometries = ((MultiGeometry) geometry).getGeometry();for (Geometry geometryToMult : geometries) {Boundary outerBoundaryIs;List<Coordinate> coordinates;if (geometryToMult instanceof Point) {coordinates = ((Point) geometryToMult).getCoordinates();addPointToList(kmlData.getKmlPoints(), coordinates, placemark);} else if (geometryToMult instanceof LineString) {coordinates = ((LineString) geometryToMult).getCoordinates();addLineStringToList(kmlData.getKmlLines(), coordinates, placemark);} else if (geometryToMult instanceof Polygon) {outerBoundaryIs = ((Polygon) geometryToMult).getOuterBoundaryIs();addPolygonToList(kmlData.getKmlPolygons(), placemark, outerBoundaryIs);}}}}}/***	 保存面状数据* * @param kmlPolygonList  已有面状数据* @param placemark       placemark对象* @param outerBoundaryIs 面状信息*/private void addPolygonToList(List<KmlPolygon> kmlPolygonList, Placemark placemark, Boundary outerBoundaryIs) {LinearRing linearRing = outerBoundaryIs.getLinearRing();// 面KmlPolygon kmlPolygon = new KmlPolygon();kmlPolygon.setPoints(linearRing.getCoordinates());kmlPolygon.setName(placemark.getName());kmlPolygon.setDescription(placemark.getDescription());kmlPolygonList.add(kmlPolygon);}/*** 保存线状数据* * @param kmlLineList 已有线状数据* @param coordinates 线状经纬度数据* @param name        线状名称*/private void addLineStringToList(List<KmlLine> kmlLineList, List<Coordinate> coordinates, Placemark placemark) {KmlLine kmlLine = new KmlLine();kmlLine.setPoints(coordinates);kmlLine.setName(placemark.getName());kmlLine.setDescription(placemark.getDescription());kmlLineList.add(kmlLine);}/*** 保存点状数据* * @param kmlPointList 已有点状数据* @param coordinates  点状经纬度数据* @param name         点状名称*/private void addPointToList(List<KmlPoint> kmlPointList, List<Coordinate> coordinates, Placemark placemark) {KmlPoint kmlPoint = new KmlPoint();kmlPoint.setName(placemark.getName());kmlPoint.setDescription(placemark.getDescription());kmlPoint.setPoints(coordinates);kmlPointList.add(kmlPoint);}}

        在定义了上述的代码之后,基本就可以实现了纯Java对KML文件的解析。下一节将调用上面的代码进行相应文件的解析。

三、KML文件的解析

        本节将重点介绍如何解析KML文件。

1、KML解析测试

package com.yelang.kmzcase;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.io.WKTWriter;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.Kml;
import java.io.*;
import com.vividsolutions.jts.geom.*;
public class KMZParser {public static void parseKml() throws IOException {ParsingKmlUtil parsingKmlUtil = new ParsingKmlUtil();File file = new File("C:/BaiduDownload/美军基地-地图数据(kmz)/美空军基地 - 副本/US-AFB.KML"); // 文件地址自己修改KmlData kmlData = parsingKmlUtil.parseKmlByFile(file);// assert kmlData != null;if (kmlData.getKmlPoints().size() > 0) {for (KmlPoint k : kmlData.getKmlPoints()) {GeometryFactory geoFactory = new GeometryFactory();Coordinate coord = k.getPoints().get(0);com.vividsolutions.jts.geom.Coordinate jtCoord = new com.vividsolutions.jts.geom.Coordinate(coord.getLongitude(), coord.getLatitude(), coord.getAltitude());// 使用GeometryFactory创建一个点Geometry point = geoFactory.createPoint(jtCoord);WKTWriter writer = new WKTWriter();String wkt = writer.write(point);System.out.println(k.getPoints() + "\t"+ wkt  +"\t"+ k.getDescription() + "\t  " + k.getName());}}}// 使用示例public static void main(String[] args) throws IOException {KMZParser.parseKml();}
}

        由于在XML中的坐标是一个数组,如果想把这些数据保存到空间数据库中,需要进行格式转换,比如从WKT字符串转为Geometry。当然,保存到空间数据库中,有很多种方法,这里我们介绍一种,基于JTS的方式构建WKT字符串,因为在MyBatis-Plus中,可以直接操作WKT字符串。将坐标转换WKT字符串的方法如下:

com.vividsolutions.jts.geom.Coordinate jtCoord = new com.vividsolutions.jts.geom.Coordinate(coord.getLongitude(), coord.getLatitude(), coord.getAltitude());
// 使用GeometryFactory创建一个点
Geometry point = geoFactory.createPoint(jtCoord);
WKTWriter writer = new WKTWriter();
String wkt = writer.write(point);

        在控制台中执行以上方法可以看到以下信息的输出,说明KML文件解析成功。

[-80.04089,32.89856]	POINT (-80.04089 32.89856)	Airport	  CHARLESTON AFB/INTL 查尔斯顿空军基地/国际机场
[-110.88226,32.16522]	POINT (-110.88226 32.16522)	Airport	  DAVIS-MONTHAN AFB 戴维斯-蒙森空军基地
[-110.34393,31.58844]	POINT (-110.34393 31.58844)	Airport	  LIBBY AAF/SIERRA VISTA MUN 利比空军基地/谢拉维斯塔
[-98.49243,33.98621]	POINT (-98.49243 33.98621)	Airport	  SHEPPARD AFB/WICHITA FALLS MUN 谢泼德空军基地/威奇托福尔斯??
[-72.52899,42.19849]	POINT (-72.52899 42.19849)	Airport	  WESTOVER ARB/METROPOLITAN 韦斯特欧弗空军基地
[-84.04541,39.82544]	POINT (-84.04541 39.82544)	Airport	  WRIGHT-PATTERSON AFB 赖特-帕特森空军基地
[-84.07013,39.80072]	POINT (-84.07013 39.80072)	Airport	  WRIGHT-PATTERSON AFB 赖特-帕特森空军基地

2、KMZ解析测试

        网上很多博客都只讲了如何解析KML,但是对于KMZ的解析介绍比较少,以JAVA为开发语言解析更少了。上面的方法也只实现了KML的解析,如果把文件换成KMZ,肯定会报错的。不信来试试。错误信息如下:

         如果发生了以上的异常,不要急。发生这个异常的原因其实在文章的开头就讲过了。如果看到这里前面没有印象的,可以翻到前面去看一下。还是简单说明一下吧,主要是KMZ是KML的压缩包,而以上代码是KML的解析,没有对KMZ进行解压。这里有两种方法来实现,第一种是将KMZ文件进行解压,然后对解压后的文件解析,肯定没问题。第二种是在压缩包中读取,然后对压缩流信息进行解析。第一种方式会增加不必要的脏文件,第二种则不会,因为原始文件只有一个。 下面我们采用第二种实现方式,首先来定义一个处理接口(必须要):

package com.yelang.kmzcase;
import java.io.IOException;
import java.io.InputStream;
/*** kml转换类,用于实现kml的自定义识别与读取* @author 夜郎king*/
public interface IKMLParser {/*** @param kmlInputStream* @throws IOException*/void parseKML(InputStream kmlInputStream) throws IOException;
}

        然后再定义针对KMZ的内容解析代码(基于在线解压的方式),然后已输入流的方式完成内容解析,这个代码网上比较少,如果需要KMZ文件解析,可以作为参考:

public static void parseKMZFile(File kmzFile, IKMLParser kmlParser) throws IOException {try (InputStream fileInputStream = new FileInputStream(kmzFile);ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(fileInputStream)) {ArchiveEntry entry;while ((entry = archiveInputStream.getNextEntry()) != null) {String name = entry.getName();if (name.toLowerCase().endsWith(".kml") || name.toLowerCase().endsWith(".kmz")) {// 如果发现.kml或.kmz文件,可以将其内容读取出来并传递给KMLParser处理kmlParser.parseKML(archiveInputStream);}}}}public static void parseKmz() throws IOException {File kmzFile = new File("C:/BaiduDownload/美军基地-地图数据(kmz)/美国全球基地.kmz");KMZParser.parseKMZFile(kmzFile, new IKMLParser() {@Overridepublic void parseKML(InputStream kmlInputStream) throws IOException {// 在这里实现你的KML解析逻辑// 例如,可以将读取的KML内容转换为字符串try (BufferedReader reader = new BufferedReader(new InputStreamReader(kmlInputStream))) {String line;StringBuffer xmlContent = new StringBuffer(1024);while ((line = reader.readLine()) != null) {// 处理每一行KML数据xmlContent.append(line);}// System.out.println(xmlContent);Kml kml = Kml.unmarshal(xmlContent.toString());ParsingKmlUtil pku = new ParsingKmlUtil();KmlData kmlData = pku.getByKml(kml);if (null != kmlData.getKmlPoints()&&kmlData.getKmlPoints().size() > 0) {for (KmlPoint kp : kmlData.getKmlPoints()) {GeometryFactory geoFactory = new GeometryFactory();Coordinate coord = kp.getPoints().get(0);com.vividsolutions.jts.geom.Coordinate jtCoord = new com.vividsolutions.jts.geom.Coordinate(coord.getLongitude(), coord.getLatitude(), coord.getAltitude());// 使用GeometryFactory创建一个点Geometry point = geoFactory.createPoint(jtCoord);WKTWriter writer = new WKTWriter();String wkt = writer.write(point);System.out.println(kp.getPoints() + "\t"+ wkt  +"\t"+ kp.getDescription() + "\t  " + kp.getName());}System.out.println("美军全球基地的数据是==>" + kmlData.getKmlPoints().size());}} catch (IOException e) {e.printStackTrace();}}});}

        上述代码的主要逻辑是,使用compress对KMZ文件进行在线解压,然后动态拼接KML内容,最后解析KML文件,然后提取空间信息。经过上述步骤,完成信息的解析。在运行以上的代码,发现KMZ文件已经成功解析。

        至此已经完成KMZ和KML文件的解析。 

四、总结

        以上就是本文的主要内容,本文主要讲解如何用JAVA语言,直接解析KMZ数据。文章首先介绍google地图中的KMZ和KML数据,然后使用代码的方式实现数据的解析,最后展示解析成果以及如何将数据转换成空间WKT数据。关于JAVA解析KML的博客和资料有不少,但是KMZ文件的还是比较稀少的,算是作为网文的一种补充,供各位朋友在工作中解析KMZ文件有一个参考。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。

        博文在编写过程中参考了以下博文:

        1、什么是 KMZ 文件?。

        2、从事地信测绘必须知道的GIS常见数据格式类型,以及数据格式和扩展名汇总。

        3、地理信息地图标记KML与KMZ的区别。

        4、java 生成kml 文件。

        5、Java解析kml文件获取点/线段/多边形面状地图经纬度信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/338128.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle mysql索引区别

文章目录 1.引言1.1 索引的基本概念1.2 Oracle和MySQL的简介 2.Oracle索引2.1 Oracle索引的类型**B-Tree索引****Bitmap索引****Function-Based索引****Partitioned索引****Text索引** 2.2 Oracle索引的工作原理2.3 Oracle索引的实例代码 3.MySQL索引3.1 MySQL索引的类型**B-Tr…

synchronized 锁的到底是什么?

通过8种情况演示锁运行案例&#xff0c;看看我们到底锁的是什么 1锁相关的8种案例演示code package com.bilibili.juc.lock;import java.util.concurrent.TimeUnit;/*** 题目&#xff1a;谈谈你对多线程锁的理解&#xff0c;8锁案例说明* 口诀&#xff1a;线程 操作 资源类* 8…

CLIP--Learning Transferable Visual Models From Natural Language Supervision

参考&#xff1a;CLIP论文笔记--《Learning Transferable Visual Models From Natural Language Supervision》_visual n-grams模型-CSDN博客 openAI&#xff0c;2021&#xff0c;将图片和文字联系在一起&#xff0c;----->得到一个能非常好表达图片和文字的模型主题&#…

Pandas 使用 concat 数据合并你学会了吗?

1. 使用pd.concat()级联 pandas使用pd.concat函数&#xff0c;与np.concatenate函数类似 # 导包import numpy as npimport pandas as pd​# 为方便讲解&#xff0c;我们首先定义一个生成DataFrame的函数def make_df(indexs,columns): data [[str(j)str(i) for j in colum…

RabbitMQ延时队列

一、RabbitMQ下载并使用插件 1、查看RabbitMQ插件的文件路径 docker inspect rabbitmq 找到Mounts下面Name:rabbitmq_plugin的Source即为插件路径 使用 cd 进入到该目录 2、下载插件 wget https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download…

C# 使用Aspose生成和修改文档

Aspose库 C#中的Aspose库是一个强大的文件处理库&#xff0c;可以用于各种文件格式的创建、编辑、转换和操作。该库提供了丰富的功能&#xff0c;包括处理文档、电子表格、幻灯片、PDF、图像等多种文件格式&#xff0c;能够轻松实现文件的读取、写入、格式化、样式设置、数据操…

Java Apache Jaccard文本相似度匹配初体验

文章目录 前言一、文本相似度算法的选择二、常见的文本相似度算法介绍三、使用示例1、引入jar包2、方法示例3、Jaccard源码剖析4、Jaccard源码解释 写在最后 前言 产品今天提了个需求&#xff0c;大概是这样的&#xff0c;来&#xff0c;请看大屏幕。。。额。。。搞错了&#…

三丰云评测:免费虚拟主机和免费云服务器体验

今天我来为大家分享一下我的三丰云评测体验。三丰云是一家提供免费虚拟主机和免费云服务器的服务商&#xff0c;为了方便大家了解他们的服务&#xff0c;我特地注册了他们的免费虚拟主机和免费云服务器进行试用。在实际体验中&#xff0c;我发现三丰云的服务表现非常出色。首先…

【产品经理】总篇章

引言: 在最近频繁的产品职位面试中&#xff0c;我深刻体会到了作为产品需要的不仅仅是对市场和技术的敏锐洞察&#xff0c;更多的是在复杂多变的环境中&#xff0c;如何运用沟通、领导力和决策能力来引导产品从概念走向市场。这一系列博客将分享我多年经历和所学到的所以知识&a…

OpenCV学习 基础图像操作(十六):图像距离变换

基础原理 顾名思义&#xff0c;我们可以利用像素之间的距离作为对该像素的一种刻画&#xff0c;并将其运用到相应的计算之中。然而&#xff0c;在一幅图像之中&#xff0c;某种类型的像素并不是唯一的&#xff0c;因此我门常计算的是一类像素到另一类的最小距离&#xff0c;并…

工厂模式详情

一.介绍工厂模式的用途与特点 工厂方法模式是一种创建型设计模式&#xff0c; 其在父类中提供一个创建对象的方法&#xff0c; 允许子类决定实例化对象的类型。定义工厂方法模式(Fatory Method Pattern)是指定义一个创建对象的接口&#xff0c;但让实现这个接口的类来决定实例…

npm install node-sass 安装失败的解决方案:利用国内镜像加速安装

在开发前端项目时&#xff0c;使用Sass作为CSS预处理器是很多开发者的选择。然而&#xff0c;在通过npm安装其Node.js绑定库node-sass时&#xff0c;一些开发者可能会遇到安装失败的问题&#xff0c;尤其是网络原因导致的下载缓慢或中断。本文将指导你如何通过更换为国内镜像源…

如何在测试/线上环境页面访问本地接口?

文章目录 一、前言二、分析三、搭建1、搭建nginx&#xff0c;监听http请求转发2、监听https请求转发 四、总结 一、前言 在工作中&#xff0c;开发完的接口&#xff0c;一般测试的话&#xff0c;基本是使用Postman&#xff0c;如果要到页面测试&#xff0c;就要发版进行测试&a…

《逆水寒》手游周年庆,热度不减反增引发热议

易采游戏网5月31日最新消息&#xff1a;随着数字娱乐时代的飞速发展&#xff0c;手游市场的竞争愈发激烈。在这样的大背景下&#xff0c;《逆水寒》手游以其独特的古风武侠世界和深度的社交体验&#xff0c;自上线以来便吸引了无数玩家的目光。如今&#xff0c;这款游戏迎来了它…

知识运维概述

文章目录 知识运维研究现状技术发展趋势 知识运维 由于构建全量的行业知识图谱成本很高&#xff0c;在真实的场景落地过程中&#xff0c;一般遵循小步快走、快速迭代的原则进行知识图谱的构建和逐步演化。知识运维是指在知识图谱初次构建完成之后&#xff0c;根据用户的使用反馈…

WSL2-Ubuntu22.04-配置

WSL2-Ubuntu22.04-配置 准备1. WSL相关命令[^1]2. WSL2-Ubuntu22.04可视化3. WSL2 设置 CUDA4. 设置OpenGL 本文介绍了WSL2的基本使用方法及可视化&#xff0c;着重介绍了GPU和OpenGL的设置。 准备 名称版本windows11wsl2CUDA12.5 1. WSL相关命令1 查看已安装的wsl distribut…

DevExpress开发WPF应用实现对话框总结

说明&#xff1a; 完整代码Github​&#xff08;https://github.com/VinciYan/DXMessageBoxDemos.git&#xff09;DevExpree v23.2.4&#xff08;链接&#xff1a;https://pan.baidu.com/s/1eGWwCKAr8lJ_PBWZ_R6SkQ?pwd9jwc 提取码&#xff1a;9jwc&#xff09;使用Visual St…

“手撕”链表的九道OJ习题

目录 1. 第一题 2. 第二题 3. 第三题 4. 第四题 5. 第五题 6. 第六题 7. 第七题 8. 第八题 9. 第九题 1. 第一题 删除链表中等于给定值 val 的所有节点。OJ链接 思路如下&#xff1a; 相当于链表的removeAll();制定prev和cur&#xff0c;prev记录前一个节点&#xff…

2021JSP普及组第三题:插入排序

2021JSP普及组第三题 题目&#xff1a; 思路&#xff1a; 题目要求排序后根据操作进行对应操作。 操作一需要显示某位置数据排序后的位置&#xff0c;所以需要定义结构体数组储存原数据的位置和数据本身排序后所得数据要根据原位置输出排序后的位置&#xff0c;所以建立一个新…

作业 递归应用

已完成&#xff1a;7 #include <iostream> using namespace std; long long f(long long,long long); int main(){long long n,m;cin>>n>>m;cout<<f(m,n);return 0; } long long f(long long a,long long b){if(a%b0){return b;}return f(b,a%b); } #i…