├── .github └── workflows │ └── maven.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── pom.xml └── src ├── main └── java │ └── org │ └── wololo │ ├── geojson │ ├── Feature.java │ ├── FeatureCollection.java │ ├── GeoJSON.java │ ├── GeoJSONFactory.java │ ├── Geometry.java │ ├── GeometryCollection.java │ ├── LineString.java │ ├── MultiLineString.java │ ├── MultiPoint.java │ ├── MultiPolygon.java │ ├── Point.java │ └── Polygon.java │ └── jts2geojson │ ├── GeoJSONReader.java │ └── GeoJSONWriter.java └── test ├── java └── org │ └── wololo │ └── jts2geojson │ ├── Data.java │ └── DataFactory.java └── scala └── org └── wololo └── jts2geojson ├── DeserializeGeometryCollectionSpec.scala ├── GeoJSONFactorySpec.scala ├── GeoJSONReaderSpec.scala └── GeoJSONWriterSpec.scala /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Maven 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build-jdk11: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up JDK 11 15 | uses: actions/setup-java@v2 16 | with: 17 | java-version: '11' 18 | distribution: 'temurin' 19 | cache: maven 20 | - name: Test with Maven 21 | run: mvn -Dmaven.javadoc.skip=true -Dgpg.skip=true -B test 22 | build-jdk17: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v2 26 | - name: Set up JDK 17 27 | uses: actions/setup-java@v2 28 | with: 29 | java-version: '17' 30 | distribution: 'temurin' 31 | cache: maven 32 | - name: Test with Maven 33 | run: mvn -Dmaven.javadoc.skip=true -Dgpg.skip=true -B test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .classpath 3 | .project 4 | .settings 5 | target 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Björn Harrtell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This Java library can convert JTS geometries to GeoJSON and back. Its API is similar to other io.* classes in JTS. 4 | 5 | [![Build Status](https://github.com/bjornharrtell/jts2geojson/actions/workflows/maven.yml/badge.svg)](https://github.com/bjornharrtell/jts2geojson/actions/workflows/maven.yml) 6 | 7 | ## Maven 8 | 9 | ```xml 10 | 11 | org.wololo 12 | jts2geojson 13 | 0.18.1 14 | 15 | ``` 16 | 17 | ## Usage 18 | 19 | ```java 20 | GeoJSONWriter writer = new GeoJSONWriter(); 21 | GeoJSON json = writer.write(geometry); 22 | String jsonstring = json.toString(); 23 | 24 | GeoJSONReader reader = new GeoJSONReader(); 25 | Geometry geometry = reader.read(json); 26 | ``` 27 | 28 | ## Features and FeatureCollections 29 | 30 | JTS does not have anything like GeoJSON Feature or FeatureCollection but they can be parsed by this library. Example: 31 | 32 | ```java 33 | // parse Feature or FeatureCollection 34 | Feature feature = (Feature) GeoJSONFactory.create(json); 35 | FeatureCollection featureCollection = (FeatureCollection) GeoJSONFactory.create(json); 36 | 37 | // parse Geometry from Feature 38 | GeoJSONReader reader = new GeoJSONReader(); 39 | Geometry geometry = reader.read(feature.getGeometry()); 40 | geometry = reader.read(featureCollection.getFeatures()[0].getGeometry()); 41 | 42 | // create and serialize a FeatureCollection 43 | List features = new ArrayList(); 44 | Map properties = new HashMap(); 45 | features.add(new Feature(geometry, properties)); 46 | GeoJSONWriter writer = new GeoJSONWriter(); 47 | GeoJSON json = writer.write(features); 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.wololo 5 | jts2geojson 6 | 0.18.1 7 | jar 8 | jts2geojson 9 | JTS to GeoJSON converter 10 | https://github.com/bjornharrtell/jts2geojson 11 | 12 | 13 | 14 | MIT license 15 | http://www.opensource.org/licenses/mit-license.php 16 | 17 | 18 | 19 | 20 | https://github.com/bjornharrtell/jts2geojson 21 | scm:git:https://github.com/bjornharrtell/jts2geojson.git 22 | scm:git:https://github.com/bjornharrtell/jts2geojson.git 23 | 24 | 25 | 26 | 27 | bjornharrtell 28 | Björn Harrtell 29 | 30 | 31 | 32 | 33 | 3.0.4 34 | 35 | 36 | 37 | 11 38 | 39 | 40 | 41 | 42 | org.scala-lang 43 | scala-library 44 | 2.13.10 45 | test 46 | 47 | 48 | org.scalatest 49 | scalatest_2.13 50 | 3.2.14 51 | test 52 | 53 | 54 | org.locationtech.jts 55 | jts-core 56 | 1.18.1 57 | 58 | 59 | com.fasterxml.jackson.core 60 | jackson-databind 61 | 2.13.4.2 62 | 63 | 64 | com.fasterxml.jackson.core 65 | jackson-annotations 66 | 2.13.4 67 | 68 | 69 | 70 | 71 | 72 | ossrh 73 | https://oss.sonatype.org/content/repositories/snapshots 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-compiler-plugin 82 | 3.10.1 83 | 84 | 11 85 | 86 | 87 | 88 | net.alchim31.maven 89 | scala-maven-plugin 90 | 4.7.2 91 | 92 | 93 | 94 | compile 95 | testCompile 96 | 97 | 98 | 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-surefire-plugin 103 | 2.22.2 104 | 105 | true 106 | 107 | 108 | 109 | org.scalatest 110 | scalatest-maven-plugin 111 | 2.2.0 112 | 113 | 114 | test 115 | 116 | test 117 | 118 | 119 | 120 | 121 | 122 | org.apache.maven.plugins 123 | maven-source-plugin 124 | 3.2.1 125 | 126 | 127 | attach-sources 128 | 129 | jar-no-fork 130 | 131 | 132 | 133 | 134 | 135 | org.apache.maven.plugins 136 | maven-javadoc-plugin 137 | 3.4.1 138 | 139 | 140 | attach-javadocs 141 | 142 | jar 143 | 144 | 145 | 146 | 147 | 148 | org.apache.maven.plugins 149 | maven-gpg-plugin 150 | 3.0.1 151 | 152 | 153 | sign-artifacts 154 | verify 155 | 156 | sign 157 | 158 | 159 | 160 | 161 | 162 | org.sonatype.plugins 163 | nexus-staging-maven-plugin 164 | 1.6.13 165 | true 166 | 167 | ossrh 168 | https://oss.sonatype.org/ 169 | true 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/Feature.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import java.util.Map; 4 | 5 | import com.fasterxml.jackson.annotation.JsonCreator; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 8 | import com.fasterxml.jackson.annotation.JsonInclude; 9 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 10 | 11 | @JsonPropertyOrder({"type", "id", "geometry", "properties"}) 12 | public class Feature extends GeoJSON { 13 | @JsonInclude(Include.NON_EMPTY) 14 | private final Object id; 15 | private final Geometry geometry; 16 | private final Map properties; 17 | 18 | public Feature( 19 | @JsonProperty("geometry") Geometry geometry, 20 | @JsonProperty("properties") Map properties) { 21 | this(null, geometry, properties); 22 | } 23 | 24 | @JsonCreator 25 | public Feature( 26 | @JsonProperty("id") Object id, 27 | @JsonProperty("geometry") Geometry geometry, 28 | @JsonProperty("properties") Map properties) { 29 | super(); 30 | this.id = id; 31 | this.geometry = geometry; 32 | this.properties = properties; 33 | } 34 | 35 | public Object getId() { 36 | return id; 37 | } 38 | 39 | public Geometry getGeometry() { 40 | return geometry; 41 | } 42 | 43 | public Map getProperties() { 44 | return properties; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/FeatureCollection.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | 7 | @JsonPropertyOrder({"type", "features"}) 8 | public class FeatureCollection extends GeoJSON { 9 | private final Feature[] features; 10 | 11 | @JsonCreator 12 | public FeatureCollection(@JsonProperty("features") Feature[] features) { 13 | super(); 14 | this.features = features; 15 | } 16 | 17 | public Feature[] getFeatures() { 18 | return features; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/GeoJSON.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import java.io.IOException; 4 | 5 | import com.fasterxml.jackson.annotation.JsonSubTypes; 6 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 7 | import com.fasterxml.jackson.core.JsonGenerationException; 8 | import com.fasterxml.jackson.annotation.JsonCreator; 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | import com.fasterxml.jackson.databind.JsonMappingException; 11 | import com.fasterxml.jackson.databind.ObjectMapper; 12 | @JsonTypeInfo( 13 | use = JsonTypeInfo.Id.NAME, 14 | include = JsonTypeInfo.As.EXISTING_PROPERTY, 15 | property = "type" 16 | ) 17 | @JsonSubTypes( { 18 | @JsonSubTypes.Type(value=Point.class, name="Point" ), 19 | @JsonSubTypes.Type(value=LineString.class, name="LineString" ), 20 | @JsonSubTypes.Type(value=Polygon.class, name="Polygon" ), 21 | @JsonSubTypes.Type(value=MultiPoint.class, name="MultiPoint" ), 22 | @JsonSubTypes.Type(value=MultiLineString.class, name="MultiLineString" ), 23 | @JsonSubTypes.Type(value=MultiPolygon.class, name="MultiPolygon" ), 24 | @JsonSubTypes.Type(value=Feature.class, name="Feature" ), 25 | @JsonSubTypes.Type(value=FeatureCollection.class, name="FeatureCollection" ), 26 | @JsonSubTypes.Type(value=GeometryCollection.class, name="GeometryCollection" ) 27 | }) 28 | public abstract class GeoJSON { 29 | private static final ObjectMapper mapper = new ObjectMapper(); 30 | 31 | @JsonProperty("type") 32 | private String type; 33 | 34 | @JsonCreator 35 | public GeoJSON() { 36 | setType(getClass().getSimpleName()); 37 | } 38 | 39 | public String toString() { 40 | try { 41 | return mapper.writeValueAsString(this); 42 | } catch (JsonGenerationException e) { 43 | return "Unhandled exception occured when serializing this instance"; 44 | } catch (JsonMappingException e) { 45 | return "Unhandled exception occured when serializing this instance"; 46 | } catch (IOException e) { 47 | return "Unhandled exception occured when serializing this instance"; 48 | } 49 | } 50 | 51 | public String getType() { 52 | return type; 53 | } 54 | 55 | public void setType(String type) { 56 | this.type = type; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/GeoJSONFactory.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | import java.util.ArrayList; 6 | 7 | import com.fasterxml.jackson.core.JsonParseException; 8 | import com.fasterxml.jackson.databind.JsonMappingException; 9 | import com.fasterxml.jackson.databind.JsonNode; 10 | import com.fasterxml.jackson.databind.ObjectMapper; 11 | 12 | public class GeoJSONFactory { 13 | private static final ObjectMapper mapper = new ObjectMapper(); 14 | 15 | public static GeoJSON create(String json) { 16 | try { 17 | var node = mapper.readTree(json); 18 | var type = node.get("type").asText(); 19 | if (type.equals("FeatureCollection")) 20 | return readFeatureCollection(node); 21 | else if (type.equals("Feature")) 22 | return readFeature(node); 23 | else 24 | return readGeometry(node, type); 25 | } catch (Exception e) { 26 | throw new RuntimeException(e); 27 | } 28 | } 29 | 30 | private static FeatureCollection readFeatureCollection(JsonNode node) 31 | throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException { 32 | var it = node.get("features").iterator(); 33 | var features = new ArrayList(); 34 | while (it.hasNext()) 35 | features.add(readFeature(it.next())); 36 | return new FeatureCollection(features.toArray(new Feature[features.size()])); 37 | } 38 | 39 | private static Feature readFeature(JsonNode node) 40 | throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException { 41 | var geometryNode = node.get("geometry"); 42 | var javaType = mapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class); 43 | var id = node.get("id"); 44 | Map properties = mapper.readValue(node.get("properties").traverse(), javaType); 45 | var geometry = readGeometry(geometryNode); 46 | return new Feature(id, geometry, properties); 47 | } 48 | 49 | private static Geometry readGeometry(JsonNode node) 50 | throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException { 51 | if (node != null && !node.isNull()) 52 | return readGeometry(node, node.get("type").asText()); 53 | else 54 | return null; 55 | } 56 | 57 | private static Geometry readGeometry(JsonNode node, String type) 58 | throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException { 59 | return (Geometry) mapper.readValue(node.traverse(), Class.forName("org.wololo.geojson." + type)); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/Geometry.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 5 | import com.fasterxml.jackson.annotation.JsonSubTypes; 6 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 7 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 8 | 9 | @JsonTypeInfo( 10 | use = JsonTypeInfo.Id.NAME, 11 | include = JsonTypeInfo.As.EXISTING_PROPERTY, 12 | property = "type" 13 | ) 14 | @JsonSubTypes( { 15 | @JsonSubTypes.Type(value=Point.class, name="Point" ), 16 | @JsonSubTypes.Type(value=LineString.class, name="LineString" ), 17 | @JsonSubTypes.Type(value=Polygon.class, name="Polygon" ), 18 | @JsonSubTypes.Type(value=MultiPoint.class, name="MultiPoint" ), 19 | @JsonSubTypes.Type(value=MultiLineString.class, name="MultiLineString" ), 20 | @JsonSubTypes.Type(value=MultiPolygon.class, name="MultiPolygon" ), 21 | @JsonSubTypes.Type(value=Feature.class, name="Feature" ), 22 | @JsonSubTypes.Type(value=FeatureCollection.class, name="FeatureCollection" ), 23 | @JsonSubTypes.Type(value=GeometryCollection.class, name="GeometryCollection" ) 24 | } ) 25 | 26 | @JsonIgnoreProperties(ignoreUnknown = true) 27 | @JsonPropertyOrder({"type", "coordinates", "bbox"}) 28 | public abstract class Geometry extends GeoJSON { 29 | @JsonCreator 30 | public Geometry() { 31 | super(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/GeometryCollection.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | 7 | @JsonPropertyOrder({"type", "geometries"}) 8 | public class GeometryCollection extends Geometry { 9 | private final Geometry[] geometries; 10 | 11 | @JsonCreator 12 | public GeometryCollection(@JsonProperty("geometries") Geometry[] geometries) { 13 | super(); 14 | this.geometries = geometries; 15 | } 16 | 17 | public Geometry[] getGeometries() { 18 | return geometries; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/LineString.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class LineString extends Geometry { 10 | private final double[][] coordinates; 11 | private final double[] bbox; 12 | 13 | @JsonCreator 14 | public LineString(@JsonProperty("coordinates") double [][] coordinates) { 15 | super(); 16 | this.coordinates = coordinates; 17 | this.bbox = null; 18 | } 19 | 20 | public double[][] getCoordinates() { 21 | return coordinates; 22 | } 23 | 24 | public double[] getBbox() { 25 | return bbox; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/MultiLineString.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class MultiLineString extends Geometry { 10 | private final double[][][] coordinates; 11 | private final double[] bbox; 12 | 13 | @JsonCreator 14 | public MultiLineString(@JsonProperty("coordinates") double [][][] coordinates) { 15 | super(); 16 | this.coordinates = coordinates; 17 | this.bbox = null; 18 | } 19 | 20 | public double[][][] getCoordinates() { 21 | return coordinates; 22 | } 23 | 24 | public double[] getBbox() { 25 | return bbox; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/MultiPoint.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class MultiPoint extends Geometry { 10 | private final double[][] coordinates; 11 | private final double[] bbox; 12 | 13 | @JsonCreator 14 | public MultiPoint(@JsonProperty("coordinates") double [][] coordinates) { 15 | super(); 16 | this.coordinates = coordinates; 17 | this.bbox = null; 18 | } 19 | 20 | public double[][] getCoordinates() { 21 | return coordinates; 22 | } 23 | 24 | public double[] getBbox() { 25 | return bbox; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/MultiPolygon.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class MultiPolygon extends Geometry { 10 | private final double[][][][] coordinates; 11 | private final double[] bbox; 12 | 13 | @JsonCreator 14 | public MultiPolygon(@JsonProperty("coordinates") double [][][][] coordinates) { 15 | super(); 16 | this.coordinates = coordinates; 17 | this.bbox = null; 18 | } 19 | 20 | public double[][][][] getCoordinates() { 21 | return coordinates; 22 | } 23 | 24 | public double[] getBbox() { 25 | return bbox; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/Point.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class Point extends Geometry { 10 | private final double[] coordinates; 11 | private final double[] bbox; 12 | 13 | @JsonCreator 14 | public Point(@JsonProperty("coordinates") double [] coordinates) { 15 | super(); 16 | this.coordinates = coordinates; 17 | this.bbox = null; 18 | } 19 | 20 | public double[] getCoordinates() { 21 | return coordinates; 22 | } 23 | 24 | public double[] getBbox() { 25 | return bbox; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/geojson/Polygon.java: -------------------------------------------------------------------------------- 1 | package org.wololo.geojson; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 7 | 8 | @JsonInclude(Include.NON_NULL) 9 | public class Polygon extends Geometry { 10 | private final double[][][] coordinates; 11 | private final double[] bbox; 12 | 13 | @JsonCreator 14 | public Polygon(@JsonProperty("coordinates") double [][][] coordinates) { 15 | super(); 16 | this.coordinates = coordinates; 17 | this.bbox = null; 18 | } 19 | 20 | public double[][][] getCoordinates() { 21 | return coordinates; 22 | } 23 | 24 | public double[] getBbox() { 25 | return bbox; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/jts2geojson/GeoJSONReader.java: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson; 2 | 3 | import org.wololo.geojson.*; 4 | 5 | import org.locationtech.jts.geom.Coordinate; 6 | import org.locationtech.jts.geom.Geometry; 7 | import org.locationtech.jts.geom.GeometryFactory; 8 | import org.locationtech.jts.geom.LinearRing; 9 | import org.locationtech.jts.geom.PrecisionModel; 10 | 11 | public class GeoJSONReader { 12 | final static GeometryFactory FACTORY = new GeometryFactory( 13 | new PrecisionModel(PrecisionModel.FLOATING)); 14 | 15 | public Geometry read(String json) { 16 | return read(json, null); 17 | } 18 | 19 | public Geometry read(String json, GeometryFactory geomFactory) { 20 | return read(GeoJSONFactory.create(json), geomFactory); 21 | } 22 | 23 | public Geometry read(GeoJSON geoJSON) { 24 | return read(geoJSON, null); 25 | } 26 | 27 | public Geometry read(GeoJSON geoJSON, GeometryFactory geomFactory) { 28 | var factory = geomFactory != null ? geomFactory : FACTORY; 29 | if (geoJSON instanceof Point) 30 | return convert((Point) geoJSON, factory); 31 | else if (geoJSON instanceof LineString) 32 | return convert((LineString) geoJSON, factory); 33 | else if (geoJSON instanceof Polygon) 34 | return convert((Polygon) geoJSON, factory); 35 | else if (geoJSON instanceof MultiPoint) 36 | return convert((MultiPoint) geoJSON, factory); 37 | else if (geoJSON instanceof MultiLineString) 38 | return convert((MultiLineString) geoJSON, factory); 39 | else if (geoJSON instanceof MultiPolygon) 40 | return convert((MultiPolygon) geoJSON, factory); 41 | else if (geoJSON instanceof GeometryCollection) 42 | return convert((GeometryCollection) geoJSON, factory); 43 | else 44 | throw new UnsupportedOperationException(); 45 | } 46 | 47 | Geometry convert(Point point, GeometryFactory factory) { 48 | return factory.createPoint(convert(point.getCoordinates())); 49 | } 50 | 51 | Geometry convert(MultiPoint multiPoint, GeometryFactory factory) { 52 | return factory.createMultiPointFromCoords(convert(multiPoint.getCoordinates())); 53 | } 54 | 55 | Geometry convert(LineString lineString, GeometryFactory factory) { 56 | return factory.createLineString(convert(lineString.getCoordinates())); 57 | } 58 | 59 | Geometry convert(MultiLineString multiLineString, GeometryFactory factory) { 60 | var size = multiLineString.getCoordinates().length; 61 | var lineStrings = new org.locationtech.jts.geom.LineString[size]; 62 | for (int i = 0; i < size; i++) 63 | lineStrings[i] = factory.createLineString(convert(multiLineString.getCoordinates()[i])); 64 | return factory.createMultiLineString(lineStrings); 65 | } 66 | 67 | Geometry convert(Polygon polygon, GeometryFactory factory) { 68 | return convertToPolygon(polygon.getCoordinates(), factory); 69 | } 70 | 71 | org.locationtech.jts.geom.Polygon convertToPolygon(double[][][] coordinates, GeometryFactory factory) { 72 | var shell = factory.createLinearRing(convert(coordinates[0])); 73 | if (coordinates.length > 1) { 74 | var size = coordinates.length - 1; 75 | var holes = new LinearRing[size]; 76 | for (var i = 0; i < size; i++) 77 | holes[i] = factory.createLinearRing(convert(coordinates[i + 1])); 78 | return factory.createPolygon(shell, holes); 79 | } else { 80 | return factory.createPolygon(shell); 81 | } 82 | } 83 | 84 | Geometry convert(MultiPolygon multiPolygon, GeometryFactory factory) { 85 | var size = multiPolygon.getCoordinates().length; 86 | var polygons = new org.locationtech.jts.geom.Polygon[size]; 87 | for (int i = 0; i < size; i++) 88 | polygons[i] = convertToPolygon(multiPolygon.getCoordinates()[i], factory); 89 | return factory.createMultiPolygon(polygons); 90 | } 91 | 92 | Geometry convert(GeometryCollection gc, GeometryFactory factory) { 93 | var size = gc.getGeometries().length; 94 | var geometries = new org.locationtech.jts.geom.Geometry[size]; 95 | for (var i = 0; i < size; i++) 96 | geometries[i] = read(gc.getGeometries()[i], factory); 97 | return factory.createGeometryCollection(geometries); 98 | } 99 | 100 | Coordinate convert(double[] c) { 101 | if (c.length == 2) 102 | return new Coordinate(c[0], c[1]); 103 | else 104 | return new Coordinate(c[0], c[1], c[2]); 105 | } 106 | 107 | Coordinate[] convert(double[][] ca) { 108 | var coordinates = new Coordinate[ca.length]; 109 | for (int i = 0; i < ca.length; i++) 110 | coordinates[i] = convert(ca[i]); 111 | return coordinates; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/org/wololo/jts2geojson/GeoJSONWriter.java: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson; 2 | 3 | import java.util.List; 4 | 5 | import org.locationtech.jts.geom.*; 6 | import org.wololo.geojson.Feature; 7 | 8 | public class GeoJSONWriter { 9 | 10 | final static GeoJSONReader reader = new GeoJSONReader(); 11 | 12 | public org.wololo.geojson.Geometry write(Geometry geometry) { 13 | Class c = geometry.getClass(); 14 | if (c.equals(Point.class)) 15 | return convert((Point) geometry); 16 | else if (c.equals(LineString.class)) 17 | return convert((LineString) geometry); 18 | else if (c.equals(LinearRing.class)) 19 | return convert((LinearRing) geometry); 20 | else if (c.equals(Polygon.class)) 21 | return convert((Polygon) geometry); 22 | else if (c.equals(MultiPoint.class)) 23 | return convert((MultiPoint) geometry); 24 | else if (c.equals(MultiLineString.class)) 25 | return convert((MultiLineString) geometry); 26 | else if (c.equals(MultiPolygon.class)) 27 | return convert((MultiPolygon) geometry); 28 | else if (c.equals(GeometryCollection.class)) 29 | return convert((GeometryCollection) geometry); 30 | else 31 | throw new UnsupportedOperationException(); 32 | } 33 | 34 | public org.wololo.geojson.FeatureCollection write(List features) { 35 | var size = features.size(); 36 | var featuresJson = new org.wololo.geojson.Feature[size]; 37 | for (var i = 0; i < size; i++) 38 | featuresJson[i] = features.get(i); 39 | return new org.wololo.geojson.FeatureCollection(featuresJson); 40 | } 41 | 42 | org.wololo.geojson.Point convert(Point point) { 43 | return new org.wololo.geojson.Point(convert(point.getCoordinate())); 44 | } 45 | 46 | org.wololo.geojson.MultiPoint convert(MultiPoint multiPoint) { 47 | return new org.wololo.geojson.MultiPoint( 48 | convert(multiPoint.getCoordinates())); 49 | } 50 | 51 | org.wololo.geojson.LineString convert(LineString lineString) { 52 | return new org.wololo.geojson.LineString( 53 | convert(lineString.getCoordinates())); 54 | } 55 | 56 | org.wololo.geojson.LineString convert(LinearRing ringString) { 57 | return new org.wololo.geojson.LineString( 58 | convert(ringString.getCoordinates())); 59 | } 60 | 61 | org.wololo.geojson.MultiLineString convert(MultiLineString multiLineString) { 62 | var size = multiLineString.getNumGeometries(); 63 | var lineStrings = new double[size][][]; 64 | for (int i = 0; i < size; i++) 65 | lineStrings[i] = convert(multiLineString.getGeometryN(i).getCoordinates()); 66 | return new org.wololo.geojson.MultiLineString(lineStrings); 67 | } 68 | 69 | org.wololo.geojson.Polygon convert(Polygon polygon) { 70 | var size = polygon.getNumInteriorRing() + 1; 71 | var rings = new double[size][][]; 72 | rings[0] = convert(polygon.getExteriorRing().getCoordinates()); 73 | for (int i = 0; i < size - 1; i++) 74 | rings[i + 1] = convert(polygon.getInteriorRingN(i).getCoordinates()); 75 | return new org.wololo.geojson.Polygon(rings); 76 | } 77 | 78 | org.wololo.geojson.MultiPolygon convert(MultiPolygon multiPolygon) { 79 | var size = multiPolygon.getNumGeometries(); 80 | var polygons = new double[size][][][]; 81 | for (int i = 0; i < size; i++) 82 | polygons[i] = convert((Polygon) multiPolygon.getGeometryN(i)).getCoordinates(); 83 | return new org.wololo.geojson.MultiPolygon(polygons); 84 | } 85 | 86 | org.wololo.geojson.GeometryCollection convert(GeometryCollection gc) { 87 | var size = gc.getNumGeometries(); 88 | var geometries = new org.wololo.geojson.Geometry[size]; 89 | for (int i = 0; i < size; i++) 90 | geometries[i] = write((Geometry) gc.getGeometryN(i)); 91 | return new org.wololo.geojson.GeometryCollection(geometries); 92 | } 93 | 94 | double[] convert(Coordinate coordinate) { 95 | if (Double.isNaN( coordinate.getZ() )) 96 | return new double[] { coordinate.x, coordinate.y }; 97 | else 98 | return new double[] { coordinate.x, coordinate.y, coordinate.getZ() }; 99 | } 100 | 101 | double[][] convert(Coordinate[] coordinates) { 102 | var array = new double[coordinates.length][]; 103 | for (int i = 0; i < coordinates.length; i++) 104 | array[i] = convert(coordinates[i]); 105 | return array; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/org/wololo/jts2geojson/Data.java: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson; 2 | 3 | import org.wololo.geojson.GeoJSON; 4 | 5 | class Data { 6 | 7 | public GeoJSON geometry; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/org/wololo/jts2geojson/DataFactory.java: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | 6 | class DataFactory { 7 | 8 | private final static ObjectMapper mapper = new ObjectMapper(); 9 | 10 | public static Data fromJson(String json) { 11 | try { 12 | return mapper.readerFor(Data.class).readValue(json); 13 | } catch (JsonProcessingException e) { 14 | throw new RuntimeException(e); 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/test/scala/org/wololo/jts2geojson/DeserializeGeometryCollectionSpec.scala: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson 2 | 3 | import java.util.HashMap 4 | 5 | import org.scalatest.wordspec.AnyWordSpec 6 | import org.wololo.geojson._ 7 | 8 | class DeserializeGeometryCollectionSpec extends AnyWordSpec { 9 | "GeoJSONFactory" when { 10 | "parsing GeoJSON to object" should { 11 | val geometry = new Point(Array(1, 1)) 12 | val properties = new HashMap[String, Object]() 13 | properties.put("test", 1.asInstanceOf[Object]) 14 | val feature = new Feature(geometry, properties) 15 | 16 | 17 | "deserialize GeometryCollection successfully" in { 18 | val geoJSON = """{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [1.1, 2.2] }]}""" 19 | val json = GeoJSONFactory.create(geoJSON) 20 | assert(json.isInstanceOf[GeometryCollection]) 21 | val gc = json.asInstanceOf[GeometryCollection] 22 | assert(gc.getGeometries.nonEmpty) 23 | val g = gc.getGeometries.head 24 | assert(g != null) 25 | assert(g.isInstanceOf[Point]) 26 | val point = g.asInstanceOf[Point] 27 | assert(point.getCoordinates.toSeq == Seq(1.1, 2.2)) 28 | } 29 | 30 | "deserialize GeometryCollection successfully if using ObjectMapper" in { 31 | val geoJSON = """{ "geometry" : {"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [1.1, 2.2] }]}}""" 32 | val value = DataFactory.fromJson(geoJSON) 33 | assert(value.isInstanceOf[Data]) 34 | } 35 | 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/scala/org/wololo/jts2geojson/GeoJSONFactorySpec.scala: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson 2 | 3 | import org.scalatest.wordspec.AnyWordSpec 4 | import org.wololo.geojson._ 5 | import java.util.HashMap 6 | 7 | class GeoJSONFactorySpec extends AnyWordSpec { 8 | "GeoJSONFactory" when { 9 | "dealing with badly encoded file" should { 10 | "read missing geometry field as null" in { 11 | val json = """{"type":"Feature","properties":{"test":1}}""" 12 | val expected = """{"type":"Feature","geometry":null,"properties":{"test":1}}""" 13 | 14 | val geojson = GeoJSONFactory.create(json) 15 | assert(geojson.toString == expected) 16 | } 17 | } 18 | 19 | "parsing GeoJSON to object" should { 20 | val geometry = new Point(Array(1, 1)) 21 | val properties = new HashMap[String, Object]() 22 | properties.put("test", 1.asInstanceOf[Object]) 23 | val feature = new Feature(geometry, properties) 24 | 25 | "be identical to programmatically created Feature" in { 26 | val expected = """{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0]},"properties":{"test":1}}""" 27 | 28 | val json = feature.toString 29 | assert(expected == json) 30 | 31 | val geoJSON = GeoJSONFactory.create(json) 32 | assert(expected == geoJSON.toString) 33 | } 34 | 35 | "be identical to programmatically created Feature with id" in { 36 | val feature = new Feature(1, geometry, properties) 37 | 38 | val expected = """{"type":"Feature","id":1,"geometry":{"type":"Point","coordinates":[1.0,1.0]},"properties":{"test":1}}""" 39 | 40 | val json = feature.toString 41 | assert(expected == json) 42 | 43 | val geoJSON = GeoJSONFactory.create(json) 44 | 45 | assert(expected == geoJSON.toString) 46 | } 47 | 48 | "be identical to programmatically created Feature without geometry" in { 49 | val feature = new Feature(null, properties) 50 | 51 | val expected = """{"type":"Feature","geometry":null,"properties":{"test":1}}""" 52 | 53 | val json = feature.toString 54 | assert(expected == json) 55 | 56 | val geoJSON = GeoJSONFactory.create(json) 57 | 58 | assert(expected == geoJSON.toString) 59 | } 60 | 61 | "be identical to programmatically created FeatureCollection" in { 62 | val expected = """{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0]},"properties":{"test":1}},{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0]},"properties":{"test":1}}]}""" 63 | 64 | val fc = new FeatureCollection(Array(feature, feature)) 65 | assert(expected == fc.toString) 66 | } 67 | 68 | "take care of bbox property" in { 69 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "Point", "coordinates": [-8.311419016226296, 53.894485921596285], "bbox": [-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 70 | val json = GeoJSONFactory.create(geoJSON) 71 | assert(json.isInstanceOf[FeatureCollection]) 72 | val fc = json.asInstanceOf[FeatureCollection] 73 | assert(fc.getFeatures.nonEmpty) 74 | val f = fc.getFeatures.head 75 | assert(f.getGeometry != null) 76 | assert(f.getGeometry.isInstanceOf[Point]) 77 | val point = f.getGeometry.asInstanceOf[Point] 78 | assert(point.getBbox != null) 79 | assert(point.getBbox.toSeq == Seq(-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285)) 80 | } 81 | 82 | "take care of MultiPoint bbox property" in { 83 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "MultiPoint", "coordinates": [[-8.311419016226296, 53.894485921596285]], "bbox": [-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 84 | val json = GeoJSONFactory.create(geoJSON) 85 | assert(json.isInstanceOf[FeatureCollection]) 86 | val fc = json.asInstanceOf[FeatureCollection] 87 | assert(fc.getFeatures.nonEmpty) 88 | val f = fc.getFeatures.head 89 | assert(f.getGeometry != null) 90 | assert(f.getGeometry.isInstanceOf[MultiPoint]) 91 | val point = f.getGeometry.asInstanceOf[MultiPoint] 92 | assert(point.getBbox != null) 93 | assert(point.getBbox.toSeq == Seq(-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285)) 94 | } 95 | 96 | "take care of LineString bbox property" in { 97 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "LineString", "coordinates": [[0.0,0.0],[1.0,1.0]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 98 | val json = GeoJSONFactory.create(geoJSON) 99 | assert(json.isInstanceOf[FeatureCollection]) 100 | val fc = json.asInstanceOf[FeatureCollection] 101 | assert(fc.getFeatures.nonEmpty) 102 | val f = fc.getFeatures.head 103 | assert(f.getGeometry != null) 104 | assert(f.getGeometry.isInstanceOf[LineString]) 105 | val point = f.getGeometry.asInstanceOf[LineString] 106 | assert(point.getBbox != null) 107 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 108 | } 109 | 110 | "take care of MultiLineString bbox property" in { 111 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "MultiLineString", "coordinates": [[[0.0,0.0],[1.0,1.0]]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 112 | val json = GeoJSONFactory.create(geoJSON) 113 | assert(json.isInstanceOf[FeatureCollection]) 114 | val fc = json.asInstanceOf[FeatureCollection] 115 | assert(fc.getFeatures.nonEmpty) 116 | val f = fc.getFeatures.head 117 | assert(f.getGeometry != null) 118 | assert(f.getGeometry.isInstanceOf[MultiLineString]) 119 | val point = f.getGeometry.asInstanceOf[MultiLineString] 120 | assert(point.getBbox != null) 121 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 122 | } 123 | 124 | "take care of Polygon bbox property" in { 125 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "Polygon", "coordinates": [[[0.0,0.0],[0.0,1.0],[1.0,1.0],[0.0,1.0],[0.0,0.0]]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 126 | val json = GeoJSONFactory.create(geoJSON) 127 | assert(json.isInstanceOf[FeatureCollection]) 128 | val fc = json.asInstanceOf[FeatureCollection] 129 | assert(fc.getFeatures.nonEmpty) 130 | val f = fc.getFeatures.head 131 | assert(f.getGeometry != null) 132 | assert(f.getGeometry.isInstanceOf[Polygon]) 133 | val point = f.getGeometry.asInstanceOf[Polygon] 134 | assert(point.getBbox != null) 135 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 136 | } 137 | 138 | "take care of MultiPolygon bbox property" in { 139 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "MultiPolygon", "coordinates": [[[[0.0,0.0],[0.0,1.0],[1.0,1.0],[0.0,1.0],[0.0,0.0]]]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 140 | val json = GeoJSONFactory.create(geoJSON) 141 | assert(json.isInstanceOf[FeatureCollection]) 142 | val fc = json.asInstanceOf[FeatureCollection] 143 | assert(fc.getFeatures.nonEmpty) 144 | val f = fc.getFeatures.head 145 | assert(f.getGeometry != null) 146 | assert(f.getGeometry.isInstanceOf[MultiPolygon]) 147 | val point = f.getGeometry.asInstanceOf[MultiPolygon] 148 | assert(point.getBbox != null) 149 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 150 | } 151 | 152 | } 153 | 154 | "parsing XYZ GeoJSON to object" should { 155 | val geometry = new Point(Array(1, 1, 1)) 156 | val properties = new HashMap[String, Object]() 157 | properties.put("test", 1.asInstanceOf[Object]) 158 | val feature = new Feature(geometry, properties) 159 | 160 | "be identical to programmatically created Feature" in { 161 | val expected = """{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0,1.0]},"properties":{"test":1}}""" 162 | 163 | val json = feature.toString 164 | assert(expected == json) 165 | 166 | val geoJSON = GeoJSONFactory.create(json) 167 | assert(expected == geoJSON.toString) 168 | } 169 | 170 | "be identical to programmatically created Feature with id" in { 171 | val feature = new Feature(1, geometry, properties) 172 | 173 | val expected = """{"type":"Feature","id":1,"geometry":{"type":"Point","coordinates":[1.0,1.0,1.0]},"properties":{"test":1}}""" 174 | 175 | val json = feature.toString 176 | assert(expected == json) 177 | 178 | val geoJSON = GeoJSONFactory.create(json) 179 | 180 | assert(expected == geoJSON.toString) 181 | } 182 | 183 | "be identical to programmatically created Feature without geometry" in { 184 | val feature = new Feature(null, properties) 185 | 186 | val expected = """{"type":"Feature","geometry":null,"properties":{"test":1}}""" 187 | 188 | val json = feature.toString 189 | assert(expected == json) 190 | 191 | val geoJSON = GeoJSONFactory.create(json) 192 | 193 | assert(expected == geoJSON.toString) 194 | } 195 | 196 | "be identical to programmatically created FeatureCollection" in { 197 | val expected = """{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0,1.0]},"properties":{"test":1}},{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0,1.0]},"properties":{"test":1}}]}""" 198 | 199 | val fc = new FeatureCollection(Array(feature, feature)) 200 | assert(expected == fc.toString) 201 | } 202 | 203 | "take care of bbox property" in { 204 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "Point", "coordinates": [-8.311419016226296, 53.894485921596285], "bbox": [-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 205 | val json = GeoJSONFactory.create(geoJSON) 206 | assert(json.isInstanceOf[FeatureCollection]) 207 | val fc = json.asInstanceOf[FeatureCollection] 208 | assert(fc.getFeatures.nonEmpty) 209 | val f = fc.getFeatures.head 210 | assert(f.getGeometry != null) 211 | assert(f.getGeometry.isInstanceOf[Point]) 212 | val point = f.getGeometry.asInstanceOf[Point] 213 | assert(point.getBbox != null) 214 | assert(point.getBbox.toSeq == Seq(-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285)) 215 | } 216 | 217 | "take care of MultiPoint bbox property" in { 218 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "MultiPoint", "coordinates": [[-8.311419016226296, 53.894485921596285]], "bbox": [-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 219 | val json = GeoJSONFactory.create(geoJSON) 220 | assert(json.isInstanceOf[FeatureCollection]) 221 | val fc = json.asInstanceOf[FeatureCollection] 222 | assert(fc.getFeatures.nonEmpty) 223 | val f = fc.getFeatures.head 224 | assert(f.getGeometry != null) 225 | assert(f.getGeometry.isInstanceOf[MultiPoint]) 226 | val point = f.getGeometry.asInstanceOf[MultiPoint] 227 | assert(point.getBbox != null) 228 | assert(point.getBbox.toSeq == Seq(-8.311419016226296, 53.894485921596285, -8.311419016226296, 53.894485921596285)) 229 | } 230 | 231 | "take care of LineString bbox property" in { 232 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "LineString", "coordinates": [[0.0,0.0],[1.0,1.0]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 233 | val json = GeoJSONFactory.create(geoJSON) 234 | assert(json.isInstanceOf[FeatureCollection]) 235 | val fc = json.asInstanceOf[FeatureCollection] 236 | assert(fc.getFeatures.nonEmpty) 237 | val f = fc.getFeatures.head 238 | assert(f.getGeometry != null) 239 | assert(f.getGeometry.isInstanceOf[LineString]) 240 | val point = f.getGeometry.asInstanceOf[LineString] 241 | assert(point.getBbox != null) 242 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 243 | } 244 | 245 | "take care of MultiLineString bbox property" in { 246 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "MultiLineString", "coordinates": [[[0.0,0.0],[1.0,1.0]]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 247 | val json = GeoJSONFactory.create(geoJSON) 248 | assert(json.isInstanceOf[FeatureCollection]) 249 | val fc = json.asInstanceOf[FeatureCollection] 250 | assert(fc.getFeatures.nonEmpty) 251 | val f = fc.getFeatures.head 252 | assert(f.getGeometry != null) 253 | assert(f.getGeometry.isInstanceOf[MultiLineString]) 254 | val point = f.getGeometry.asInstanceOf[MultiLineString] 255 | assert(point.getBbox != null) 256 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 257 | } 258 | 259 | "take care of Polygon bbox property" in { 260 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "Polygon", "coordinates": [[[0.0,0.0],[0.0,1.0],[1.0,1.0],[0.0,1.0],[0.0,0.0]]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 261 | val json = GeoJSONFactory.create(geoJSON) 262 | assert(json.isInstanceOf[FeatureCollection]) 263 | val fc = json.asInstanceOf[FeatureCollection] 264 | assert(fc.getFeatures.nonEmpty) 265 | val f = fc.getFeatures.head 266 | assert(f.getGeometry != null) 267 | assert(f.getGeometry.isInstanceOf[Polygon]) 268 | val point = f.getGeometry.asInstanceOf[Polygon] 269 | assert(point.getBbox != null) 270 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 271 | } 272 | 273 | "take care of MultiPolygon bbox property" in { 274 | val geoJSON = """{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 1, "geometry": {"type": "MultiPolygon", "coordinates": [[[[0.0,0.0],[0.0,1.0],[1.0,1.0],[0.0,1.0],[0.0,0.0]]]], "bbox": [0.0,0.0,1.0,1.0] }, "properties": {"FID": 335, "PLAN_REF": "151", "APP_TYPE": "RETENTION", "LOCATION": "Knockglass, Ballinameen, Co. Roscommon.", "REC_DATE": "05/01/2015", "DESCRIPT": "Of entrance to existing forest plantation for extraction of timber at various times at ", "APPSTATUS": "Application Finalised", "DEC_DATE": "20/02/2015", "DECISION": "Granted (Conditional)", "APPE_DEC": "n/a", "APPE_DAT": "n/a", "MOREINFO": "http://www.eplanning.ie/roscommoneplan/FileRefDetails.aspx?file_number=151", "WGS_LONG": "-8.31141", "WGS_LAT": "53.89448"} }] }""" 275 | val json = GeoJSONFactory.create(geoJSON) 276 | assert(json.isInstanceOf[FeatureCollection]) 277 | val fc = json.asInstanceOf[FeatureCollection] 278 | assert(fc.getFeatures.nonEmpty) 279 | val f = fc.getFeatures.head 280 | assert(f.getGeometry != null) 281 | assert(f.getGeometry.isInstanceOf[MultiPolygon]) 282 | val point = f.getGeometry.asInstanceOf[MultiPolygon] 283 | assert(point.getBbox != null) 284 | assert(point.getBbox.toSeq == Seq(0.0, 0.0, 1.0, 1.0)) 285 | } 286 | 287 | } 288 | 289 | } 290 | 291 | } 292 | -------------------------------------------------------------------------------- /src/test/scala/org/wololo/jts2geojson/GeoJSONReaderSpec.scala: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson 2 | 3 | import org.locationtech.jts.geom.Coordinate 4 | import org.locationtech.jts.geom.GeometryFactory 5 | import org.locationtech.jts.geom.PrecisionModel 6 | 7 | import org.scalatest.wordspec.AnyWordSpec 8 | 9 | class GeoJSONReaderSpec extends AnyWordSpec { 10 | "GeoJSONReader" when { 11 | "reading JTS object from GeoJSON" should { 12 | 13 | val reader = new GeoJSONReader() 14 | val writer = new GeoJSONWriter() 15 | val factory = new GeometryFactory() 16 | val srid = 25832 17 | val factorySrid = new GeometryFactory(new PrecisionModel(), srid) 18 | 19 | val coordArray = Array( 20 | new Coordinate(1, 1), 21 | new Coordinate(1, 2), 22 | new Coordinate(2, 2), 23 | new Coordinate(1, 1)) 24 | 25 | "expected result for Point" in { 26 | val expected = factory.createPoint(new Coordinate(1, 1)); 27 | val expectedSrid = factorySrid.createPoint(new Coordinate(1, 1)); 28 | val json = """{"type":"Point","coordinates":[1.0,1.0]}""" 29 | 30 | var geometry = reader.read(json) 31 | assert(expected === geometry) 32 | assert(0 === geometry.getSRID()) 33 | 34 | geometry = reader.read(json, factorySrid) 35 | assert(expectedSrid === geometry) 36 | assert(srid === geometry.getSRID()) 37 | } 38 | 39 | "expected result for MultiPoint" in { 40 | val expected = factory.createMultiPointFromCoords(coordArray) 41 | val expectedSrid = factorySrid.createMultiPointFromCoords(coordArray) 42 | val json = """{"type":"MultiPoint","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]}""" 43 | 44 | var geometry = reader.read(json) 45 | assert(expected === geometry) 46 | assert(0 === geometry.getSRID()) 47 | 48 | geometry = reader.read(json, factorySrid) 49 | assert(expectedSrid === geometry) 50 | assert(srid === geometry.getSRID()) 51 | } 52 | } 53 | 54 | "reading XYZ JTS object from GeoJSON" should { 55 | 56 | val reader = new GeoJSONReader() 57 | val writer = new GeoJSONWriter() 58 | val factory = new GeometryFactory() 59 | val srid = 25832 60 | val factorySrid = new GeometryFactory(new PrecisionModel(), srid) 61 | 62 | val coordArray = Array( 63 | new Coordinate(1, 1, 1), 64 | new Coordinate(1, 2, 1), 65 | new Coordinate(2, 2, 2), 66 | new Coordinate(1, 1, 1)) 67 | 68 | "expected result for Point" in { 69 | val expected = factory.createPoint(new Coordinate(1, 1, 1)); 70 | val expectedSrid = factorySrid.createPoint(new Coordinate(1, 1, 1)); 71 | val json = """{"type":"Point","coordinates":[1.0,1.0,1.0]}""" 72 | 73 | var geometry = reader.read(json) 74 | assert(expected === geometry) 75 | assert(0 === geometry.getSRID()) 76 | 77 | geometry = reader.read(json, factorySrid) 78 | assert(expectedSrid === geometry) 79 | assert(srid === geometry.getSRID()) 80 | } 81 | 82 | "expected result for MultiPoint" in { 83 | val expected = factory.createMultiPointFromCoords(coordArray) 84 | val expectedSrid = factorySrid.createMultiPointFromCoords(coordArray) 85 | val json = """{"type":"MultiPoint","coordinates":[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]}""" 86 | 87 | var geometry = reader.read(json) 88 | assert(expected === geometry) 89 | assert(0 === geometry.getSRID()) 90 | 91 | geometry = reader.read(json, factorySrid) 92 | assert(expectedSrid === geometry) 93 | assert(srid === geometry.getSRID()) 94 | } 95 | } 96 | 97 | } 98 | } -------------------------------------------------------------------------------- /src/test/scala/org/wololo/jts2geojson/GeoJSONWriterSpec.scala: -------------------------------------------------------------------------------- 1 | package org.wololo.jts2geojson 2 | 3 | import org.scalatest.wordspec.AnyWordSpec 4 | import org.locationtech.jts.geom.GeometryFactory 5 | import org.locationtech.jts.geom.Coordinate 6 | import org.wololo.geojson.Feature 7 | import org.wololo.geojson.FeatureCollection 8 | 9 | class GeoJSONWriterSpec extends AnyWordSpec { 10 | "GeoJSONWriter" when { 11 | "writing GeoJSON from JTS object" should { 12 | 13 | val reader = new GeoJSONReader() 14 | val writer = new GeoJSONWriter() 15 | val factory = new GeometryFactory() 16 | 17 | val point = factory.createPoint(new Coordinate(1, 1)) 18 | val lineString = factory.createLineString(Array( 19 | new Coordinate(1, 1), 20 | new Coordinate(1, 2), 21 | new Coordinate(2, 2), 22 | new Coordinate(1, 1))) 23 | 24 | val polygon = factory.createPolygon(lineString.getCoordinates()) 25 | 26 | "expected result for Point" in { 27 | val expected = """{"type":"Point","coordinates":[1.0,1.0]}""" 28 | 29 | val json = writer.write(point) 30 | assert(expected === json.toString) 31 | 32 | val geometry = reader.read(json) 33 | assert("POINT (1 1)" === geometry.toString) 34 | } 35 | 36 | "expected result for LineString" in { 37 | val json = writer.write(lineString) 38 | assert("""{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]}""" === json.toString) 39 | } 40 | 41 | "expected result for LineString with id" in { 42 | val json = writer.write(lineString) 43 | assert("""{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]}""" === json.toString) 44 | } 45 | 46 | "expected result for LinearString with id" in { 47 | val ring = factory.createLinearRing(lineString.getCoordinates) 48 | val json = writer.write(ring) 49 | assert("""{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]}""" === json.toString) 50 | } 51 | 52 | "expected result for Polygon" in { 53 | val json = writer.write(polygon); 54 | assert("""{"type":"Polygon","coordinates":[[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]]}""" === json.toString) 55 | } 56 | 57 | "expected result for MultiPoint" in { 58 | val multiPoint = factory.createMultiPointFromCoords(lineString.getCoordinates()) 59 | val json = writer.write(multiPoint) 60 | assert("""{"type":"MultiPoint","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]}""" === json.toString) 61 | } 62 | 63 | "expected result for MultiLineString" in { 64 | val multiLineString = factory.createMultiLineString(Array(lineString, lineString)) 65 | val json = writer.write(multiLineString) 66 | assert("""{"type":"MultiLineString","coordinates":[[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]],[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]]}""" === json.toString) 67 | } 68 | 69 | "expected result for MultiPolygon" in { 70 | val multiPolygon = factory.createMultiPolygon(Array(polygon, polygon)) 71 | val json = writer.write(multiPolygon) 72 | assert("""{"type":"MultiPolygon","coordinates":[[[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]],[[[1.0,1.0],[1.0,2.0],[2.0,2.0],[1.0,1.0]]]]}""" === json.toString) 73 | } 74 | 75 | "expected result for FeatureCollection" in { 76 | val json = writer.write(point) 77 | val feature1 = new Feature(json, null) 78 | val feature2 = new Feature(json, null) 79 | val featureCollection = new FeatureCollection(Array(feature1, feature2)) 80 | assert("""{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0]},"properties":null},{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0]},"properties":null}]}""" === featureCollection.toString) 81 | } 82 | } 83 | 84 | "writing XYZ GeoJSON from JTS object" should { 85 | 86 | val reader = new GeoJSONReader() 87 | val writer = new GeoJSONWriter() 88 | val factory = new GeometryFactory() 89 | 90 | val point = factory.createPoint(new Coordinate(1, 1, 1)) 91 | val lineString = factory.createLineString(Array( 92 | new Coordinate(1, 1, 1), 93 | new Coordinate(1, 2, 1), 94 | new Coordinate(2, 2, 2), 95 | new Coordinate(1, 1, 1))) 96 | val polygon = factory.createPolygon(lineString.getCoordinates()) 97 | 98 | "expected result for Point" in { 99 | val expected = """{"type":"Point","coordinates":[1.0,1.0,1.0]}""" 100 | 101 | val json = writer.write(point) 102 | assert(expected === json.toString) 103 | 104 | val geometry = reader.read(json) 105 | assert("POINT (1 1)" === geometry.toString) 106 | } 107 | 108 | "expected result for LineString" in { 109 | val json = writer.write(lineString) 110 | assert("""{"type":"LineString","coordinates":[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]}""" === json.toString) 111 | } 112 | 113 | "expected result for LineString with id" in { 114 | val json = writer.write(lineString) 115 | assert("""{"type":"LineString","coordinates":[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]}""" === json.toString) 116 | } 117 | 118 | "expected result for Polygon" in { 119 | val json = writer.write(polygon); 120 | assert("""{"type":"Polygon","coordinates":[[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]]}""" === json.toString) 121 | } 122 | 123 | "expected result for MultiPoint" in { 124 | val multiPoint = factory.createMultiPointFromCoords(lineString.getCoordinates()) 125 | val json = writer.write(multiPoint) 126 | assert("""{"type":"MultiPoint","coordinates":[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]}""" === json.toString) 127 | } 128 | 129 | "expected result for MultiLineString" in { 130 | val multiLineString = factory.createMultiLineString(Array(lineString, lineString)) 131 | val json = writer.write(multiLineString) 132 | assert("""{"type":"MultiLineString","coordinates":[[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]],[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]]}""" === json.toString) 133 | } 134 | 135 | "expected result for MultiPolygon" in { 136 | val multiPolygon = factory.createMultiPolygon(Array(polygon, polygon)) 137 | val json = writer.write(multiPolygon) 138 | assert("""{"type":"MultiPolygon","coordinates":[[[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]],[[[1.0,1.0,1.0],[1.0,2.0,1.0],[2.0,2.0,2.0],[1.0,1.0,1.0]]]]}""" === json.toString) 139 | } 140 | 141 | "expected result for FeatureCollection" in { 142 | val json = writer.write(point) 143 | val feature1 = new Feature(json, null) 144 | val feature2 = new Feature(json, null) 145 | val featureCollection = new FeatureCollection(Array(feature1, feature2)) 146 | assert("""{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0,1.0]},"properties":null},{"type":"Feature","geometry":{"type":"Point","coordinates":[1.0,1.0,1.0]},"properties":null}]}""" === featureCollection.toString) 147 | } 148 | } 149 | 150 | } 151 | } 152 | --------------------------------------------------------------------------------