001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.io;
003
004 import java.util.Map;
005 import java.util.Map.Entry;
006 import org.openstreetmap.josm.data.coor.LatLon;
007 import org.openstreetmap.josm.data.osm.Changeset;
008 import org.openstreetmap.josm.data.osm.Node;
009 import org.openstreetmap.josm.data.osm.OsmPrimitive;
010 import org.openstreetmap.josm.data.osm.Relation;
011 import org.openstreetmap.josm.data.osm.Way;
012 import org.openstreetmap.josm.data.osm.visitor.Visitor;
013 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
014
015 public class GeoJSONWriter implements Visitor {
016
017 private OsmDataLayer layer;
018 private StringBuilder out;
019 private final boolean skipEmptyNodes = true;
020 private boolean insertComma = false;
021
022 public GeoJSONWriter(OsmDataLayer layer) {
023 this.layer = layer;
024 }
025
026 public String write() {
027 out = new StringBuilder(1 << 12);
028 out.append("{\"type\": \"FeatureCollection\",\n");
029 out.append("\"features\": [\n");
030 for (Node n : layer.data.getNodes()) {
031 appendPrimitive(n);
032 }
033 for (Way w : layer.data.getWays()) {
034 appendPrimitive(w);
035 }
036 out.append("\n]\n}");
037 return out.toString();
038 }
039
040 @Override
041 public void visit(Node n) {
042 out.append("\"type\": \"Point\", \"coordinates\": ");
043 appendCoord(n.getCoor());
044 }
045
046 @Override
047 public void visit(Way w) {
048 out.append("\"type\": \"LineString\", \"coordinates\": [");
049 boolean insertCommaCoords = false;
050 for (Node n : w.getNodes()) {
051 if (insertCommaCoords) {
052 out.append(", ");
053 }
054 insertCommaCoords = true;
055 appendCoord(n.getCoor());
056 }
057 out.append("]");
058 }
059
060 @Override
061 public void visit(Relation e) {
062 }
063
064 @Override
065 public void visit(Changeset cs) {
066 }
067
068 protected String escape(String s) {
069 return s.replace("\"", "\\\"").replace("\\", "\\\\").replace("\n", "\\n");
070 }
071
072 protected void appendPrimitive(OsmPrimitive p) {
073 if (p.isIncomplete()) {
074 return;
075 } else if (skipEmptyNodes && p instanceof Node && p.getKeys().isEmpty()) {
076 return;
077 }
078 if (insertComma) {
079 out.append(",\n");
080 }
081 insertComma = true;
082 out.append("{\"type\": \"Feature\",\n");
083 Map<String, String> tags = p.getKeys();
084 if (!tags.isEmpty()) {
085 out.append("\t\"properties\": {\n");
086 boolean insertCommaTags = false;
087 for (Entry<String, String> t : tags.entrySet()) {
088 if (insertCommaTags) {
089 out.append(",\n");
090 }
091 insertCommaTags = true;
092 out.append("\t\t\"").append(escape(t.getKey())).append("\": ");
093 out.append("\"").append(escape(t.getValue())).append("\"");
094 }
095 out.append("\n\t},\n");
096 } else {
097 out.append("\t\"properties\": {},\n");
098 }
099 { // append primitive specific
100 out.append("\t\"geometry\": {");
101 p.visit(this);
102 out.append("}");
103 }
104 out.append("}");
105 }
106
107 protected void appendCoord(LatLon c) {
108 if (c != null) {
109 out.append("[").append(c.lon()).append(", ").append(c.lat()).append("]");
110 }
111 }
112 }