]> git.argeo.org Git - gpl/argeo-suite.git/blob - org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java
Trim single line text input in forms
[gpl/argeo-suite.git] / org.argeo.app.geo / src / org / argeo / app / geo / GeoJson.java
1 package org.argeo.app.geo;
2
3 import org.locationtech.jts.geom.Coordinate;
4 import org.locationtech.jts.geom.Envelope;
5 import org.locationtech.jts.geom.Geometry;
6 import org.locationtech.jts.geom.GeometryCollection;
7 import org.locationtech.jts.geom.LineString;
8 import org.locationtech.jts.geom.LinearRing;
9 import org.locationtech.jts.geom.MultiPoint;
10 import org.locationtech.jts.geom.Point;
11 import org.locationtech.jts.geom.Polygon;
12
13 import jakarta.json.JsonArray;
14 import jakarta.json.JsonObject;
15 import jakarta.json.stream.JsonGenerator;
16
17 /**
18 * GeoJSon format.
19 *
20 * @see https://datatracker.ietf.org/doc/html/rfc7946
21 */
22 public class GeoJson {
23 public final static String POINT_TYPE = "Point";
24 public final static String MULTI_POINT_TYPE = "MultiPoint";
25 public final static String LINE_STRING_TYPE = "LineString";
26 public final static String POLYGON_TYPE = "Polygon";
27 public final static String GEOMETRY_COLLECTION_TYPE = "GeometryCollection";
28
29 public final static String TYPE = "type";
30 public final static String GEOMETRY = "geometry";
31 public final static String GEOMETRIES = "geometries";
32 public final static String COORDINATES = "coordinates";
33 public final static String BBOX = "bbox";
34 public final static String PROPERTIES = "properties";
35
36 /*
37 * WRITE
38 */
39 /** Writes a {@link Geometry} as GeoJSON. */
40 public static void writeGeometry(JsonGenerator g, Geometry geometry) {
41 if (geometry instanceof Point point) {
42 g.write(TYPE, POINT_TYPE);
43 g.writeStartArray(COORDINATES);
44 writeCoordinate(g, point.getCoordinate());
45 g.writeEnd();// coordinates array
46 } else if (geometry instanceof MultiPoint multiPoint) {
47 g.write(TYPE, MULTI_POINT_TYPE);
48 g.writeStartArray(COORDINATES);
49 writeCoordinates(g, multiPoint.getCoordinates());
50 g.writeEnd();// coordinates array
51 } else if (geometry instanceof LineString lineString) {
52 g.write(TYPE, LINE_STRING_TYPE);
53 g.writeStartArray(COORDINATES);
54 writeCoordinates(g, lineString.getCoordinates());
55 g.writeEnd();// coordinates array
56 } else if (geometry instanceof Polygon polygon) {
57 g.write(TYPE, POLYGON_TYPE);
58 g.writeStartArray(COORDINATES);
59 LinearRing exteriorRing = polygon.getExteriorRing();
60 g.writeStartArray();
61 writeCoordinates(g, exteriorRing.getCoordinates());
62 g.writeEnd();
63 for (int i = 0; i < polygon.getNumInteriorRing(); i++) {
64 LinearRing interiorRing = polygon.getInteriorRingN(i);
65 // TODO verify that holes are clockwise
66 g.writeStartArray();
67 writeCoordinates(g, interiorRing.getCoordinates());
68 g.writeEnd();
69 }
70 g.writeEnd();// coordinates array
71 } else if (geometry instanceof GeometryCollection geometryCollection) {// must be last
72 g.write(TYPE, GEOMETRY_COLLECTION_TYPE);
73 g.writeStartArray(GEOMETRIES);
74 for (int i = 0; i < geometryCollection.getNumGeometries(); i++) {
75 g.writeStartObject();
76 writeGeometry(g, geometryCollection.getGeometryN(i));
77 g.writeEnd();// geometry object
78 }
79 g.writeEnd();// geometries array
80 } else {
81 throw new IllegalArgumentException(geometry.getClass() + " is not supported.");
82 }
83 }
84
85 /** Writes a sequence of coordinates [[lat,lon],[lat,lon]] */
86 public static void writeCoordinates(JsonGenerator g, Coordinate[] coordinates) {
87 for (Coordinate coordinate : coordinates) {
88 g.writeStartArray();
89 writeCoordinate(g, coordinate);
90 g.writeEnd();
91 }
92 }
93
94 /** Writes a pair of coordinates [lat,lon]. */
95 public static void writeCoordinate(JsonGenerator g, Coordinate coordinate) {
96 // !! longitude is first in GeoJSON
97 g.write(coordinate.getY());
98 g.write(coordinate.getX());
99 double z = coordinate.getZ();
100 if (!Double.isNaN(z)) {
101 g.write(z);
102 }
103 }
104
105 /**
106 * Writes the {@link Envelope} of a {@link Geometry} as a bbox GeoJSON object.
107 */
108 public static void writeBBox(JsonGenerator g, Geometry geometry) {
109 g.writeStartArray(BBOX);
110 Envelope envelope = geometry.getEnvelopeInternal();
111 g.write(envelope.getMinX());
112 g.write(envelope.getMinY());
113 g.write(envelope.getMaxX());
114 g.write(envelope.getMaxY());
115 g.writeEnd();
116 }
117
118 /*
119 * READ
120 */
121 /** Reads a geometry from the geometry object of a GEoJSON feature. */
122 @SuppressWarnings("unchecked")
123 public static <T extends Geometry> T readGeometry(JsonObject geom, Class<T> clss) {
124 String type = geom.getString(TYPE);
125 JsonArray coordinates = geom.getJsonArray(COORDINATES);
126 Geometry res = switch (type) {
127 case POINT_TYPE: {
128 Coordinate coord = readCoordinate(coordinates);
129 yield JTS.GEOMETRY_FACTORY_WGS84.createPoint(coord);
130 }
131 case LINE_STRING_TYPE: {
132 Coordinate[] coords = readCoordinates(coordinates);
133 yield JTS.GEOMETRY_FACTORY_WGS84.createLineString(coords);
134 }
135 case POLYGON_TYPE: {
136 assert coordinates.size() > 0;
137 LinearRing exterior = JTS.GEOMETRY_FACTORY_WGS84
138 .createLinearRing(readCoordinates(coordinates.getJsonArray(0)));
139 LinearRing[] holes = new LinearRing[coordinates.size() - 1];
140 for (int i = 0; i < coordinates.size() - 1; i++) {
141 holes[i] = JTS.GEOMETRY_FACTORY_WGS84
142 .createLinearRing(readCoordinates(coordinates.getJsonArray(i + 1)));
143 }
144 yield JTS.GEOMETRY_FACTORY_WGS84.createPolygon(exterior, holes);
145 }
146 default:
147 throw new IllegalArgumentException("Unexpected value: " + type);
148 };
149 // res.normalize();
150 return (T) res;
151 }
152
153 /** Reads a coordinate pair [lon,lat]. */
154 public static Coordinate readCoordinate(JsonArray arr) {
155 assert arr.size() >= 2;
156 // !! longitude is first in GeoJSon
157 return new Coordinate(arr.getJsonNumber(1).doubleValue(), arr.getJsonNumber(0).doubleValue());
158 }
159
160 /** Reads a coordinate sequence [[lon,lat],[lon,lat]]. */
161 public static Coordinate[] readCoordinates(JsonArray arr) {
162 Coordinate[] coords = new Coordinate[arr.size()];
163 for (int i = 0; i < arr.size(); i++)
164 coords[i] = readCoordinate(arr.getJsonArray(i));
165 return coords;
166 }
167
168 /** singleton */
169 private GeoJson() {
170 }
171
172 }