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 | 47755 | fdiaz | |
---|---|---|---|
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 | } |