Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.geometry / org.gvsig.fmap.geometry.operation / src / main / java / org / gvsig / fmap / geom / operation / fromwkt / WKTParser.java @ 40559

History | View | Annotate | Download (21.7 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.geom.operation.fromwkt;
25

    
26
import java.io.IOException;
27
import java.io.Reader;
28
import java.io.StreamTokenizer;
29
import java.io.StringReader;
30
import java.util.ArrayList;
31

    
32
import org.gvsig.fmap.geom.Geometry;
33
import org.gvsig.fmap.geom.GeometryLocator;
34
import org.gvsig.fmap.geom.GeometryManager;
35
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
36
import org.gvsig.fmap.geom.Geometry.TYPES;
37
import org.gvsig.fmap.geom.aggregate.MultiPoint;
38
import org.gvsig.fmap.geom.exception.CreateGeometryException;
39
import org.gvsig.fmap.geom.primitive.Curve;
40
import org.gvsig.fmap.geom.primitive.GeneralPathX;
41
import org.gvsig.fmap.geom.primitive.Point;
42
import org.gvsig.fmap.geom.primitive.Surface;
43

    
44
import com.vividsolutions.jts.geom.Coordinate;
45
import com.vividsolutions.jts.io.ParseException;
46

    
47
/**
48
 *  Converts a Well-Known Text string to a <code>Geometry</code>.
49
 * <p>
50
 *  The <code>WKTReader</code> allows
51
 *  extracting <code>Geometry</code> objects from either input streams or
52
 *  internal strings. This allows it to function as a parser to read <code>Geometry</code>
53
 *  objects from text blocks embedded in other data formats (e.g. XML). <P>
54
 * <p>
55
 * The Well-known
56
 *  Text format is defined in the <A HREF="http://www.opengis.org/techno/specs.htm">
57
 *  OpenGIS Simple Features Specification for SQL</A> . <P>
58
 * <p>
59
 *  <B>Note: </B> There is an inconsistency in the SFS. The WKT grammar states
60
 *  that <code>MultiPoints</code> are represented by <code>MULTIPOINT ( ( x y), (x y) )</code>
61
 *  , but the examples show <code>MultiPoint</code>s as <code>MULTIPOINT ( x y, x y )</code>
62
 *  . Other implementations follow the latter syntax, so JTS will adopt it as
63
 *  well.
64
 *
65
 *  A <code>WKTReader</code> is parameterized by a <code>GeometryFactory</code>
66
 *  , to allow it to create <code>Geometry</code> objects of the appropriate
67
 *  implementation. In particular, the <code>GeometryFactory</code> will
68
 *  determine the <code>PrecisionModel</code> and <code>SRID</code> that is
69
 *  used. <P>
70
 *
71
 *  The <code>WKTReader</code> will convert the input numbers to the precise
72
 *  internal representation.
73
 *
74
 *  Reads non-standard "LINEARRING" tags.
75
 *
76
 *@version 1.5
77
 */
78
public class WKTParser {
79

    
80
        private GeometryManager manager = GeometryLocator.getGeometryManager();
81
        /**
82
         * Creates a WKTReader that creates objects using a basic GeometryFactory.
83
         */
84
        public WKTParser() {
85
        }
86

    
87

    
88

    
89
        /**
90
         * Converts a Well-known Text representation to a <code>Geometry</code>.
91
         * 
92
         * @param wellKnownText
93
         *            one or more <Geometry Tagged Text>strings (see the OpenGIS
94
         *            Simple Features Specification) separated by whitespace
95
         * @return a <code>Geometry</code> specified by <code>wellKnownText</code>
96
         * @throws ParseException
97
         *             if a parsing problem occurs
98
         */
99
        public Geometry read(String wellKnownText) throws ParseException {
100
                StringReader reader = new StringReader(wellKnownText);
101
                try {
102
                        return read(reader);
103
                }
104
                finally {
105
                        reader.close();
106
                }
107
        }
108

    
109
        /**
110
         *  Converts a Well-known Text representation to a <code>Geometry</code>.
111
         *
112
         *@param  reader           a Reader which will return a <Geometry Tagged Text>
113
         *      string (see the OpenGIS Simple Features Specification)
114
         *@return                  a <code>Geometry</code> read from <code>reader</code>
115
         *@throws  ParseException  if a parsing problem occurs
116
         */
117
        public Geometry read(Reader reader) throws ParseException {
118
                StreamTokenizer tokenizer = new StreamTokenizer(reader);
119
                try {
120
                        return readGeometryTaggedText(tokenizer);
121
                }
122
                catch (IOException e) {
123
                        throw new ParseException(e.toString());
124
                } catch (CreateGeometryException e) {
125
                        throw new ParseException(e.toString());
126
                }
127
        }
128

    
129
        /**
130
         *  Returns the next array of <code>Coordinate</code>s in the stream.
131
         *
132
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
133
         *      format. The next element returned by the stream should be "(" (the
134
         *      beginning of "(x1 y1, x2 y2, ..., xn yn)") or "EMPTY".
135
         *@return                  the next array of <code>Coordinate</code>s in the
136
         *      stream, or an empty array if "EMPTY" is the next element returned by
137
         *      the stream.
138
         *@throws  IOException     if an I/O error occurs
139
         *@throws  ParseException  if an unexpected token was encountered
140
         */
141
        private Coordinate[] getCoordinates(StreamTokenizer tokenizer)
142
        throws IOException, ParseException
143
        {
144
                String nextToken = getNextEmptyOrOpener(tokenizer);
145
                if (nextToken.equals("EMPTY")) {
146
                        return new Coordinate[]{};
147
                }
148
                ArrayList coordinates = new ArrayList();
149
                coordinates.add(getPreciseCoordinate(tokenizer));
150
                nextToken = getNextCloserOrComma(tokenizer);
151
                while (nextToken.equals(",")) {
152
                        coordinates.add(getPreciseCoordinate(tokenizer));
153
                        nextToken = getNextCloserOrComma(tokenizer);
154
                }
155
                Coordinate[] array = new Coordinate[coordinates.size()];
156
                return (Coordinate[]) coordinates.toArray(array);
157
        }
158

    
159
        private Coordinate getPreciseCoordinate(StreamTokenizer tokenizer)
160
        throws IOException, ParseException
161
        {
162
                Coordinate coord = new Coordinate();
163
                coord.x = getNextNumber(tokenizer);
164
                coord.y = getNextNumber(tokenizer);
165
                if (isNumberNext(tokenizer)) {
166
                        coord.z = getNextNumber(tokenizer);
167
                }
168
                return coord;
169
        }
170
        private boolean isNumberNext(StreamTokenizer tokenizer) throws IOException {
171
                try {
172
                        return tokenizer.nextToken() == StreamTokenizer.TT_NUMBER;
173
                }
174
                finally {
175
                        tokenizer.pushBack();
176
                }
177
        }
178
        /**
179
         *  Returns the next number in the stream.
180
         *
181
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
182
         *      format. The next token must be a number.
183
         *@return                  the next number in the stream
184
         *@throws  ParseException  if the next token is not a number
185
         *@throws  IOException     if an I/O error occurs
186
         */
187
        private double getNextNumber(StreamTokenizer tokenizer) throws IOException,
188
        ParseException {
189
                int type = tokenizer.nextToken();
190
                switch (type) {
191
                case StreamTokenizer.TT_EOF:
192
                        throw new ParseException("Expected number but encountered end of stream");
193
                case StreamTokenizer.TT_EOL:
194
                        throw new ParseException("Expected number but encountered end of line");
195
                case StreamTokenizer.TT_NUMBER:
196
                        return tokenizer.nval;
197
                case StreamTokenizer.TT_WORD:
198
                        throw new ParseException("Expected number but encountered word: " +
199
                                        tokenizer.sval);
200
                case '(':
201
                        throw new ParseException("Expected number but encountered '('");
202
                case ')':
203
                        throw new ParseException("Expected number but encountered ')'");
204
                case ',':
205
                        throw new ParseException("Expected number but encountered ','");
206
                }
207
                return 0;
208
        }
209

    
210
        /**
211
         *  Returns the next "EMPTY" or "(" in the stream as uppercase text.
212
         *
213
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
214
         *      format. The next token must be "EMPTY" or "(".
215
         *@return                  the next "EMPTY" or "(" in the stream as uppercase
216
         *      text.
217
         *@throws  ParseException  if the next token is not "EMPTY" or "("
218
         *@throws  IOException     if an I/O error occurs
219
         */
220
        private String getNextEmptyOrOpener(StreamTokenizer tokenizer) throws IOException, ParseException {
221
                String nextWord = getNextWord(tokenizer);
222
                if (nextWord.equals("EMPTY") || nextWord.equals("(")) {
223
                        return nextWord;
224
                }
225
                throw new ParseException("Expected 'EMPTY' or '(' but encountered '" +
226
                                nextWord + "'");
227
        }
228

    
229
        /**
230
         *  Returns the next ")" or "," in the stream.
231
         *
232
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
233
         *      format. The next token must be ")" or ",".
234
         *@return                  the next ")" or "," in the stream
235
         *@throws  ParseException  if the next token is not ")" or ","
236
         *@throws  IOException     if an I/O error occurs
237
         */
238
        private String getNextCloserOrComma(StreamTokenizer tokenizer) throws IOException, ParseException {
239
                String nextWord = getNextWord(tokenizer);
240
                if (nextWord.equals(",") || nextWord.equals(")")) {
241
                        return nextWord;
242
                }
243
                throw new ParseException("Expected ')' or ',' but encountered '" + nextWord
244
                                + "'");
245
        }
246

    
247
        /**
248
         *  Returns the next ")" in the stream.
249
         *
250
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
251
         *      format. The next token must be ")".
252
         *@return                  the next ")" in the stream
253
         *@throws  ParseException  if the next token is not ")"
254
         *@throws  IOException     if an I/O error occurs
255
         */
256
        private String getNextCloser(StreamTokenizer tokenizer) throws IOException, ParseException {
257
                String nextWord = getNextWord(tokenizer);
258
                if (nextWord.equals(")")) {
259
                        return nextWord;
260
                }
261
                throw new ParseException("Expected ')' but encountered '" + nextWord + "'");
262
        }
263

    
264
        /**
265
         *  Returns the next word in the stream as uppercase text.
266
         *
267
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
268
         *      format. The next token must be a word.
269
         *@return                  the next word in the stream as uppercase text
270
         *@throws  ParseException  if the next token is not a word
271
         *@throws  IOException     if an I/O error occurs
272
         */
273
        private String getNextWord(StreamTokenizer tokenizer) throws IOException, ParseException {
274
                int type = tokenizer.nextToken();
275
                switch (type) {
276
                case StreamTokenizer.TT_EOF:
277
                        throw new ParseException("Expected word but encountered end of stream");
278
                case StreamTokenizer.TT_EOL:
279
                        throw new ParseException("Expected word but encountered end of line");
280
                case StreamTokenizer.TT_NUMBER:
281
                        throw new ParseException("Expected word but encountered number: " +
282
                                        tokenizer.nval);
283
                case StreamTokenizer.TT_WORD:
284
                        return tokenizer.sval.toUpperCase();
285
                case '(':
286
                        return "(";
287
                case ')':
288
                        return ")";
289
                case ',':
290
                        return ",";
291
                }
292
                // Assert.shouldNeverReachHere("Encountered unexpected StreamTokenizer type: " + type);
293
                return null;
294
        }
295

    
296
        /**
297
         *  Creates a <code>Geometry</code> using the next token in the stream.
298
         *
299
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
300
         *      format. The next tokens must form a &lt;Geometry Tagged Text&gt;.
301
         *@return                  a <code>Geometry</code> specified by the next token
302
         *      in the stream
303
         *@throws  ParseException  if the coordinates used to create a <code>Polygon</code>
304
         *      shell and holes do not form closed linestrings, or if an unexpected
305
         *      token was encountered
306
         *@throws  IOException     if an I/O error occurs
307
         * @throws CreateGeometryException 
308
         */
309
        private Geometry readGeometryTaggedText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException{
310
                String type = getNextWord(tokenizer);
311
                if (type.equals("POINT")) {
312
                        return readPointText(tokenizer);
313
                }
314
                else if (type.equals("LINESTRING")) {
315
                        return readLineStringText(tokenizer);
316
                }
317
                else if (type.equals("LINEARRING")) {
318
                        return readLinearRingText(tokenizer);
319
                }
320
                else if (type.equals("POLYGON")) {
321
                        return readPolygonText(tokenizer);
322
                }
323
                else if (type.equals("MULTIPOINT")) {
324
                        return readMultiPointText(tokenizer);
325
                }
326
                else if (type.equals("MULTILINESTRING")) {
327
                        return readMultiLineStringText(tokenizer);
328
                }
329
                else if (type.equals("MULTIPOLYGON")) {
330
                        return readMultiPolygonText(tokenizer);
331
                }
332
                /* else if (type.equals("GEOMETRYCOLLECTION")) {
333
      return readGeometryCollectionText(tokenizer);
334
    } */
335
                System.err.println("Unknown type: " + type);
336
                throw new ParseException("Unknown type: " + type);
337
        }
338

    
339
        /**
340
         *  Creates a <code>Point</code> using the next token in the stream.
341
         *
342
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
343
         *      format. The next tokens must form a &lt;Point Text&gt;.
344
         *@return                  a <code>Point</code> specified by the next token in
345
         *      the stream
346
         *@throws  IOException     if an I/O error occurs
347
         *@throws  ParseException  if an unexpected token was encountered
348
         * @throws IllegalAccessException 
349
         * @throws InstantiationException 
350
         * @throws CreateGeometryException 
351
         */
352
        private Geometry readPointText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
353
                String nextToken = getNextEmptyOrOpener(tokenizer);
354
                if (nextToken.equals("EMPTY")) {
355
                        return null;
356
                }
357
                Coordinate c = getPreciseCoordinate(tokenizer);
358
                Point point = (Point)manager.create(TYPES.POINT, SUBTYPES.GEOM2D);
359
                point.setX(c.x);
360
                point.setY(c.y);
361
                getNextCloser(tokenizer);
362

    
363
                return point;
364
        }
365

    
366
        /**
367
         *  Creates a <code>LineString</code> using the next token in the stream.
368
         *
369
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
370
         *      format. The next tokens must form a &lt;LineString Text&gt;.
371
         *@return                  a <code>LineString</code> specified by the next
372
         *      token in the stream
373
         *@throws  IOException     if an I/O error occurs
374
         *@throws  ParseException  if an unexpected token was encountered
375
         * @throws CreateGeometryException 
376
         * @throws IllegalAccessException 
377
         * @throws InstantiationException 
378
         */
379
        private Geometry readLineStringText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
380
                Coordinate[] arrayC = getCoordinates(tokenizer);
381
                GeneralPathX gp = new GeneralPathX();
382
                gp.moveTo(arrayC[0].x,arrayC[0].y);
383
                for (int i=1;i < arrayC.length; i++)
384
                {
385
                        gp.lineTo(arrayC[i].x, arrayC[i].y);
386
                }
387
        // IJM: Cambiado Surface por Curve 
388
        Curve curve = (Curve) manager.create(TYPES.CURVE, SUBTYPES.GEOM2D); 
389
        curve.setGeneralPath(gp); 
390
        return curve; 
391
        }
392

    
393
        /**
394
         *  Creates a <code>LinearRing</code> using the next token in the stream.
395
         *
396
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
397
         *      format. The next tokens must form a &lt;LineString Text&gt;.
398
         *@return                  a <code>LinearRing</code> specified by the next
399
         *      token in the stream
400
         *@throws  IOException     if an I/O error occurs
401
         *@throws  ParseException  if the coordinates used to create the <code>LinearRing</code>
402
         *      do not form a closed linestring, or if an unexpected token was
403
         *      encountered
404
         * @throws IllegalAccessException 
405
         * @throws InstantiationException 
406
         * @throws CreateGeometryException 
407
         */
408
        private Geometry readLinearRingText(StreamTokenizer tokenizer)
409
        throws IOException, ParseException, CreateGeometryException
410
        {
411
                Coordinate[] arrayC = getCoordinates(tokenizer);
412
                GeneralPathX gp = new GeneralPathX();
413
                gp.moveTo(arrayC[0].x, arrayC[0].y);
414
                for (int i=1;i < arrayC.length; i++)
415
                {
416
                        gp.lineTo(arrayC[i].x, arrayC[i].y);
417
                }
418
                Surface surface = (Surface)manager.create(TYPES.SURFACE, SUBTYPES.GEOM2D);
419
                surface.setGeneralPath(gp);
420
                return surface;
421
        }
422

    
423
        /**
424
         *  Creates a <code>MultiPoint</code> using the next token in the stream.
425
         *
426
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
427
         *      format. The next tokens must form a &lt;MultiPoint Text&gt;.
428
         *@return                  a <code>MultiPoint</code> specified by the next
429
         *      token in the stream
430
         *@throws  IOException     if an I/O error occurs
431
         *@throws  ParseException  if an unexpected token was encountered
432
         * @throws IllegalAccessException 
433
         * @throws InstantiationException 
434
         * @throws CreateGeometryException 
435
         */
436
        private Geometry readMultiPointText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
437
                Coordinate[] coords = getCoordinates(tokenizer);
438
                MultiPoint multiPoint = (MultiPoint)manager.create(TYPES.MULTIPOINT, SUBTYPES.GEOM2D);
439
                for (int i=0; i < coords.length; i++)
440
                {
441
                        Point point = (Point)manager.create(TYPES.POINT, SUBTYPES.GEOM2D);
442
                        point.setX(coords[i].x);
443
                        point.setY(coords[i].y);
444
                        multiPoint.addPoint(point);
445
                }   
446

    
447
                return multiPoint;
448
        }
449

    
450

    
451
        /**
452
         *  Creates a <code>Polygon</code> using the next token in the stream.
453
         *
454
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
455
         *      format. The next tokens must form a &lt;Polygon Text&gt;.
456
         *@return                  a <code>Polygon</code> specified by the next token
457
         *      in the stream
458
         *@throws  ParseException  if the coordinates used to create the <code>Polygon</code>
459
         *      shell and holes do not form closed linestrings, or if an unexpected
460
         *      token was encountered.
461
         *@throws  IOException     if an I/O error occurs
462
         * @throws IllegalAccessException 
463
         * @throws InstantiationException 
464
         * @throws CreateGeometryException 
465
         */
466
        private Geometry readPolygonText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
467
                String nextToken = getNextEmptyOrOpener(tokenizer);
468
                if (nextToken.equals("EMPTY")) {
469
                        return null;
470
                }
471
                ArrayList holes = new ArrayList();
472
                Geometry shell = readLinearRingText(tokenizer);
473
                nextToken = getNextCloserOrComma(tokenizer);
474
                while (nextToken.equals(",")) {
475
                        Geometry hole = readLinearRingText(tokenizer);
476
                        holes.add(hole);
477
                        nextToken = getNextCloserOrComma(tokenizer);
478
                }
479
                // LinearRing[] array = new LinearRing[holes.size()];
480
                return shell; //geometryFactory.createPolygon(shell, (LinearRing[]) holes.toArray(array));
481
        }
482

    
483
        /**
484
         *  Creates a <code>MultiLineString</code> using the next token in the stream.
485
         *
486
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
487
         *      format. The next tokens must form a &lt;MultiLineString Text&gt;.
488
         *@return                  a <code>MultiLineString</code> specified by the
489
         *      next token in the stream
490
         *@throws  IOException     if an I/O error occurs
491
         *@throws  ParseException  if an unexpected token was encountered
492
         * @throws IllegalAccessException 
493
         * @throws InstantiationException 
494
         * @throws CreateGeometryException 
495
         */
496
        private Geometry readMultiLineStringText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
497
                // TODO: HACER ESTO BIEN, CON UN GENERAL PATH
498
                String nextToken = getNextEmptyOrOpener(tokenizer);
499
                if (nextToken.equals("EMPTY")) {
500
                        return null;
501
                }
502
                ArrayList lineStrings = new ArrayList();
503
                Geometry lineString = readLineStringText(tokenizer);
504
                lineStrings.add(lineString);
505
                nextToken = getNextCloserOrComma(tokenizer);
506
                while (nextToken.equals(",")) {
507
                        lineString = readLineStringText(tokenizer);
508
                        lineStrings.add(lineString);
509
                        nextToken = getNextCloserOrComma(tokenizer);
510
                } 
511
                // LineString[] array = new LineString[lineStrings.size()];
512
                return lineString; // geometryFactory.createMultiLineString((LineString[]) lineStrings.toArray(array));
513
        }
514

    
515
        /**
516
         *  Creates a <code>MultiPolygon</code> using the next token in the stream.
517
         *
518
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
519
         *      format. The next tokens must form a &lt;MultiPolygon Text&gt;.
520
         *@return                  a <code>MultiPolygon</code> specified by the next
521
         *      token in the stream, or if if the coordinates used to create the
522
         *      <code>Polygon</code> shells and holes do not form closed linestrings.
523
         *@throws  IOException     if an I/O error occurs
524
         *@throws  ParseException  if an unexpected token was encountered
525
         * @throws CreateGeometryException 
526
         */
527
        // TODO:
528
        private Geometry readMultiPolygonText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
529
                String nextToken = getNextEmptyOrOpener(tokenizer);
530
                if (nextToken.equals("EMPTY")) {
531
                        return null;
532
                }
533
                ArrayList polygons = new ArrayList();
534
                Geometry polygon = readPolygonText(tokenizer);
535
                /* polygons.add(polygon);
536
    nextToken = getNextCloserOrComma(tokenizer);
537
    while (nextToken.equals(",")) {
538
      polygon = readPolygonText(tokenizer);
539
      polygons.add(polygon);
540
      nextToken = getNextCloserOrComma(tokenizer);
541
    } */
542
                // Polygon[] array = new Polygon[polygons.size()];
543
                return polygon; //geometryFactory.createMultiPolygon((Polygon[]) polygons.toArray(array));
544
        } 
545

    
546
        /**
547
         *  Creates a <code>GeometryCollection</code> using the next token in the
548
         *  stream.
549
         *
550
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
551
         *      format. The next tokens must form a &lt;GeometryCollection Text&gt;.
552
         *@return                  a <code>GeometryCollection</code> specified by the
553
         *      next token in the stream
554
         *@throws  ParseException  if the coordinates used to create a <code>Polygon</code>
555
         *      shell and holes do not form closed linestrings, or if an unexpected
556
         *      token was encountered
557
         *@throws  IOException     if an I/O error occurs
558
         */
559
        // TODO:
560
        /* private GeometryCollection readGeometryCollectionText(StreamTokenizer tokenizer) throws IOException, ParseException {
561
    String nextToken = getNextEmptyOrOpener(tokenizer);
562
    if (nextToken.equals("EMPTY")) {
563
      return geometryFactory.createGeometryCollection(new Geometry[]{});
564
    }
565
    ArrayList geometries = new ArrayList();
566
    Geometry geometry = readGeometryTaggedText(tokenizer);
567
    geometries.add(geometry);
568
    nextToken = getNextCloserOrComma(tokenizer);
569
    while (nextToken.equals(",")) {
570
      geometry = readGeometryTaggedText(tokenizer);
571
      geometries.add(geometry);
572
      nextToken = getNextCloserOrComma(tokenizer);
573
    }
574
    Geometry[] array = new Geometry[geometries.size()];
575
    return geometryFactory.createGeometryCollection((Geometry[]) geometries.toArray(array));
576
  } */
577
}
578