Statistics
| Revision:

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 / gml / GeometryStrategies.java @ 47632

History | View | Annotate | Download (16.9 KB)

1
/*
2
 * The JTS Topology Suite is a collection of Java classes that
3
 * implement the fundamental operations required to validate a given
4
 * geo-spatial data set to a known topological specification.
5
 *
6
 * Copyright (C) 2001 Vivid Solutions
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
 *
22
 * For more information, contact:
23
 *
24
 *     Vivid Solutions
25
 *     Suite #1A
26
 *     2328 Government Street
27
 *     Victoria BC  V8T 5G5
28
 *     Canada
29
 *
30
 *     (250)385-6040
31
 *     www.vividsolutions.com
32
 */
33
package org.gvsig.fmap.geom.jts.gml;
34

    
35
import java.util.*;
36
import java.util.regex.Pattern;
37

    
38
import org.xml.sax.Attributes;
39
import org.xml.sax.SAXException;
40

    
41
import com.vividsolutions.jts.geom.*;
42
import com.vividsolutions.jts.io.gml2.GMLConstants;
43
import com.vividsolutions.jts.util.StringUtil;
44
import org.apache.commons.lang3.StringUtils;
45
import org.gvsig.fmap.geom.jts.gml.GMLHandler.Handler;
46

    
47
/**
48
 * Container for GML2 Geometry parsing strategies which can be represented in JTS.
49
 *
50
 * @author David Zwiers, Vivid Solutions.
51
 */
52
public class GeometryStrategies{
53

    
54
        /**
55
         * This set of strategies is not expected to be used directly outside of this distribution.
56
         * 
57
         * The implementation of this class are intended to be used as static function points in C. These strategies should be associated with an element when the element begins. The strategy is utilized at the end of the element to create an object of value to the user. 
58
         * 
59
         * In this case all the objects are either java.lang.* or JTS Geometry objects
60
         *
61
         * @author David Zwiers, Vivid Solutions.
62
         */
63
        static interface ParseStrategy{
64
                /**
65
                 * @param arg Value to interpret
66
                 * @param gf GeometryFactory
67
                 * @return The interpreted value
68
                 * @throws SAXException 
69
                 */
70
                Object parse(Handler arg, GeometryFactory gf) throws SAXException;
71
        }
72
        
73
        private static HashMap strategies = loadStrategies();
74
        private static HashMap loadStrategies(){
75
                HashMap strats = new HashMap();
76
                loadStrategies(strats);
77
                GeometryStrategiesGML3.loadStrategies(strats);
78
                return strats;
79
            
80
        }
81
        
82
        private static HashMap loadStrategies(HashMap strats){
83
                
84
                // point
85
                strats.put(GMLConstants.GML_POINT.toLowerCase(),new ParseStrategy(){
86

    
87
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
88
                                // one child, either a coord
89
                                // or a coordinate sequence
90
                                
91
                                if(arg.children.size()!=1)
92
                                        throw new SAXException("Cannot create a point without exactly one coordinate");
93

    
94
                                int srid = getSrid(arg.attrs,gf.getSRID());
95

    
96
                                Object c = arg.children.get(0);
97
                                Point p = null;
98
                                if(c instanceof Coordinate){
99
                                        p = gf.createPoint((Coordinate)c);
100
                                }else{
101
                                        p = gf.createPoint((CoordinateSequence)c);
102
                                }
103
                                if(p.getSRID()!=srid)
104
                                        p.setSRID(srid);
105
                                
106
                                return p;
107
                        }
108
                });
109
                
110
                // linestring
111
                strats.put(GMLConstants.GML_LINESTRING.toLowerCase(),new ParseStrategy(){
112

    
113
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
114
                                // one child, either a coord
115
                                // or a coordinate sequence
116
                                
117
                                if(arg.children.size()<1)
118
                                        throw new SAXException("Cannot create a linestring without atleast two coordinates or one coordinate sequence");
119

    
120
                                int srid = getSrid(arg.attrs,gf.getSRID());
121
                                
122
                                LineString ls = null;
123
                                if(arg.children.size() == 1){
124
                                        // coord set
125
                                        try{
126
                                                CoordinateSequence cs = (CoordinateSequence) arg.children.get(0);
127
                                                ls = gf.createLineString(cs);
128
                                        }catch(ClassCastException e){
129
                                                throw new SAXException("Cannot create a linestring without atleast two coordinates or one coordinate sequence",e);
130
                                        }
131
                                }else{
132
                                        try{
133
                                                Coordinate[] coords = (Coordinate[]) arg.children.toArray(new Coordinate[arg.children.size()]);
134
                                                ls = gf.createLineString(coords);
135
                                        }catch(ClassCastException e){
136
                                                throw new SAXException("Cannot create a linestring without atleast two coordinates or one coordinate sequence",e);
137
                                        }
138
                                }
139
                                
140
                                if(ls.getSRID()!=srid)
141
                                        ls.setSRID(srid);
142
                                
143
                                return ls;
144
                        }
145
                });
146
                
147
                // linearring
148
                strats.put(GMLConstants.GML_LINEARRING.toLowerCase(),new ParseStrategy(){
149

    
150
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
151
                                // one child, either a coord
152
                                // or a coordinate sequence
153
                                
154
                                if(arg.children.size()!=1 && arg.children.size()<4)
155
                                        throw new SAXException("Cannot create a linear ring without atleast four coordinates or one coordinate sequence");
156

    
157
                                int srid = getSrid(arg.attrs,gf.getSRID());
158
                                
159
                                LinearRing ls = null;
160
                                if(arg.children.size() == 1){
161
                                        // coord set
162
                                        try{
163
                                                CoordinateSequence cs = (CoordinateSequence) arg.children.get(0);
164
                                                ls = gf.createLinearRing(cs);
165
                                        }catch(ClassCastException e){
166
                                                throw new SAXException("Cannot create a linear ring without atleast four coordinates or one coordinate sequence",e);
167
                                        }
168
                                }else{
169
                                        try{
170
                                                Coordinate[] coords = (Coordinate[]) arg.children.toArray(new Coordinate[arg.children.size()]);
171
                                                ls = gf.createLinearRing(coords);
172
                                        }catch(ClassCastException e){
173
                                                throw new SAXException("Cannot create a linear ring without atleast four coordinates or one coordinate sequence",e);
174
                                        }
175
                                }
176
                                
177
                                if(ls.getSRID()!=srid)
178
                                        ls.setSRID(srid);
179
                                
180
                                return ls;
181
                        }
182
                });
183
                
184
                // polygon
185
                strats.put(GMLConstants.GML_POLYGON.toLowerCase(),new ParseStrategy(){
186

    
187
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
188
                                // one child, either a coord
189
                                // or a coordinate sequence
190
                                
191
                                if(arg.children.size()<1)
192
                                        throw new SAXException("Cannot create a polygon without atleast one linear ring");
193

    
194
                                int srid = getSrid(arg.attrs,gf.getSRID());
195
                                
196
                                LinearRing outer = (LinearRing) arg.children.get(0); // will be the first
197
                                List t = arg.children.size()>1?arg.children.subList(1,arg.children.size()):null;
198
                                LinearRing[] inner = t==null?null:(LinearRing[]) t.toArray(new LinearRing[t.size()]);
199
                                
200
                                Polygon p = gf.createPolygon(outer,inner);
201
                                
202
                                if(p.getSRID()!=srid)
203
                                        p.setSRID(srid);
204
                                
205
                                return p;
206
                        }
207
                });
208
                
209
                // box
210
                strats.put(GMLConstants.GML_BOX.toLowerCase(),new ParseStrategy(){
211

    
212
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
213
                                // one child, either a coord
214
                                // or a coordinate sequence
215
                                
216
                                if(arg.children.size()<1 || arg.children.size()>2)
217
                                        throw new SAXException("Cannot create a box without either two coords or one coordinate sequence");
218

    
219
//                                int srid = getSrid(arg.attrs,gf.getSRID());
220
                                
221
                                Envelope box = null;
222
                                if(arg.children.size() == 1){
223
                                        CoordinateSequence cs = (CoordinateSequence) arg.children.get(0);
224
                                        box = cs.expandEnvelope(new Envelope());
225
                                }else{
226
                                        box = new Envelope((Coordinate)arg.children.get(0),(Coordinate)arg.children.get(1));
227
                                }
228
                                
229
                                return box;
230
                        }
231
                });
232
                
233
                // multi-point
234
                strats.put(GMLConstants.GML_MULTI_POINT.toLowerCase(),new ParseStrategy(){
235

    
236
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
237
                                // one child, either a coord
238
                                // or a coordinate sequence
239
                                
240
                                if(arg.children.size()<1)
241
                                        throw new SAXException("Cannot create a multi-point without atleast one point");
242

    
243
                                int srid = getSrid(arg.attrs,gf.getSRID());
244
                                
245
                                Point[] pts = (Point[]) arg.children.toArray(new Point[arg.children.size()]);
246
                                
247
                                MultiPoint mp = gf.createMultiPoint(pts);
248
                                
249
                                if(mp.getSRID()!=srid)
250
                                        mp.setSRID(srid);
251
                                
252
                                return mp;
253
                        }
254
                });
255
                
256
                // multi-linestring
257
                strats.put(GMLConstants.GML_MULTI_LINESTRING.toLowerCase(),new ParseStrategy(){
258

    
259
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
260
                                // one child, either a coord
261
                                // or a coordinate sequence
262
                                
263
                                if(arg.children.size()<1)
264
                                        throw new SAXException("Cannot create a multi-linestring without atleast one linestring");
265

    
266
                                int srid = getSrid(arg.attrs,gf.getSRID());
267
                                
268
                                LineString[] lns = (LineString[]) arg.children.toArray(new LineString[arg.children.size()]);
269
                                
270
                                MultiLineString mp = gf.createMultiLineString(lns);
271
                                
272
                                if(mp.getSRID()!=srid)
273
                                        mp.setSRID(srid);
274
                                
275
                                return mp;
276
                        }
277
                });
278
                
279
                // multi-poly
280
                strats.put(GMLConstants.GML_MULTI_POLYGON.toLowerCase(),new ParseStrategy(){
281

    
282
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
283
                                // one child, either a coord
284
                                // or a coordinate sequence
285
                                
286
                                if(arg.children.size()<1)
287
                                        throw new SAXException("Cannot create a multi-polygon without atleast one polygon");
288

    
289
                                int srid = getSrid(arg.attrs,gf.getSRID());
290
                                
291
                                Polygon[] plys = (Polygon[]) arg.children.toArray(new Polygon[arg.children.size()]);
292
                                
293
                                MultiPolygon mp = gf.createMultiPolygon(plys);
294
                                
295
                                if(mp.getSRID()!=srid)
296
                                        mp.setSRID(srid);
297
                                
298
                                return mp;
299
                        }
300
                });
301
                
302
                // multi-geom
303
                strats.put(GMLConstants.GML_MULTI_GEOMETRY.toLowerCase(),new ParseStrategy(){
304

    
305
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
306
                                // one child, either a coord
307
                                // or a coordinate sequence
308
                                
309
                                if(arg.children.size()<1)
310
                                        throw new SAXException("Cannot create a multi-polygon without atleast one geometry");
311
                                
312
                                Geometry[] geoms = (Geometry[]) arg.children.toArray(new Geometry[arg.children.size()]);
313
                                
314
                                GeometryCollection gc = gf.createGeometryCollection(geoms);
315
                                                                
316
                                return gc;
317
                        }
318
                });
319
                
320
                // coordinates
321
                strats.put(GMLConstants.GML_COORDINATES.toLowerCase(),new ParseStrategy(){
322

    
323
                        private WeakHashMap patterns = new WeakHashMap();
324
                        
325
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
326
                                // one child, either a coord
327
                                // or a coordinate sequence
328

    
329
                                if(arg.text == null || "".equals(arg.text))
330
                                        throw new SAXException("Cannot create a coordinate sequence without text to parse");
331
                                
332
                                String decimal = ".";
333
                                String coordSeperator = ",";
334
                                String toupleSeperator = " ";
335
                                
336
                                // get overides from coordinates
337
                                if(arg.attrs.getIndex("decimal")>=0)
338
                                        decimal = arg.attrs.getValue("decimal");
339
                                else if(arg.attrs.getIndex(GMLConstants.GML_NAMESPACE,"decimal")>=0)
340
                                        decimal = arg.attrs.getValue(GMLConstants.GML_NAMESPACE,"decimal");
341

    
342
                                if(arg.attrs.getIndex("cs")>=0)
343
                                        coordSeperator = arg.attrs.getValue("cs");
344
                                else if(arg.attrs.getIndex(GMLConstants.GML_NAMESPACE,"cs")>=0)
345
                                        coordSeperator = arg.attrs.getValue(GMLConstants.GML_NAMESPACE,"cs");
346

    
347
                                if(arg.attrs.getIndex("ts")>=0)
348
                                        toupleSeperator = arg.attrs.getValue("ts");
349
                                else if(arg.attrs.getIndex(GMLConstants.GML_NAMESPACE,"ts")>=0)
350
                                        toupleSeperator = arg.attrs.getValue(GMLConstants.GML_NAMESPACE,"ts");
351
                                
352
                                // now to start parse
353
                                String t = arg.text.toString();
354
                                t = t.replaceAll("\\s"," ");
355
                                
356
                                Pattern ptn = (Pattern) patterns.get(toupleSeperator);
357
                                if(ptn == null){
358
                                        String ts = new String(toupleSeperator);
359
                                        if(ts.indexOf('\\')>-1){
360
                                                        // need to escape it
361
                                                        ts = ts.replaceAll("\\","\\\\");
362
                                        }
363
                                        if(ts.indexOf('.')>-1){
364
                                                // need to escape it
365
                                                ts = ts.replaceAll("\\.","\\\\.");
366
                                        }
367
                                        ptn = Pattern.compile(ts);
368
                                        patterns.put(toupleSeperator,ptn);
369
                                }
370
                                String[] touples = ptn.split(t.trim());//  t.trim().split(toupleSeperator);
371
                                
372
                                if(touples.length == 0)
373
                                        throw new SAXException("Cannot create a coordinate sequence without a touple to parse");
374
                                
375
                                // we may have null touples, so calculate the num first
376
                                int numNonNullTouples = 0;
377
                                for(int i=0;i<touples.length;i++){
378
                                        if(touples[i] !=null && !"".equals(touples[i].trim())){
379
                                                if(i!=numNonNullTouples){
380
                                                        touples[numNonNullTouples] = touples[i]; // always shift left
381
                                                }
382
                                                numNonNullTouples++;
383
                                        }
384
                                }
385
                                for(int i=numNonNullTouples;i<touples.length;i++)
386
                                        touples[i] = null;
387
                                
388
                                // null touples now at end of array
389
                                if(numNonNullTouples == 0)
390
                                        throw new SAXException("Cannot create a coordinate sequence without a non-null touple to parse");
391
                                
392
                                int dim = StringUtil.split(touples[0], coordSeperator).length;
393
                                CoordinateSequence cs = gf.getCoordinateSequenceFactory().create(numNonNullTouples,dim);
394
                                dim = cs.getDimension(); // max dim
395
                                
396
                                boolean replaceDec = !".".equals(decimal);
397
                                
398
                                for(int i=0;i<numNonNullTouples;i++){
399
                                        // for each touple, split, parse, add
400

    
401
                                        ptn = (Pattern) patterns.get(coordSeperator);
402
                                        if(ptn == null){
403
                                                String ts = new String(coordSeperator);
404
                                                if(ts.indexOf('\\')>-1){
405
                                                                // need to escape it
406
                                                        ts = ts.replaceAll("\\","\\\\");
407
                                                }
408
                                                if(ts.indexOf('.')>-1){
409
                                                        // need to escape it
410
                                                        ts = ts.replaceAll("\\.","\\\\.");
411
                                                }
412
                                                ptn = Pattern.compile(ts);
413
                                                patterns.put(coordSeperator,ptn);
414
                                        }
415
                                        String[] coords = ptn.split(touples[i]);//  touples[i].split(coordSeperator);
416
                                        
417
                                        int dimIndex = 0;
418
                                        for(int j=0;j<coords.length && j<dim;j++){
419
                                                if(coords[j] != null && !"".equals(coords[j].trim())){
420
                                                        double ordinate = Double.parseDouble(replaceDec?coords[j].replaceAll(decimal,"."):coords[j]);
421
                                                        cs.setOrdinate(i,dimIndex++,ordinate);
422
                                                }
423
                                        }
424
                                                // fill remaining dim
425
                                        for(;dimIndex<dim;)cs.setOrdinate(i,dimIndex++,Double.NaN);
426
                                }
427
                                
428
                                return cs;
429
                        }
430
                });
431
                
432
                // coord
433
                strats.put(GMLConstants.GML_COORD.toLowerCase(),new ParseStrategy(){
434

    
435
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
436
                                // one child, either a coord
437
                                // or a coordinate sequence
438

    
439
                                if(arg.children.size()<1)
440
                                        throw new SAXException("Cannot create a coordinate without atleast one axis");
441
                                if(arg.children.size()>3)
442
                                        throw new SAXException("Cannot create a coordinate with more than 3 axis");
443
                                
444
                                Double[] axis = (Double[]) arg.children.toArray(new Double[arg.children.size()]);
445
                                Coordinate c = new Coordinate();
446
                                c.x = axis[0].doubleValue();
447
                                if(axis.length>1)
448
                                        c.y = axis[1].doubleValue();
449
                                if(axis.length>2)
450
                                        c.z = axis[2].doubleValue();
451
                                
452
                                return c;
453
                        }
454
                });
455
                
456
                ParseStrategy coord_child = new ParseStrategy(){
457

    
458
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
459
                                if(arg.text == null)
460
                                        return null;
461
                                return new Double((arg.text.toString()));
462
                        }
463
                };
464
                
465
                // coord-x
466
                strats.put(GMLConstants.GML_COORD_X.toLowerCase(),coord_child);
467
                
468
                // coord-y
469
                strats.put(GMLConstants.GML_COORD_Y.toLowerCase(),coord_child);
470
                
471
                // coord-z
472
                strats.put(GMLConstants.GML_COORD_Z.toLowerCase(),coord_child);
473
                
474
                ParseStrategy member = new ParseStrategy(){
475

    
476
                        public Object parse(Handler arg, GeometryFactory gf) throws SAXException {
477
                                if(arg.children.size()!=1)
478
                                        throw new SAXException("Geometry Members may only contain one geometry.");
479
                                
480
                                // type checking will occur in the parent geom collection.
481
                                // may wish to add this in the future
482
                                
483
                                return arg.children.get(0);
484
                        }
485
                };
486
                // outerBoundary - linear ring member
487
                strats.put(GMLConstants.GML_OUTER_BOUNDARY_IS.toLowerCase(),member);
488
                
489
                // innerBoundary - linear ring member
490
                strats.put(GMLConstants.GML_INNER_BOUNDARY_IS.toLowerCase(),member);
491
                
492
                // point member
493
                strats.put(GMLConstants.GML_POINT_MEMBER.toLowerCase(),member);
494
                
495
                // line string member
496
                strats.put(GMLConstants.GML_LINESTRING_MEMBER.toLowerCase(),member);
497
                
498
                // polygon member
499
                strats.put(GMLConstants.GML_POLYGON_MEMBER.toLowerCase(),member);
500
                
501
                return strats;
502
        }
503
        
504
        
505
        static int getSrid(Attributes attrs, int defaultValue){
506
                String srs = null;
507
                if(attrs.getIndex(GMLConstants.GML_ATTR_SRSNAME)>=0)
508
                        srs = attrs.getValue(GMLConstants.GML_ATTR_SRSNAME);
509
                else if(attrs.getIndex(GMLConstants.GML_NAMESPACE,GMLConstants.GML_ATTR_SRSNAME)>=0)
510
                        srs = attrs.getValue(GMLConstants.GML_NAMESPACE,GMLConstants.GML_ATTR_SRSNAME);
511
                
512
                if(srs != null){
513
                        srs = srs.trim();
514
                        if(srs != null && !"".equals(srs)){
515
                                try{
516
                                        return Integer.parseInt(srs);
517
                                }catch(NumberFormatException e){
518
                                        // rip out the end, uri's are used here sometimes
519
                                        int index = srs.lastIndexOf('#');
520
                                        if(index > -1)
521
                                                srs = srs.substring(index);
522
                                        try{
523
                                                return Integer.parseInt(srs);
524
                                        }catch(NumberFormatException e2){
525
                                                // ignore
526
                                        }
527
                                }
528
                        }
529
                }
530
                
531
                return defaultValue;
532
        }
533
        
534
        /**
535
         * @param uri Not currently used, included for future work
536
         * @param localName Used to look up an appropriate parse strategy
537
         * @return The ParseStrategy which should be employed
538
         * 
539
         * @see ParseStrategy
540
         */
541
        public static ParseStrategy findStrategy(String uri,String localName){
542
                return localName == null?null:(ParseStrategy) strategies.get(localName.toLowerCase());
543
        }
544
}