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