-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWKTReader.java
327 lines (282 loc) · 8.06 KB
/
WKTReader.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*
* Copyright 2010 Aalto University, ComNet
* Released under GPLv3. See LICENSE.txt for details.
*/
package input;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import core.Coord;
/**
* Class for reading "Well-known text syntax" files. See e.g.
* <A HREF="http://en.wikipedia.org/wiki/Well-known_text">Wikipedia</A> for
* WKT syntax details. For example, <A HREF="http://openjump.org/">Open JUMP</A>
* GIS program can save compatible data from many other formats.<BR>
*/
public class WKTReader {
/** known WKT type LINESTRING */
public static final String LINESTRING = "LINESTRING";
/** known WKT type MULTILINESTRING */
public static final String MULTILINESTRING = "MULTILINESTRING";
/** known WKT type POINT */
public static final String POINT = "POINT";
/** are all lines of the file read */
private boolean done;
/** reader for the data */
private BufferedReader reader;
/**
* Read point data from a file
* @param file The file to read points from
* @return A list of coordinates read from the file
* @throws IOException if something went wrong while reading
*/
public List<Coord> readPoints(File file) throws IOException {
return readPoints(new FileReader(file));
}
/**
* Read point data from a Reader
* @param r The Reader to read points from
* @return A list of coordinates that were read
* @throws IOException if something went wrong while reading
*/
public List<Coord> readPoints(Reader r) throws IOException {
List<Coord> points = new ArrayList<Coord>();
String type;
init(r);
while((type = nextType()) != null) {
if (type.equals(POINT)) {
points.add(parsePoint());
}
else {
// known type but not interesting -> skip
readNestedContents();
}
}
return points;
}
/**
* Read line (LINESTRING) data from a file
* @param file The file to read data from
* @return A list of coordinate lists read from the file
* @throws IOException if something went wrong while reading
*/
public List<List<Coord>> readLines(File file) throws IOException {
List<List<Coord>> lines = new ArrayList<List<Coord>>();
String type;
init(new FileReader(file));
while((type = nextType()) != null) {
if (type.equals(LINESTRING)) {
lines.add(parseLineString(readNestedContents()));
}
else {
// known type but not interesting -> skip
readNestedContents();
}
}
return lines;
}
/**
* Initialize the reader to use a certain input reader
* @param input The input to use
*/
protected void init(Reader input) {
setDone(false);
reader = new BufferedReader(input);
}
/**
* Returns the next type read from the reader given at init or null
* if no more types can be read
* @return the next type read from the reader given at init
* @throws IOException
*/
protected String nextType() throws IOException {
String type = null;
while (!done && type == null) {
type = readWord(reader);
if (type.length() < 1) { // discard empty lines
type = null;
continue;
}
}
return type;
}
/**
* Returns true if type is one of the known WKT types
* @param type The type to check
* @return true if type is one of the known WKT types
*/
protected boolean isKnownType(String type) {
if (type.equals(LINESTRING)) {
return true;
}
else if (type.equals(MULTILINESTRING)) {
return true;
}
else if (type.equals(POINT)) {
return true;
}
else {
return false;
}
}
/**
* Reads a "word", ie whitespace delimited string of characters, from
* the reader
* @param r Reader to read the characters from
* @return The word that was read (or empty string if nothing was read)
* @throws IOException
*/
protected String readWord(Reader r) throws IOException {
StringBuffer buf = new StringBuffer();
char c = skipAllWhitespace(r);
// read non-whitespace part
while(c != (char)-1 && !Character.isWhitespace(c)) {
buf.append(c);
c = (char)r.read();
}
if (c == (char)-1) {
setDone(true);
}
return buf.toString();
}
/**
* Parses a MULTILINESTRING statement that has nested linestrings from
* the current reader
* @return List of parsed Coord lists
* @throws IOException
*/
protected List<List<Coord>> parseMultilinestring()
throws IOException {
List<List<Coord>> list = new ArrayList<List<Coord>>();
String multiContents = readNestedContents(reader);
StringReader r2 = new StringReader(multiContents);
String lineString = readNestedContents(r2);
while (lineString.length() > 0) {
list.add(parseLineString(lineString));
lineString = readNestedContents(r2);
}
return list;
}
/**
* Parses a WKT point data from the intialized reader
* @return Point data as a Coordinate
* @throws IOException if couldn't parse coordinate values
*/
protected Coord parsePoint() throws IOException {
String coords = readNestedContents(reader);
Scanner s = new Scanner(coords);
double x,y;
try {
x = s.nextDouble();
y = s.nextDouble();
} catch (RuntimeException e) {
throw new IOException("Bad coordinate values: '" + coords + "'");
}
return new Coord(x,y);
}
/**
* Reads and skips all characters until character "until" is read or
* end of stream is reached. Also the expected character is discarded.
* @param r Reader to read characters from
* @param until What character to expect
* @throws IOException
*/
protected void skipUntil(Reader r, char until) throws IOException {
char c;
do {
c = (char)r.read();
} while (c != until && c != (char)-1);
}
/**
* Skips all consecutive whitespace characters from reader
* @param r Reader where the whitespace is skipped
* @return First non-whitespace character read from the reader
* @throws IOException
*/
protected char skipAllWhitespace(Reader r) throws IOException {
char c;
do {
c = (char)r.read();
} while (Character.isWhitespace(c) && c != (char)-1);
return c;
}
/**
* Reads everything from the first opening parenthesis until line that
* ends to a closing parenthesis and returns the contents in one string
* @param r Reader to read the input from
* @return The text between the parentheses
*/
public String readNestedContents(Reader r) throws IOException {
StringBuffer contents = new StringBuffer();
int parOpen; // nrof open parentheses
char c = '\0';
skipUntil(r,'(');
parOpen = 1;
while (c != (char)-1 && parOpen > 0) {
c = (char)r.read();
if (c == '(') {
parOpen++;
}
if (c == ')') {
parOpen--;
}
if (Character.isWhitespace(c)) {
c = ' '; // convert all whitespace to basic space
}
contents.append(c);
}
contents.deleteCharAt(contents.length()-1); // remove last ')'
return contents.toString();
}
/**
* Returns nested contents from the reader given at init
* @return nested contents from the reader given at init
* @throws IOException
* @see #readNestedContents(Reader)
*/
public String readNestedContents() throws IOException {
return readNestedContents(reader);
}
/**
* Parses coordinate tuples from "LINESTRING" lines
* @param line String that contains the whole "LINESTRING"'s content
* @return List of coordinates parsed from the linestring
*/
protected List<Coord> parseLineString(String line) {
List<Coord> coords = new ArrayList<Coord>();
Scanner lineScan;
Scanner tupleScan;
double x,y;
Coord c;
lineScan = new Scanner(line);
lineScan.useDelimiter(",");
while (lineScan.hasNext()) {
tupleScan = new Scanner(lineScan.next());
x = Double.parseDouble(tupleScan.next());
y = Double.parseDouble(tupleScan.next());
c = new Coord(x,y);
coords.add(c);
}
return coords;
}
/**
* Returns true if the whole file has been read
* @return true if the whole file has been read
*/
protected boolean isDone() {
return this.done;
}
/**
* Sets the "is file read" state
* @param done If true, reading is done
*/
protected void setDone(boolean done) {
this.done = done;
}
}