├── .gitignore
├── LICENSE
├── README.md
├── giscat-vector
├── giscat-vector-mbexpression
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── org
│ │ │ └── wowtools
│ │ │ └── giscat
│ │ │ └── vector
│ │ │ └── mbexpression
│ │ │ ├── Expression.java
│ │ │ ├── ExpressionName.java
│ │ │ ├── ExpressionParams.java
│ │ │ ├── decision
│ │ │ ├── All.java
│ │ │ ├── Any.java
│ │ │ ├── Case.java
│ │ │ ├── Compare.java
│ │ │ ├── Equal.java
│ │ │ ├── GreaterOrEqualThan.java
│ │ │ ├── GreaterThan.java
│ │ │ ├── LessOrEqualThan.java
│ │ │ ├── LessThan.java
│ │ │ ├── Match.java
│ │ │ ├── Negation.java
│ │ │ └── NotEqual.java
│ │ │ ├── lookup
│ │ │ ├── At.java
│ │ │ ├── Get.java
│ │ │ ├── Has.java
│ │ │ ├── In.java
│ │ │ ├── IndexOf.java
│ │ │ ├── Length.java
│ │ │ └── Slice.java
│ │ │ ├── spatial
│ │ │ ├── BboxIntersection.java
│ │ │ ├── BboxIntersects.java
│ │ │ ├── GeoIntersection.java
│ │ │ ├── GeoIntersects.java
│ │ │ └── Read.java
│ │ │ └── string
│ │ │ ├── Concat.java
│ │ │ ├── Downcase.java
│ │ │ └── Upcase.java
│ │ └── test
│ │ └── java
│ │ ├── com
│ │ └── Test.java
│ │ └── org
│ │ └── wowtools
│ │ └── giscat
│ │ └── vector
│ │ └── mbexpression
│ │ └── ExpressionTest.java
├── giscat-vector-mvt
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── org
│ │ │ └── wowtools
│ │ │ └── giscat
│ │ │ └── vector
│ │ │ └── mvt
│ │ │ ├── Command.java
│ │ │ ├── MvtBuilder.java
│ │ │ ├── MvtCoordinateConvertor.java
│ │ │ ├── MvtFeature.java
│ │ │ ├── MvtLayer.java
│ │ │ ├── MvtParser.java
│ │ │ └── VectorTile.java
│ │ └── test
│ │ ├── java
│ │ └── org
│ │ │ └── wowtools
│ │ │ └── giscat
│ │ │ └── vector
│ │ │ └── mvt
│ │ │ ├── MvtBuilderTest.java
│ │ │ ├── MvtCoordinateConvertorTest.java
│ │ │ ├── Test1.java
│ │ │ ├── WebDemo.java
│ │ │ └── demos
│ │ │ ├── hello
│ │ │ └── WebDemo.java
│ │ │ └── reload
│ │ │ └── WebDemoReload.java
│ │ └── resources
│ │ ├── china.json
│ │ ├── china_bak.json
│ │ └── static
│ │ ├── test.html
│ │ └── testreload.html
├── giscat-vector-pojo
│ ├── README.md
│ ├── doc
│ │ └── imgs
│ │ │ └── geojson_vs.jpg
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ │ └── wowtools
│ │ │ │ └── giscat
│ │ │ │ └── vector
│ │ │ │ └── pojo
│ │ │ │ ├── Feature.java
│ │ │ │ ├── FeatureCollection.java
│ │ │ │ ├── GeoJsonObject.java
│ │ │ │ ├── PojoConstant.java
│ │ │ │ ├── converter
│ │ │ │ ├── FoolStyleFeatureConverter.java
│ │ │ │ ├── GeoJsonFeatureConverter.java
│ │ │ │ └── ProtoFeatureConverter.java
│ │ │ │ └── proto
│ │ │ │ └── ProtoFeature.java
│ │ └── resources
│ │ │ └── ProtoFeature.proto
│ │ └── test
│ │ └── java
│ │ └── org
│ │ └── wowtools
│ │ └── giscat
│ │ └── vector
│ │ └── pojo
│ │ ├── converter
│ │ ├── FoolStyleFeatureConverterTest.java
│ │ ├── GeoJsonFeatureConverterJmhTest.java
│ │ ├── GeoJsonFeatureConverterTest.java
│ │ ├── MakePbfTest1.java
│ │ ├── ProtoFeatureConverterGeometryJmhTest.java
│ │ ├── ProtoFeatureConverterTest.java
│ │ └── Test1.java
│ │ └── util
│ │ └── SampleData.java
├── giscat-vector-rocksrtree
│ ├── README.md
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ │ └── wowtools
│ │ │ │ └── giscat
│ │ │ │ └── vector
│ │ │ │ └── rocksrtree
│ │ │ │ ├── Branch.java
│ │ │ │ ├── FeatureConsumer.java
│ │ │ │ ├── Leaf.java
│ │ │ │ ├── Node.java
│ │ │ │ ├── PointNd.java
│ │ │ │ ├── ProtoAble.java
│ │ │ │ ├── RTree.java
│ │ │ │ ├── RectNd.java
│ │ │ │ ├── RocksRtreePb.java
│ │ │ │ ├── Stats.java
│ │ │ │ ├── TreeBuilder.java
│ │ │ │ └── TreeTransaction.java
│ │ └── resources
│ │ │ └── RocksRtree.proto
│ │ └── test
│ │ └── java
│ │ └── org
│ │ └── wowtools
│ │ └── giscat
│ │ └── vector
│ │ └── rocksrtreetest
│ │ └── Test.java
├── giscat-vector-util
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── org
│ │ │ └── wowtools
│ │ │ └── giscat
│ │ │ └── vector
│ │ │ └── util
│ │ │ ├── analyse
│ │ │ ├── Bbox.java
│ │ │ └── TileClip.java
│ │ │ └── cst
│ │ │ ├── LonLat.java
│ │ │ ├── Tile2Wgs84.java
│ │ │ ├── Utm2Wgs84.java
│ │ │ └── WebMercator2Wgs84.java
│ │ └── test
│ │ └── java
│ │ └── org
│ │ └── wowtools
│ │ └── giscat
│ │ └── vector
│ │ └── util
│ │ ├── analyse
│ │ ├── TileClipJmhTest.java
│ │ └── TileClipTest.java
│ │ └── cst
│ │ └── Utm2Wgs84Test.java
└── pom.xml
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven #
2 | target
3 |
4 | logs
5 | *.log
6 |
7 | Thumbs.db
8 |
9 | .DS_Store
10 |
11 | .settings
12 | .project
13 | .classpath
14 | .log
15 | *.class
16 |
17 | .idea
18 | *.iml
19 |
20 | *.war
21 | *.ear
22 | /target
23 | /public
24 |
25 | jmhResult.json
26 | /D_tmp1rocksrtree/
27 | /arthas-output/
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | giscat是一套简洁、快速的java gis工具集,包含如下工具:
2 |
3 | (持续施工中)
4 |
5 | # 矢量
6 |
7 | ## pojo
8 |
9 | 基于jts,提供了一套基础gis对象(Feature Geometry properties)的定义,及其与geojson的互转。
10 | 同时定义了一套基于protobuf的二进制压缩规范ProtoFeature,提供了比wkb、geojson更高压缩率的序列化方法。
11 |
12 | [pojo详细说明与示例](giscat-vector/giscat-vector-pojo)
13 |
14 | [ProtoFeature规范](giscat-vector/giscat-vector-pojo/src/main/resources/ProtoFeature.proto)
15 |
16 | ## util
17 |
18 | 一系列处理矢量数据的工具,包含坐标转换、图形分析裁剪等
19 | 详见[测试用例](giscat-vector/giscat-vector-util/src/test/java)
20 |
21 | ## mvt
22 |
23 | 矢量瓦片生成与解析工具
24 | [基于springboot编写矢量瓦片服务示例](https://blog.wowtools.org/2022/04/28/2022-04-28-mapbox-gl-tutorial-8/)
25 |
26 | # 栅格
27 |
28 | # license
29 |
30 | 本软件采用自定义协议,请阅读[LICENSE文件](https://github.com/codingmiao/giscat/blob/main/LICENSE)
31 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | giscat-vector
7 | org.wowtools
8 | g1.7.0
9 |
10 | 4.0.0
11 |
12 | giscat-vector-mbexpression
13 | g1.7.0
14 | mapbox expressions表达式解析为java对象,用以支持数据过滤等场景
15 |
16 |
17 |
18 | com.fasterxml.jackson.core
19 | jackson-databind
20 |
21 |
22 | org.projectlombok
23 | lombok
24 |
25 |
26 | org.reflections
27 | reflections
28 |
29 |
30 | junit
31 | junit
32 | test
33 |
34 |
35 | org.wowtools
36 | giscat-vector-util
37 |
38 |
39 | org.jetbrains
40 | annotations
41 | compile
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/ExpressionName.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mbexpression;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | /**
7 | * 表达式名称
8 | *
9 | * @author liuyu
10 | * @date 2022/7/26
11 | */
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface ExpressionName {
14 | String value();
15 | }
16 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/ExpressionParams.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mbexpression;
2 |
3 | import org.jetbrains.annotations.Nullable;
4 | import org.locationtech.jts.geom.GeometryFactory;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * 绑定参数 表达式支持使用以$开头的字符串进行参数绑定。
11 | * 例如表达式["concat", "$a","$b"],对其传入绑定参数{"$a":"hello","$b":"world"}时,表达式被解析为["concat", "hello","world"],表达式输出结果"helloworld"。
12 | * 换言之,所有$开头的字符串都会被认定为绑定参数,如果字符串的真实值确实以$开头,可通过绑定参数传入具体值来解决,
13 | * 例如,希望表达式["concat", "$a","sss"]输出结果为"$asss",则可通过传入参数{"$a":"$a"}来解决。
14 | * 使用参数绑定可减少解析时的性能消耗。
15 | *
16 | * 包含一个geometryFactory对象,用于geometry对象变换相关的表达式,可根据需要通过setGeometryFactory设置自定义的geometryFactory
17 | *
18 | * @author liuyu
19 | * @date 2022/7/28
20 | */
21 | public class ExpressionParams {
22 | private static final GeometryFactory defaultGeometryFactory = new GeometryFactory();
23 | /**
24 | * 空对象 用以避免实际值为null时缓存重复查询的问题
25 | */
26 | public static final Object empty = new Object();
27 |
28 | /**
29 | * 参数
30 | */
31 | private final @Nullable Map params;
32 |
33 | //取值缓存,供表达式解析用,减少重复的解析
34 | private final Map cache = new HashMap<>();
35 |
36 | private GeometryFactory geometryFactory = defaultGeometryFactory;
37 |
38 | /**
39 | * @param params 绑定参数 例如 {"$a":"hello","$b":"world"}
40 | */
41 | public ExpressionParams(Map params) {
42 | this.params = params;
43 | }
44 |
45 | public ExpressionParams() {
46 | this.params = null;
47 | }
48 |
49 | public @Nullable Object getValue(String paramKey) {
50 | if (null == params) {
51 | return null;
52 | }
53 | return params.get(paramKey);
54 | }
55 |
56 | public void putCache(Expression key, @Nullable Object value) {
57 | if (null == value) {
58 | value = empty;
59 | }
60 | cache.put(key, value);
61 | }
62 |
63 | public Object getCache(Expression key) {
64 | return cache.get(key);
65 | }
66 |
67 | public GeometryFactory getGeometryFactory() {
68 | return geometryFactory;
69 | }
70 |
71 | public void setGeometryFactory(GeometryFactory geometryFactory) {
72 | this.geometryFactory = geometryFactory;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/All.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["all", boolean, boolean, ...]: boolean
36 | *
37 | * @author liuyu
38 | * @date 2022/7/15
39 | */
40 | @ExpressionName("all")
41 | public class All extends Expression {
42 | protected All(ArrayList expressionArray) {
43 | super(expressionArray);
44 | }
45 |
46 | @Override
47 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
48 | for (int i = 1; i < expressionArray.size(); i++) {
49 | Object o = expressionArray.get(i);
50 | o = getRealValue(feature, o, expressionParams);
51 |
52 | if (null == o) {
53 | return false;
54 | }
55 | if (Boolean.FALSE.equals(o)) {
56 | return false;
57 | }
58 | }
59 | return true;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/Any.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["any", boolean, boolean, ...]: boolean
36 | *
37 | * @author liuyu
38 | * @date 2022/7/15
39 | */
40 | @ExpressionName("any")
41 | public class Any extends Expression {
42 | protected Any(ArrayList expressionArray) {
43 | super(expressionArray);
44 | }
45 |
46 | @Override
47 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
48 | for (int i = 1; i < expressionArray.size(); i++) {
49 | Object o = expressionArray.get(i);
50 | o = getRealValue(feature, o, expressionParams);
51 |
52 | if (null == o) {
53 | continue;
54 | }
55 | if (Boolean.FALSE.equals(o)) {
56 | continue;
57 | }
58 | return true;
59 | }
60 | return false;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/Case.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.Nullable;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["case",
36 | * condition: boolean, output: OutputType,
37 | * condition: boolean, output: OutputType,
38 | * ...,
39 | * fallback: OutputType
40 | * ]: OutputType
41 | *
42 | * @author liuyu
43 | * @date 2022/7/15
44 | */
45 | @ExpressionName("case")
46 | public class Case extends Expression {
47 | protected Case(ArrayList expressionArray) {
48 | super(expressionArray);
49 | }
50 |
51 | @Override
52 | public @Nullable Object getValue(Feature feature, ExpressionParams expressionParams) {
53 | for (int i = 1; i < expressionArray.size() - 1; i += 2) {
54 | Object o = expressionArray.get(i);
55 | Boolean condition = (Boolean) getRealValue(feature, o, expressionParams);
56 | if (Boolean.TRUE.equals(condition)) {
57 | return getRealValue(feature, expressionArray.get(i + 1), expressionParams);
58 | }
59 | }
60 | return getRealValue(feature, expressionArray.get(expressionArray.size() - 1), expressionParams);
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/Compare.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mbexpression.decision;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 | import org.wowtools.giscat.vector.mbexpression.Expression;
5 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
6 | import org.wowtools.giscat.vector.pojo.Feature;
7 |
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * 比较大小工具
12 | *
13 | * @author liuyu
14 | * @date 2022/7/27
15 | */
16 | class Compare {
17 |
18 | /**
19 | * 不成立
20 | */
21 | public static final int impossible = -2;
22 |
23 | /**
24 | * 比较大小
25 | *
26 | * @param expressionArray expressionArray
27 | * @param feature feature
28 | * @param expressionParams expressionParams
29 | * @return 1 大于 0 等于 -1小于 -2 因为空值等原因不成立
30 | */
31 | public static int compare(@NotNull ArrayList expressionArray, Feature feature, ExpressionParams expressionParams) {
32 | Object o1 = expressionArray.get(1);
33 | if (o1 instanceof Expression) {
34 | Expression expression = (Expression) o1;
35 | o1 = expression.getValue(feature, expressionParams);
36 | }
37 | Object o2 = expressionArray.get(2);
38 | if (o2 instanceof Expression) {
39 | Expression expression = (Expression) o2;
40 | o2 = expression.getValue(feature, expressionParams);
41 | }
42 | if (o1 == null && o2 == null) {
43 | return 0;
44 | }
45 | if (o1 == null ^ o2 == null) {
46 | return impossible;
47 | }
48 |
49 | if (o1 instanceof Number) {
50 | Number n1 = (Number) o1;
51 | Number n2 = (Number) o2;
52 | double d = n1.doubleValue() - n2.doubleValue();
53 | if (d > 0) {
54 | return 1;
55 | } else if (d < 0) {
56 | return -1;
57 | } else {
58 | return 0;
59 | }
60 | } else if (o1 instanceof String) {
61 | String s1 = (String) o1;
62 | String s2 = (String) o2;
63 | return s1.compareTo(s2);
64 | } else {
65 | throw new RuntimeException("暂未实现的类型比较 " + o1.getClass());
66 | }
67 | }
68 |
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/Equal.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 | import java.util.Objects;
30 |
31 | /**
32 | *
33 | * 参见 ...
34 | *
35 | * Syntax
36 | * ["==", value, value]: boolean
37 | * ["==", value, value, collator]: boolean
38 | *
39 | * @author liuyu
40 | * @date 2022/7/15
41 | */
42 | @ExpressionName("==")
43 | public class Equal extends Expression {
44 | protected Equal(@NotNull ArrayList expressionArray) {
45 | super(expressionArray);
46 | if (expressionArray.size() == 4) {
47 | throw new UnsupportedOperationException("collator参数暂未实现");
48 | }
49 | }
50 |
51 | @Override
52 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
53 | Object o1 = expressionArray.get(1);
54 | o1 = getRealValue(feature, o1, expressionParams);
55 | Object o2 = expressionArray.get(2);
56 | o2 = getRealValue(feature, o2, expressionParams);
57 | return Objects.equals(o1, o2);
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/GreaterOrEqualThan.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * [">=", value, value]: boolean
36 | * [">=", value, value, collator]: boolean 未实现
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName(">=")
42 | public class GreaterOrEqualThan extends Expression {
43 | protected GreaterOrEqualThan(@NotNull ArrayList expressionArray) {
44 | super(expressionArray);
45 | if (expressionArray.size() == 4) {
46 | throw new UnsupportedOperationException("collator参数暂未实现");
47 | }
48 | }
49 |
50 | @Override
51 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
52 | int flag = Compare.compare(expressionArray, feature, expressionParams);
53 | return flag != Compare.impossible && flag >= 0;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/GreaterThan.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * [">", value, value]: boolean
36 | * [">", value, value, collator]: boolean 未实现
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName(">")
42 | public class GreaterThan extends Expression {
43 | protected GreaterThan(@NotNull ArrayList expressionArray) {
44 | super(expressionArray);
45 | if (expressionArray.size() == 4) {
46 | throw new UnsupportedOperationException("collator参数暂未实现");
47 | }
48 | }
49 |
50 | @Override
51 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
52 | int flag = Compare.compare(expressionArray, feature, expressionParams);
53 | return flag != Compare.impossible && flag > 0;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/LessOrEqualThan.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["<=", value, value]: boolean
36 | * ["<=", value, value, collator]: boolean 未实现
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName("<=")
42 | public class LessOrEqualThan extends Expression {
43 | protected LessOrEqualThan(@NotNull ArrayList expressionArray) {
44 | super(expressionArray);
45 | if (expressionArray.size() == 4) {
46 | throw new UnsupportedOperationException("collator参数暂未实现");
47 | }
48 | }
49 |
50 | @Override
51 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
52 | int flag = Compare.compare(expressionArray, feature, expressionParams);
53 | return flag != Compare.impossible && flag <= 0;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/LessThan.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["<", value, value]: boolean
36 | * ["<", value, value, collator]: boolean 未实现
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName("<")
42 | public class LessThan extends Expression {
43 | protected LessThan(@NotNull ArrayList expressionArray) {
44 | super(expressionArray);
45 | if (expressionArray.size() == 4) {
46 | throw new UnsupportedOperationException("collator参数暂未实现");
47 | }
48 | }
49 |
50 | @Override
51 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
52 | int flag = Compare.compare(expressionArray, feature, expressionParams);
53 | return flag != Compare.impossible && flag < 0;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/Match.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.Nullable;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 | import java.util.Objects;
30 |
31 | /**
32 | *
33 | * 参见 ...
34 | *
35 | * Syntax
36 | * ["match",
37 | * input: InputType (number or string),
38 | * label: InputType | [InputType, InputType, ...], output: OutputType,
39 | * label: InputType | [InputType, InputType, ...], output: OutputType,
40 | * ...,
41 | * fallback: OutputType
42 | * ]: OutputType
43 | *
44 | * @author liuyu
45 | * @date 2022/7/15
46 | */
47 | @ExpressionName("match")
48 | public class Match extends Expression {
49 | protected Match(ArrayList expressionArray) {
50 | super(expressionArray);
51 | }
52 |
53 | @Override
54 | public @Nullable Object getValue(Feature feature, ExpressionParams expressionParams) {
55 | Object input = getRealValue(feature, expressionArray.get(1), expressionParams);
56 | for (int i = 2; i < expressionArray.size() - 1; i += 2) {
57 | Object o = expressionArray.get(i);
58 | o = getRealValue(feature, o, expressionParams);
59 | if (Objects.equals(input, o)) {
60 | return getRealValue(feature, expressionArray.get(i + 1), expressionParams);
61 | }
62 | }
63 | return getRealValue(feature, expressionArray.get(expressionArray.size() - 1), expressionParams);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/Negation.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ... !
33 | *
34 | * Syntax
35 | * ["!", boolean]: boolean
36 | *
37 | * @author liuyu
38 | * @date 2022/7/15
39 | */
40 | @ExpressionName("!")
41 | public class Negation extends Expression {
42 | protected Negation(ArrayList expressionArray) {
43 | super(expressionArray);
44 | }
45 |
46 | @Override
47 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
48 | Object value = expressionArray.get(1);
49 | value = getRealValue(feature, value, expressionParams);
50 | if (value instanceof Boolean) {
51 | return Boolean.FALSE.equals(value);
52 | }
53 | if (value instanceof Number) {
54 | return ((Number) value).doubleValue() <= 0;
55 | }
56 | return value == null;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/decision/NotEqual.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.decision;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 | import java.util.Objects;
30 |
31 | /**
32 | *
33 | * 参见 ...
34 | *
35 | * Syntax
36 | * ["!=", value, value]: boolean
37 | * ["!=", value, value, collator]: boolean 未实现
38 | *
39 | * @author liuyu
40 | * @date 2022/7/15
41 | */
42 | @ExpressionName("!=")
43 | public class NotEqual extends Expression {
44 | protected NotEqual(@NotNull ArrayList expressionArray) {
45 | super(expressionArray);
46 | if (expressionArray.size() == 4) {
47 | throw new UnsupportedOperationException("collator参数暂未实现");
48 | }
49 | }
50 |
51 | @Override
52 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
53 | Object o1 = expressionArray.get(1);
54 | o1 = getRealValue(feature, o1, expressionParams);
55 | Object o2 = expressionArray.get(2);
56 | o2 = getRealValue(feature, o2, expressionParams);
57 | return !Objects.equals(o1, o2);
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/lookup/At.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.lookup;
21 |
22 | import org.jetbrains.annotations.Nullable;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["at", number, array]: ItemType
36 | *
37 | * @author liuyu
38 | * @date 2022/7/15
39 | */
40 | @ExpressionName("at")
41 | public class At extends Expression {
42 | protected At(ArrayList expressionArray) {
43 | super(expressionArray);
44 | }
45 |
46 | @Override
47 | public @Nullable Object getValue(Feature feature, ExpressionParams expressionParams) {
48 | int idx = (int) expressionArray.get(1);
49 | ArrayList array = (ArrayList) expressionArray.get(2);
50 | Object value = array.get(idx);
51 | value = getRealValue(feature, value, expressionParams);
52 | return value;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/lookup/Get.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.lookup;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.jetbrains.annotations.Nullable;
24 | import org.wowtools.giscat.vector.mbexpression.Expression;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
26 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
27 | import org.wowtools.giscat.vector.pojo.Feature;
28 |
29 | import java.util.ArrayList;
30 | import java.util.Map;
31 |
32 | /**
33 | *
34 | * 参见 ...
35 | *
36 | * Syntax
37 | * ["get", string]: value
38 | * ["get", string, object]: value
39 | *
40 | * @author liuyu
41 | * @date 2022/7/15
42 | */
43 | @ExpressionName("get")
44 | public class Get extends Expression {
45 | protected Get(ArrayList expressionArray) {
46 | super(expressionArray);
47 | }
48 |
49 | @Override
50 | public @Nullable Object getValue(@NotNull Feature feature, ExpressionParams expressionParams) {
51 | String key = (String) expressionArray.get(1);
52 | Map featureProperties = feature.getProperties();
53 | if (null == featureProperties) {
54 | return null;
55 | }
56 | Object value = featureProperties.get(key);
57 | if (null != value && expressionArray.size() == 3) {
58 | value = expressionArray.get(2);
59 | }
60 | value = getRealValue(feature, value, expressionParams);
61 | return value;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/lookup/Has.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.lookup;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["has", string]: boolean
36 | * ["has", string, object]: boolean未实现
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName("has")
42 | public class Has extends Expression {
43 | protected Has(ArrayList expressionArray) {
44 | super(expressionArray);
45 | }
46 |
47 | @Override
48 | public @NotNull Boolean getValue(@NotNull Feature feature, ExpressionParams expressionParams) {
49 | String key = (String) getRealValue(feature, expressionArray.get(1), expressionParams);
50 | return null != feature.getProperties() && feature.getProperties().containsKey(key);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/lookup/In.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.lookup;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 | import java.util.Objects;
30 |
31 | /**
32 | *
33 | * 参见 ...
34 | * 当keyword input都是string时,相当于strInput.indexOf(strKeyword)
35 | * 否则,相当于 keyword in(xxx,xxx)
36 | *
37 | * Syntax
38 | * ["in",
39 | * keyword: InputType (boolean, string, or number),
40 | * input: InputType (array or string)
41 | * ]: boolean
42 | *
43 | * @author liuyu
44 | * @date 2022/7/15
45 | */
46 | @ExpressionName("in")
47 | public class In extends Expression {
48 | protected In(ArrayList expressionArray) {
49 | super(expressionArray);
50 | }
51 |
52 | @Override
53 | public @NotNull Boolean getValue(Feature feature, ExpressionParams expressionParams) {
54 | Object keyword = getRealValue(feature, expressionArray.get(1), expressionParams);
55 | Object input = getRealValue(feature, expressionArray.get(2), expressionParams);
56 | if (keyword instanceof String && input instanceof String) {
57 | String strKeyword = (String) keyword;
58 | String strInput = (String) input;
59 | return strInput.contains(strKeyword);
60 | } else {
61 | ArrayList inputArr = (ArrayList) input;
62 | for (Object inputObj : inputArr) {
63 | if (Objects.equals(keyword, inputObj)) {
64 | return true;
65 | }
66 | }
67 | return false;
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/lookup/IndexOf.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.lookup;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 | import java.util.Objects;
30 |
31 | /**
32 | *
33 | * 参见 ...
34 | *
35 | * Syntax
36 | * ["index-of",
37 | * keyword: InputType (boolean, string, or number),
38 | * input: InputType (array or string)
39 | * ]: number
40 | *
41 | * ["index-of",
42 | * keyword: InputType (boolean, string, or number),
43 | * input: InputType (array or string),
44 | * index: number
45 | * ]: number
46 | *
47 | * @author liuyu
48 | * @date 2022/7/15
49 | */
50 | @ExpressionName("index-of")
51 | public class IndexOf extends Expression {
52 | protected IndexOf(ArrayList expressionArray) {
53 | super(expressionArray);
54 | }
55 |
56 | @Override
57 | public @NotNull Object getValue(Feature feature, ExpressionParams expressionParams) {
58 | Object keyword = getRealValue(feature, expressionArray.get(1), expressionParams);
59 | Object input = getRealValue(feature, expressionArray.get(2), expressionParams);
60 | int index = 0;
61 | if (expressionArray.size() == 4) {
62 | index = (int) getRealValue(feature, expressionArray.get(3), expressionParams);
63 | }
64 | if (keyword instanceof String && input instanceof String) {
65 | String strKeyword = (String) keyword;
66 | String strInput = (String) input;
67 | return strInput.indexOf(strKeyword, index);
68 | } else {
69 | ArrayList inputArr = (ArrayList) input;
70 | for (int i = index; i < inputArr.size(); i++) {
71 | Object inputObj = inputArr.get(i);
72 | if (Objects.equals(keyword, inputObj)) {
73 | return i;
74 | }
75 | }
76 | return -1;
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/lookup/Length.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.lookup;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["length", string | array | value]: number
36 | *
37 | * @author liuyu
38 | * @date 2022/7/15
39 | */
40 | @ExpressionName("length")
41 | public class Length extends Expression {
42 | protected Length(ArrayList expressionArray) {
43 | super(expressionArray);
44 | }
45 |
46 | @Override
47 | public @NotNull Integer getValue(Feature feature, ExpressionParams expressionParams) {
48 | Object input = getRealValue(feature, expressionArray.get(1), expressionParams);
49 | if (input instanceof String) {
50 | return ((String) input).length();
51 | } else if (input instanceof ArrayList) {
52 | return ((ArrayList) input).size();
53 | } else {
54 | throw new RuntimeException("未知类型 " + feature);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/lookup/Slice.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.lookup;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["slice",
36 | * input: InputType (array or string),
37 | * index: number
38 | * ]: OutputType (ItemType or string)
39 | *
40 | * ["slice",
41 | * input: InputType (array or string),
42 | * index: number,
43 | * index: number
44 | * ]: OutputType (ItemType or string)
45 | *
46 | * @author liuyu
47 | * @date 2022/7/15
48 | */
49 | @ExpressionName("slice")
50 | public class Slice extends Expression {
51 | protected Slice(ArrayList expressionArray) {
52 | super(expressionArray);
53 | }
54 |
55 | @Override
56 | public @NotNull Object getValue(Feature feature, ExpressionParams expressionParams) {
57 | Object input = getRealValue(feature, expressionArray.get(1), expressionParams);
58 | int start = (int) getRealValue(feature, expressionArray.get(2), expressionParams);
59 | int end;
60 | if (expressionArray.size() == 4) {
61 | end = (int) getRealValue(feature, expressionArray.get(3), expressionParams);
62 | } else {
63 | end = -1;
64 | }
65 | if (input instanceof String) {
66 | if (end > 0) {
67 | return ((String) input).substring(start, end);
68 | } else {
69 | return ((String) input).substring(start);
70 | }
71 | } else if (input instanceof ArrayList) {
72 | ArrayList inputArr = (ArrayList) input;
73 | if (end < 0) {
74 | end = inputArr.size();
75 | }
76 | ArrayList res = new ArrayList(end - start);
77 | for (int i = start; i < end; i++) {
78 | res.add(getRealValue(feature, inputArr.get(i), expressionParams));
79 | }
80 | return res;
81 | } else {
82 | throw new RuntimeException("未知类型 " + feature);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/spatial/BboxIntersection.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.spatial;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.jetbrains.annotations.Nullable;
24 | import org.locationtech.jts.geom.Geometry;
25 | import org.wowtools.giscat.vector.util.analyse.TileClip;
26 | import org.wowtools.giscat.vector.mbexpression.Expression;
27 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
28 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
29 | import org.wowtools.giscat.vector.pojo.Feature;
30 |
31 | import java.util.ArrayList;
32 |
33 | /**
34 | * 输入bbox,若geometry与要素相交则裁剪要素的geometry并返回裁剪后的要素,若不相交则返回null
35 | * Syntax
36 | * ["bboxIntersection", [xmin,ymin,xmax,ymax] or TileClip]: boolean
37 | * 示例
38 | * ["bboxIntersection", [90,20,92.5,21.3]]
39 | *
40 | * @author liuyu
41 | * @date 2022/7/15
42 | */
43 | @ExpressionName("bboxIntersection")
44 | public class BboxIntersection extends Expression {
45 |
46 |
47 | protected BboxIntersection(ArrayList expressionArray) {
48 | super(expressionArray);
49 | }
50 |
51 |
52 | @Override
53 | public @Nullable Feature getValue(@NotNull Feature feature, @NotNull ExpressionParams expressionParams) {
54 | TileClip tileClip;
55 | {
56 | Object cache = expressionParams.getCache(this);
57 | if (ExpressionParams.empty == cache) {
58 | tileClip = null;
59 | } else if (null == cache) {
60 | Object value = expressionArray.get(1);
61 | tileClip = Read.readTileClip(feature, value, expressionParams);
62 | expressionParams.putCache(this, tileClip);
63 | } else {
64 | tileClip = (TileClip) cache;
65 | }
66 | }
67 |
68 | Geometry featureGeometry = feature.getGeometry();
69 | if (null == featureGeometry) {
70 | return null;
71 | }
72 | if (null == tileClip) {
73 | return null;
74 | }
75 | featureGeometry = tileClip.intersection(featureGeometry);
76 | if (null == featureGeometry || featureGeometry.isEmpty()) {
77 | return null;
78 | }
79 | Feature newFeature = new Feature(featureGeometry, feature.getProperties());
80 | return newFeature;
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/spatial/BboxIntersects.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.spatial;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.locationtech.jts.geom.Geometry;
24 | import org.wowtools.giscat.vector.util.analyse.Bbox;
25 | import org.wowtools.giscat.vector.mbexpression.Expression;
26 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
27 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
28 | import org.wowtools.giscat.vector.pojo.Feature;
29 |
30 | import java.util.ArrayList;
31 |
32 | /**
33 | * 判断输入的bbox是否与要素的geometry相交(envIntersects)
34 | * Syntax
35 | * ["bboxIntersects", [xmin,ymin,xmax,ymax] or Bbox]: boolean
36 | * 示例
37 | * ["bboxIntersects", [90,20,92.5,21.3]]
38 | *
39 | * @author liuyu
40 | * @date 2022/7/15
41 | */
42 | @ExpressionName("bboxIntersects")
43 | public class BboxIntersects extends Expression {
44 |
45 | protected BboxIntersects(ArrayList expressionArray) {
46 | super(expressionArray);
47 | }
48 |
49 | @Override
50 | public @NotNull Boolean getValue(@NotNull Feature feature, @NotNull ExpressionParams expressionParams) {
51 | Bbox bbox;
52 | {
53 | Object cache = expressionParams.getCache(this);
54 | if (ExpressionParams.empty == cache) {
55 | bbox = null;
56 | } else if (null == cache) {
57 | Object value = expressionArray.get(1);
58 | bbox = Read.readBbox(feature, value, expressionParams);
59 | expressionParams.putCache(this, bbox);
60 | } else {
61 | bbox = (Bbox) cache;
62 | }
63 | }
64 | Geometry featureGeometry = feature.getGeometry();
65 | if (null == featureGeometry) {
66 | return false;
67 | }
68 | if (null == bbox) {
69 | return false;
70 | }
71 | return bbox.envIntersects(featureGeometry);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/spatial/GeoIntersection.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.spatial;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.jetbrains.annotations.Nullable;
24 | import org.locationtech.jts.geom.Geometry;
25 | import org.wowtools.giscat.vector.mbexpression.Expression;
26 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
27 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
28 | import org.wowtools.giscat.vector.pojo.Feature;
29 |
30 | import java.util.ArrayList;
31 |
32 | /**
33 | * 输入geometry,若geometry与要素相交则裁剪要素的geometry并返回裁剪后的要素,若不相交则返回null
34 | * Syntax
35 | * ["geoIntersection", wkt_string or geometry]: Feature
36 | * 示例
37 | * ["geoIntersection", "LINESTRING(100 20,120 30)"]
38 | *
39 | * @author liuyu
40 | * @date 2022/7/15
41 | */
42 | @ExpressionName("geoIntersection")
43 | public class GeoIntersection extends Expression {
44 |
45 | protected GeoIntersection(ArrayList expressionArray) {
46 | super(expressionArray);
47 | }
48 |
49 |
50 | @Override
51 | public @Nullable Feature getValue(@NotNull Feature feature, @NotNull ExpressionParams expressionParams) {
52 | Geometry inputGeometry;
53 | {
54 | Object cache = expressionParams.getCache(this);
55 | if (ExpressionParams.empty == cache) {
56 | inputGeometry = null;
57 | } else if (null == cache) {
58 | Object value = expressionArray.get(1);
59 | inputGeometry = Read.readGeometry(feature, value, expressionParams);
60 | expressionParams.putCache(this, inputGeometry);
61 | } else {
62 | inputGeometry = (Geometry) cache;
63 | }
64 | }
65 |
66 | Geometry featureGeometry = feature.getGeometry();
67 | if (null == featureGeometry) {
68 | return null;
69 | }
70 | if (null == inputGeometry) {
71 | return null;
72 | }
73 | featureGeometry = inputGeometry.intersection(featureGeometry);
74 | if (featureGeometry.isEmpty()) {
75 | return null;
76 | }
77 | Feature newFeature = new Feature(featureGeometry, feature.getProperties());
78 | return newFeature;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/spatial/GeoIntersects.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.spatial;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.locationtech.jts.geom.Geometry;
24 | import org.wowtools.giscat.vector.mbexpression.Expression;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
26 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
27 | import org.wowtools.giscat.vector.pojo.Feature;
28 |
29 | import java.util.ArrayList;
30 |
31 | /**
32 | * 判断输入的wkt geometry是否与要素的geometry相交
33 | * Syntax
34 | * ["geoIntersects", wkt_string or geometry]: boolean
35 | * 示例
36 | * ["geoIntersects", "LINESTRING(100 20,120 30)"]
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName("geoIntersects")
42 | public class GeoIntersects extends Expression {
43 |
44 | protected GeoIntersects(ArrayList expressionArray) {
45 | super(expressionArray);
46 | }
47 |
48 |
49 | @Override
50 | public @NotNull Boolean getValue(@NotNull Feature feature, @NotNull ExpressionParams expressionParams) {
51 | Geometry inputGeometry;
52 | {
53 | Object cache = expressionParams.getCache(this);
54 | if (ExpressionParams.empty == cache) {
55 | inputGeometry = null;
56 | } else if (null == cache) {
57 | Object value = expressionArray.get(1);
58 | inputGeometry = Read.readGeometry(feature, value, expressionParams);
59 | expressionParams.putCache(this, inputGeometry);
60 | } else {
61 | inputGeometry = (Geometry) cache;
62 | }
63 | }
64 |
65 | Geometry featureGeometry = feature.getGeometry();
66 | if (null == featureGeometry) {
67 | return false;
68 | }
69 | if (null == inputGeometry) {
70 | return false;
71 | }
72 | return inputGeometry.intersects(featureGeometry);
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/spatial/Read.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mbexpression.spatial;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 | import org.jetbrains.annotations.Nullable;
5 | import org.locationtech.jts.geom.Geometry;
6 | import org.locationtech.jts.io.ParseException;
7 | import org.locationtech.jts.io.WKTReader;
8 | import org.wowtools.giscat.vector.util.analyse.Bbox;
9 | import org.wowtools.giscat.vector.util.analyse.TileClip;
10 | import org.wowtools.giscat.vector.mbexpression.Expression;
11 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
12 | import org.wowtools.giscat.vector.pojo.Feature;
13 |
14 | import java.util.ArrayList;
15 |
16 | /**
17 | * 从表达式中读取geometry或bbox
18 | *
19 | * @author liuyu
20 | * @date 2022/7/26
21 | */
22 | class Read {
23 | private static final WKTReader wktReader = new WKTReader();
24 |
25 |
26 | public static Geometry readGeometry(Feature feature, @Nullable Object value, ExpressionParams expressionParams) {
27 | if (null == value) {
28 | return null;
29 | }
30 | value = Expression.getRealValue(feature, value, expressionParams);
31 | Geometry inputGeometry;
32 | if (value instanceof String) {
33 | String wkt = (String) value;
34 | try {
35 | inputGeometry = wktReader.read(wkt);
36 | } catch (ParseException e) {
37 | throw new RuntimeException("非法的wkt " + wkt, e);
38 | }
39 | } else if (value instanceof Geometry) {
40 | inputGeometry = (Geometry) value;
41 | } else {
42 | throw new RuntimeException("未知的value " + value);
43 | }
44 | return inputGeometry;
45 | }
46 |
47 | public static Bbox readBbox(Feature feature, @Nullable Object value, ExpressionParams expressionParams) {
48 | if (null == value) {
49 | return null;
50 | }
51 | value = Expression.getRealValue(feature, value, expressionParams);
52 | if (value instanceof ArrayList) {
53 | ArrayList list = (ArrayList) value;
54 | return new Bbox(((Number) Expression.getRealValue(feature, list.get(0), expressionParams)).doubleValue(),
55 | ((Number) Expression.getRealValue(feature, list.get(1), expressionParams)).doubleValue(),
56 | ((Number) Expression.getRealValue(feature, list.get(2), expressionParams)).doubleValue(),
57 | ((Number) Expression.getRealValue(feature, list.get(3), expressionParams)).doubleValue());
58 | }
59 | if (value instanceof Bbox) {
60 | return (Bbox) value;
61 | }
62 | throw new RuntimeException("未知的Bbox数据类型 " + value);
63 | }
64 |
65 | public static TileClip readTileClip(Feature feature, @Nullable Object value, @NotNull ExpressionParams expressionParams) {
66 | if (null == value) {
67 | return null;
68 | }
69 | value = Expression.getRealValue(feature, value, expressionParams);
70 | if (value instanceof ArrayList) {
71 | ArrayList list = (ArrayList) value;
72 | return new TileClip(((Number) Expression.getRealValue(feature, list.get(0), expressionParams)).doubleValue(),
73 | ((Number) Expression.getRealValue(feature, list.get(1), expressionParams)).doubleValue(),
74 | ((Number) Expression.getRealValue(feature, list.get(2), expressionParams)).doubleValue(),
75 | ((Number) Expression.getRealValue(feature, list.get(3), expressionParams)).doubleValue(),
76 | expressionParams.getGeometryFactory()
77 | );
78 | }
79 | if (value instanceof TileClip) {
80 | return (TileClip) value;
81 | }
82 | if (value instanceof Bbox) {
83 | Bbox bbox = (Bbox) value;
84 | return new TileClip(bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax, expressionParams.getGeometryFactory());
85 | }
86 | throw new RuntimeException("未知的TileClip数据类型 " + value);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/string/Concat.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.string;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 |
30 | /**
31 | *
32 | * 参见 ...
33 | *
34 | * Syntax
35 | * ["concat", value, value, ...]: string
36 | *
37 | * @author liuyu
38 | * @date 2022/7/15
39 | */
40 | @ExpressionName("concat")
41 | public class Concat extends Expression {
42 | protected Concat(ArrayList expressionArray) {
43 | super(expressionArray);
44 | }
45 |
46 | @Override
47 | public @NotNull String getValue(Feature feature, ExpressionParams expressionParams) {
48 | StringBuilder sb = new StringBuilder();
49 | for (int i = 1; i < expressionArray.size(); i++) {
50 | Object o = expressionArray.get(i);
51 | o = getRealValue(feature, o, expressionParams);
52 | sb.append(o);
53 | }
54 | return sb.toString();
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/string/Downcase.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.string;
21 |
22 | import org.jetbrains.annotations.Nullable;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 | import java.util.Locale;
30 |
31 | /**
32 | *
33 | * 参见 ...
34 | *
35 | * Syntax
36 | * ["downcase", string]: string
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName("downcase")
42 | public class Downcase extends Expression {
43 | protected Downcase(ArrayList expressionArray) {
44 | super(expressionArray);
45 | }
46 |
47 | @Override
48 | public @Nullable String getValue(Feature feature, ExpressionParams expressionParams) {
49 | String s = (String) getRealValue(feature, expressionArray.get(1), expressionParams);
50 | if (s == null) {
51 | return null;
52 | }
53 | return s.toLowerCase(Locale.ROOT);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/main/java/org/wowtools/giscat/vector/mbexpression/string/Upcase.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mbexpression.string;
21 |
22 | import org.jetbrains.annotations.Nullable;
23 | import org.wowtools.giscat.vector.mbexpression.Expression;
24 | import org.wowtools.giscat.vector.mbexpression.ExpressionName;
25 | import org.wowtools.giscat.vector.mbexpression.ExpressionParams;
26 | import org.wowtools.giscat.vector.pojo.Feature;
27 |
28 | import java.util.ArrayList;
29 | import java.util.Locale;
30 |
31 | /**
32 | *
33 | * 参见 ...
34 | *
35 | * Syntax
36 | * ["upcase", string]: string
37 | *
38 | * @author liuyu
39 | * @date 2022/7/15
40 | */
41 | @ExpressionName("upcase")
42 | public class Upcase extends Expression {
43 | protected Upcase(ArrayList expressionArray) {
44 | super(expressionArray);
45 | }
46 |
47 | @Override
48 | public @Nullable String getValue(Feature feature, ExpressionParams expressionParams) {
49 | String s = (String) getRealValue(feature, expressionArray.get(1), expressionParams);
50 | if (s == null) {
51 | return null;
52 | }
53 | return s.toUpperCase(Locale.ROOT);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mbexpression/src/test/java/com/Test.java:
--------------------------------------------------------------------------------
1 | package com;
2 |
3 | /**
4 | * @author liuyu
5 | * @date 2022/7/15
6 | */
7 | public class Test {
8 |
9 | public static void main(String[] args) throws Exception {
10 |
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | giscat
7 | org.wowtools
8 | g1.7.0
9 |
10 | 4.0.0
11 |
12 | giscat-vector-mvt
13 | g1.7.0
14 | Mapbox vector tile (mvt) 的序列化与反序列化
15 |
16 |
17 |
18 | giscat-vector-util
19 | org.wowtools
20 |
21 |
22 | junit
23 | junit
24 | test
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-web
29 | test
30 |
31 |
32 | org.openjdk.jmh
33 | jmh-core
34 | test
35 |
36 |
37 | org.openjdk.jmh
38 | jmh-generator-annprocess
39 | test
40 |
41 |
42 | org.wowtools
43 | catframe-common
44 | 1.4.2
45 | test
46 |
47 |
48 | org.jetbrains
49 | annotations
50 | compile
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/main/java/org/wowtools/giscat/vector/mvt/Command.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * This document is adapted from https://github.com/ElectronicChartCentre/java-vector-tile
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mvt;
21 |
22 | final class Command {
23 |
24 | /**
25 | * MoveTo: 1. (2 parameters follow)
26 | */
27 | static final int MoveTo = 1;
28 |
29 | /**
30 | * LineTo: 2. (2 parameters follow)
31 | */
32 | static final int LineTo = 2;
33 |
34 | /**
35 | * ClosePath: 7. (no parameters follow)
36 | */
37 | static final int ClosePath = 7;
38 |
39 | private Command() {
40 |
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/main/java/org/wowtools/giscat/vector/mvt/MvtCoordinateConvertor.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mvt;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 |
24 | /**
25 | * 矢量瓦片的坐标系与wgs84坐标系互转
26 | *
27 | * @author liuyu
28 | * @date 2022/4/20
29 | */
30 | class MvtCoordinateConvertor {
31 | private static final short TILE_SIZE = 256;
32 |
33 | private static final long @NotNull [] zoomPow;
34 |
35 | static {
36 | int n = 30;
37 | zoomPow = new long[n];
38 | long s = TILE_SIZE;
39 | for (int i = 0; i < n; i++) {
40 | zoomPow[i] = s;
41 | s = s * 2;
42 | }
43 | }
44 |
45 | private final double px;
46 | private final double py;
47 | private final long zoomMultiple;// 使用int的话超过22级就溢出了
48 |
49 | /**
50 | * @param z 瓦片 z
51 | * @param x 瓦片 x
52 | * @param y 瓦片 y
53 | */
54 | public MvtCoordinateConvertor(byte z, int x, int y) {
55 | px = x * TILE_SIZE;
56 | py = y * TILE_SIZE;
57 |
58 | zoomMultiple = zoomPow[z];
59 | }
60 |
61 | /**
62 | * wgs84 x 转mvt
63 | *
64 | * @param x wgs84 x
65 | * @return mvt x
66 | */
67 | public int wgs84X2mvt(double x) {
68 | double ppx = (x + 180) / 360 * zoomMultiple;
69 | return (int) ((ppx - px) * 16 + Math.sin(x) + 0.5);
70 | }
71 |
72 | /**
73 | * wgs84 y 转mvt
74 | *
75 | * @param y wgs84 y
76 | * @return mvt y
77 | */
78 | public int wgs84Y2mvt(double y) {
79 | double sinLatitude = Math.sin(y * Math.PI / 180);
80 | double mp = Math.log((1 + sinLatitude) / (1 - sinLatitude));
81 | double ppy = (0.5 - mp / (4 * Math.PI)) * zoomMultiple;
82 | return (int) ((ppy - py) * 16 + Math.cos(y) + 0.5);
83 | }
84 |
85 |
86 | /**
87 | * mvt x 转 wgs84
88 | *
89 | * @param pixelX mvt x
90 | * @return wgs84
91 | */
92 | public double mvtX2wgs84(double pixelX) {
93 | double ppx = pixelX / 16d + px;
94 | return ppx / zoomMultiple * 360d - 180d;
95 | }
96 |
97 | /**
98 | * mvt y 转 wgs84
99 | *
100 | * @param pixelY mvt y
101 | * @return wgs84
102 | */
103 | public double mvtY2wgs84(double pixelY) {
104 | double ppy = pixelY / 16d + py;
105 | double mp = (0.5d - ppy / zoomMultiple) * (4d * Math.PI);
106 | double exp = Math.exp(mp);
107 | double sinLatitude = (exp - 1d) / (exp + 1d);
108 | return Math.asin(sinLatitude) * 180d / Math.PI;
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/main/java/org/wowtools/giscat/vector/mvt/MvtFeature.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mvt;
21 |
22 | import org.locationtech.jts.geom.Geometry;
23 |
24 | import java.util.ArrayList;
25 |
26 | /**
27 | * mvt feature
28 | *
29 | * @author liuyu
30 | * @date 2022/4/24
31 | */
32 | public final class MvtFeature {
33 |
34 | Geometry geometry;
35 | ArrayList tags;
36 | }
37 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/main/java/org/wowtools/giscat/vector/mvt/MvtLayer.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.mvt;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.jetbrains.annotations.Nullable;
24 | import org.locationtech.jts.geom.Geometry;
25 | import org.locationtech.jts.geom.GeometryCollection;
26 | import org.locationtech.jts.geom.TopologyException;
27 | import org.locationtech.jts.simplify.TopologyPreservingSimplifier;
28 | import org.wowtools.giscat.vector.pojo.Feature;
29 | import org.wowtools.giscat.vector.util.analyse.Bbox;
30 |
31 | import java.util.*;
32 |
33 | /**
34 | * mvt layer
35 | *
36 | * @author liuyu
37 | * @date 2022/4/24
38 | */
39 | public final class MvtLayer {
40 |
41 | protected final List features = new LinkedList<>();
42 |
43 | private final Map keys = new LinkedHashMap<>();
44 | private final Map values = new LinkedHashMap<>();
45 |
46 | private final MvtBuilder mvtBuilder;
47 |
48 | private final double wgs84SimplifyDistance;
49 |
50 |
51 | /**
52 | * @param mvtBuilder mvtBuilder
53 | * @param simplifyDistance 对geometry进行简化的长度,单位是瓦片像素,取值范围[0,extent+clipBuffer],为0时表示不做简化
54 | */
55 | protected MvtLayer(@NotNull MvtBuilder mvtBuilder, int simplifyDistance) {
56 | this.mvtBuilder = mvtBuilder;
57 |
58 | if (simplifyDistance > 0) {
59 | Bbox bbox = mvtBuilder.getBbox();
60 | double d = Math.sqrt(Math.pow(bbox.xmax - bbox.xmin, 2) + Math.pow(bbox.ymax - bbox.ymin, 2)) / mvtBuilder.extent;
61 | wgs84SimplifyDistance = simplifyDistance * d;
62 | } else {
63 | wgs84SimplifyDistance = 0;
64 | }
65 | }
66 |
67 | public void addFeatures(@NotNull Iterable features) {
68 | for (Feature feature : features) {
69 | addFeature(feature);
70 | }
71 | }
72 |
73 | public void addClipedFeatures(@NotNull Iterable features) {
74 | for (Feature feature : features) {
75 | addClipedFeature(feature);
76 | }
77 | }
78 |
79 | public void addFeature(@NotNull Feature feature) {
80 | Geometry clipedGeometry = clipGeometry(feature.getGeometry());
81 | addCipedGeometryAndAttributes(feature.getProperties(), clipedGeometry);
82 | }
83 |
84 | public void addClipedFeature(@NotNull Feature feature) {
85 | addCipedGeometryAndAttributes(feature.getProperties(), feature.getGeometry());
86 | }
87 |
88 | public void addCipedGeometryAndAttributes(Map attributes, @Nullable Geometry clipedGeometry) {
89 | if (null == clipedGeometry || clipedGeometry.isEmpty()) {
90 | return;//裁剪完没有交集则直接return
91 | }
92 | if (wgs84SimplifyDistance > 0) {
93 | clipedGeometry = TopologyPreservingSimplifier.simplify(clipedGeometry, wgs84SimplifyDistance);
94 | }
95 | // 转换并添加feature
96 | ArrayList tags = tags(attributes);
97 | List resolveGeometries = new LinkedList<>();
98 | resolveGeometryCollection(clipedGeometry, resolveGeometries);
99 | for (Geometry resolveGeometry : resolveGeometries) {
100 | addSampleGeometryFeature(tags, resolveGeometry);
101 | }
102 | }
103 |
104 | //拆出GeometryCollection中的geometry塞到list中
105 | private void resolveGeometryCollection(@NotNull Geometry geometry, @NotNull List resolveGeometries) {
106 | for (int i = 0; i < geometry.getNumGeometries(); i++) {
107 | Geometry subGeometry = geometry.getGeometryN(i);
108 | if (subGeometry.getClass().equals(GeometryCollection.class)) {
109 | resolveGeometryCollection(subGeometry, resolveGeometries);
110 | } else {
111 | resolveGeometries.add(subGeometry);
112 | }
113 | }
114 | }
115 |
116 |
117 | private void addSampleGeometryFeature(ArrayList tags, Geometry geometry) {
118 |
119 | MvtFeature feature = new MvtFeature();
120 | feature.geometry = geometry;
121 |
122 | feature.tags = tags;
123 |
124 | features.add(feature);
125 | }
126 |
127 | //将attributes转为tags以便加入到feature
128 | private ArrayList tags(@Nullable Map attributes) {
129 | if (null == attributes) {
130 | return null;
131 | }
132 | ArrayList tags = new ArrayList<>(attributes.size() * 2);
133 | for (Map.Entry e : attributes.entrySet()) {
134 | // skip attribute without value
135 | if (e.getValue() == null) {
136 | continue;
137 | }
138 | tags.add(key(e.getKey()));
139 | tags.add(value(e.getValue()));
140 | }
141 | return tags;
142 | }
143 |
144 | private @NotNull Integer key(String key) {
145 | return keys.computeIfAbsent(key, k -> keys.size());
146 | }
147 |
148 | protected @NotNull Set keys() {
149 | return keys.keySet();
150 | }
151 |
152 | private @NotNull Integer value(Object value) {
153 | return values.computeIfAbsent(value, k -> values.size());
154 | }
155 |
156 | protected Set values() {
157 | return values.keySet();
158 | }
159 |
160 |
161 | private Geometry clipGeometry(Geometry geometry) {
162 | try {
163 | return mvtBuilder.tileClip.intersection(geometry);
164 | } catch (TopologyException e) {
165 | geometry = geometry.buffer(0);
166 | return mvtBuilder.tileClip.intersection(geometry);
167 | }
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/test/java/org/wowtools/giscat/vector/mvt/MvtBuilderTest.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mvt;
2 |
3 |
4 | import org.locationtech.jts.geom.Coordinate;
5 | import org.locationtech.jts.geom.GeometryFactory;
6 | import org.wowtools.giscat.vector.pojo.Feature;
7 |
8 | import java.util.Map;
9 |
10 | public class MvtBuilderTest {
11 | @org.junit.Test
12 | public void test() {
13 | GeometryFactory gf = new GeometryFactory();
14 | byte z = 12;
15 | int x = 3223, y = 1774;
16 | MvtBuilder mvtBuilder = new MvtBuilder(z, x, y, gf);
17 | MvtLayer mvtLayer = mvtBuilder.getOrCreateLayer("testLayer");
18 | mvtLayer.addFeature(new Feature(
19 | gf.createPoint(new Coordinate(103.31, 23.35)),
20 | Map.of("name", "233")
21 | ));
22 |
23 | byte[] bytes = mvtBuilder.toBytes();
24 |
25 | MvtParser.MvtFeatureLayer[] mvtFeatureLayers = MvtParser.parse2Wgs84Coords(z, x, y, bytes, gf);
26 | System.out.println(mvtFeatureLayers[0].getFeatures()[0].getGeometry());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/test/java/org/wowtools/giscat/vector/mvt/MvtCoordinateConvertorTest.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mvt;
2 |
3 | import org.wowtools.giscat.vector.util.cst.Tile2Wgs84;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | public class MvtCoordinateConvertorTest {
8 |
9 | @org.junit.Test
10 | public void testWgs842mvt() {
11 | byte z = 12;
12 | int x = 3223, y = 1774;
13 | MvtCoordinateConvertor mvtCoordinateConvertor = new MvtCoordinateConvertor(z, x, y);
14 | System.out.println("瓦片wgs84范围:[" +
15 | Tile2Wgs84.tileX2lon(x, z) + ", " +
16 | Tile2Wgs84.tileY2lat(y + 1, z) + ", " +
17 | Tile2Wgs84.tileX2lon(x + 1, z) + ", " +
18 | Tile2Wgs84.tileY2lat(y, z) +
19 | "]");
20 | double wgs84X = 103.31;
21 | int mvtX = mvtCoordinateConvertor.wgs84X2mvt(wgs84X);
22 | assertEquals(1795, mvtX);
23 | double wgs84Y = 23.35;
24 | int mvtY = mvtCoordinateConvertor.wgs84Y2mvt(wgs84Y);
25 | assertEquals(2679, mvtY);
26 |
27 | wgs84X = 103.41;
28 | mvtX = mvtCoordinateConvertor.wgs84X2mvt(wgs84X);
29 | assertEquals(6456, mvtX);
30 | wgs84Y = 23.41;
31 | mvtY = mvtCoordinateConvertor.wgs84Y2mvt(wgs84Y);
32 | assertEquals(-367, mvtY);
33 |
34 | }
35 |
36 | @org.junit.Test
37 | public void testMvt2Wgs84() {
38 |
39 | byte z = 12;
40 | int x = 3223, y = 1774;
41 | MvtCoordinateConvertor mvtCoordinateConvertor = new MvtCoordinateConvertor(z, x, y);
42 |
43 | assertEquals(103.31, mvtCoordinateConvertor.mvtX2wgs84(1795), 0.0001);
44 | assertEquals(103.41, mvtCoordinateConvertor.mvtX2wgs84(6456), 0.0001);
45 |
46 | assertEquals(23.35, mvtCoordinateConvertor.mvtY2wgs84(2679), 0.0001);
47 | assertEquals(23.41, mvtCoordinateConvertor.mvtY2wgs84(-367), 0.0001);
48 |
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/test/java/org/wowtools/giscat/vector/mvt/WebDemo.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mvt;
2 |
3 | /**
4 | * 用springboot起一个web服务演示矢量瓦片的使用
5 | * 注:由于springboot的包扫描冲突,此文件启动时会报错,仅供一些较老的博客转载本文时方便查找,具体启动和调试请移步包demos.hello
6 | *
7 | * @author liuyu
8 | * @date 2022/4/26
9 | */
10 | public class WebDemo {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/test/java/org/wowtools/giscat/vector/mvt/demos/hello/WebDemo.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mvt.demos.hello;
2 |
3 | import org.locationtech.jts.geom.*;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.web.bind.annotation.CrossOrigin;
7 | import org.springframework.web.bind.annotation.PathVariable;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 | import org.wowtools.giscat.vector.mvt.MvtBuilder;
11 | import org.wowtools.giscat.vector.mvt.MvtLayer;
12 | import org.wowtools.giscat.vector.pojo.Feature;
13 | import org.wowtools.giscat.vector.pojo.FeatureCollection;
14 | import org.wowtools.giscat.vector.pojo.converter.GeoJsonFeatureConverter;
15 |
16 | import javax.servlet.http.HttpServletResponse;
17 | import java.io.IOException;
18 | import java.io.OutputStream;
19 | import java.util.ArrayList;
20 | import java.util.Map;
21 |
22 | /**
23 | * 用springboot起一个web服务演示矢量瓦片的使用
24 | *
25 | * @author liuyu
26 | * @date 2022/4/26
27 | */
28 | @SpringBootApplication
29 | @RestController()
30 | @RequestMapping("/tile")
31 | @CrossOrigin
32 | public class WebDemo {
33 | public static void main(String[] args) {
34 | SpringApplication.run(WebDemo.class, args);
35 | }
36 |
37 | /**
38 | * 测试数据,中国省份
39 | * 数据来源
40 | * https://datav.aliyun.com/portal/school/atlas/area_selector
41 | */
42 | private static final FeatureCollection areaFeatureCollection;//面数据
43 | private static final FeatureCollection lineFeatureCollection;//线数据
44 | private static final FeatureCollection pointFeatureCollection;//点数据
45 |
46 | private static final GeometryFactory geometryFactory = new GeometryFactory();
47 |
48 | static {
49 | //构造示例数据
50 | GeometryFactory gf = new GeometryFactory();
51 | String strJson = org.wowtools.common.utils.ResourcesReader.readStr(WebDemo.class, "china.json");
52 | areaFeatureCollection = GeoJsonFeatureConverter.fromGeoJsonFeatureCollection(strJson, gf);
53 | ArrayList pointFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
54 | ArrayList lineFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
55 | for (Feature feature : areaFeatureCollection.getFeatures()) {
56 |
57 | Feature pointFeature = new Feature();
58 | ArrayList center = (ArrayList) feature.getProperties().get("center");
59 | if (center != null) {
60 | Point point = gf.createPoint(new Coordinate((Double) center.get(0), (Double) center.get(1)));
61 | pointFeature.setProperties(Map.of("name", feature.getProperties().get("name")));
62 | pointFeature.setGeometry(point);
63 | pointFeatures.add(pointFeature);
64 | }
65 |
66 | Feature lineFeature = new Feature();
67 | if (feature.getGeometry() instanceof MultiPolygon) {
68 |
69 | MultiPolygon multiPolygon = (MultiPolygon) feature.getGeometry();
70 | LineString[] lines = new LineString[multiPolygon.getNumGeometries()];
71 | for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
72 | Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
73 | lines[i] = gf.createLineString(polygon.getExteriorRing().getCoordinates());
74 | }
75 | MultiLineString ml = gf.createMultiLineString(lines);
76 | lineFeature.setGeometry(ml);
77 | } else {
78 | LineString line = gf.createLineString(feature.getGeometry().getCoordinates());
79 | lineFeature.setGeometry(line);
80 | }
81 |
82 | lineFeatures.add(lineFeature);
83 | }
84 |
85 | lineFeatureCollection = new FeatureCollection();
86 | lineFeatureCollection.setFeatures(lineFeatures);
87 |
88 | pointFeatureCollection = new FeatureCollection();
89 | pointFeatureCollection.setFeatures(pointFeatures);
90 |
91 | // StringBuilder sb = new StringBuilder();
92 | // {
93 | // int i = 1;
94 | // for (Feature pointFeature : pointFeatures) {
95 | // sb.append("insert into test_point values (" + i + ",st_geometryfromtext('" + pointFeature.getGeometry() + "',4326));\n");
96 | // i++;
97 | // }
98 | // }
99 | // {
100 | // int i = 1;
101 | // for (Feature lineFeature : lineFeatures) {
102 | // sb.append("insert into test_line values (" + i + ",'line" + i + "',st_geometryfromtext('" + lineFeature.getGeometry() + "',4326));\n");
103 | // i++;
104 | // }
105 | // }
106 | // {
107 | // int i = 1;
108 | // for (Feature feature : areaFeatureCollection.getFeatures()) {
109 | // sb.append("insert into test_polygon values (" + i + ",'" + feature.getProperties().get("name") + "',st_geometryfromtext('" + feature.getGeometry() + "',4326));\n");
110 | // i++;
111 | // }
112 | // }
113 | // System.out.println(sb);
114 | }
115 |
116 |
117 | private static final String vtContentType = "application/octet-stream";
118 |
119 | @RequestMapping("/{z}/{x}/{y}")
120 | public void getTile(@PathVariable byte z, @PathVariable int x, @PathVariable int y, HttpServletResponse response) {
121 | //构造一个MvtBuilder对象
122 | MvtBuilder mvtBuilder = new MvtBuilder(z, x, y, geometryFactory);
123 |
124 | //向mvt中添加layer
125 | MvtLayer layer = mvtBuilder.getOrCreateLayer("省区域");
126 | //向layer中添加feature
127 | for (Feature feature : areaFeatureCollection.getFeatures()) {
128 | //这里简单地从内存中取数据并判断其是否与瓦片有交集,实际运用中可从数据库查询,例如postgis的ST_intersects函数
129 | if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
130 | layer.addFeature(feature);
131 | }
132 | }
133 |
134 | //如法炮制添加layer
135 | layer = mvtBuilder.getOrCreateLayer("省边界");
136 | for (Feature feature : lineFeatureCollection.getFeatures()) {
137 | if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
138 | layer.addFeature(feature);
139 | }
140 | }
141 |
142 | //如法炮制添加layer
143 | layer = mvtBuilder.getOrCreateLayer("省会位置");
144 | for (Feature feature : pointFeatureCollection.getFeatures()) {
145 | if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
146 | layer.addFeature(feature);
147 | }
148 | }
149 |
150 | //数据添加完毕,转为
151 | byte[] bytes = mvtBuilder.toBytes();
152 | exportByte(bytes, vtContentType, response);
153 | }
154 |
155 | //将bytes写进HttpServletResponse
156 | private void exportByte(byte[] bytes, String contentType, HttpServletResponse response) {
157 | response.setContentType(contentType);
158 | try (OutputStream os = response.getOutputStream()) {
159 | os.write(bytes);
160 | os.flush();
161 | } catch (org.apache.catalina.connector.ClientAbortException e) {
162 | //地图移动时客户端主动取消, 产生异常"你的主机中的软件中止了一个已建立的连接",无需处理
163 | } catch (IOException e) {
164 | throw new RuntimeException(e);
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/test/java/org/wowtools/giscat/vector/mvt/demos/reload/WebDemoReload.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.mvt.demos.reload;
2 |
3 | import org.locationtech.jts.geom.*;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.context.annotation.ComponentScan;
7 | import org.springframework.web.bind.annotation.CrossOrigin;
8 | import org.springframework.web.bind.annotation.PathVariable;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import org.wowtools.giscat.vector.util.analyse.Bbox;
12 | import org.wowtools.giscat.vector.mvt.MvtBuilder;
13 | import org.wowtools.giscat.vector.mvt.MvtLayer;
14 | import org.wowtools.giscat.vector.pojo.Feature;
15 | import org.wowtools.giscat.vector.pojo.FeatureCollection;
16 | import org.wowtools.giscat.vector.pojo.converter.GeoJsonFeatureConverter;
17 |
18 | import javax.servlet.http.HttpServletResponse;
19 | import java.io.IOException;
20 | import java.io.OutputStream;
21 | import java.util.*;
22 |
23 | /**
24 | * 利用Expires实现前端在瓦片过期后自动刷新
25 | *
26 | * @author liuyu
27 | * @date 2022/4/26
28 | */
29 | @ComponentScan("org.wowtools.giscat.vector.mvt.demos.reload")
30 | @SpringBootApplication
31 | @RestController()
32 | @RequestMapping("/tile")
33 | @CrossOrigin
34 | public class WebDemoReload {
35 | public static void main(String[] args) {
36 | SpringApplication.run(WebDemoReload.class, args);
37 | }
38 |
39 | /**
40 | * 测试数据,中国省份
41 | * 数据来源
42 | * https://datav.aliyun.com/portal/school/atlas/area_selector
43 | */
44 | private static final FeatureCollection areaFeatureCollection;//面数据
45 | private static final FeatureCollection lineFeatureCollection;//线数据
46 | private static final FeatureCollection pointFeatureCollection;//点数据
47 |
48 | private static final GeometryFactory geometryFactory = new GeometryFactory();
49 |
50 | static {
51 | System.out.println(new Date());
52 | //构造示例数据
53 | GeometryFactory gf = new GeometryFactory();
54 | String strJson = org.wowtools.common.utils.ResourcesReader.readStr(WebDemoReload.class, "china.json");
55 | areaFeatureCollection = GeoJsonFeatureConverter.fromGeoJsonFeatureCollection(strJson, gf);
56 | ArrayList pointFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
57 | ArrayList lineFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
58 | for (Feature feature : areaFeatureCollection.getFeatures()) {
59 |
60 | Feature pointFeature = new Feature();
61 | ArrayList center = (ArrayList) feature.getProperties().get("center");
62 | if (center != null) {
63 | Point point = gf.createPoint(new Coordinate((Double) center.get(0), (Double) center.get(1)));
64 | pointFeature.setProperties(Map.of("name", feature.getProperties().get("name")));
65 | pointFeature.setGeometry(point);
66 | pointFeatures.add(pointFeature);
67 | }
68 |
69 | Feature lineFeature = new Feature();
70 | if (feature.getGeometry() instanceof MultiPolygon) {
71 |
72 | MultiPolygon multiPolygon = (MultiPolygon) feature.getGeometry();
73 | LineString[] lines = new LineString[multiPolygon.getNumGeometries()];
74 | for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
75 | Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
76 | lines[i] = gf.createLineString(polygon.getExteriorRing().getCoordinates());
77 | }
78 | MultiLineString ml = gf.createMultiLineString(lines);
79 | lineFeature.setGeometry(ml);
80 | } else {
81 | LineString line = gf.createLineString(feature.getGeometry().getCoordinates());
82 | lineFeature.setGeometry(line);
83 | }
84 |
85 | lineFeatures.add(lineFeature);
86 | }
87 |
88 | lineFeatureCollection = new FeatureCollection();
89 | lineFeatureCollection.setFeatures(lineFeatures);
90 |
91 | pointFeatureCollection = new FeatureCollection();
92 | pointFeatureCollection.setFeatures(pointFeatures);
93 | }
94 |
95 |
96 | private static final String vtContentType = "application/octet-stream";
97 |
98 | @RequestMapping("/{z}/{x}/{y}")
99 | public void getTile(@PathVariable byte z, @PathVariable int x, @PathVariable int y, HttpServletResponse response) {
100 | Calendar calendar = Calendar.getInstance();
101 | calendar.setTime(new Date());
102 | calendar.add(Calendar.SECOND, 5);
103 | Date expirationDate = calendar.getTime();
104 | response.setDateHeader("Expires", expirationDate.getTime());
105 |
106 | if (Math.random() > 5) {
107 | try {
108 | response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
109 | } catch (IOException e) {
110 | e.printStackTrace();
111 | }
112 | return;
113 | }
114 | //构造一个MvtBuilder对象
115 | MvtBuilder mvtBuilder = new MvtBuilder(z, x, y, geometryFactory);
116 |
117 | //向mvt中添加layer
118 | MvtLayer layer = mvtBuilder.getOrCreateLayer("省区域");
119 | //向layer中添加feature
120 | for (Feature feature : areaFeatureCollection.getFeatures()) {
121 | //这里简单地从内存中取数据并判断其是否与瓦片有交集,实际运用中可从数据库查询,例如postgis的ST_intersects函数
122 | if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
123 | layer.addFeature(feature);
124 | }
125 | }
126 |
127 | //如法炮制添加layer
128 | layer = mvtBuilder.getOrCreateLayer("省边界");
129 | for (Feature feature : lineFeatureCollection.getFeatures()) {
130 | if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
131 | layer.addFeature(feature);
132 | }
133 | }
134 |
135 | //如法炮制添加layer
136 | layer = mvtBuilder.getOrCreateLayer("省会位置");
137 | for (Feature feature : pointFeatureCollection.getFeatures()) {
138 | if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
139 | layer.addFeature(feature);
140 | }
141 | }
142 |
143 | //随机添加点,演示动态变化效果
144 | Bbox bbox = mvtBuilder.getBbox();
145 | Random random = new Random();
146 | layer = mvtBuilder.getOrCreateLayer("实时位置");
147 | Coordinate coord = new Coordinate(bbox.xmin + (bbox.xmax - bbox.xmin) * random.nextDouble(), bbox.ymin + (bbox.ymax - bbox.ymin) * random.nextDouble());
148 | layer.addFeature(new Feature(geometryFactory.createPoint(coord), Map.of()));
149 |
150 | //数据添加完毕,转为
151 | byte[] bytes = mvtBuilder.toBytes();
152 | exportByte(bytes, vtContentType, response);
153 | }
154 |
155 | //将bytes写进HttpServletResponse
156 | private void exportByte(byte[] bytes, String contentType, HttpServletResponse response) {
157 | response.setContentType(contentType);
158 | try (OutputStream os = response.getOutputStream()) {
159 | os.write(bytes);
160 | os.flush();
161 | } catch (org.apache.catalina.connector.ClientAbortException e) {
162 | //地图移动时客户端主动取消, 产生异常"你的主机中的软件中止了一个已建立的连接",无需处理
163 | } catch (IOException e) {
164 | throw new RuntimeException(e);
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/test/resources/static/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | test
6 |
7 |
8 |
27 |
28 |
29 |
30 |
31 |
32 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-mvt/src/test/resources/static/testreload.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | test
6 |
7 |
8 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/README.md:
--------------------------------------------------------------------------------
1 | 基于jts,提供了一套基础gis对象(Feature Geometry properties)的定义,及其与geojson的互转。
2 | 同时定义了一套基于protobuf的二进制压缩规范ProtoFeature,提供了比wkb、geojson更高压缩率的序列化方法。
3 |
4 | # install
5 |
6 | maven add dependency:
7 |
8 | ```xml
9 |
10 | org.wowtools
11 | giscat-vector-pojo
12 | 1.1.1-STABLE
13 |
14 | ```
15 |
16 | # 与geojson互转
17 |
18 | geojson to FeatureCollection
19 |
20 | ```java
21 | String strGeoJson = "{\"features\":[{\"geometry\":{\"coordinates\":[30,10],\"type\":\"Point\"},\"type\":\"Feature\",\"properties\":{\"id\":1}},{\"geometry\":{\"coordinates\":[[30,10],[10,30],[40,40]],\"type\":\"LineString\"},\"type\":\"Feature\",\"properties\":{\"name\":\"hello\"}}],\"type\":\"FeatureCollection\"}";
22 | GeometryFactory geometryFactory = new GeometryFactory();// jts GeometryFactory
23 | FeatureCollection featureCollection = GeoJsonFeatureConverter.fromGeoJsonFeatureCollection(strGeoJson, geometryFactory);
24 | for (Feature feature : featureCollection.getFeatures()) {
25 | System.out.println(feature.getGeometry());//POINT (30 10)
26 | System.out.println(feature.getProperties());//{name=hello ...}
27 | }
28 | ```
29 |
30 | FeatureCollection to geojson
31 |
32 | ```java
33 | GeoJsonObject.FeatureCollection geoJson = GeoJsonFeatureConverter.toGeoJson(featureCollection);
34 | System.out.println(geoJson.toGeoJsonString());
35 | ```
36 |
37 | 完整的示例请参阅[测试用例](src/test/java/org/wowtools/giscat/vector/pojo/converter/GeoJsonFeatureConverterTest.java)
38 |
39 | 与 [bjornharrtell](https://github.com/bjornharrtell/jts2geojson) 的geojson的性能比对
40 | 
41 |
42 | | ~ |反序列化 |序列化 |
43 | |--|--|--|
44 | |bjornharrtell |52998.875 ± 14695.850 |3284.615 ± 983.774 |
45 | |giscat |33918.695 ± 4993.636 |2875.404 ± 242.143 |
46 |
47 | [JMH测试代码](src/test/java/org/wowtools/giscat/vector/pojo/converter/GeoJsonFeatureConverterJmhTest.java)
48 |
49 | # 与wkb互转
50 |
51 | 由于geometry对象使用了jts
52 | geometry,所以与wkb互转可以直接参考[jts的示例](https://github.com/locationtech/jts/blob/master/modules/core/src/test/java/org/locationtech/jts/io/WKTReadWriteTest.java)
53 |
54 | # 与protobuf互转
55 |
56 | ProtoFeature是一套基于protobuf的二进制压缩规范,提供了比wkb、geojson更高压缩率的序列化方法。
57 |
58 | [ProtoFeature压缩规范](src/main/resources/ProtoFeature.proto)
59 |
60 | FeatureCollection to ProtoFeature bytes
61 |
62 | ```java
63 | FeatureCollection featureCollection = new FeatureCollection();
64 | ArrayList features = new ArrayList<>(2);
65 | for (int i = 0; i < 2; i++) {
66 | Feature feature = new Feature();
67 | feature.setGeometry(new WKTReader().read("POINT (30 10)"));
68 | feature.setProperties(Map.of("id",1,"name","tom"));
69 | }
70 | featureCollection.setFeatures(features);
71 | byte[] bytes = ProtoFeatureConverter.featureCollection2Proto(featureCollection);
72 | ```
73 |
74 | ProtoFeature bytes to FeatureCollection
75 |
76 | ```java
77 | byte[] bytes = xxx;
78 | FeatureCollection featureCollection1 = ProtoFeatureConverter.proto2featureCollection(bytes, SampleData.geometryFactory);
79 | for (Feature feature : featureCollection1.getFeatures()) {
80 | System.out.println(feature.getGeometry());//jts geometry
81 | System.out.println(feature.getProperties());//Map
82 | }
83 | ```
84 |
85 | jts Geometry to ProtoFeature bytes
86 |
87 | ```java
88 | Geometry geometry = new WKTReader().read("POINT (30 10)");
89 | byte[] bytes = ProtoFeatureConverter.geometry2Proto(geometry);
90 | ```
91 |
92 | ProtoFeature bytes to jts Geometry
93 |
94 | ```java
95 | byte[] bytes = xxx;
96 | Geometry geometry = ProtoFeatureConverter.proto2Geometry(bytes, SampleData.geometryFactory);
97 | ```
98 |
99 | 完整的示例请参阅[测试用例](src/test/java/org/wowtools/giscat/vector/pojo/converter/ProtoFeatureConverterTest.java)
100 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/doc/imgs/geojson_vs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingmiao/giscat/fdc08006f5ba46b8edbda28c28290506285c8acc/giscat-vector/giscat-vector-pojo/doc/imgs/geojson_vs.jpg
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | giscat-vector
7 | org.wowtools
8 | g1.7.0
9 |
10 | 4.0.0
11 |
12 | giscat-vector-pojo
13 | g1.7.0
14 |
15 |
16 | org.locationtech.jts
17 | jts-core
18 |
19 |
20 | com.fasterxml.jackson.core
21 | jackson-databind
22 |
23 |
24 | com.google.protobuf
25 | protobuf-java
26 |
27 |
28 | org.projectlombok
29 | lombok
30 |
31 |
32 | junit
33 | junit
34 | test
35 |
36 |
37 | org.openjdk.jmh
38 | jmh-core
39 | test
40 |
41 |
42 | org.openjdk.jmh
43 | jmh-generator-annprocess
44 | test
45 |
46 |
47 | org.wololo
48 | jts2geojson
49 | 0.17.0
50 | test
51 |
52 |
53 | org.jetbrains
54 | annotations
55 | compile
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/main/java/org/wowtools/giscat/vector/pojo/Feature.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.pojo;
21 |
22 | import org.locationtech.jts.geom.Geometry;
23 |
24 | import java.util.Map;
25 |
26 | /**
27 | * 要素 包含properties和geometry
28 | *
29 | * @author liuyu
30 | * @date 2022/3/15
31 | */
32 | public class Feature {
33 | private Geometry geometry;
34 | private Map properties;
35 |
36 | public Feature(Geometry geometry, Map properties) {
37 | this.geometry = geometry;
38 | this.properties = properties;
39 | }
40 |
41 | public Feature(Geometry geometry) {
42 | this.geometry = geometry;
43 | }
44 |
45 | public Feature(Map properties) {
46 | this.properties = properties;
47 | }
48 |
49 | public Feature() {
50 | }
51 |
52 | public Geometry getGeometry() {
53 | return geometry;
54 | }
55 |
56 | public void setGeometry(Geometry geometry) {
57 | this.geometry = geometry;
58 | }
59 |
60 | public Map getProperties() {
61 | return properties;
62 | }
63 |
64 | public void setProperties(Map properties) {
65 | this.properties = properties;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/main/java/org/wowtools/giscat/vector/pojo/FeatureCollection.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.pojo;
21 |
22 | import java.util.List;
23 | import java.util.Map;
24 |
25 | /**
26 | * FeatureCollection
27 | *
28 | * @author liuyu
29 | * @date 2022/3/15
30 | */
31 | public class FeatureCollection {
32 | /**
33 | * 要素
34 | */
35 | private List features;
36 |
37 | /**
38 | * 头信息,可以在headers中添加一些关于FeatureCollection、features等的描述信息
39 | */
40 | private Map headers;
41 |
42 | public List getFeatures() {
43 | return features;
44 | }
45 |
46 | public void setFeatures(List features) {
47 | this.features = features;
48 | }
49 |
50 | public Map getHeaders() {
51 | return headers;
52 | }
53 |
54 | public void setHeaders(Map headers) {
55 | this.headers = headers;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/main/java/org/wowtools/giscat/vector/pojo/PojoConstant.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.pojo;
12 |
13 | import org.locationtech.jts.geom.GeometryFactory;
14 |
15 | /**
16 | * 常量
17 | * @author liuyu
18 | * @date 2023/4/6
19 | */
20 | public class PojoConstant {
21 |
22 | /**
23 | * 通用的geometryFactory
24 | */
25 | public static final GeometryFactory geometryFactory = new GeometryFactory();
26 | }
27 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/main/resources/ProtoFeature.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package pojo;
3 | option java_package = "org.wowtools.giscat.vector.pojo.proto";
4 | option java_outer_classname = "ProtoFeature";
5 |
6 | // geometry具体实现。
7 |
8 | // 空几何对象 解析后返回null
9 | message NullGeometry{
10 |
11 | }
12 | // Point,包含点的 x y z坐标 ,z可选。
13 | message Point{
14 | double x = 1;
15 | double y = 2;
16 | double z = 3;
17 | }
18 |
19 | // LineString 包含线段上各个点的x y z坐标,z可选。
20 | message LineString{
21 | repeated double xs = 1;
22 | repeated double ys = 2;
23 | repeated double zs = 3;
24 | }
25 |
26 | // Polygon 包含多边形上各个点的x y z坐标,z可选。
27 | // separators用于将坐标串分割为环 例如,xs ys zs 形成了坐标串[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9],
28 | // 则separators=[3,7]将坐标串分割为多边形Polygon((p0 p1 p2),(p3 p4 p5 p6),(p7 p8 p9))。
29 | // 即separators[i]的意义为第i个环的终点(从0开始计数);最后一个环的终点显然是数组的最后一位,故将其省略。
30 | // 注意,由于环的最后一个坐标必然和第一个坐标相等,故将环的最后一个坐标省略,仅在转换为jts等对象时将其补全。
31 | message Polygon{
32 | repeated double xs = 1;
33 | repeated double ys = 2;
34 | repeated double zs = 3;
35 | repeated int32 separators = 4;
36 | }
37 |
38 | // MultiPoint 包含MultiPoint上各个点的x y z坐标,z可选。
39 | message MultiPoint{
40 | repeated double xs = 1;
41 | repeated double ys = 2;
42 | repeated double zs = 3;
43 | }
44 |
45 | // MultiLineString 包含MultiLineString上各个点的x y z坐标,z可选。
46 | // separators用于将坐标串分割为子线段 例如,xs ys zs 形成了坐标串[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9],
47 | // 则separators=[3,7]将坐标串分割为MultiLineString((p0 p1 p2),(p3 p4 p5 p6),(p7 p8 p9))。
48 | // 即separators[i]的意义为第i条子线段的终点(从0开始计数);最后一条子线段的终点显然是数组的最后一位,故将其省略。
49 | message MultiLineString{
50 | repeated double xs = 1;
51 | repeated double ys = 2;
52 | repeated double zs = 3;
53 | repeated int32 separators = 4;
54 | }
55 |
56 | // MultiPolygon 包含MultiPolygon上各个点的x y z坐标,z可选。
57 | // polygonSeparators用于将坐标串分割为子多边形 例如,xs ys zs 形成了坐标串[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9],
58 | // 则polygonSeparators=[3,7]将坐标串分割为MultiPolygon(((p0 p1 p2)),((p3 p4 p5 p6)),((p7 p8 p9)))。
59 | // 即polygonSeparators[i]的意义为第i个子多边形的终点(从0开始计数);最后一个子多边形的终点显然是数组的最后一位,故将其省略。
60 | // 经过polygonSeparators分割后的子多边形坐标串,进一步由coordSeparators分割为环,分割依据与Polygon的separators一致
61 | message MultiPolygon{
62 | repeated double xs = 1;
63 | repeated double ys = 2;
64 | repeated double zs = 3;
65 | repeated int32 coordSeparators = 4;
66 | repeated int32 polygonSeparators = 5;
67 | }
68 |
69 | // GeometryCollection
70 | // GeometryCollection允许嵌套
71 | message GeometryCollection{
72 | repeated Point points = 1;
73 | repeated LineString lineStrings = 2;
74 | repeated Polygon polygons = 3;
75 |
76 | repeated MultiPoint multiPoints = 4;
77 | repeated MultiLineString multiLineStrings = 5;
78 | repeated MultiPolygon multiPolygons = 6;
79 |
80 | repeated GeometryCollection geometryCollections = 7; // 允许嵌套
81 | }
82 |
83 |
84 | // geometry 包含了所有jts规范中所罗列的Geometry类型 每个Geometry允许且仅允许其中一种对象非空
85 | message Geometry{
86 | Point point = 1;
87 | LineString lineString = 2;
88 | Polygon polygon = 3;
89 |
90 | MultiPoint multiPoint = 4;
91 | MultiLineString multiLineString = 5;
92 | MultiPolygon multiPolygon = 6;
93 |
94 | GeometryCollection geometryCollection = 7;
95 |
96 | NullGeometry nullGeometry = 8;
97 | }
98 |
99 | // Feature 仅作保留,单个Feature没有压缩优势,若确实需要,放入FeatureCollection中
100 | message Feature{
101 | }
102 |
103 | // 属性映射 支持的属性类型 double float sint32 sint64 bool string bytes subProperty
104 | // 属性映射使用keyId-value或keyId-valueId格式,与FeatureCollection中的key、value结合来存实际键值
105 | // sint64、string等可能占用4字节及以上的对象,用valueId(int32)取代value来存储以减少体积 value本身则存放到FeatureCollection中
106 | // 示例 [{id:4,name:'tom'},{id:5,name:'jerry',age:4}]转换后:
107 | // FeatureCollection {
108 | // keys = ['id','name','age'],//所有的key收集到keys中
109 | // sint32Values = [4,5],//所有的int value收集到sint32Values中
110 | // stringValues = ['tom','jerry'],//所有的string value收集到stringValues中
111 | // //其它类型的属性也是类似的方式收集为key value
112 | // propertiess = [//具体的属性用keyId-value或keyId-valueId格式来存储
113 | // {sint32KeyIds=[0], sint32ValueIds=[0], stringKeyIds=[1], stringValueIds=[0]},//tom的属性 {0:0, 1:0}
114 | // {sint32KeyIds=[0,2], sint32ValueIds=[1,0], stringKeyIds=[1], stringValueIds=[1]}//jerry的属性 {0:1, 1:1, 2:1}
115 | // ]
116 | // }
117 | message Map{
118 | // keyId、valueId/value
119 | repeated int32 doubleKeyIds = 1;
120 | repeated int32 doubleValueIds = 2;
121 |
122 | repeated int32 floatKeyIds = 3;
123 | repeated int32 floatValueIds = 4;
124 |
125 | repeated int32 sint32KeyIds = 5;
126 | repeated int32 sint32ValueIds = 6;
127 |
128 | repeated int32 sint64KeyIds = 7;
129 | repeated int32 sint64ValueIds = 8;
130 |
131 | repeated int32 boolKeyIds = 9;
132 | repeated bool boolValues = 10;
133 |
134 | repeated int32 stringKeyIds = 11;
135 | repeated int32 stringValueIds = 12;
136 |
137 | repeated int32 bytesKeyIds = 13;
138 | repeated int32 bytesValueIds = 14;
139 |
140 | // list keyId、valueId
141 | repeated int32 listKeyIds = 15;
142 | repeated List listValues = 16;
143 |
144 | // children keyId、valueId
145 | repeated int32 subMapKeyIds = 17;
146 | repeated Map subMapValues = 18;
147 |
148 | }
149 |
150 | // list 属性
151 | message List{
152 | // indexes 标注list中的第n个元素的类型是什么类型,如[1L,2D,'SSS'] 的indexes为 [5,2,7]
153 | repeated int32 indexes = 1;
154 | // 数组值id,按数组先后顺序填入
155 | // valueId/value
156 | repeated int32 doubleValueIds = 2;
157 | repeated int32 floatValueIds = 3;
158 | repeated int32 sint32ValueIds = 4;
159 | repeated int32 sint64ValueIds = 5;
160 | repeated bool boolValues = 6;
161 | repeated int32 stringValueIds = 7;
162 | repeated int32 bytesValueIds = 8;
163 | // map
164 | repeated Map mapValues = 9;
165 | // children
166 | repeated List subListValues = 10;
167 |
168 | }
169 |
170 | // FeatureCollection
171 | message FeatureCollection{
172 | // key id、value id对应的具体值
173 | repeated string keys = 1;
174 | repeated double doubleValues = 2;
175 | repeated float floatValues = 3;
176 | repeated sint32 sint32Values = 4;
177 | repeated sint64 sint64Values = 5;
178 | repeated string stringValues = 6;
179 | repeated bytes bytesValues = 7;
180 |
181 | // features 为了最大限度压缩数据,这里单独列了geometry properties,而未使用Feature对象
182 | repeated Geometry geometries = 8;
183 | repeated Map propertiess = 9;
184 |
185 | // features头信息,可以在headers中添加一些关于FeatureCollection、features等的描述信息
186 | Map headers = 10;
187 | }
188 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/test/java/org/wowtools/giscat/vector/pojo/converter/FoolStyleFeatureConverterTest.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.pojo.converter;
2 |
3 | import junit.framework.TestCase;
4 | import org.junit.Assert;
5 | import org.locationtech.jts.geom.LineString;
6 | import org.locationtech.jts.geom.Point;
7 | import org.locationtech.jts.geom.Polygon;
8 |
9 | import java.util.List;
10 |
11 | public class FoolStyleFeatureConverterTest extends TestCase {
12 |
13 | public void testXy2Point() {
14 | Point point = FoolStyleFeatureConverter.xy2Point(20, 30);
15 | Assert.assertEquals("POINT (20 30)", point.toText());
16 | }
17 |
18 | public void testList2Point() {
19 | Point point = FoolStyleFeatureConverter.list2Point(List.of(20d, 30d));
20 | Assert.assertEquals("POINT (20 30)", point.toText());
21 | }
22 |
23 | public void testArray2Point() {
24 | Point point = FoolStyleFeatureConverter.array2Point(new double[]{20, 30});
25 | Assert.assertEquals("POINT (20 30)", point.toText());
26 | }
27 |
28 | public void testStr2Point() {
29 | Point point = FoolStyleFeatureConverter.str2Point("20 30", " ");
30 | Assert.assertEquals("POINT (20 30)", point.toText());
31 | }
32 |
33 | public void testList2Line() {
34 | LineString line = FoolStyleFeatureConverter.list2Line(List.of(1d, 2d, 3d, 4d));
35 | Assert.assertEquals("LINESTRING (1 2, 3 4)", line.toText());
36 | }
37 |
38 | public void testArray2Line() {
39 | LineString line = FoolStyleFeatureConverter.array2Line(new double[]{1, 2, 3, 4});
40 | Assert.assertEquals("LINESTRING (1 2, 3 4)", line.toText());
41 | }
42 |
43 | public void testLists2Line() {
44 | LineString line = FoolStyleFeatureConverter.lists2Line(List.of(new double[]{1, 2}, new double[]{3, 4}));
45 | Assert.assertEquals("LINESTRING (1 2, 3 4)", line.toText());
46 | }
47 |
48 | public void testArrays2Line() {
49 | LineString line = FoolStyleFeatureConverter.arrays2Line(new double[][]{new double[]{1, 2}, new double[]{3, 4}});
50 | Assert.assertEquals("LINESTRING (1 2, 3 4)", line.toText());
51 | }
52 |
53 | public void testStr2Line() {
54 | LineString line = FoolStyleFeatureConverter.str2Line("1,2;3,4",",",";");
55 | Assert.assertEquals("LINESTRING (1 2, 3 4)", line.toText());
56 | }
57 |
58 | public void testList2Polygon() {
59 | Polygon polygon = FoolStyleFeatureConverter.list2Polygon(List.of(1d, 2d, 3d, 4d, 6d, 6d));
60 | Assert.assertEquals("POLYGON ((1 2, 3 4, 6 6, 1 2))", polygon.toText());
61 | }
62 |
63 | public void testArray2Polygon() {
64 | Polygon polygon = FoolStyleFeatureConverter.array2Polygon(new double[]{1d, 2d, 3d, 4d, 6d, 6d});
65 | Assert.assertEquals("POLYGON ((1 2, 3 4, 6 6, 1 2))", polygon.toText());
66 | }
67 |
68 | public void testLists2Polygon() {
69 | Polygon polygon = FoolStyleFeatureConverter.lists2Polygon(List.of(new double[]{1,2},new double[]{3,4},new double[]{6,6}));
70 | Assert.assertEquals("POLYGON ((1 2, 3 4, 6 6, 1 2))", polygon.toText());
71 | }
72 |
73 | public void testArrays2Polygon() {
74 | Polygon polygon = FoolStyleFeatureConverter.arrays2Polygon(new double[][]{new double[]{1,2},new double[]{3,4},new double[]{6,6}});
75 | Assert.assertEquals("POLYGON ((1 2, 3 4, 6 6, 1 2))", polygon.toText());
76 | }
77 |
78 | public void testStr2Polygon() {
79 | Polygon polygon = FoolStyleFeatureConverter.str2Polygon("1 2,3 4,6 6, 1 2"," ",",");
80 | Assert.assertEquals("POLYGON ((1 2, 3 4, 6 6, 1 2))", polygon.toText());
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/test/java/org/wowtools/giscat/vector/pojo/converter/GeoJsonFeatureConverterJmhTest.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.pojo.converter;
2 |
3 |
4 | import org.locationtech.jts.geom.Geometry;
5 | import org.openjdk.jmh.annotations.*;
6 | import org.openjdk.jmh.infra.Blackhole;
7 | import org.openjdk.jmh.results.format.ResultFormatType;
8 | import org.openjdk.jmh.runner.Runner;
9 | import org.openjdk.jmh.runner.options.Options;
10 | import org.openjdk.jmh.runner.options.OptionsBuilder;
11 | import org.wololo.geojson.Feature;
12 | import org.wololo.geojson.GeoJSON;
13 | import org.wololo.geojson.GeoJSONFactory;
14 | import org.wololo.jts2geojson.GeoJSONReader;
15 | import org.wololo.jts2geojson.GeoJSONWriter;
16 | import org.wowtools.giscat.vector.pojo.FeatureCollection;
17 | import org.wowtools.giscat.vector.pojo.GeoJsonObject;
18 | import org.wowtools.giscat.vector.pojo.util.SampleData;
19 |
20 | import java.util.ArrayList;
21 | import java.util.Map;
22 | import java.util.concurrent.TimeUnit;
23 |
24 |
25 | /**
26 | * 与https://github.com/bjornharrtell/jts2geojson的jmh性能对比测试
27 | */
28 | @BenchmarkMode(Mode.AverageTime)
29 | @Warmup(iterations = 3, time = 1)
30 | @Measurement(iterations = 5, time = 3)
31 | @Threads(1)
32 | @Fork(1)
33 | @State(value = Scope.Benchmark)
34 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
35 | public class GeoJsonFeatureConverterJmhTest {
36 |
37 | GeoJSONWriter writer = new GeoJSONWriter();
38 | GeoJSONReader reader = new GeoJSONReader();
39 |
40 | /////////////to json
41 | @Benchmark
42 | public void bjornharrtellParseJson(Blackhole blackhole) throws Exception {
43 | org.wololo.geojson.FeatureCollection geoJsonFeatureCollection = (org.wololo.geojson.FeatureCollection) GeoJSONFactory.create(SampleData.strFeatureCollection1);
44 | for (Feature geoJsonFeature : geoJsonFeatureCollection.getFeatures()) {
45 | Geometry geometry = reader.read(geoJsonFeature.getGeometry());
46 | blackhole.consume(geometry);
47 | blackhole.consume(geoJsonFeature.getProperties());
48 | }
49 | }
50 |
51 | @Benchmark
52 | public void geoJsonFeatureParseJson(Blackhole blackhole) throws Exception {
53 | FeatureCollection featureCollection = GeoJsonFeatureConverter.fromGeoJsonFeatureCollection(SampleData.strFeatureCollection1, SampleData.geometryFactory);
54 | for (org.wowtools.giscat.vector.pojo.Feature feature : featureCollection.getFeatures()) {
55 | Geometry geometry = feature.getGeometry();
56 | blackhole.consume(geometry);
57 | blackhole.consume(feature.getProperties());
58 | }
59 | }
60 |
61 | //////////////parse json
62 | private final Geometry[] geometryArr = new Geometry[]{
63 | SampleData.point,
64 | SampleData.lineString,
65 | // SampleData.polygon1,//bjornharrtell 解析报错
66 | SampleData.multiPoint,
67 | };
68 |
69 | private final Map[] propertiesArr = new Map[]{
70 | Map.of("sada", 1, "saidoje", true, "oisejoi", "saoidj"),
71 | Map.of("sada", 1, "saidoje", true, "oisejoi", "saoidj"),
72 | Map.of("sada", 1, "saidoje", true, "oisejoi", "saoidj"),
73 | Map.of("sada", 1, "saidoje", true, "oisejoi", "saoidj"),
74 | };
75 |
76 | @Benchmark
77 | public void bjornharrtellToJson(Blackhole blackhole) throws Exception {
78 | ArrayList features = new ArrayList<>(geometryArr.length);
79 | for (int i = 0; i < geometryArr.length; i++) {
80 | org.wololo.geojson.Geometry jsonGeometry = writer.write(geometryArr[i]);
81 | Map properties = propertiesArr[i];
82 | features.add(new Feature(jsonGeometry, properties));
83 | }
84 | GeoJSON json = writer.write(features);
85 | blackhole.consume(json.toString());
86 | }
87 |
88 | @Benchmark
89 | public void geoJsonFeatureToJson(Blackhole blackhole) throws Exception {
90 | GeoJsonObject.Feature[] features = new GeoJsonObject.Feature[geometryArr.length];
91 | for (int i = 0; i < geometryArr.length; i++) {
92 | GeoJsonObject.Feature feature = new GeoJsonObject.Feature();
93 | GeoJsonObject.Geometry geometry = GeoJsonFeatureConverter.geometry2GeoJson(geometryArr[i]);
94 | feature.setGeometry(geometry);
95 | feature.setProperties(propertiesArr[i]);
96 | features[i] = feature;
97 | }
98 | GeoJsonObject.FeatureCollection featureCollection = new GeoJsonObject.FeatureCollection();
99 | featureCollection.setFeatures(features);
100 | blackhole.consume(featureCollection.toGeoJsonString());
101 | }
102 |
103 | public static void main(String[] args) throws Exception {
104 | // Blackhole blackhole = new Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.");
105 | // GeoJsonFeatureConverterJmhTest t = new GeoJsonFeatureConverterJmhTest();
106 | // while (true) {
107 | // t.testGeoJsonFeature(blackhole);
108 | // }
109 |
110 |
111 | Options opt = new OptionsBuilder()
112 | .include(GeoJsonFeatureConverterJmhTest.class.getSimpleName())
113 | .result("jmhResult.json")
114 | .resultFormat(ResultFormatType.JSON).build();
115 | new Runner(opt).run();
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/test/java/org/wowtools/giscat/vector/pojo/converter/MakePbfTest1.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.pojo.converter;
2 |
3 | import org.wowtools.giscat.vector.pojo.Feature;
4 | import org.wowtools.giscat.vector.pojo.FeatureCollection;
5 | import org.wowtools.giscat.vector.pojo.util.SampleData;
6 |
7 | import java.io.*;
8 | import java.util.LinkedList;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | /**
13 | * @author liuyu
14 | * @date 2022/4/1
15 | */
16 | public class MakePbfTest1 {
17 |
18 |
19 | public static void main(String[] args) throws Exception {
20 | Map p = Map.of("a", List.of("1", 2.5d, true, "x", Map.of("xx", 111)), "b", "测试");
21 | FeatureCollection fc = new FeatureCollection();
22 | fc.setHeaders(Map.of(
23 | "version",1.1,
24 | "list",List.of(1,"ss",1.23)
25 |
26 | ));
27 | List features = new LinkedList<>();
28 | fc.setFeatures(features);
29 | features.add(new Feature(SampleData.point, p));
30 | features.add(new Feature(SampleData.lineString, p));
31 | features.add(new Feature(SampleData.polygon1, p));
32 | features.add(new Feature(SampleData.polygon2, p));
33 | features.add(new Feature(SampleData.polygon3, p));
34 | features.add(new Feature(SampleData.multiPoint, p));
35 | features.add(new Feature(SampleData.multiLineString, p));
36 | features.add(new Feature(SampleData.multiPolygon1, p));
37 | features.add(new Feature(SampleData.multiPolygon2, p));
38 | features.add(new Feature(SampleData.geometryCollection, p));
39 | byte[] bytes = ProtoFeatureConverter.featureCollection2Proto(fc);
40 | save2File("D:/_test/1/testbytes.pbf", bytes);
41 | System.out.println(GeoJsonFeatureConverter.toGeoJson(fc).toGeoJsonString());
42 | }
43 |
44 |
45 | public static boolean save2File(String fname, byte[] msg) {
46 | OutputStream fos = null;
47 | try {
48 | File file = new File(fname);
49 | file.mkdirs();
50 | System.out.println(file.getAbsolutePath());
51 | fos = new FileOutputStream(file);
52 | fos.write(msg);
53 | fos.flush();
54 | return true;
55 | } catch (FileNotFoundException e) {
56 | return false;
57 | } catch (IOException e) {
58 | File parent;
59 | return false;
60 | } finally {
61 | if (fos != null) {
62 | try {
63 | fos.close();
64 | } catch (IOException e) {
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/test/java/org/wowtools/giscat/vector/pojo/converter/ProtoFeatureConverterGeometryJmhTest.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.pojo.converter;
2 |
3 | import org.locationtech.jts.geom.Geometry;
4 | import org.locationtech.jts.geom.GeometryFactory;
5 | import org.locationtech.jts.io.WKBReader;
6 | import org.locationtech.jts.io.WKBWriter;
7 | import org.locationtech.jts.io.WKTReader;
8 | import org.openjdk.jmh.annotations.*;
9 | import org.openjdk.jmh.infra.Blackhole;
10 | import org.openjdk.jmh.results.format.ResultFormatType;
11 | import org.openjdk.jmh.runner.Runner;
12 | import org.openjdk.jmh.runner.options.Options;
13 | import org.openjdk.jmh.runner.options.OptionsBuilder;
14 |
15 | import java.util.concurrent.TimeUnit;
16 |
17 | /**
18 | * ProtoFeatureConverter转换bytes与wkb转换bytes的jmh性能测试
19 | *
20 | * @author liuyu
21 | * @date 2022/4/1
22 | */
23 | @BenchmarkMode(Mode.AverageTime)
24 | @Warmup(iterations = 3, time = 1)
25 | @Measurement(iterations = 5, time = 3)
26 | @Threads(1)
27 | @Fork(2)
28 | @State(value = Scope.Benchmark)
29 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
30 | public class ProtoFeatureConverterGeometryJmhTest {
31 |
32 | private final Geometry[] geometries;
33 |
34 | {
35 | try {
36 | WKTReader wktReader = new WKTReader();
37 | geometries = new Geometry[]{
38 | wktReader.read("POINT (30 10)"),
39 | wktReader.read("LINESTRING (30 10, 10 30, 40 40)"),
40 | wktReader.read("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"),
41 | wktReader.read("MULTIPOINT ((10 40), (40 30), (20 20), (30 10))"),
42 | wktReader.read("MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10), (41 41, 31 31, 41 21, 31 11))"),
43 | wktReader.read("MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((41 41, 21 46, 46 31, 41 41)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))"),
44 | wktReader.read("GEOMETRYCOLLECTION (POINT (40 10), LINESTRING (10 10, 20 20, 10 40), POLYGON ((40 40, 20 45, 45 30, 40 40)))"),
45 | };
46 | } catch (Exception e) {
47 | throw new RuntimeException(e);
48 | }
49 | }
50 |
51 | @Param(value = {"0", "1", "2", "3", "4", "5", "6"})
52 | // @Param(value = {"1"})
53 | private int geometryIndex = 0;
54 |
55 | // private final WKBWriter wkbWriter = new WKBWriter(2,false);
56 |
57 | @Benchmark
58 | public void testWkb(Blackhole blackhole) throws Exception {
59 | WKBWriter wkbWriter = new WKBWriter(2, false);
60 | Geometry geometry = geometries[geometryIndex];
61 | byte[] bytes = wkbWriter.write(geometry);
62 | WKBReader wkbReader = new WKBReader();
63 | Geometry res = wkbReader.read(bytes);
64 | blackhole.consume(res);
65 | }
66 |
67 | @Benchmark
68 | public void testProtoFeature(Blackhole blackhole) {
69 | Geometry geometry = geometries[geometryIndex];
70 | byte[] bytes = ProtoFeatureConverter.geometry2Proto(geometry);
71 | Geometry res = ProtoFeatureConverter.proto2Geometry(bytes, new GeometryFactory());
72 | blackhole.consume(res);
73 | }
74 |
75 | public static void main(String[] args) throws Exception {
76 | // Blackhole blackhole = new Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.");
77 | // ProtoFeatureConverterGeometryJmhTest t = new ProtoFeatureConverterGeometryJmhTest();
78 | // while (true){
79 | // t.testProtoFeature(blackhole);
80 | // }
81 | Options opt = new OptionsBuilder()
82 | .include(ProtoFeatureConverterGeometryJmhTest.class.getSimpleName())
83 | .result("jmhResult.json")
84 | .resultFormat(ResultFormatType.JSON).build();
85 | new Runner(opt).run();
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-pojo/src/test/java/org/wowtools/giscat/vector/pojo/converter/Test1.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.pojo.converter;
2 |
3 | import org.wowtools.giscat.vector.pojo.converter.FoolStyleFeatureConverter;
4 | import org.locationtech.jts.geom.*;
5 |
6 | public class Test1 {
7 | public static void main(String[] args) {
8 |
9 | {
10 | Polygon p1 = FoolStyleFeatureConverter.array2Polygon(new double[]{150, 330, 260, 380, 380, 240});
11 | Polygon p2 = FoolStyleFeatureConverter.array2Polygon(new double[]{190, 260, 269, 325, 290, 160});
12 | System.out.println("p1与p2是否相交 "+p1.intersects(p2));//true
13 | System.out.println("p1与p2的交集 "+p1.intersection(p2));//POLYGON ((274.56738768718805 281.25623960066554, 234.76427923844062 296.83136899365365, 269 325, 274.56738768718805 281.25623960066554))
14 | System.out.println("交集的面积 "+p1.intersection(p2).getArea());//827.2124277609248
15 | System.out.println("交集的周长 "+p1.intersection(p2).getLength());//131.17314524175666
16 | }
17 |
18 | {
19 | LineString l1 = FoolStyleFeatureConverter.array2Line(new double[]{190, 180, 170, 240, 250, 320, 323, 205});
20 | Polygon p1 = FoolStyleFeatureConverter.array2Polygon(new double[]{150, 330, 260, 380, 380, 240});
21 | System.out.println("线与多边形是否相交 " + l1.intersects(p1));//true
22 | System.out.println("线与多边形的交集 "+l1.intersection(p1));//LINESTRING (229.0625 299.0625, 250 320, 274.60261569416497 281.2424547283702)
23 | System.out.println("相交线段长度 "+l1.intersection(p1).getLength());//75.51691528550752
24 | }
25 |
26 | {
27 | Point p = FoolStyleFeatureConverter.xy2Point(250, 310);
28 | Polygon p1 = FoolStyleFeatureConverter.array2Polygon(new double[]{150, 330, 260, 380, 380, 240});
29 | System.out.println("点与多边形是否相交 " + p.intersects(p1));//true
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/README.md:
--------------------------------------------------------------------------------
1 | 本模块基于[conversant rtree](https://github.com/conversant/rtree),和[RocksDb](https://github.com/facebook/rocksdb),构建了一棵磁盘上的rtree
2 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | giscat-vector
7 | org.wowtools
8 | g1.7.0
9 |
10 | 4.0.0
11 |
12 | giscat-vector-rocksrtree
13 | 基于RocksDb实现的文件存储Rtree
14 |
15 |
16 |
17 | org.rocksdb
18 | rocksdbjni
19 |
20 |
21 | org.wowtools
22 | giscat-vector-util
23 |
24 |
25 | org.wowtools
26 | catframe-common
27 |
28 |
29 |
30 | org.openjdk.jmh
31 | jmh-generator-annprocess
32 | test
33 |
34 |
35 | junit
36 | junit
37 | test
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/FeatureConsumer.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | import org.wowtools.giscat.vector.pojo.Feature;
14 |
15 | /**
16 | * 结果消费者
17 | * @author liuyu
18 | * @date 2023/3/24
19 | */
20 | @FunctionalInterface
21 | public interface FeatureConsumer {
22 |
23 | boolean accept(Feature feature);
24 |
25 | default boolean accept(RectNd rectNd) {
26 | return accept(rectNd.feature);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/Node.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | /*
14 | * #%L
15 | * Conversant RTree
16 | * ~~
17 | * Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, Inc.
18 | * ~~
19 | * Licensed under the Apache License, Version 2.0 (the "License");
20 | * you may not use this file except in compliance with the License.
21 | * You may obtain a copy of the License at
22 | *
23 | * http://www.apache.org/licenses/LICENSE-2.0
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS,
27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | * See the License for the specific language governing permissions and
29 | * limitations under the License.
30 | * #L%
31 | */
32 |
33 |
34 | import java.util.function.Consumer;
35 |
36 | /**
37 | * Created by jcairns on 4/30/15.
38 | */
39 | abstract class Node extends ProtoAble{
40 |
41 | public Node(TreeBuilder builder, String id) {
42 | super(builder, id);
43 | }
44 |
45 | /**
46 | * @return boolean - true if this node is a leaf
47 | */
48 | abstract boolean isLeaf();
49 |
50 | /**
51 | * @return Rect - the bounding rectangle for this node
52 | */
53 | public abstract RectNd getBound();
54 |
55 | /**
56 | * Add t to the index
57 | *
58 | * @param t - value to add to index
59 | */
60 | abstract Node add(RectNd t, TreeTransaction tx);
61 |
62 | /**
63 | * Remove t from the index
64 | *
65 | * @param t - value to remove from index
66 | */
67 | abstract Node remove(RectNd t, TreeTransaction tx);
68 |
69 | /**
70 | * update an existing t in the index
71 | *
72 | * @param told - old index to be updated
73 | * @param tnew - value to update old index to
74 | */
75 | abstract Node update(RectNd told, RectNd tnew, TreeTransaction tx);
76 |
77 |
78 | /**
79 | * Visitor pattern:
80 | *
81 | * Consumer "accepts" every node intersecting the given rect, if consumer return false, break it.
82 | *
83 | * @param rect - limiting rect
84 | * @param consumer consumer
85 | */
86 | public abstract boolean intersects(RectNd rect, FeatureConsumer consumer, TreeTransaction tx);
87 |
88 | /**
89 | * Visitor pattern:
90 | *
91 | * Consumer "accepts" every node contained by the given rect
92 | *
93 | * @param rect - limiting rect
94 | * @param consumer
95 | */
96 | public abstract boolean contains(RectNd rect, FeatureConsumer consumer, TreeTransaction tx);
97 |
98 | /**
99 | * @param rect
100 | * @param t
101 | * @return boolean true if subtree contains t
102 | */
103 | protected abstract boolean contains(RectNd rect, RectNd t, TreeTransaction tx);
104 |
105 | /**
106 | * The number of entries in the node
107 | *
108 | * @return int - entry count
109 | */
110 | public abstract int size();
111 |
112 | /**
113 | * The number of entries in the subtree
114 | *
115 | * @return int - entry count
116 | */
117 | public abstract int totalSize(TreeTransaction tx);
118 |
119 | /**
120 | * Consumer "accepts" every node in the entire index
121 | *
122 | * @param consumer
123 | */
124 | public abstract void forEach(Consumer consumer, TreeTransaction tx);
125 |
126 | /**
127 | * Recurses over index collecting stats
128 | *
129 | * @param stats - Stats object being populated
130 | * @param depth - current depth in tree
131 | */
132 | public abstract void collectStats(Stats stats, int depth, TreeTransaction tx);
133 |
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/PointNd.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | /*
14 | * #%L
15 | * Conversant RTree
16 | * ~~
17 | * Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, Inc.
18 | * ~~
19 | * Licensed under the Apache License, Version 2.0 (the "License");
20 | * you may not use this file except in compliance with the License.
21 | * You may obtain a copy of the License at
22 | *
23 | * http://www.apache.org/licenses/LICENSE-2.0
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS,
27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | * See the License for the specific language governing permissions and
29 | * limitations under the License.
30 | * #L%
31 | */
32 |
33 | import java.util.ArrayList;
34 | import java.util.Arrays;
35 | import java.util.List;
36 |
37 | /**
38 | * N dimensional point used to signify the bounds of a HyperRect
39 | *
40 | * Created by jcairns on 5/5/15.
41 | */
42 | final class PointNd {
43 |
44 | final double[] xs;
45 |
46 | protected List toList() {
47 | ArrayList list = new ArrayList<>(xs.length);
48 | for (double x : xs) {
49 | list.add(x);
50 | }
51 | return list;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | StringBuilder sb = new StringBuilder('[');
57 | for (double x : xs) {
58 | sb.append(x).append(' ');
59 | }
60 | sb.deleteCharAt(sb.length() - 1);
61 | sb.append(']');
62 | return sb.toString();
63 | }
64 |
65 | public PointNd(double[] xs) {
66 | this.xs = xs;
67 | }
68 |
69 | public PointNd(List list) {
70 | double[] arr = new double[list.size()];
71 | int i = 0;
72 | for (Double v : list) {
73 | arr[i] = v;
74 | i++;
75 | }
76 | xs = arr;
77 | }
78 | /**
79 | * The number of dimensions represented by this point
80 | *
81 | * @return dimension count
82 | */
83 | public int getNDim() {
84 | return xs.length;
85 | }
86 |
87 | /**
88 | * Get the value of this point in the given dimension
89 | *
90 | * @param d - dimension
91 | * @return D - value of this point in the dimension
92 | */
93 | public double getCoord(int d) {
94 | return xs[d];
95 | }
96 |
97 | /**
98 | * Calculate the distance from this point to the given point across all dimensions
99 | *
100 | * @param p - point to calculate distance to
101 | * @return distance to the point
102 | * @throws IllegalArgumentException if a non-existent dimension is requested
103 | */
104 | public double distance(PointNd p) {
105 | if (xs.length != p.xs.length) {
106 | throw new IllegalArgumentException("输入维度不相等");
107 | }
108 | double ds = 0;
109 | for (int i = 0; i < xs.length; i++) {
110 | double d = xs[i] - p.xs[i];
111 | ds += d * d;
112 | }
113 | return Math.sqrt(ds);
114 | }
115 |
116 | /**
117 | * Calculate the distance from this point to the given point in a specific dimension
118 | *
119 | * @param p - point to calculate distance to
120 | * @param d - dimension to use in calculation
121 | * @return distance to the point in the fiven dimension
122 | */
123 | double distance(PointNd p, int d) {
124 | double res = xs[d] - p.xs[d];
125 | return Math.abs(res);
126 | }
127 |
128 | public PointNd clone() {
129 | double[] newXs = Arrays.copyOf(xs, xs.length);
130 | return new PointNd(newXs);
131 | }
132 |
133 | // public final static class Builder implements RectBuilder {
134 | //
135 | // @Override
136 | // public RectNd getBBox(final RectNd point) {
137 | // return new RectNd(point.clone(), point.clone());
138 | // }
139 | //
140 | // @Override
141 | // public RectNd getMbr(PointNd p1, PointNd p2) {
142 | // return new RectNd(p1, p2);
143 | // }
144 | //
145 | // }
146 | }
147 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/ProtoAble.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | import java.lang.reflect.Constructor;
14 | import java.util.HashMap;
15 | import java.util.List;
16 | import java.util.Map;
17 |
18 | /**
19 | * 可以转为proto对象的接口标识
20 | *
21 | * @author liuyu
22 | * @date 2023/3/28
23 | */
24 | abstract class ProtoAble {
25 |
26 | protected final TreeBuilder builder;
27 | protected final String id;
28 |
29 | private static final Map, Constructor extends ProtoAble>> implConstructors;
30 |
31 | static {
32 | List> impls = List.of(
33 | Branch.class,
34 | Leaf.class
35 | );
36 | try {
37 | Map, Constructor extends ProtoAble>> constructors = new HashMap<>();
38 | for (Class extends ProtoAble> impl : impls) {
39 | Constructor extends ProtoAble> constructor = impl.getConstructor(TreeBuilder.class, String.class);
40 | constructors.put(impl, constructor);
41 | }
42 | implConstructors = Map.copyOf(constructors);
43 | } catch (Exception e) {
44 | throw new RuntimeException(e);
45 | }
46 | }
47 |
48 | public ProtoAble(TreeBuilder builder, String id) {
49 | this.builder = builder;
50 | this.id = id;
51 | }
52 |
53 | public abstract void fill(byte[] bytes);
54 |
55 | protected abstract byte[] toBytes();
56 |
57 | public static T fromBytes(Class t, TreeBuilder builder, String id, byte[] bytes) {
58 | Constructor constructor = (Constructor) implConstructors.get(t);
59 | T instance;
60 | try {
61 | instance = constructor.newInstance(builder, id);
62 | } catch (Exception e) {
63 | throw new RuntimeException(e);
64 | }
65 | instance.fill(bytes);
66 | return instance;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/RTree.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | /*
14 | * #%L
15 | * Conversant RTree
16 | * ~~
17 | * Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, Inc.
18 | * ~~
19 | * Licensed under the Apache License, Version 2.0 (the "License");
20 | * you may not use this file except in compliance with the License.
21 | * You may obtain a copy of the License at
22 | *
23 | * http://www.apache.org/licenses/LICENSE-2.0
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS,
27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | * See the License for the specific language governing permissions and
29 | * limitations under the License.
30 | * #L%
31 | */
32 |
33 | import org.wowtools.giscat.vector.pojo.Feature;
34 |
35 | import java.nio.charset.StandardCharsets;
36 | import java.util.function.Consumer;
37 |
38 |
39 | /**
40 | * Data structure to make range searching more efficient. Indexes multi-dimensional information
41 | * such as geographical coordinates or rectangles. Groups information and represents them with a
42 | * minimum bounding rectangle (mbr). When searching through the tree, any query that does not
43 | * intersect an mbr can ignore any data entries in that mbr.
44 | * More information can be found here @see https://en.wikipedia.org/wiki/R-tree
45 | *
46 | * Created by jcairns on 4/30/15.
47 | */
48 | public final class RTree {
49 |
50 | public static final byte[] TreeDbKey = "T".getBytes(StandardCharsets.UTF_8);
51 |
52 | private static final double EPSILON = 1e-12;
53 |
54 | private final TreeBuilder builder;
55 |
56 | protected RTree(TreeBuilder builder) {
57 | this.builder = builder;
58 | }
59 |
60 | /**
61 | * 查询被输入的范围完全覆盖的要素范围
62 | *
63 | * @param rect 输入范围
64 | * @param consumer 查询结果消费者,若accept返回false,则终止查询过程
65 | * @param tx 事务
66 | */
67 | public void contains(RectNd rect, FeatureConsumer consumer, TreeTransaction tx) {
68 | if (builder.rootId != null) {
69 | builder.getNode(builder.rootId, tx).contains(rect, consumer, tx);
70 | }
71 | }
72 |
73 |
74 | /**
75 | * 查询与输入范围相交的要素范围
76 | *
77 | * @param rect 输入范围
78 | * @param consumer 查询结果消费者,若accept返回false,则终止查询过程
79 | * @param tx 事务
80 | */
81 | public void intersects(RectNd rect, FeatureConsumer consumer, TreeTransaction tx) {
82 | if (builder.rootId != null) {
83 | builder.getNode(builder.rootId, tx).intersects(rect, consumer, tx);
84 | }
85 | }
86 |
87 |
88 | /**
89 | * 添加一个feature
90 | *
91 | * @param feature feature
92 | * @param tx 事务
93 | */
94 | public void add(Feature feature, TreeTransaction tx) {
95 | RectNd t = builder.buildFeatureRect(feature);
96 | add(t, tx);
97 | }
98 |
99 |
100 | /**
101 | * Add the data entry to the SpatialSearch structure
102 | *
103 | * @param t Data entry to be added
104 | * @param tx 事务
105 | */
106 | protected void add(final RectNd t, TreeTransaction tx) {
107 | if (builder.rootId != null) {
108 | Node node = builder.getNode(builder.rootId, tx);
109 | Node newNode = node.add(t, tx);
110 | builder.rootId = newNode.id;
111 | } else {
112 | builder.rootId = builder.newLeaf(tx).id;
113 | builder.getNode(builder.rootId, tx).add(t, tx);
114 | }
115 | }
116 |
117 | // TODO 删除和修改由于equals不易判断,暂不开放 后续通过featurekey拿到RectNd再 featureEquals来比较删除和修改
118 |
119 | // /**
120 | // * 添加一个feature
121 | // * @param feature feature
122 | // * @param tx 事务
123 | // */
124 | // public void remove(Feature feature,Transaction tx) {
125 | // RectNd t = builder.getFeatureRect(feature);
126 | // remove(t,tx);
127 | // }
128 | //
129 | // /**
130 | // * Remove the data entry from the SpatialSearch structure
131 | // *
132 | // * @param t Data entry to be removed
133 | // */
134 | // protected void remove(final RectNd t, Transaction tx) {
135 | // if (root != null) {
136 | // root = root.remove(t, tx);
137 | // }
138 | // }
139 | //
140 | // /**
141 | // * Update entry in tree
142 | // *
143 | // * @param told - Entry to update
144 | // * @param tnew - Entry to update it to
145 | // */
146 | // protected void update(final RectNd told, final RectNd tnew, Transaction tx) {
147 | // if (root != null) {
148 | // root = root.update(told, tnew, tx);
149 | // }
150 | // }
151 |
152 | /**
153 | * Get the number of entries in the tree
154 | *
155 | * @return entry count
156 | */
157 | public int getEntryCount(TreeTransaction tx) {
158 | if (builder.rootId != null) {
159 | return builder.getNode(builder.rootId, tx).totalSize(tx);
160 | }
161 | return 0;
162 | }
163 |
164 | protected static boolean isEqual(final double a, final double b) {
165 | return isEqual(a, b, EPSILON);
166 | }
167 |
168 | static boolean isEqual(final double a, final double b, final double eps) {
169 | return Math.abs(a - b) <= ((Math.abs(a) < Math.abs(b) ? Math.abs(b) : Math.abs(a)) * eps);
170 | }
171 |
172 | /**
173 | * Iterate over all entries in the tree
174 | *
175 | * @param consumer - callback for each element
176 | */
177 | protected void forEach(Consumer consumer, TreeTransaction tx) {
178 | if (builder.rootId != null) {
179 | builder.getNode(builder.rootId, tx).forEach(consumer, tx);
180 | }
181 | }
182 |
183 | protected Stats collectStats(TreeTransaction tx) {
184 | Stats stats = new Stats();
185 | stats.setMaxFill(builder.mMax);
186 | stats.setMinFill(builder.mMin);
187 | builder.getNode(builder.rootId, tx).collectStats(stats, 0, tx);
188 | return stats;
189 | }
190 |
191 | Node getRoot(TreeTransaction tx) {
192 | return builder.getNode(builder.rootId, tx);
193 | }
194 |
195 |
196 | protected byte[] toBytes() {
197 | RocksRtreePb.RTreePb.Builder rtreeBuilder = RocksRtreePb.RTreePb.newBuilder();
198 | rtreeBuilder.setMMax(builder.mMax);
199 | rtreeBuilder.setMMin(builder.mMin);
200 | rtreeBuilder.setRootId(builder.rootId);
201 | return rtreeBuilder.build().toByteArray();
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/RectNd.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | /*
14 | * #%L
15 | * Conversant RTree
16 | * ~~
17 | * Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, Inc.
18 | * ~~
19 | * Licensed under the Apache License, Version 2.0 (the "License");
20 | * you may not use this file except in compliance with the License.
21 | * You may obtain a copy of the License at
22 | *
23 | * http://www.apache.org/licenses/LICENSE-2.0
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS,
27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | * See the License for the specific language governing permissions and
29 | * limitations under the License.
30 | * #L%
31 | */
32 |
33 | import org.wowtools.giscat.vector.pojo.Feature;
34 |
35 | /**
36 | * An N dimensional rectangle or "hypercube" that is a representation of a data entry.
37 | *
38 | * Created by jcairns on 4/30/15.
39 | */
40 | public final class RectNd {
41 |
42 | final PointNd min, max;
43 |
44 | Feature feature;
45 |
46 | String leafId;
47 |
48 | protected RocksRtreePb.RectNdPb.Builder toBuilder() {
49 | RocksRtreePb.RectNdPb.Builder builder = RocksRtreePb.RectNdPb.newBuilder();
50 | builder.addAllMin(min.toList());
51 | builder.addAllMax(max.toList());
52 | return builder;
53 | }
54 |
55 | public boolean featureEquals(RectNd other, TreeBuilder builder) {
56 | return false;
57 | // if (feature == null) {
58 | // throw new RuntimeException("feature为空,不符合逻辑");
59 | // }
60 | // if (other.feature == null) {
61 | // throw new RuntimeException("feature为空,不符合逻辑");
62 | // }
63 | // return Objects.equals(builder.getFeatureKey(feature), builder.getFeatureKey(other.feature));
64 | }
65 |
66 | protected RectNd(PointNd min, PointNd max) {
67 | if (min.xs.length != max.xs.length) {
68 | throw new IllegalArgumentException("输入维度不相等");
69 | }
70 | this.min = min;
71 | this.max = max;
72 | }
73 |
74 | public RectNd(double[] min, double[] max) {
75 | if (min.length != max.length) {
76 | throw new IllegalArgumentException("输入维度不相等");
77 | }
78 | this.min = new PointNd(min);
79 | this.max = new PointNd(max);
80 | }
81 |
82 | protected RectNd(RocksRtreePb.RectNdPb pb) {
83 | min = new PointNd(pb.getMinList());
84 | max = new PointNd(pb.getMaxList());
85 | }
86 |
87 |
88 | @Override
89 | public String toString() {
90 | return min + " " + max;
91 | }
92 |
93 | private RectNd getMbrCache;
94 | /**
95 | * Calculate the resulting mbr when combining param HyperRect with this HyperRect
96 | *
97 | * @param r - mbr to add
98 | * @return new HyperRect representing mbr of both HyperRects combined
99 | */
100 | public RectNd getMbr(RectNd r) {
101 | if (null != getMbrCache) {
102 | return getMbrCache;
103 | }
104 | int dim = min.xs.length;
105 | double[] min = new double[dim];
106 | double[] max = new double[dim];
107 | for (int i = 0; i < dim; i++) {
108 | try {
109 | min[i] = Math.min(this.min.xs[i], r.min.xs[i]);
110 | max[i] = Math.max(this.max.xs[i], r.max.xs[i]);
111 | } catch (Exception e) {
112 | throw new RuntimeException(e);
113 | }
114 | }
115 | getMbrCache = new RectNd(new PointNd(min), new PointNd(max));
116 | return getMbrCache;
117 | }
118 |
119 | /**
120 | * Get number of dimensions used in creating the HyperRect
121 | *
122 | * @return number of dimensions
123 | */
124 | int getNDim() {
125 | return min.xs.length;
126 | }
127 |
128 | /**
129 | * Get the minimum HyperPoint of this HyperRect
130 | *
131 | * @return min HyperPoint
132 | */
133 | PointNd getMin() {
134 | return min;
135 | }
136 |
137 | /**
138 | * Get the minimum HyperPoint of this HyperRect
139 | *
140 | * @return min HyperPoint
141 | */
142 | PointNd getMax() {
143 | return max;
144 | }
145 |
146 | /**
147 | * Get the HyperPoint representing the center point in all dimensions of this HyperRect
148 | *
149 | * @return middle HyperPoint
150 | */
151 | PointNd getCentroid() {
152 | double[] xs = new double[min.xs.length];
153 | for (int i = 0; i < xs.length; i++) {
154 | xs[i] = (min.xs[i] + max.xs[i]) / 2;
155 | }
156 | return new PointNd(xs);
157 | }
158 |
159 | /**
160 | * Calculate the distance between the min and max HyperPoints in given dimension
161 | *
162 | * @param d - dimension to calculate
163 | * @return double - the numeric range of the dimention (min - max)
164 | */
165 | double getRange(final int d) {
166 | return max.xs[d] - max.xs[d];
167 | }
168 |
169 | /**
170 | * Determines if this HyperRect fully encloses parameter HyperRect
171 | *
172 | * @param r - HyperRect to test
173 | * @return true if contains, false otherwise
174 | */
175 | boolean contains(RectNd r) {
176 | for (int i = 0; i < min.xs.length; i++) {
177 | if (min.xs[i] > r.min.xs[i]) {
178 | return false;
179 | }
180 | if (max.xs[i] < r.max.xs[i]) {
181 | return false;
182 | }
183 | }
184 | return true;
185 | }
186 |
187 | /**
188 | * Determines if this HyperRect intersects parameter HyperRect on any axis
189 | *
190 | * @param r2 - HyperRect to test
191 | * @return true if intersects, false otherwise
192 | */
193 | boolean intersects(RectNd r2) {
194 | for (int i = 0; i < min.getNDim(); i++) {
195 | if (min.getCoord(i) > r2.max.getCoord(i) ||
196 | r2.min.getCoord(i) > max.getCoord(i)) {
197 | return false;
198 | }
199 | }
200 | return true;
201 | }
202 |
203 | private double costCache = -1;
204 | /**
205 | * Calculate the "cost" of this HyperRect - usually the area across all dimensions
206 | *
207 | * @return - cost
208 | */
209 | double cost() {
210 | if (costCache >= 0) {
211 | return costCache;
212 | }
213 | double res = 1;
214 | for (int i = 0; i < min.getNDim(); i++) {
215 | res = res * (max.getCoord(i) - min.getCoord(i));
216 | }
217 |
218 | costCache = Math.abs(res);
219 | return costCache;
220 | }
221 |
222 | private double perimeterCache = -1;
223 | /**
224 | * Calculate the perimeter of this HyperRect - across all dimesnions
225 | *
226 | * @return - perimeter
227 | */
228 | double perimeter() {
229 | if (perimeterCache >= 0) {
230 | return perimeterCache;
231 | }
232 | double n = Math.pow(2, getNDim());
233 | double p = 0.0;
234 | final int nD = this.getNDim();
235 | for (int d = 0; d < nD; d++) {
236 | p += n * this.getRange(d);
237 | }
238 | perimeterCache = p;
239 | return p;
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/Stats.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | /*
14 | * #%L
15 | * Conversant RTree
16 | * ~~
17 | * Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, Inc.
18 | * ~~
19 | * Licensed under the Apache License, Version 2.0 (the "License");
20 | * you may not use this file except in compliance with the License.
21 | * You may obtain a copy of the License at
22 | *
23 | * http://www.apache.org/licenses/LICENSE-2.0
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS,
27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | * See the License for the specific language governing permissions and
29 | * limitations under the License.
30 | * #L%
31 | */
32 |
33 | import java.io.PrintStream;
34 |
35 | /**
36 | * Created by jcovert on 5/20/15.
37 | */
38 | public class Stats {
39 |
40 | private int maxFill;
41 | private int minFill;
42 |
43 | private int maxDepth = 0;
44 | private int branchCount = 0;
45 | private int leafCount = 0;
46 | private int entryCount = 0;
47 | private int[] entriesAtDepth = new int[1000];
48 | private int[] branchesAtDepth = new int[1000];
49 | private int[] leavesAtDepth = new int[1000];
50 |
51 | public void print(PrintStream out) {
52 | out.println("m=" + minFill + " M=" + maxFill);
53 | out.println(" Branches (" + branchCount + " total)");
54 | out.print(" ");
55 | for (int i = 0; i <= maxDepth; i++) {
56 | out.print(i + ": " + branchesAtDepth[i] + " ");
57 | }
58 | out.println("\n Leaves (" + leafCount + " total)");
59 | out.print(" ");
60 | for (int i = 0; i <= maxDepth; i++) {
61 | out.print(i + ": " + leavesAtDepth[i] + " ");
62 | }
63 | out.println("\n Entries (" + entryCount + " total)");
64 | out.print(" ");
65 | for (int i = 0; i <= maxDepth; i++) {
66 | out.print(i + ": " + entriesAtDepth[i] + " ");
67 | }
68 | out.printf("\n Leaf Fill Percentage: %.2f%%\n", getLeafFillPercentage());
69 | out.printf(" Entries per Leaf: %.2f\n", getEntriesPerLeaf());
70 | out.println(" Max Depth: " + maxDepth);
71 | out.println();
72 | }
73 |
74 | public float getEntriesPerLeaf() {
75 | return ((entryCount * 1.0f) / leafCount);
76 | }
77 |
78 | public float getLeafFillPercentage() {
79 | return (getEntriesPerLeaf() * 100) / maxFill;
80 | }
81 |
82 |
83 | public void setMaxFill(int maxFill) {
84 | this.maxFill = maxFill;
85 | }
86 |
87 | public void setMinFill(int minFill) {
88 | this.minFill = minFill;
89 | }
90 |
91 | public int getBranchCount() {
92 | return branchCount;
93 | }
94 |
95 | public int getLeafCount() {
96 | return leafCount;
97 | }
98 |
99 | public int getEntryCount() {
100 | return entryCount;
101 | }
102 |
103 | public int getMaxDepth() {
104 | return maxDepth;
105 | }
106 |
107 | public void setMaxDepth(int maxDepth) {
108 | this.maxDepth = maxDepth;
109 | }
110 |
111 | public void countEntriesAtDepth(int entries, int depth) {
112 | entryCount += entries;
113 | entriesAtDepth[depth] += entries;
114 | }
115 |
116 | public void countLeafAtDepth(int depth) {
117 | leafCount++;
118 | leavesAtDepth[depth]++;
119 | }
120 |
121 | public void countBranchAtDepth(int depth) {
122 | branchCount++;
123 | branchesAtDepth[depth]++;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/java/org/wowtools/giscat/vector/rocksrtree/TreeTransaction.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * Copyright (c) 2022- "giscat (https://github.com/codingmiao/giscat)"
4 | * *
5 | * * 本项目采用自定义版权协议,在不同行业使用时有不同约束,详情参阅:
6 | * *
7 | * * https://github.com/codingmiao/giscat/blob/main/LICENSE
8 | *
9 | */
10 |
11 | package org.wowtools.giscat.vector.rocksrtree;
12 |
13 | import org.rocksdb.RocksDB;
14 | import org.rocksdb.RocksDBException;
15 | import org.rocksdb.WriteBatch;
16 | import org.rocksdb.WriteOptions;
17 |
18 | import java.nio.charset.StandardCharsets;
19 | import java.util.HashMap;
20 | import java.util.HashSet;
21 | import java.util.LinkedHashMap;
22 | import java.util.Map;
23 | import java.util.concurrent.locks.ReadWriteLock;
24 |
25 | import static org.wowtools.giscat.vector.rocksrtree.RTree.TreeDbKey;
26 |
27 | /**
28 | * 操作树的事务
29 | *
30 | * @author liuyu
31 | * @date 2023/3/27
32 | */
33 | public class TreeTransaction implements AutoCloseable {
34 |
35 | private static final byte[] nullBytes = new byte[0];
36 |
37 | private static final ProtoAble nullProtoAble = new ProtoAble(null, null) {
38 | @Override
39 | public void fill(byte[] bytes) {
40 |
41 | }
42 |
43 | @Override
44 | protected byte[] toBytes() {
45 | return nullBytes;
46 | }
47 | };
48 |
49 | private final RocksDB db;
50 | private final WriteOptions writeOpt;
51 | private final WriteBatch batch;
52 |
53 | private final HashMap txAdded = new HashMap<>();
54 | private final HashSet txDeleted = new HashSet<>();
55 |
56 | private final TreeBuilder builder;
57 |
58 | private final String treeRootId;
59 |
60 | private final ReadWriteLock lock;
61 |
62 | private boolean commited = false;
63 |
64 |
65 | //TODO 一二级缓存设计考虑
66 | private final Map protoAbleCaches2;
67 | private final Map protoAbleCaches1;
68 |
69 | protected TreeTransaction(RocksDB db, TreeBuilder builder, int cache1Size, Map protoAbleCaches2, ReadWriteLock lock) {
70 | protoAbleCaches1 = new LinkedHashMap(cache1Size, 0.75f, true) {
71 | private static final long serialVersionUID = 1L;
72 |
73 | @Override
74 | protected boolean removeEldestEntry(Map.Entry eldest) {
75 | return size() > cache1Size;
76 | }
77 | };
78 | this.db = db;
79 | this.builder = builder;
80 | this.protoAbleCaches2 = protoAbleCaches2;
81 | writeOpt = new WriteOptions();
82 | batch = new WriteBatch();
83 | treeRootId = builder.rootId;
84 | this.lock = lock;
85 | lock.readLock().lock();
86 | }
87 |
88 | protected void put(String key, ProtoAble value) {
89 | txDeleted.remove(key);
90 | txAdded.put(key, value);
91 | }
92 |
93 |
94 | protected void remove(String key) {
95 | txAdded.remove(key);
96 | txDeleted.add(key);
97 | }
98 |
99 |
100 | protected T get(Class t, String key) {
101 | if (txDeleted.contains(key)) {
102 | return null;
103 | }
104 | T txb = (T) txAdded.get(key);
105 | if (null != txb) {
106 | return txb;
107 | }
108 | ProtoAble cache;
109 | cache = protoAbleCaches1.get(key);
110 | if (null != cache) {
111 | if (cache == nullProtoAble) {
112 | return null;
113 | } else {
114 | return (T) cache;
115 | }
116 | }
117 |
118 | cache = protoAbleCaches2.get(key);
119 | if (null != cache) {
120 | if (cache == nullProtoAble) {
121 | return null;
122 | } else {
123 | return (T) cache;
124 | }
125 | }
126 |
127 |
128 | byte[] bytes;
129 | try {
130 | bytes = db.get(key.getBytes(StandardCharsets.UTF_8));
131 | } catch (RocksDBException e) {
132 | throw new RuntimeException(e);
133 | }
134 | if (null == bytes) {
135 | protoAbleCaches1.put(key, nullProtoAble);
136 | return null;
137 | } else {
138 | txb = ProtoAble.fromBytes(t, builder, key, bytes);
139 | protoAbleCaches1.put(key, txb);
140 | return txb;
141 | }
142 |
143 | }
144 |
145 |
146 | public void commit() {
147 | if (commited) {
148 | throw new RuntimeException("事务已经提交过一次了");
149 | }
150 | commited = true;
151 | try {
152 | for (Map.Entry e : txAdded.entrySet()) {
153 | batch.put(e.getKey().getBytes(StandardCharsets.UTF_8), e.getValue().toBytes());
154 | }
155 | for (String k : txDeleted) {
156 | batch.delete(k.getBytes(StandardCharsets.UTF_8));
157 | }
158 | if (null == treeRootId || !treeRootId.equals(builder.rootId)) {
159 | //rtree发生过变化,存储一次rtree
160 | batch.put(TreeDbKey, builder.getRTree().toBytes());
161 | }
162 | lock.readLock().unlock();
163 | lock.writeLock().lock();
164 | try {
165 | db.write(writeOpt, batch);
166 | protoAbleCaches2.putAll(txAdded);
167 | for (String s : txDeleted) {
168 | protoAbleCaches2.remove(s);
169 | }
170 | } finally {
171 | lock.writeLock().unlock();
172 | }
173 | } catch (RocksDBException e) {
174 | throw new RuntimeException(e);
175 | }
176 | }
177 |
178 | public void rollback() {
179 | txAdded.clear();
180 | txDeleted.clear();
181 | protoAbleCaches1.clear();
182 | }
183 |
184 |
185 | @Override
186 | public void close() {
187 | if (!commited) {
188 | lock.readLock().unlock();
189 | if (protoAbleCaches1.size() > 0) {
190 | lock.writeLock().lock();
191 | protoAbleCaches2.putAll(protoAbleCaches1);
192 | lock.writeLock().unlock();
193 | }
194 | }
195 | batch.close();
196 | writeOpt.close();
197 | }
198 |
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/main/resources/RocksRtree.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package pojo;
3 | option java_package = "org.wowtools.giscat.vector.rocksrtree";
4 | option java_outer_classname = "RocksRtreePb";
5 |
6 | // Rect
7 | message RectNdPb{
8 | repeated double min = 1;
9 | repeated double max = 2;
10 | }
11 |
12 | // 非叶子节点
13 | message BranchPb{
14 | // 节点Rect
15 | RectNdPb mbr = 1;
16 |
17 | // 子节点id
18 | repeated string childIds = 2;
19 | }
20 |
21 | // 叶子节点
22 | message LeafPb{
23 | // 节点Rect
24 | RectNdPb mbr = 1;
25 |
26 | // 实体Rect
27 | repeated RectNdPb entryRects = 2;
28 | // 实体
29 | bytes entries = 3;
30 |
31 | }
32 |
33 | // RTree
34 | message RTreePb{
35 | // 根节点id
36 | string rootId = 1;
37 | // 每个节点最少有几个子节点
38 | int32 mMin = 2;
39 | // 每个节点最多有几个子节点
40 | int32 mMax = 3;
41 | }
42 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-rocksrtree/src/test/java/org/wowtools/giscat/vector/rocksrtreetest/Test.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.rocksrtreetest;
2 |
3 |
4 | import org.locationtech.jts.geom.Coordinate;
5 | import org.locationtech.jts.geom.GeometryFactory;
6 | import org.locationtech.jts.geom.Point;
7 | import org.locationtech.jts.util.Assert;
8 | import org.wowtools.giscat.vector.pojo.Feature;
9 | import org.wowtools.giscat.vector.rocksrtree.*;
10 | import org.wowtools.giscat.vector.util.analyse.Bbox;
11 |
12 | import java.io.File;
13 | import java.util.LinkedList;
14 | import java.util.List;
15 | import java.util.function.Function;
16 |
17 | /**
18 | * @author liuyu
19 | * @date 2023/3/23
20 | */
21 | public class Test {
22 |
23 |
24 | public static void deleteFolder(File folder) {
25 | if (folder.isDirectory()) {
26 | File[] files = folder.listFiles(); // 获取文件夹中的所有文件和子文件夹
27 | if (files != null) {
28 | for (File file : files) {
29 | deleteFolder(file); // 递归删除子文件夹或文件
30 | }
31 | }
32 | }
33 | folder.delete(); // 删除空文件夹或文件
34 | }
35 |
36 | private static void add(String dir, Function featureRectNdFunction, GeometryFactory geometryFactory) {
37 | deleteFolder(new File(dir));
38 | int num = 10000;
39 | int txSize = 2000;
40 |
41 | TreeBuilder builder = new TreeBuilder(dir, null);
42 | RTree pTree = builder.getRTree();
43 |
44 | long t = System.currentTimeMillis();
45 | TreeTransaction tx = builder.newTx();
46 | for (int i = 0; i < num; i++) {
47 | Point point = geometryFactory.createPoint(new Coordinate(i, i));
48 | pTree.add(new Feature(point), tx);
49 | if (i % txSize == 0) {
50 | tx.commit();
51 | tx.close();
52 | tx = builder.newTx();
53 | System.out.println("add " + i);
54 | }
55 | }
56 | tx.commit();
57 | System.out.println("add success,cost " + (System.currentTimeMillis() - t));
58 |
59 | builder.close();
60 | }
61 |
62 | private static void query(String dir, Function featureRectNdFunction) throws Exception {
63 | TreeBuilder builder = new TreeBuilder(dir, null);
64 | final RectNd rect = new RectNd(new double[]{1.9, 1.9}, new double[]{8.1, 8.1});
65 | RTree pTree = builder.getRTree();
66 |
67 | List res = new LinkedList<>();
68 | FeatureConsumer consumer = new FeatureConsumer() {
69 | @Override
70 | public boolean accept(Feature f) {
71 | res.add(f);
72 | return true;
73 | }
74 | };
75 |
76 | long t = System.currentTimeMillis();
77 | try (TreeTransaction tx = builder.newTx()) {
78 | pTree.contains(rect, consumer, tx);
79 | }
80 | System.out.println("1 query success,cost " + (System.currentTimeMillis() - t));
81 |
82 | Assert.equals(7, res.size());
83 | System.out.println(res.size());
84 |
85 | for (Feature feature : res) {
86 | Assert.isTrue(feature.getGeometry().getCoordinate().x >= 2);
87 | Assert.isTrue(feature.getGeometry().getCoordinate().x <= 8);
88 | Assert.isTrue(feature.getGeometry().getCoordinate().y >= 2);
89 | Assert.isTrue(feature.getGeometry().getCoordinate().y <= 8);
90 | }
91 |
92 | for (int i = 0; i < 10; i++) {
93 | res.clear();
94 | t = System.currentTimeMillis();
95 | try (TreeTransaction tx = builder.newTx()) {
96 | pTree.contains(rect, consumer, tx);
97 | }
98 | System.out.println("2 query success,cost " + (System.currentTimeMillis() - t));
99 | Assert.equals(7, res.size());
100 | }
101 |
102 | builder.close();
103 | }
104 |
105 | public static void main(String[] args) throws Exception {
106 | String dir = "D:\\_tmp\\1\\rocksrtree";
107 |
108 | Function featureRectNdFunction = (feature) -> {
109 | Bbox bbox = new Bbox(feature.getGeometry());
110 | return new RectNd(new double[]{bbox.xmin, bbox.ymin}, new double[]{bbox.xmax, bbox.ymax});
111 | };
112 | GeometryFactory geometryFactory = new GeometryFactory();
113 |
114 | add(dir, featureRectNdFunction, geometryFactory);
115 |
116 | query(dir, featureRectNdFunction);
117 |
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | giscat
7 | org.wowtools
8 | g1.7.0
9 |
10 | 4.0.0
11 |
12 | giscat-vector-util
13 | g1.7.0
14 |
15 | 常用gis工具
16 |
17 |
18 |
19 | giscat-vector-pojo
20 | org.wowtools
21 |
22 |
23 | org.apache.commons
24 | commons-math
25 |
26 |
27 | org.openjdk.jmh
28 | jmh-core
29 | test
30 |
31 |
32 | org.openjdk.jmh
33 | jmh-generator-annprocess
34 | test
35 |
36 |
37 | junit
38 | junit
39 | test
40 |
41 |
42 | org.jetbrains
43 | annotations
44 | compile
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/src/main/java/org/wowtools/giscat/vector/util/analyse/Bbox.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.util.analyse;
21 |
22 | import org.jetbrains.annotations.NotNull;
23 | import org.locationtech.jts.geom.*;
24 |
25 | /**
26 | * 获取geometry的bbox,并利用bbox进行一些空间分析操作
27 | *
28 | * @author liuyu
29 | * @date 2020/1/13
30 | */
31 | public class Bbox {
32 | public final double xmin, ymin, xmax, ymax;
33 |
34 | public Bbox(double xmin, double ymin, double xmax, double ymax) {
35 | this.xmin = xmin;
36 | this.ymin = ymin;
37 | this.xmax = xmax;
38 | this.ymax = ymax;
39 | }
40 |
41 | public Bbox(@NotNull Geometry geometry) {
42 | double xmin, ymin, xmax, ymax;
43 | Geometry envelope = geometry.getEnvelope();
44 | if (envelope instanceof LineString) {
45 | Coordinate[] coords = envelope.getCoordinates();
46 | Coordinate coord = coords[0];
47 | xmin = coord.x;
48 | ymin = coord.y;
49 | xmax = coord.x;
50 | ymax = coord.y;
51 | coord = coords[1];
52 | if (coord.x > xmax) {
53 | xmax = coord.x;
54 | } else {
55 | xmin = coord.x;
56 | }
57 | if (coord.y > ymax) {
58 | ymax = coord.y;
59 | } else {
60 | ymin = coord.y;
61 | }
62 | } else {
63 | Coordinate[] coords = envelope.getCoordinates();
64 | if (coords.length == 1) {
65 | Coordinate c = coords[0];
66 | xmin = c.x;
67 | ymin = c.y;
68 | xmax = c.x;
69 | ymax = c.y;
70 | } else {
71 | Coordinate low = coords[0];
72 | xmin = low.x;
73 | ymin = low.y;
74 | Coordinate up = coords[2];
75 | xmax = up.x;
76 | ymax = up.y;
77 | }
78 | }
79 | this.xmin = xmin;
80 | this.ymin = ymin;
81 | this.xmax = xmax;
82 | this.ymax = ymax;
83 | }
84 |
85 | /**
86 | * 判断bbox是否与geometry的bbox
87 | *
88 | * @param geometry geometry
89 | * @return 是否相交
90 | */
91 | public boolean envIntersects(@NotNull Geometry geometry) {
92 | Bbox bbox = new Bbox(geometry);
93 | return intersects(bbox);
94 | }
95 |
96 | /**
97 | * 判断bbox是否与另一个bbox相交
98 | *
99 | * @param bbox bbox
100 | * @return 是否相交
101 | */
102 | public boolean intersects(@NotNull Bbox bbox) {
103 | return intersects(bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax);
104 | }
105 |
106 | /**
107 | * 判断bbox是否与范围相交
108 | *
109 | * @param xmin xmin
110 | * @param ymin ymin
111 | * @param xmax xmax
112 | * @param ymax ymax
113 | * @return 是否相交
114 | */
115 | public boolean intersects(double xmin, double ymin, double xmax, double ymax) {
116 | if (this.xmin > xmax) {
117 | return false;
118 | }
119 | if (this.xmax < xmin) {
120 | return false;
121 | }
122 | if (this.ymin > ymax) {
123 | return false;
124 | }
125 | return !(this.ymax < ymin);
126 | }
127 |
128 | /**
129 | * 判断bbox是否与点相交
130 | *
131 | * @param x x
132 | * @param y y
133 | * @return 是否相交
134 | */
135 | public boolean intersects(double x, double y) {
136 | return x >= xmin && x <= xmax && y >= ymin && y <= ymax;
137 | }
138 |
139 |
140 | public Polygon toPolygon(@NotNull GeometryFactory gf) {
141 | return gf.createPolygon(new Coordinate[]{
142 | new Coordinate(xmin, ymin),
143 | new Coordinate(xmax, ymin),
144 | new Coordinate(xmax, ymax),
145 | new Coordinate(xmin, ymax),
146 | new Coordinate(xmin, ymin)
147 | });
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/src/main/java/org/wowtools/giscat/vector/util/cst/LonLat.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.util.cst;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 |
6 | /**
7 | * 经纬度对象
8 | *
9 | * @author liuyu
10 | * @date 2022/6/7
11 | */
12 | @Setter
13 | @Getter
14 | public class LonLat {
15 | private double latitude;
16 | private double longitude;
17 |
18 | public LonLat(double longitude, double latitude) {
19 | this.latitude = latitude;
20 | this.longitude = longitude;
21 | }
22 |
23 | public LonLat() {
24 |
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/src/main/java/org/wowtools/giscat/vector/util/cst/Tile2Wgs84.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.util.cst;
21 |
22 | import org.apache.commons.math.util.FastMath;
23 | import org.jetbrains.annotations.NotNull;
24 |
25 | /**
26 | * wgs84经纬度坐标与瓦片index互转
27 | *
28 | * @author liuyu
29 | * @date 2020/1/13
30 | */
31 | public class Tile2Wgs84 {
32 |
33 | private static final int @NotNull [] pow2;//2的n次方
34 |
35 | static {
36 | int n = 30;
37 | pow2 = new int[n];
38 | int s = 1;
39 | for (int i = 0; i < n; i++) {
40 | pow2[i] = s;
41 | s = s * 2;
42 | }
43 | }
44 |
45 | /**
46 | * 瓦片转换纬度(左上角)
47 | *
48 | * @param y 瓦片y
49 | * @param z 瓦片z
50 | * @return 纬度
51 | */
52 | public static double tileY2lat(int y, byte z) {
53 | double n = Math.PI - (2.0 * Math.PI * y) / pow2[z];
54 | return Math.toDegrees(Math.atan(Math.sinh(n)));
55 | }
56 |
57 | /**
58 | * 瓦片转换经度(左上角)
59 | *
60 | * @param x 瓦片x
61 | * @param z 瓦片z
62 | * @return 经度
63 | */
64 | public static double tileX2lon(int x, byte z) {
65 | return x * 360d / pow2[z] - 180;
66 | }
67 |
68 | /**
69 | * 经度转瓦片x
70 | *
71 | * @param lon 经度
72 | * @param z 瓦片z
73 | * @return 瓦片x,整数部分表示列号,小数部分表示从左边开始到处于瓦片位置的百分比
74 | */
75 | public static double lon2tileX(double lon, byte z) {
76 | return ((lon + 180.0) / 360.0 * pow2[z]);
77 | }
78 |
79 | /**
80 | * 经度转瓦片y
81 | *
82 | * @param lat 经度
83 | * @param z 瓦片z
84 | * @return 瓦片y,整数部分表示行,小数部分表示从上边开始到处于瓦片位置的百分比
85 | */
86 | public static double lat2tileY(double lat, byte z) {
87 | return (Math.PI - FastMath.asinh(Math.tan(lat * Math.PI / 180.0))) * pow2[z] / (2 * Math.PI);
88 | }
89 |
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/src/main/java/org/wowtools/giscat/vector/util/cst/WebMercator2Wgs84.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************
2 | * Copyright (c) 2022- "giscat by 刘雨 (https://github.com/codingmiao/giscat)"
3 | * Licensed to the Apache Software Foundation (ASF) under one
4 | * or more contributor license agreements. See the NOTICE file
5 | * distributed with this work for additional information
6 | * regarding copyright ownership. The ASF licenses this file
7 | * to you under the Apache License, Version 2.0 (the
8 | * "License"); you may not use this file except in compliance
9 | * with the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing,
14 | * software distributed under the License is distributed on an
15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | * KIND, either express or implied. See the License for the
17 | * specific language governing permissions and limitations
18 | * under the License.
19 | ****************************************************************/
20 | package org.wowtools.giscat.vector.util.cst;
21 |
22 | /**
23 | * web墨卡托与wgs84坐标互转
24 | *
25 | * @author liuyu
26 | * @date 2019/11/7
27 | */
28 | public class WebMercator2Wgs84 {
29 |
30 | // public static void main(String[] args) {
31 | // double lon = 91;
32 | // double lat = 21;
33 | //
34 | // double x = lon2WebMercatorX(lon);
35 | // double y = lat2WebMercator(lat);
36 | //
37 | // System.out.println(x);
38 | // System.out.println(y);
39 | //
40 | // System.out.println(webMercatorX2lon(x));
41 | // System.out.println(webMercatorY2lat(y));
42 | //
43 | // }
44 |
45 |
46 | private static final double d = 20037508.342789;
47 |
48 | /**
49 | * wgs84 x 转 web墨卡托 x
50 | *
51 | * @param lon wgs84 x
52 | * @return web墨卡托 x
53 | */
54 | public static double lon2WebMercatorX(double lon) {
55 | return lon * d / 180D;
56 | }
57 |
58 | /**
59 | * wgs84 y 转 web墨卡托 y
60 | *
61 | * @param lat wgs84 y
62 | * @return web墨卡托 y
63 | */
64 | public static double lat2WebMercatorY(double lat) {
65 | double y = Math.log(Math.tan((90D + lat) * Math.PI / 360D)) / (Math.PI / 180D);
66 | y = y * d / 180D;
67 | return y;
68 | }
69 |
70 | /**
71 | * web墨卡托 x 转 wgs84 x
72 | *
73 | * @param mercatorX web墨卡托 x
74 | * @return wgs84 x
75 | */
76 | public static double webMercatorX2lon(double mercatorX) {
77 | return mercatorX / d * 180D;
78 | }
79 |
80 | /**
81 | * web墨卡托 y 转 wgs84 y
82 | *
83 | * @param mercatorY web墨卡托 y
84 | * @return wgs84 y
85 | */
86 | public static double webMercatorY2lat(double mercatorY) {
87 | double y = mercatorY / d * 180D;
88 | y = 180D / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180D)) - Math.PI / 2);
89 | return y;
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/src/test/java/org/wowtools/giscat/vector/util/analyse/TileClipJmhTest.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.util.analyse;
2 |
3 | import org.locationtech.jts.geom.Coordinate;
4 | import org.locationtech.jts.geom.Geometry;
5 | import org.locationtech.jts.geom.GeometryFactory;
6 | import org.locationtech.jts.geom.LineString;
7 | import org.openjdk.jmh.annotations.*;
8 | import org.openjdk.jmh.infra.Blackhole;
9 | import org.openjdk.jmh.results.format.ResultFormatType;
10 | import org.openjdk.jmh.runner.Runner;
11 | import org.openjdk.jmh.runner.options.Options;
12 | import org.openjdk.jmh.runner.options.OptionsBuilder;
13 |
14 | import java.util.Random;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | @BenchmarkMode(Mode.AverageTime)
18 | @Warmup(iterations = 3, time = 1)
19 | @Measurement(iterations = 5, time = 3)
20 | @Threads(1)
21 | @Fork(1)
22 | @State(value = Scope.Benchmark)
23 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
24 | public class TileClipJmhTest {
25 | private static final GeometryFactory geometryFactory = new GeometryFactory();
26 |
27 | private final LineString[] lines;
28 | private final Geometry clipGeometry;
29 | private final TileClip tileClip;
30 |
31 | {
32 | GeometryFactory gf = new GeometryFactory();
33 | clipGeometry = gf.createPolygon(new Coordinate[]{
34 | new Coordinate(0.2, 0.2),
35 | new Coordinate(0.8, 0.2),
36 | new Coordinate(0.8, 0.8),
37 | new Coordinate(0.2, 0.8),
38 | new Coordinate(0.2, 0.2)
39 | });
40 | tileClip = new TileClip(0.2, 0.2, 0.8, 0.8, geometryFactory);
41 | Random random = new Random(233);
42 | int n = 100;
43 | lines = new LineString[n];
44 | for (int i = 0; i < n; i++) {
45 | Coordinate[] coords = new Coordinate[2 + random.nextInt(50)];
46 |
47 | for (int i1 = 0; i1 < coords.length; i1++) {
48 | coords[i1] = new Coordinate(random.nextDouble(), random.nextDouble());
49 | }
50 | LineString line = gf.createLineString(coords);
51 | lines[i] = line;
52 | }
53 | }
54 |
55 | @Benchmark
56 | public void jts(Blackhole blackhole) {
57 | for (LineString line : lines) {
58 | Geometry g = clipGeometry.intersection(line);
59 | blackhole.consume(g);
60 | }
61 | }
62 |
63 | @Benchmark
64 | public void tileClip(Blackhole blackhole) {
65 | for (LineString line : lines) {
66 | Geometry g = tileClip.intersection(line);
67 | blackhole.consume(g);
68 | }
69 | }
70 |
71 | public static void main(String[] args) throws Exception {
72 | Options opt = new OptionsBuilder()
73 | .include(TileClipJmhTest.class.getSimpleName())
74 | .result("jmhResult.json")
75 | .resultFormat(ResultFormatType.JSON).build();
76 | new Runner(opt).run();
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/src/test/java/org/wowtools/giscat/vector/util/analyse/TileClipTest.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.util.analyse;
2 |
3 | import org.locationtech.jts.geom.*;
4 | import org.locationtech.jts.io.ParseException;
5 | import org.locationtech.jts.io.WKTReader;
6 |
7 | import java.util.Random;
8 |
9 | public class TileClipTest {
10 | private static final GeometryFactory geometryFactory = new GeometryFactory();
11 |
12 | @org.junit.Test
13 | public void test() throws ParseException {
14 | GeometryFactory gf = new GeometryFactory();
15 | Geometry clipGeometry = gf.createPolygon(new Coordinate[]{
16 | new Coordinate(20, 20),
17 | new Coordinate(80, 20),
18 | new Coordinate(80, 80),
19 | new Coordinate(20, 80),
20 | new Coordinate(20, 20)
21 | });
22 | TileClip tileClip = new TileClip(20, 20, 80, 80, geometryFactory);
23 | testGeo(clipGeometry, tileClip,
24 | (LineString) new WKTReader().read("LINESTRING (37 51, 5 17, 21 34)")
25 | );
26 |
27 | Random random = new Random(233);
28 | int n = 100000;
29 | for (int i = 0; i < n; i++) {
30 | Coordinate[] coords = new Coordinate[2 + random.nextInt(3)];
31 |
32 | for (int i1 = 0; i1 < coords.length; i1++) {
33 | coords[i1] = new Coordinate(random.nextInt(100), random.nextInt(100));
34 | }
35 | LineString line = gf.createLineString(coords);
36 | try {
37 | testGeo(clipGeometry, tileClip, line);
38 | } catch (Exception e) {
39 | System.out.println(line.toText());
40 | throw new RuntimeException(e);
41 | }
42 | }
43 | }
44 |
45 | private void testGeo(Geometry clipGeometry, TileClip tileClip, LineString line) {
46 | Geometry c1 = clipGeometry.intersection(line);
47 | if (c1 instanceof GeometryCollection) {
48 | return;
49 | }
50 | Geometry c2 = tileClip.intersection(line);
51 | int area1 = c1 instanceof Point ? 0 : (int) (c1.buffer(1).getArea() * 100);
52 | int area2 = c2 == null ? 0 : (int) (c2.buffer(1).getArea() * 100);
53 | if (Math.abs(area1 - area2) > 314) {
54 | throw new RuntimeException();
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/giscat-vector/giscat-vector-util/src/test/java/org/wowtools/giscat/vector/util/cst/Utm2Wgs84Test.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.giscat.vector.util.cst;
2 |
3 |
4 | import org.junit.Assert;
5 |
6 | public class Utm2Wgs84Test {
7 | @org.junit.Test
8 | public void testUtm2wgs84() {
9 | String strUtm = "18 G 615471.66 4789269.78";
10 | LonLat lonlat = Utm2Wgs84.utm2wgs84(strUtm);
11 | Assert.assertEquals(-73.48, lonlat.getLongitude(), 0.00001);
12 | Assert.assertEquals(-47.04, lonlat.getLatitude(), 0.00001);
13 |
14 | strUtm = "18G 615471.66 4789269.78";
15 | lonlat = Utm2Wgs84.utm2wgs84(strUtm);
16 | Assert.assertEquals(-73.48, lonlat.getLongitude(), 0.00001);
17 | Assert.assertEquals(-47.04, lonlat.getLatitude(), 0.00001);
18 |
19 | strUtm = "18g 615471.66 4789269.78";
20 | lonlat = Utm2Wgs84.utm2wgs84(strUtm);
21 | Assert.assertEquals(-73.48, lonlat.getLongitude(), 0.00001);
22 | Assert.assertEquals(-47.04, lonlat.getLatitude(), 0.00001);
23 | }
24 |
25 | @org.junit.Test
26 | public void testTestUtm2wgs84() {
27 | Utm2Wgs84.UtmCoord utm = Utm2Wgs84.wgs842utm(-73.48, -47.04);
28 | Assert.assertEquals(18, utm.getZone());
29 | Assert.assertEquals('G', utm.getLetter());
30 | Assert.assertEquals(615471.66, utm.getEasting(), 0.00001);
31 | Assert.assertEquals(4789269.78, utm.getNorthing(), 0.00001);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/giscat-vector/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | giscat
7 | org.wowtools
8 | g1.7.0
9 |
10 | 4.0.0
11 |
12 | giscat-vector
13 | g1.7.0
14 |
15 | pom
16 |
17 | giscat-vector-pojo
18 | giscat-vector-mvt
19 | giscat-vector-util
20 | giscat-vector-mbexpression
21 | giscat-vector-rocksrtree
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------