Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.geometry / org.gvsig.fmap.geometry.jts / src / main / java / org / gvsig / fmap / geom / jts / formats / geojson / GeoJsonWriter.java @ 47755

History | View | Annotate | Download (8.16 KB)

1

    
2
package org.gvsig.fmap.geom.jts.formats.geojson;
3

    
4
import java.io.IOException;
5
import java.io.StringWriter;
6
import java.io.Writer;
7
import java.util.ArrayList;
8
import java.util.LinkedHashMap;
9
import java.util.List;
10
import java.util.Map;
11

    
12
import org.json.simple.JSONAware;
13
import org.json.simple.JSONObject;
14

    
15
import com.vividsolutions.jts.geom.CoordinateSequence;
16
import com.vividsolutions.jts.geom.Geometry;
17
import com.vividsolutions.jts.geom.GeometryCollection;
18
import com.vividsolutions.jts.geom.LineString;
19
import com.vividsolutions.jts.geom.MultiLineString;
20
import com.vividsolutions.jts.geom.MultiPoint;
21
import com.vividsolutions.jts.geom.MultiPolygon;
22
import com.vividsolutions.jts.geom.Point;
23
import com.vividsolutions.jts.geom.Polygon;
24
import com.vividsolutions.jts.util.Assert;
25

    
26
/**
27
 * Writes {@link Geometry}s as JSON fragments in GeoJson format.
28
 * 
29
 * @author Martin Davis
30
 * @author Paul Howells, Vivid Solutions
31
 */
32
public class GeoJsonWriter {
33
  
34
  public static final String EPSG_PREFIX = "EPSG:";
35
  
36
  private double scale;
37
  protected boolean isEncodeCRS = true;
38

    
39
  /**
40
   * Constructs a GeoJsonWriter instance.
41
   */
42
  public GeoJsonWriter() {
43
    this(8);
44
  }
45

    
46
  /**
47
   * Constructs a GeoJsonWriter instance specifying the number of decimals to
48
   * use when encoding floating point numbers.
49
   */
50
  public GeoJsonWriter(int decimals) {
51
    this.scale = Math.pow(10, decimals);
52
  }
53

    
54
  public void setEncodeCRS(boolean isEncodeCRS) {
55
    this.isEncodeCRS  = isEncodeCRS;
56
  }
57
  
58
  /**
59
   * Writes a {@link Geometry} in GeoJson format to a String.
60
   * 
61
   * @param geometry
62
   * @return String GeoJson Encoded Geometry
63
   */
64
  public String write(Geometry geometry) {
65

    
66
    StringWriter writer = new StringWriter();
67
    try {
68
      write(geometry, writer);
69
    } catch (IOException ex) {
70
      Assert.shouldNeverReachHere();
71
    }
72

    
73
    return writer.toString();
74
  }
75

    
76
  /**
77
   * Writes a {@link Geometry} in GeoJson format into a {@link Writer}.
78
   * 
79
   * @param geometry
80
   *          Geometry to encode
81
   * @param writer
82
   *          Stream to encode to.
83
   * @throws IOException
84
   *           throws an IOException when unable to write the JSON string
85
   */
86
  public void write(Geometry geometry, Writer writer) throws IOException {
87
    Map<String, Object> map = create(geometry, isEncodeCRS);
88
    JSONObject.writeJSONString(map, writer);
89
    writer.flush();
90
  }
91

    
92
  protected Map<String, Object> create(Geometry geometry, boolean encodeCRS) {
93

    
94
    Map<String, Object> result = new LinkedHashMap<String, Object>();
95
    result.put(GeoJsonConstants.NAME_TYPE, geometry.getGeometryType());
96

    
97
    if (geometry instanceof Point) {
98
      Point point = (Point) geometry;
99

    
100
      final String jsonString = getJsonString(point.getCoordinateSequence());
101

    
102
      result.put(GeoJsonConstants.NAME_COORDINATES, new JSONAware() {
103

    
104
        public String toJSONString() {
105
          return jsonString;
106
        }
107
      });
108

    
109
    } else if (geometry instanceof LineString) {
110
      LineString lineString = (LineString) geometry;
111

    
112
      final String jsonString = getJsonString(lineString
113
          .getCoordinateSequence());
114

    
115
      result.put(GeoJsonConstants.NAME_COORDINATES, new JSONAware() {
116

    
117
        public String toJSONString() {
118
          return jsonString;
119
        }
120
      });
121

    
122
    } else if (geometry instanceof Polygon) {
123
      Polygon polygon = (Polygon) geometry;
124

    
125
      result.put(GeoJsonConstants.NAME_COORDINATES, makeJsonAware(polygon));
126

    
127
    } else if (geometry instanceof MultiPoint) {
128
      MultiPoint multiPoint = (MultiPoint) geometry;
129

    
130
      result.put(GeoJsonConstants.NAME_COORDINATES, makeJsonAware(multiPoint));
131

    
132
    } else if (geometry instanceof MultiLineString) {
133
      MultiLineString multiLineString = (MultiLineString) geometry;
134

    
135
      result.put(GeoJsonConstants.NAME_COORDINATES, makeJsonAware(multiLineString));
136

    
137
    } else if (geometry instanceof MultiPolygon) {
138
      MultiPolygon multiPolygon = (MultiPolygon) geometry;
139

    
140
      result.put(GeoJsonConstants.NAME_COORDINATES, makeJsonAware(multiPolygon));
141

    
142
    } else if (geometry instanceof GeometryCollection) {
143
      GeometryCollection geometryCollection = (GeometryCollection) geometry;
144

    
145
      ArrayList<Map<String, Object>> geometries = new ArrayList<Map<String, Object>>(
146
          geometryCollection.getNumGeometries());
147

    
148
      for (int i = 0; i < geometryCollection.getNumGeometries(); i++) {
149
        geometries.add(create(geometryCollection.getGeometryN(i), false));
150
      }
151

    
152
      result.put(GeoJsonConstants.NAME_GEOMETRIES, geometries);
153

    
154
    } else {
155
      throw new IllegalArgumentException("Unable to encode geometry " + geometry.getGeometryType() );
156
    }
157

    
158
    if (encodeCRS) {
159
      result.put(GeoJsonConstants.NAME_CRS, createCRS(geometry.getSRID()));
160
    }
161

    
162
    return result;
163
  }
164

    
165
  private Map<String, Object> createCRS(int srid) {
166

    
167
    Map<String, Object> result = new LinkedHashMap<String, Object>();
168
    result.put(GeoJsonConstants.NAME_TYPE, GeoJsonConstants.NAME_NAME);
169

    
170
    Map<String, Object> props = new LinkedHashMap<String, Object>();
171
    props.put(GeoJsonConstants.NAME_NAME, EPSG_PREFIX + srid);
172

    
173
    result.put(GeoJsonConstants.NAME_PROPERTIES, props);
174

    
175
    return result;
176
  }
177

    
178
  private List<JSONAware> makeJsonAware(Polygon poly) {
179
    ArrayList<JSONAware> result = new ArrayList<JSONAware>();
180

    
181
    {
182
      final String jsonString = getJsonString(poly.getExteriorRing()
183
          .getCoordinateSequence());
184
      result.add(new JSONAware() {
185

    
186
        public String toJSONString() {
187
          return jsonString;
188
        }
189
      });
190
    }
191
    for (int i = 0; i < poly.getNumInteriorRing(); i++) {
192
      final String jsonString = getJsonString(poly.getInteriorRingN(i)
193
          .getCoordinateSequence());
194
      result.add(new JSONAware() {
195

    
196
        public String toJSONString() {
197
          return jsonString;
198
        }
199
      });
200
    }
201

    
202
    return result;
203
  }
204

    
205
  private List<Object> makeJsonAware(GeometryCollection geometryCollection) {
206

    
207
    ArrayList<Object> list = new ArrayList<Object>(
208
        geometryCollection.getNumGeometries());
209
    for (int i = 0; i < geometryCollection.getNumGeometries(); i++) {
210
      Geometry geometry = geometryCollection.getGeometryN(i);
211
      
212
      if (geometry instanceof Polygon) {
213
        Polygon polygon = (Polygon) geometry;
214
        list.add(makeJsonAware(polygon));
215
      } 
216
      else if (geometry instanceof LineString) {
217
        LineString lineString = (LineString) geometry;
218
        final String jsonString = getJsonString(lineString
219
            .getCoordinateSequence());
220
        list.add(new JSONAware() {
221

    
222
          public String toJSONString() {
223
            return jsonString;
224
          }
225
        });
226
      } 
227
      else if (geometry instanceof Point) {
228
        Point point = (Point) geometry;
229
        final String jsonString = getJsonString(point.getCoordinateSequence());
230
        list.add(new JSONAware() {
231

    
232
          public String toJSONString() {
233
            return jsonString;
234
          }
235
        });
236
      }
237
    }
238

    
239
    return list;
240
  }
241

    
242
  private String getJsonString(CoordinateSequence coordinateSequence) {
243
    StringBuffer result = new StringBuffer();
244

    
245
    if (coordinateSequence.size() > 1) {
246
      result.append("[");
247
    }
248
    for (int i = 0; i < coordinateSequence.size(); i++) {
249
      if (i > 0) {
250
        result.append(",");
251
      }
252
      result.append("[");
253
      result.append(formatOrdinate(coordinateSequence.getOrdinate(i, CoordinateSequence.X))); 
254
      result.append(",");
255
      result.append(formatOrdinate(coordinateSequence.getOrdinate(i, CoordinateSequence.Y)));
256

    
257
      if (coordinateSequence.getDimension() > 2 ) {
258
        double z = coordinateSequence.getOrdinate(i, CoordinateSequence.Z);
259
        if (!  Double.isNaN(z)) {
260
          result.append(",");
261
          result.append(formatOrdinate(z));
262
        }
263
      }
264

    
265
      result.append("]");
266

    
267
    }
268

    
269
    if (coordinateSequence.size() > 1) {
270
      result.append("]");
271
    }
272

    
273
    return result.toString();
274
  }
275

    
276
  private String formatOrdinate(double x) {
277
    String result = null;
278

    
279
    if (Math.abs(x) >= Math.pow(10, -3) && x < Math.pow(10, 7)) {
280
      x = Math.floor(x * scale + 0.5) / scale;
281
      long lx = (long) x;
282
      if (lx == x) {
283
        result = Long.toString(lx);
284
      } else {
285
        result = Double.toString(x);
286
      }
287
    } else {
288
      result = Double.toString(x);
289
    }
290

    
291
    return result;
292
  }
293

    
294
}