1
2
3
4
5
6
7
8
9 package org.locationtech.spatial4j.io;
10
11 import org.locationtech.spatial4j.context.SpatialContext;
12 import org.locationtech.spatial4j.context.SpatialContextFactory;
13 import org.locationtech.spatial4j.distance.DistanceUtils;
14 import org.locationtech.spatial4j.shape.*;
15 import org.locationtech.spatial4j.shape.impl.BufferedLine;
16 import org.locationtech.spatial4j.shape.impl.BufferedLineString;
17 import org.locationtech.spatial4j.shape.impl.GeoCircle;
18
19 import java.io.IOException;
20 import java.io.StringWriter;
21 import java.io.Writer;
22 import java.text.NumberFormat;
23 import java.util.Iterator;
24
25 import static org.locationtech.spatial4j.io.GeoJSONReader.BUFFER;
26 import static org.locationtech.spatial4j.io.GeoJSONReader.BUFFER_UNITS;
27
28 public class GeoJSONWriter implements ShapeWriter {
29
30 public GeoJSONWriter(SpatialContext ctx, SpatialContextFactory factory) {
31
32 }
33
34 @Override
35 public String getFormatName() {
36 return ShapeIO.GeoJSON;
37 }
38
39 protected void write(Writer output, NumberFormat nf, double... coords) throws IOException {
40 output.write('[');
41 for (int i = 0; i < coords.length; i++) {
42 if (Double.isNaN(coords[i])) {
43 break;
44 }
45 if (i > 0) {
46 output.append(',');
47 }
48 output.append(nf.format(coords[i]));
49 }
50 output.write(']');
51 }
52
53 @Override
54 public void write(Writer output, Shape shape) throws IOException {
55 if (shape == null) {
56 throw new NullPointerException("Shape can not be null");
57 }
58 NumberFormat nf = LegacyShapeWriter.makeNumberFormat(6);
59 if (shape instanceof Point) {
60 Point v = (Point) shape;
61 output.append("{\"type\":\"Point\",\"coordinates\":");
62 write(output, nf, v.getX(), v.getY());
63 output.append('}');
64 return;
65 }
66 if (shape instanceof Rectangle) {
67 Rectangle v = (Rectangle) shape;
68 output.append("{\"type\":\"Polygon\",\"coordinates\":[[");
69 write(output, nf, v.getMinX(), v.getMinY());
70 output.append(',');
71 write(output, nf, v.getMinX(), v.getMaxY());
72 output.append(',');
73 write(output, nf, v.getMaxX(), v.getMaxY());
74 output.append(',');
75 write(output, nf, v.getMaxX(), v.getMinY());
76 output.append(',');
77 write(output, nf, v.getMinX(), v.getMinY());
78 output.append("]]}");
79 return;
80 }
81 if (shape instanceof BufferedLine) {
82 BufferedLine v = (BufferedLine) shape;
83 output.append("{\"type\":\"LineString\",\"coordinates\":[");
84 write(output, nf, v.getA().getX(), v.getA().getY());
85 output.append(',');
86 write(output, nf, v.getB().getX(), v.getB().getY());
87 output.append(',');
88 output.append("]");
89 if (v.getBuf() > 0) {
90 output.append(',');
91 output.append("\"buffer\":");
92 output.append(nf.format(v.getBuf()));
93 }
94 output.append('}');
95 return;
96 }
97 if (shape instanceof BufferedLineString) {
98 BufferedLineString v = (BufferedLineString) shape;
99 output.append("{\"type\":\"LineString\",\"coordinates\":[");
100 BufferedLine last = null;
101 Iterator<BufferedLine> iter = v.getSegments().iterator();
102 while (iter.hasNext()) {
103 BufferedLine seg = iter.next();
104 if (last != null) {
105 output.append(',');
106 }
107 write(output, nf, seg.getA().getX(), seg.getA().getY());
108 last = seg;
109 }
110 if (last != null) {
111 output.append(',');
112 write(output, nf, last.getB().getX(), last.getB().getY());
113 }
114 output.append("]");
115 if (v.getBuf() > 0) {
116 writeDistance(output, nf, v.getBuf(), shape.getContext().isGeo(), BUFFER, BUFFER_UNITS);
117 }
118 output.append('}');
119 return;
120 }
121 if (shape instanceof Circle) {
122
123 Circle v = (Circle) shape;
124 Point center = v.getCenter();
125 output.append("{\"type\":\"Circle\",\"coordinates\":");
126 write(output, nf, center.getX(), center.getY());
127 writeDistance(output, nf, v.getRadius(), v instanceof GeoCircle, "radius", "radius_units");
128 output.append("}");
129 return;
130 }
131 if (shape instanceof ShapeCollection) {
132 ShapeCollection v = (ShapeCollection) shape;
133 output.append("{\"type\":\"GeometryCollection\",\"geometries\":[");
134 for (int i = 0; i < v.size(); i++) {
135 if (i > 0) {
136 output.append(',');
137 }
138 write(output, v.get(i));
139 }
140 output.append("]}");
141 return;
142 }
143 output.append("{\"type\":\"Unknown\",\"wkt\":\"");
144 output.append(LegacyShapeWriter.writeShape(shape));
145 output.append("\"}");
146 }
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163 void writeDistance(Writer output, NumberFormat nf, double dist, boolean isGeo, String distProperty, String distUnitsProperty)
164 throws IOException {
165 output.append(",\"").append(distProperty).append("\":");
166 if (isGeo) {
167 double distKm =
168 DistanceUtils.degrees2Dist(dist, DistanceUtils.EARTH_MEAN_RADIUS_KM);
169 output.append(nf.format(distKm));
170 output.append(",\"properties\":{");
171 output.append("\"").append(distUnitsProperty).append("\":\"km\"}");
172 } else {
173 output.append(nf.format(dist));
174 }
175 }
176
177 @Override
178 public String toString(Shape shape) {
179 try {
180 StringWriter buffer = new StringWriter();
181 write(buffer, shape);
182 return buffer.toString();
183 } catch (IOException ex) {
184 throw new RuntimeException(ex);
185 }
186 }
187 }