source: josm/trunk/src/org/openstreetmap/josm/io/GeoJSONWriter.java@ 11493

Last change on this file since 11493 was 11191, checked in by Don-vip, 8 years ago

sonar - fix some recent warnings

  • Property svn:eol-style set to native
File size: 7.9 KB
RevLine 
[4886]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
[6756]4import java.io.StringWriter;
[10165]5import java.math.BigDecimal;
6import java.math.RoundingMode;
[6756]7import java.util.HashMap;
[6485]8import java.util.Iterator;
[10817]9import java.util.List;
[4886]10import java.util.Map;
11import java.util.Map.Entry;
[10817]12import java.util.stream.Stream;
[6484]13
[6756]14import javax.json.Json;
15import javax.json.JsonArrayBuilder;
16import javax.json.JsonObjectBuilder;
17import javax.json.JsonWriter;
18import javax.json.stream.JsonGenerator;
19
[11166]20import org.openstreetmap.josm.Main;
[6485]21import org.openstreetmap.josm.data.Bounds;
[8813]22import org.openstreetmap.josm.data.coor.EastNorth;
[4886]23import org.openstreetmap.josm.data.coor.LatLon;
[6756]24import org.openstreetmap.josm.data.osm.DataSet;
[10817]25import org.openstreetmap.josm.data.osm.MultipolygonBuilder;
26import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon;
[4886]27import org.openstreetmap.josm.data.osm.Node;
28import org.openstreetmap.josm.data.osm.OsmPrimitive;
[10817]29import org.openstreetmap.josm.data.osm.Relation;
[4886]30import org.openstreetmap.josm.data.osm.Way;
[10817]31import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
[8813]32import org.openstreetmap.josm.data.projection.Projection;
[4886]33import org.openstreetmap.josm.gui.layer.OsmDataLayer;
[10817]34import org.openstreetmap.josm.gui.mappaint.ElemStyles;
[10852]35import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
[10817]36import org.openstreetmap.josm.tools.Pair;
[4886]37
[6756]38/**
39 * Writes OSM data as a GeoJSON string, using JSR 353: Java API for JSON Processing (JSON-P).
[10852]40 * <p>
41 * See <a href="https://tools.ietf.org/html/rfc7946">RFC7946: The GeoJSON Format</a>
[6756]42 */
43public class GeoJSONWriter {
[4886]44
[8813]45 private final OsmDataLayer layer;
46 private final Projection projection;
[6246]47 private static final boolean skipEmptyNodes = true;
[4886]48
[6756]49 /**
50 * Constructs a new {@code GeoJSONWriter}.
51 * @param layer The OSM data layer to save
[10852]52 * @since 10852
[6756]53 */
[10852]54 public GeoJSONWriter(OsmDataLayer layer) {
[4886]55 this.layer = layer;
[10852]56 this.projection = ProjectionPreference.wgs84.getProjection();
[4886]57 }
58
[6756]59 /**
60 * Writes OSM data as a GeoJSON string (prettified).
61 * @return The GeoJSON data
62 */
[4886]63 public String write() {
[6756]64 return write(true);
[4886]65 }
66
[6756]67 /**
68 * Writes OSM data as a GeoJSON string (prettified or not).
69 * @param pretty {@code true} to have pretty output, {@code false} otherwise
70 * @return The GeoJSON data
71 * @since 6756
72 */
73 public String write(boolean pretty) {
74 StringWriter stringWriter = new StringWriter();
[7005]75 Map<String, Object> config = new HashMap<>(1);
[6756]76 config.put(JsonGenerator.PRETTY_PRINTING, pretty);
[7030]77 try (JsonWriter writer = Json.createWriterFactory(config).createWriter(stringWriter)) {
78 JsonObjectBuilder object = Json.createObjectBuilder()
79 .add("type", "FeatureCollection")
80 .add("generator", "JOSM");
81 appendLayerBounds(layer.data, object);
82 appendLayerFeatures(layer.data, object);
83 writer.writeObject(object.build());
84 return stringWriter.toString();
85 }
[4886]86 }
[7509]87
[10817]88 private class GeometryPrimitiveVisitor extends AbstractVisitor {
[7509]89
[6806]90 private final JsonObjectBuilder geomObj;
[7509]91
[8836]92 GeometryPrimitiveVisitor(JsonObjectBuilder geomObj) {
[6806]93 this.geomObj = geomObj;
94 }
[4886]95
[6806]96 @Override
[10817]97 public void visit(Node n) {
[6806]98 geomObj.add("type", "Point");
99 LatLon ll = n.getCoor();
100 if (ll != null) {
[10817]101 geomObj.add("coordinates", getCoorArray(null, n.getCoor()));
[6806]102 }
103 }
104
105 @Override
[10817]106 public void visit(Way w) {
107 if (w != null) {
108 final JsonArrayBuilder array = getCoorsArray(w.getNodes());
109 if (ElemStyles.hasAreaElemStyle(w, false)) {
110 final JsonArrayBuilder container = Json.createArrayBuilder().add(array);
111 geomObj.add("type", "Polygon");
112 geomObj.add("coordinates", container);
113 } else {
114 geomObj.add("type", "LineString");
115 geomObj.add("coordinates", array);
[6806]116 }
117 }
118 }
119
120 @Override
[10817]121 public void visit(Relation r) {
[11166]122 if (r == null || !r.isMultipolygon() || r.hasIncompleteMembers()) {
123 return;
124 }
125 try {
[10817]126 final Pair<List<JoinedPolygon>, List<JoinedPolygon>> mp = MultipolygonBuilder.joinWays(r);
127 final JsonArrayBuilder polygon = Json.createArrayBuilder();
128 Stream.concat(mp.a.stream(), mp.b.stream())
129 .map(p -> getCoorsArray(p.getNodes())
130 // since first node is not duplicated as last node
131 .add(getCoorArray(null, p.getNodes().get(0).getCoor())))
132 .forEach(polygon::add);
133 geomObj.add("type", "MultiPolygon");
134 final JsonArrayBuilder multiPolygon = Json.createArrayBuilder().add(polygon);
135 geomObj.add("coordinates", multiPolygon);
[11166]136 } catch (MultipolygonBuilder.JoinedPolygonCreationException ex) {
[11191]137 Main.warn("GeoJSON: Failed to export multipolygon {0}", r.getUniqueId());
[11166]138 Main.warn(ex);
[10817]139 }
[6806]140 }
[8813]141 }
[6806]142
[8813]143 private JsonArrayBuilder getCoorArray(JsonArrayBuilder builder, LatLon c) {
144 return getCoorArray(builder, projection.latlon2eastNorth(c));
[6806]145 }
146
[8839]147 private static JsonArrayBuilder getCoorArray(JsonArrayBuilder builder, EastNorth c) {
[10817]148 return builder != null ? builder : Json.createArrayBuilder()
[10165]149 .add(BigDecimal.valueOf(c.getX()).setScale(11, RoundingMode.HALF_UP))
[10171]150 .add(BigDecimal.valueOf(c.getY()).setScale(11, RoundingMode.HALF_UP));
[8813]151 }
152
[10817]153 private JsonArrayBuilder getCoorsArray(Iterable<Node> nodes) {
154 final JsonArrayBuilder builder = Json.createArrayBuilder();
155 for (Node n : nodes) {
156 LatLon ll = n.getCoor();
157 if (ll != null) {
158 builder.add(getCoorArray(null, ll));
159 }
160 }
161 return builder;
162 }
163
[8813]164 protected void appendPrimitive(OsmPrimitive p, JsonArrayBuilder array) {
[4886]165 if (p.isIncomplete()) {
166 return;
167 } else if (skipEmptyNodes && p instanceof Node && p.getKeys().isEmpty()) {
168 return;
169 }
[6756]170
171 // Properties
172 final JsonObjectBuilder propObj = Json.createObjectBuilder();
173 for (Entry<String, String> t : p.getKeys().entrySet()) {
174 propObj.add(t.getKey(), t.getValue());
[4886]175 }
176
[6756]177 // Geometry
178 final JsonObjectBuilder geomObj = Json.createObjectBuilder();
[6806]179 p.accept(new GeometryPrimitiveVisitor(geomObj));
[6756]180
181 // Build primitive JSON object
182 array.add(Json.createObjectBuilder()
183 .add("type", "Feature")
184 .add("properties", propObj)
185 .add("geometry", geomObj));
[4886]186 }
[6485]187
[8813]188 protected void appendLayerBounds(DataSet ds, JsonObjectBuilder object) {
[6756]189 if (ds != null) {
190 Iterator<Bounds> it = ds.getDataSourceBounds().iterator();
191 if (it.hasNext()) {
192 Bounds b = new Bounds(it.next());
193 while (it.hasNext()) {
194 b.extend(it.next());
195 }
196 appendBounds(b, object);
[6485]197 }
198 }
199 }
200
[8813]201 protected void appendBounds(Bounds b, JsonObjectBuilder object) {
[6485]202 if (b != null) {
[8813]203 JsonArrayBuilder builder = Json.createArrayBuilder();
204 getCoorArray(builder, b.getMin());
205 getCoorArray(builder, b.getMax());
206 object.add("bbox", builder);
[6485]207 }
208 }
[6756]209
[8813]210 protected void appendLayerFeatures(DataSet ds, JsonObjectBuilder object) {
[6756]211 JsonArrayBuilder array = Json.createArrayBuilder();
212 if (ds != null) {
[10817]213 ds.allPrimitives().forEach(p -> appendPrimitive(p, array));
[6756]214 }
215 object.add("features", array);
216 }
[4886]217}
Note: See TracBrowser for help on using the repository browser.