Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2060 / libraries / libFMap_geometries / src / org / gvsig / fmap / geom / operation / fromwkt / WKTParser.java @ 39365

History | View | Annotate | Download (20.8 KB)

1
package org.gvsig.fmap.geom.operation.fromwkt;
2

    
3
import java.io.IOException;
4
import java.io.Reader;
5
import java.io.StreamTokenizer;
6
import java.io.StringReader;
7
import java.util.ArrayList;
8

    
9
import org.gvsig.fmap.geom.Geometry;
10
import org.gvsig.fmap.geom.GeometryLocator;
11
import org.gvsig.fmap.geom.GeometryManager;
12
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
13
import org.gvsig.fmap.geom.Geometry.TYPES;
14
import org.gvsig.fmap.geom.aggregate.MultiPoint;
15
import org.gvsig.fmap.geom.exception.CreateGeometryException;
16
import org.gvsig.fmap.geom.primitive.Curve;
17
import org.gvsig.fmap.geom.primitive.GeneralPathX;
18
import org.gvsig.fmap.geom.primitive.Point;
19
import org.gvsig.fmap.geom.primitive.Surface;
20

    
21
import com.vividsolutions.jts.geom.Coordinate;
22
import com.vividsolutions.jts.io.ParseException;
23

    
24
/**
25
 *  Converts a Well-Known Text string to a <code>Geometry</code>.
26
 * <p>
27
 *  The <code>WKTReader</code> allows
28
 *  extracting <code>Geometry</code> objects from either input streams or
29
 *  internal strings. This allows it to function as a parser to read <code>Geometry</code>
30
 *  objects from text blocks embedded in other data formats (e.g. XML). <P>
31
 * <p>
32
 * The Well-known
33
 *  Text format is defined in the <A HREF="http://www.opengis.org/techno/specs.htm">
34
 *  OpenGIS Simple Features Specification for SQL</A> . <P>
35
 * <p>
36
 *  <B>Note: </B> There is an inconsistency in the SFS. The WKT grammar states
37
 *  that <code>MultiPoints</code> are represented by <code>MULTIPOINT ( ( x y), (x y) )</code>
38
 *  , but the examples show <code>MultiPoint</code>s as <code>MULTIPOINT ( x y, x y )</code>
39
 *  . Other implementations follow the latter syntax, so JTS will adopt it as
40
 *  well.
41
 *
42
 *  A <code>WKTReader</code> is parameterized by a <code>GeometryFactory</code>
43
 *  , to allow it to create <code>Geometry</code> objects of the appropriate
44
 *  implementation. In particular, the <code>GeometryFactory</code> will
45
 *  determine the <code>PrecisionModel</code> and <code>SRID</code> that is
46
 *  used. <P>
47
 *
48
 *  The <code>WKTReader</code> will convert the input numbers to the precise
49
 *  internal representation.
50
 *
51
 *  Reads non-standard "LINEARRING" tags.
52
 *
53
 *@version 1.5
54
 */
55
public class WKTParser {
56

    
57
        private GeometryManager manager = GeometryLocator.getGeometryManager();
58
        /**
59
         * Creates a WKTReader that creates objects using a basic GeometryFactory.
60
         */
61
        public WKTParser() {
62
        }
63

    
64

    
65

    
66
        /**
67
         * Converts a Well-known Text representation to a <code>Geometry</code>.
68
         * 
69
         * @param wellKnownText
70
         *            one or more <Geometry Tagged Text>strings (see the OpenGIS
71
         *            Simple Features Specification) separated by whitespace
72
         * @return a <code>Geometry</code> specified by <code>wellKnownText</code>
73
         * @throws ParseException
74
         *             if a parsing problem occurs
75
         */
76
        public Geometry read(String wellKnownText) throws ParseException {
77
                StringReader reader = new StringReader(wellKnownText);
78
                try {
79
                        return read(reader);
80
                }
81
                finally {
82
                        reader.close();
83
                }
84
        }
85

    
86
        /**
87
         *  Converts a Well-known Text representation to a <code>Geometry</code>.
88
         *
89
         *@param  reader           a Reader which will return a <Geometry Tagged Text>
90
         *      string (see the OpenGIS Simple Features Specification)
91
         *@return                  a <code>Geometry</code> read from <code>reader</code>
92
         *@throws  ParseException  if a parsing problem occurs
93
         */
94
        public Geometry read(Reader reader) throws ParseException {
95
                StreamTokenizer tokenizer = new StreamTokenizer(reader);
96
                try {
97
                        return readGeometryTaggedText(tokenizer);
98
                }
99
                catch (IOException e) {
100
                        throw new ParseException(e.toString());
101
                } catch (CreateGeometryException e) {
102
                        throw new ParseException(e.toString());
103
                }
104
        }
105

    
106
        /**
107
         *  Returns the next array of <code>Coordinate</code>s in the stream.
108
         *
109
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
110
         *      format. The next element returned by the stream should be "(" (the
111
         *      beginning of "(x1 y1, x2 y2, ..., xn yn)") or "EMPTY".
112
         *@return                  the next array of <code>Coordinate</code>s in the
113
         *      stream, or an empty array if "EMPTY" is the next element returned by
114
         *      the stream.
115
         *@throws  IOException     if an I/O error occurs
116
         *@throws  ParseException  if an unexpected token was encountered
117
         */
118
        private Coordinate[] getCoordinates(StreamTokenizer tokenizer)
119
        throws IOException, ParseException
120
        {
121
                String nextToken = getNextEmptyOrOpener(tokenizer);
122
                if (nextToken.equals("EMPTY")) {
123
                        return new Coordinate[]{};
124
                }
125
                ArrayList coordinates = new ArrayList();
126
                coordinates.add(getPreciseCoordinate(tokenizer));
127
                nextToken = getNextCloserOrComma(tokenizer);
128
                while (nextToken.equals(",")) {
129
                        coordinates.add(getPreciseCoordinate(tokenizer));
130
                        nextToken = getNextCloserOrComma(tokenizer);
131
                }
132
                Coordinate[] array = new Coordinate[coordinates.size()];
133
                return (Coordinate[]) coordinates.toArray(array);
134
        }
135

    
136
        private Coordinate getPreciseCoordinate(StreamTokenizer tokenizer)
137
        throws IOException, ParseException
138
        {
139
                Coordinate coord = new Coordinate();
140
                coord.x = getNextNumber(tokenizer);
141
                coord.y = getNextNumber(tokenizer);
142
                if (isNumberNext(tokenizer)) {
143
                        coord.z = getNextNumber(tokenizer);
144
                }
145
                return coord;
146
        }
147
        private boolean isNumberNext(StreamTokenizer tokenizer) throws IOException {
148
                try {
149
                        return tokenizer.nextToken() == StreamTokenizer.TT_NUMBER;
150
                }
151
                finally {
152
                        tokenizer.pushBack();
153
                }
154
        }
155
        /**
156
         *  Returns the next number in the stream.
157
         *
158
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
159
         *      format. The next token must be a number.
160
         *@return                  the next number in the stream
161
         *@throws  ParseException  if the next token is not a number
162
         *@throws  IOException     if an I/O error occurs
163
         */
164
        private double getNextNumber(StreamTokenizer tokenizer) throws IOException,
165
        ParseException {
166
                int type = tokenizer.nextToken();
167
                switch (type) {
168
                case StreamTokenizer.TT_EOF:
169
                        throw new ParseException("Expected number but encountered end of stream");
170
                case StreamTokenizer.TT_EOL:
171
                        throw new ParseException("Expected number but encountered end of line");
172
                case StreamTokenizer.TT_NUMBER:
173
                        return tokenizer.nval;
174
                case StreamTokenizer.TT_WORD:
175
                        throw new ParseException("Expected number but encountered word: " +
176
                                        tokenizer.sval);
177
                case '(':
178
                        throw new ParseException("Expected number but encountered '('");
179
                case ')':
180
                        throw new ParseException("Expected number but encountered ')'");
181
                case ',':
182
                        throw new ParseException("Expected number but encountered ','");
183
                }
184
                return 0;
185
        }
186

    
187
        /**
188
         *  Returns the next "EMPTY" or "(" in the stream as uppercase text.
189
         *
190
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
191
         *      format. The next token must be "EMPTY" or "(".
192
         *@return                  the next "EMPTY" or "(" in the stream as uppercase
193
         *      text.
194
         *@throws  ParseException  if the next token is not "EMPTY" or "("
195
         *@throws  IOException     if an I/O error occurs
196
         */
197
        private String getNextEmptyOrOpener(StreamTokenizer tokenizer) throws IOException, ParseException {
198
                String nextWord = getNextWord(tokenizer);
199
                if (nextWord.equals("EMPTY") || nextWord.equals("(")) {
200
                        return nextWord;
201
                }
202
                throw new ParseException("Expected 'EMPTY' or '(' but encountered '" +
203
                                nextWord + "'");
204
        }
205

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

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

    
241
        /**
242
         *  Returns the next word in the stream as uppercase text.
243
         *
244
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
245
         *      format. The next token must be a word.
246
         *@return                  the next word in the stream as uppercase text
247
         *@throws  ParseException  if the next token is not a word
248
         *@throws  IOException     if an I/O error occurs
249
         */
250
        private String getNextWord(StreamTokenizer tokenizer) throws IOException, ParseException {
251
                int type = tokenizer.nextToken();
252
                switch (type) {
253
                case StreamTokenizer.TT_EOF:
254
                        throw new ParseException("Expected word but encountered end of stream");
255
                case StreamTokenizer.TT_EOL:
256
                        throw new ParseException("Expected word but encountered end of line");
257
                case StreamTokenizer.TT_NUMBER:
258
                        throw new ParseException("Expected word but encountered number: " +
259
                                        tokenizer.nval);
260
                case StreamTokenizer.TT_WORD:
261
                        return tokenizer.sval.toUpperCase();
262
                case '(':
263
                        return "(";
264
                case ')':
265
                        return ")";
266
                case ',':
267
                        return ",";
268
                }
269
                // Assert.shouldNeverReachHere("Encountered unexpected StreamTokenizer type: " + type);
270
                return null;
271
        }
272

    
273
        /**
274
         *  Creates a <code>Geometry</code> using the next token in the stream.
275
         *
276
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
277
         *      format. The next tokens must form a &lt;Geometry Tagged Text&gt;.
278
         *@return                  a <code>Geometry</code> specified by the next token
279
         *      in the stream
280
         *@throws  ParseException  if the coordinates used to create a <code>Polygon</code>
281
         *      shell and holes do not form closed linestrings, or if an unexpected
282
         *      token was encountered
283
         *@throws  IOException     if an I/O error occurs
284
         * @throws CreateGeometryException 
285
         */
286
        private Geometry readGeometryTaggedText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException{
287
                String type = getNextWord(tokenizer);
288
                if (type.equals("POINT")) {
289
                        return readPointText(tokenizer);
290
                }
291
                else if (type.equals("LINESTRING")) {
292
                        return readLineStringText(tokenizer);
293
                }
294
                else if (type.equals("LINEARRING")) {
295
                        return readLinearRingText(tokenizer);
296
                }
297
                else if (type.equals("POLYGON")) {
298
                        return readPolygonText(tokenizer);
299
                }
300
                else if (type.equals("MULTIPOINT")) {
301
                        return readMultiPointText(tokenizer);
302
                }
303
                else if (type.equals("MULTILINESTRING")) {
304
                        return readMultiLineStringText(tokenizer);
305
                }
306
                else if (type.equals("MULTIPOLYGON")) {
307
                        return readMultiPolygonText(tokenizer);
308
                }
309
                /* else if (type.equals("GEOMETRYCOLLECTION")) {
310
      return readGeometryCollectionText(tokenizer);
311
    } */
312
                System.err.println("Unknown type: " + type);
313
                throw new ParseException("Unknown type: " + type);
314
        }
315

    
316
        /**
317
         *  Creates a <code>Point</code> using the next token in the stream.
318
         *
319
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
320
         *      format. The next tokens must form a &lt;Point Text&gt;.
321
         *@return                  a <code>Point</code> specified by the next token in
322
         *      the stream
323
         *@throws  IOException     if an I/O error occurs
324
         *@throws  ParseException  if an unexpected token was encountered
325
         * @throws IllegalAccessException 
326
         * @throws InstantiationException 
327
         * @throws CreateGeometryException 
328
         */
329
        private Geometry readPointText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
330
                String nextToken = getNextEmptyOrOpener(tokenizer);
331
                if (nextToken.equals("EMPTY")) {
332
                        return null;
333
                }
334
                Coordinate c = getPreciseCoordinate(tokenizer);
335
                Point point = (Point)manager.create(TYPES.POINT, SUBTYPES.GEOM2D);
336
                point.setX(c.x);
337
                point.setY(c.y);
338
                getNextCloser(tokenizer);
339

    
340
                return point;
341
        }
342

    
343
        /**
344
         *  Creates a <code>LineString</code> using the next token in the stream.
345
         *
346
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
347
         *      format. The next tokens must form a &lt;LineString Text&gt;.
348
         *@return                  a <code>LineString</code> specified by the next
349
         *      token in the stream
350
         *@throws  IOException     if an I/O error occurs
351
         *@throws  ParseException  if an unexpected token was encountered
352
         * @throws CreateGeometryException 
353
         * @throws IllegalAccessException 
354
         * @throws InstantiationException 
355
         */
356
        private Geometry readLineStringText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
357
                Coordinate[] arrayC = getCoordinates(tokenizer);
358
                GeneralPathX gp = new GeneralPathX();
359
                gp.moveTo(arrayC[0].x,arrayC[0].y);
360
                for (int i=1;i < arrayC.length; i++)
361
                {
362
                        gp.lineTo(arrayC[i].x, arrayC[i].y);
363
                }
364
        // IJM: Cambiado Surface por Curve 
365
        Curve curve = (Curve) manager.create(TYPES.CURVE, SUBTYPES.GEOM2D); 
366
        curve.setGeneralPath(gp); 
367
        return curve; 
368
        }
369

    
370
        /**
371
         *  Creates a <code>LinearRing</code> using the next token in the stream.
372
         *
373
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
374
         *      format. The next tokens must form a &lt;LineString Text&gt;.
375
         *@return                  a <code>LinearRing</code> specified by the next
376
         *      token in the stream
377
         *@throws  IOException     if an I/O error occurs
378
         *@throws  ParseException  if the coordinates used to create the <code>LinearRing</code>
379
         *      do not form a closed linestring, or if an unexpected token was
380
         *      encountered
381
         * @throws IllegalAccessException 
382
         * @throws InstantiationException 
383
         * @throws CreateGeometryException 
384
         */
385
        private Geometry readLinearRingText(StreamTokenizer tokenizer)
386
        throws IOException, ParseException, CreateGeometryException
387
        {
388
                Coordinate[] arrayC = getCoordinates(tokenizer);
389
                GeneralPathX gp = new GeneralPathX();
390
                gp.moveTo(arrayC[0].x, arrayC[0].y);
391
                for (int i=1;i < arrayC.length; i++)
392
                {
393
                        gp.lineTo(arrayC[i].x, arrayC[i].y);
394
                }
395
                Surface surface = (Surface)manager.create(TYPES.SURFACE, SUBTYPES.GEOM2D);
396
                surface.setGeneralPath(gp);
397
                return surface;
398
        }
399

    
400
        /**
401
         *  Creates a <code>MultiPoint</code> using the next token in the stream.
402
         *
403
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
404
         *      format. The next tokens must form a &lt;MultiPoint Text&gt;.
405
         *@return                  a <code>MultiPoint</code> specified by the next
406
         *      token in the stream
407
         *@throws  IOException     if an I/O error occurs
408
         *@throws  ParseException  if an unexpected token was encountered
409
         * @throws IllegalAccessException 
410
         * @throws InstantiationException 
411
         * @throws CreateGeometryException 
412
         */
413
        private Geometry readMultiPointText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
414
                Coordinate[] coords = getCoordinates(tokenizer);
415
                MultiPoint multiPoint = (MultiPoint)manager.create(TYPES.MULTIPOINT, SUBTYPES.GEOM2D);
416
                for (int i=0; i < coords.length; i++)
417
                {
418
                        Point point = (Point)manager.create(TYPES.POINT, SUBTYPES.GEOM2D);
419
                        point.setX(coords[i].x);
420
                        point.setY(coords[i].y);
421
                        multiPoint.addPoint(point);
422
                }   
423

    
424
                return multiPoint;
425
        }
426

    
427

    
428
        /**
429
         *  Creates a <code>Polygon</code> using the next token in the stream.
430
         *
431
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
432
         *      format. The next tokens must form a &lt;Polygon Text&gt;.
433
         *@return                  a <code>Polygon</code> specified by the next token
434
         *      in the stream
435
         *@throws  ParseException  if the coordinates used to create the <code>Polygon</code>
436
         *      shell and holes do not form closed linestrings, or if an unexpected
437
         *      token was encountered.
438
         *@throws  IOException     if an I/O error occurs
439
         * @throws IllegalAccessException 
440
         * @throws InstantiationException 
441
         * @throws CreateGeometryException 
442
         */
443
        private Geometry readPolygonText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
444
                String nextToken = getNextEmptyOrOpener(tokenizer);
445
                if (nextToken.equals("EMPTY")) {
446
                        return null;
447
                }
448
                ArrayList holes = new ArrayList();
449
                Geometry shell = readLinearRingText(tokenizer);
450
                nextToken = getNextCloserOrComma(tokenizer);
451
                while (nextToken.equals(",")) {
452
                        Geometry hole = readLinearRingText(tokenizer);
453
                        holes.add(hole);
454
                        nextToken = getNextCloserOrComma(tokenizer);
455
                }
456
                // LinearRing[] array = new LinearRing[holes.size()];
457
                return shell; //geometryFactory.createPolygon(shell, (LinearRing[]) holes.toArray(array));
458
        }
459

    
460
        /**
461
         *  Creates a <code>MultiLineString</code> using the next token in the stream.
462
         *
463
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
464
         *      format. The next tokens must form a &lt;MultiLineString Text&gt;.
465
         *@return                  a <code>MultiLineString</code> specified by the
466
         *      next token in the stream
467
         *@throws  IOException     if an I/O error occurs
468
         *@throws  ParseException  if an unexpected token was encountered
469
         * @throws IllegalAccessException 
470
         * @throws InstantiationException 
471
         * @throws CreateGeometryException 
472
         */
473
        private Geometry readMultiLineStringText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
474
                // TODO: HACER ESTO BIEN, CON UN GENERAL PATH
475
                String nextToken = getNextEmptyOrOpener(tokenizer);
476
                if (nextToken.equals("EMPTY")) {
477
                        return null;
478
                }
479
                ArrayList lineStrings = new ArrayList();
480
                Geometry lineString = readLineStringText(tokenizer);
481
                lineStrings.add(lineString);
482
                nextToken = getNextCloserOrComma(tokenizer);
483
                while (nextToken.equals(",")) {
484
                        lineString = readLineStringText(tokenizer);
485
                        lineStrings.add(lineString);
486
                        nextToken = getNextCloserOrComma(tokenizer);
487
                } 
488
                // LineString[] array = new LineString[lineStrings.size()];
489
                return lineString; // geometryFactory.createMultiLineString((LineString[]) lineStrings.toArray(array));
490
        }
491

    
492
        /**
493
         *  Creates a <code>MultiPolygon</code> using the next token in the stream.
494
         *
495
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
496
         *      format. The next tokens must form a &lt;MultiPolygon Text&gt;.
497
         *@return                  a <code>MultiPolygon</code> specified by the next
498
         *      token in the stream, or if if the coordinates used to create the
499
         *      <code>Polygon</code> shells and holes do not form closed linestrings.
500
         *@throws  IOException     if an I/O error occurs
501
         *@throws  ParseException  if an unexpected token was encountered
502
         * @throws CreateGeometryException 
503
         */
504
        // TODO:
505
        private Geometry readMultiPolygonText(StreamTokenizer tokenizer) throws IOException, ParseException, CreateGeometryException {
506
                String nextToken = getNextEmptyOrOpener(tokenizer);
507
                if (nextToken.equals("EMPTY")) {
508
                        return null;
509
                }
510
                ArrayList polygons = new ArrayList();
511
                Geometry polygon = readPolygonText(tokenizer);
512
                /* polygons.add(polygon);
513
    nextToken = getNextCloserOrComma(tokenizer);
514
    while (nextToken.equals(",")) {
515
      polygon = readPolygonText(tokenizer);
516
      polygons.add(polygon);
517
      nextToken = getNextCloserOrComma(tokenizer);
518
    } */
519
                // Polygon[] array = new Polygon[polygons.size()];
520
                return polygon; //geometryFactory.createMultiPolygon((Polygon[]) polygons.toArray(array));
521
        } 
522

    
523
        /**
524
         *  Creates a <code>GeometryCollection</code> using the next token in the
525
         *  stream.
526
         *
527
         *@param  tokenizer        tokenizer over a stream of text in Well-known Text
528
         *      format. The next tokens must form a &lt;GeometryCollection Text&gt;.
529
         *@return                  a <code>GeometryCollection</code> specified by the
530
         *      next token in the stream
531
         *@throws  ParseException  if the coordinates used to create a <code>Polygon</code>
532
         *      shell and holes do not form closed linestrings, or if an unexpected
533
         *      token was encountered
534
         *@throws  IOException     if an I/O error occurs
535
         */
536
        // TODO:
537
        /* private GeometryCollection readGeometryCollectionText(StreamTokenizer tokenizer) throws IOException, ParseException {
538
    String nextToken = getNextEmptyOrOpener(tokenizer);
539
    if (nextToken.equals("EMPTY")) {
540
      return geometryFactory.createGeometryCollection(new Geometry[]{});
541
    }
542
    ArrayList geometries = new ArrayList();
543
    Geometry geometry = readGeometryTaggedText(tokenizer);
544
    geometries.add(geometry);
545
    nextToken = getNextCloserOrComma(tokenizer);
546
    while (nextToken.equals(",")) {
547
      geometry = readGeometryTaggedText(tokenizer);
548
      geometries.add(geometry);
549
      nextToken = getNextCloserOrComma(tokenizer);
550
    }
551
    Geometry[] array = new Geometry[geometries.size()];
552
    return geometryFactory.createGeometryCollection((Geometry[]) geometries.toArray(array));
553
  } */
554
}
555