Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_geometries / src / org / gvsig / fmap / geom / operation / fromwkb / WKBParser3.java @ 40415

History | View | Annotate | Download (13.7 KB)

1
/*
2
 * WKBParser.java
3
 * Based in
4
 * PostGIS extension for PostgreSQL JDBC driver - Binary Parser
5
 *
6
 * NOTA: Es posible que lo mejor sea crear un PostGisGeometry que implemente
7
 * la interfaz IGeometry, y as? nos sirve de base para tener IGeometries
8
 * que encapsulan otras posibles geometr?as. Por ejemplo, un JTSGeometry.
9
 * De esta forma, un driver no necesitar?a reescribirse.
10
 *
11
 * (C) 2005 Markus Schaber, schabios@logi-track.com
12
 *
13
 * This library is free software; you can redistribute it and/or modify it under
14
 * the terms of the GNU Lesser General Public License as published by the Free
15
 * Software Foundation, either version 2.1 of the License.
16
 *
17
 * This library is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Lesser General Public License
23
 * along with this library; if not, write to the Free Software Foundation, Inc.,
24
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at
25
 * http://www.gnu.org.
26
 *
27
 * $Id: WKBParser2.java 24154 2008-10-21 10:01:05Z jpiera $
28
 */
29
package org.gvsig.fmap.geom.operation.fromwkb;
30

    
31
import java.nio.ByteBuffer;
32
import java.nio.ByteOrder;
33

    
34
import org.gvsig.fmap.geom.Geometry;
35
import org.gvsig.fmap.geom.GeometryLocator;
36
import org.gvsig.fmap.geom.GeometryManager;
37
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
38
import org.gvsig.fmap.geom.Geometry.TYPES;
39
import org.gvsig.fmap.geom.aggregate.MultiPoint;
40
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
41
import org.gvsig.fmap.geom.aggregate.MultiSurface;
42
import org.gvsig.fmap.geom.exception.CreateGeometryException;
43
import org.gvsig.fmap.geom.primitive.Curve;
44
import org.gvsig.fmap.geom.primitive.OrientablePrimitive;
45
import org.gvsig.fmap.geom.primitive.Point;
46
import org.gvsig.fmap.geom.primitive.Primitive;
47
import org.gvsig.fmap.geom.primitive.Surface;
48
import org.gvsig.fmap.geom.primitive.impl.Point2D;
49
import org.gvsig.fmap.geom.type.GeometryType;
50
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
51
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
52
import org.slf4j.Logger;
53
import org.slf4j.LoggerFactory;
54

    
55
import com.vividsolutions.jts.io.WKBConstants;
56

    
57
/**
58
 * Parse binary representation of geometries. Currently, only text rep (hexed)
59
 * implementation is tested.
60
 * 
61
 * It should be easy to add char[] and CharSequence ByteGetter instances,
62
 * although the latter one is not compatible with older jdks.
63
 * 
64
 * I did not implement real unsigned 32-bit integers or emulate them with long,
65
 * as both java Arrays and Strings currently can have only 2^31-1 elements
66
 * (bytes), so we cannot even get or build Geometries with more than approx.
67
 * 2^28 coordinates (8 bytes each).
68
 * 
69
 * @author markus.schaber@logi-track.com
70
 * 
71
 */
72
// jomarlla
73
// Read 3D and build 3D geometries using gvSIG objects.
74
// XY, XYZ and XYM supported.
75
// MultiPoint2DM is not supported by gvSIG.
76
// When gvSIg edit a polygon it makes the polygon 2d, so the update
77
// operations will just write 2d geometries even though the postgis
78
// driver is ready for writing 3D geometries.
79

    
80
public class WKBParser3 {
81

    
82
        private boolean gHaveM, gHaveZ, gHaveS; // M, Z y SRID
83

    
84
        private static final Logger LOG = LoggerFactory.getLogger(WKBParser2.class);
85
        private GeometryManager geomManager = GeometryLocator.getGeometryManager();
86
        private GeometryType[] pointGeometryTypes;
87

    
88
        /**
89
         * @throws GeometryTypeNotValidException
90
         * @throws GeometryTypeNotSupportedException
91
         * 
92
         */
93
        public WKBParser3() {
94
                pointGeometryTypes =
95
                        new GeometryType[] {
96
                                loadPointGeometryType(Geometry.SUBTYPES.GEOM2D, "2D"),
97
                                loadPointGeometryType(Geometry.SUBTYPES.GEOM3D, "3D"),
98
                                loadPointGeometryType(Geometry.SUBTYPES.GEOM2DM, "2DM"),
99
                                loadPointGeometryType(Geometry.SUBTYPES.GEOM3DM, "3DM") };
100
        }
101

    
102
        private GeometryType loadPointGeometryType(int subtype, String subTypeName) {
103
                try {
104
                        return geomManager.getGeometryType(Geometry.TYPES.POINT, subtype);
105
                } catch (Exception e) {
106
                        LOG.warn("Unable to get a reference to the geometry "
107
                                        + "type Point{}, to be cached", subTypeName);
108
                        return null;
109
                }
110
        }
111

    
112
        /**
113
         * Parse a binary encoded geometry.
114
         * 
115
         * Is synchronized to protect offset counter. (Unfortunately, Java does not
116
         * have neither call by reference nor multiple return values.)
117
         * @throws CreateGeometryException 
118
         */
119
        public synchronized Geometry parse(byte[] value) throws CreateGeometryException {
120
                // BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value);
121
                ByteBuffer buf = ByteBuffer.wrap(value);
122
                return parseGeometry(buf);
123
        }
124

    
125

    
126
        /** Parse a geometry starting at offset. 
127
         * @throws CreateGeometryException */
128
        protected Geometry parseGeometry(ByteBuffer data) throws CreateGeometryException {
129
                int realtype = parseTypeAndSRID(data);
130

    
131
                Geometry result1 = null;
132
                switch (realtype) {
133
                case WKBConstants.wkbPoint:
134
                        result1 = parsePoint(data, gHaveZ, gHaveM);
135
                        break;
136
                case WKBConstants.wkbLineString:
137
                        result1 = parseLineString(data, gHaveZ, gHaveM);
138
                        break;
139
                case WKBConstants.wkbPolygon:
140
                        result1 = parsePolygon(data, gHaveZ, gHaveM);
141
                        break;
142
                case WKBConstants.wkbMultiPoint:
143
                        result1 = parseMultiPoint(data);
144
                        break;
145
                case WKBConstants.wkbMultiLineString:
146
                        result1 = parseMultiLineString(data);
147
                        return result1;
148
                case WKBConstants.wkbMultiPolygon:
149
                        result1 = parseMultiPolygon(data);
150
                        break;
151
                case WKBConstants.wkbGeometryCollection:
152
                        result1 = parseCollection(data);
153
                        break;
154
                default:
155
                        //throw new IllegalArgumentException("Unknown Geometry Type!");
156
                }
157

    
158
                return result1;
159
        }
160

    
161
        protected int parseTypeAndSRID(ByteBuffer data) {
162
                byte endian = data.get(); // skip and test endian flag
163
                if (endian == 1) {
164
                        data.order(ByteOrder.LITTLE_ENDIAN);
165
                }
166
                int typeword = data.getInt();
167

    
168
                int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits
169

    
170
                gHaveZ = (typeword & 0x80000000) != 0;
171
                gHaveM = (typeword & 0x40000000) != 0;
172
                gHaveS = (typeword & 0x20000000) != 0;
173
                
174
                // not used
175
                int srid = -1;
176

    
177
                if (gHaveS) {
178
                        srid = data.getInt();
179
                }
180

    
181
                return realtype;
182

    
183
        }
184

    
185
        private Point parsePoint(ByteBuffer data, boolean haveZ, boolean haveM) 
186
        throws CreateGeometryException {
187
                double x = data.getDouble();
188
                double y = data.getDouble();
189
                Point point;
190

    
191
                int subtype = getSubType(haveZ, haveM);
192

    
193
                // If we have a cached GeometryType use it, otherwise call the manager
194
                point = (Point) (pointGeometryTypes[subtype] == null ? geomManager.create(
195
                                Geometry.TYPES.POINT, subtype) : pointGeometryTypes[subtype].create());
196
                point.setX(x);
197
                point.setY(y);
198

    
199
                // Other dimensions
200
                if (haveZ) {
201
                        point.setCoordinateAt(Geometry.DIMENSIONS.Z, data.getDouble());
202
                        if (haveM) {
203
                                /*point.setCoordinateAt(Geometry.DIMENSIONS.Z + 1,
204
                                                data.getDouble());*/
205
                                data.getDouble();
206
                        }
207
                } else {
208
                        if (haveM) {
209
                                /*point.setCoordinateAt(Geometry.DIMENSIONS.Y + 1,
210
                                                data.getDouble());*/
211
                                data.getDouble();
212
                        }
213
                }
214

    
215
                return point;
216
        }
217

    
218
        /**
219
         * @param haveZ
220
         * @param haveM
221
         * @return
222
         */
223
        private int getSubType(boolean haveZ, boolean haveM) {
224
                /*int subtype =
225
                        haveZ ? (haveM ? Geometry.SUBTYPES.GEOM3DM
226
                                        : Geometry.SUBTYPES.GEOM3D) : (haveM
227
                                                        ? Geometry.SUBTYPES.GEOM2DM : Geometry.SUBTYPES.GEOM2D);*/
228
                //TODO: No hay soporte para M
229
                int subtype = haveZ ? Geometry.SUBTYPES.GEOM3D : Geometry.SUBTYPES.GEOM2D;
230
                return subtype;
231
        }
232

    
233
        private Curve parseMultiLineString(ByteBuffer data) throws CreateGeometryException {
234
                Curve curve = (Curve) geomManager.create(TYPES.CURVE, getSubType(gHaveZ, gHaveM));
235
                fillOrientablePrimitive(data, curve);
236
                return curve;
237
        }
238

    
239
        /**
240
         * @param data
241
         * @return
242
         * @throws CreateGeometryException
243
         */
244
        private void fillOrientablePrimitive(ByteBuffer data, OrientablePrimitive orientablePrimitive)
245
        throws CreateGeometryException {
246
                int count = data.getInt();
247

    
248
                for (int i=0; i < count; i++)
249
                {
250
                        parseTypeAndSRID(data);
251
                        Point[] points = parsePointArray(data, gHaveZ, gHaveM);
252

    
253
                        orientablePrimitive.addMoveToVertex(points[0]);
254
                        for (int j = 1; j < points.length; j++) {
255
                                orientablePrimitive.addVertex(points[j]);
256
                        }           
257
                }                
258
        }
259

    
260
        private MultiSurface parseMultiPolygon(ByteBuffer data)
261
        throws CreateGeometryException {
262
                int count = data.getInt();
263
                
264
                if(count != 1)
265
                        System.out.println("===>>" + count);
266
                
267
                int subType = getSubType(gHaveZ, gHaveM);        
268
                MultiSurface multiSurface = (MultiSurface)geomManager.create(TYPES.MULTISURFACE, subType);        
269

    
270
                Point point;
271
                for (int i = 0; i < count; i++) {
272
                        Surface surface = (Surface)geomManager.create(TYPES.SURFACE, subType); 
273
                        parseTypeAndSRID(data);
274
                        int countRings = data.getInt();            
275
                        for (int j = 0; j < countRings; j++) {
276
                                double[][] points = parsePointsAsDoubleArray(data, gHaveZ, gHaveM);
277

    
278
                                //Add the initial point
279
                                point = geomManager.createPoint(points[0][0], points[0][1], subType);
280
                                if(gHaveZ)
281
                                        point.setCoordinateAt(Geometry.DIMENSIONS.Z, points[0][2]);
282
                                surface.addMoveToVertex(point);
283
                                
284

    
285
                                //Add the other points
286
                                int lastPoint = points.length - 1;
287
                                for (int k = 1; k < lastPoint; k++){                    
288
                                        point = geomManager.createPoint(points[k][0], points[k][1], subType);
289
                                        if(gHaveZ)
290
                                                point.setCoordinateAt(Geometry.DIMENSIONS.Z, points[0][2]);
291
                                        /*for (int l = 2; l < points[k].length; i++){
292
                                                point.setCoordinateAt(l, points[k][l]);
293
                                        }*/
294
                                        surface.addVertex(point);
295
                                }   
296
                                surface.closePrimitive();
297
                        }
298
                        multiSurface.addSurface(surface);
299
                }
300
                return multiSurface;
301
        }
302

    
303
        private double[][] parsePointsAsDoubleArray(ByteBuffer data, boolean haveZ,
304
                        boolean haveM) throws CreateGeometryException {
305
                int count = data.getInt();
306
                double points[][] = null;
307
                int subtype = getSubType(haveZ, haveM);
308

    
309
                switch (subtype) {
310
                case Geometry.SUBTYPES.GEOM2D:
311
                        points = new double[count][2];
312
                        break;
313
                case Geometry.SUBTYPES.GEOM3D:
314
                case Geometry.SUBTYPES.GEOM2DM:
315
                        points = new double[count][3];
316
                        break;
317
                case Geometry.SUBTYPES.GEOM3DM:
318
                        points = new double[count][4];
319
                        break;
320
                default:
321
                        break;
322
                }
323

    
324
                for (int i = 0; i < count; i++) {
325
                        points[i][0] = data.getDouble(); // x
326
                        points[i][1] = data.getDouble(); // y
327
                        switch (subtype) {
328
                        case Geometry.SUBTYPES.GEOM3D:
329
                        case Geometry.SUBTYPES.GEOM2DM:
330
                                points[i][2] = data.getDouble(); // z or m
331
                                break;
332
                        case Geometry.SUBTYPES.GEOM3DM:
333
                                points[i][2] = data.getDouble(); // z
334
                                points[i][3] = data.getDouble(); // m
335
                                break;
336
                        default:
337
                                break;
338
                        }
339
                        //TODO: Remove when M be supported
340
                        if(haveZ && haveM)
341
                                data.getDouble();
342
                }
343
                return points;
344
        }
345

    
346
        private MultiPrimitive parseCollection(ByteBuffer data) throws CreateGeometryException {
347
                int count = data.getInt();
348
                Geometry[] geoms = new Geometry[count];
349
                parseGeometryArray(data, geoms);
350
                MultiPrimitive multiPrimitive = (MultiPrimitive) geomManager.create(TYPES.AGGREGATE, SUBTYPES.GEOM2D);
351
                for (int i = 0 ; i < geoms.length ; i++){
352
                        multiPrimitive.addPrimitive((Primitive) geoms[i]);
353
                }
354
                return multiPrimitive;
355
        }        
356

    
357
        /** Parse an Array of "full" Geometries 
358
         * @throws CreateGeometryException */
359
        private void parseGeometryArray(ByteBuffer data, Geometry[] container) throws CreateGeometryException {
360
                for (int i = 0; i < container.length; i++) {
361
                        container[i] = parseGeometry(data);
362
                }
363
        }
364

    
365
        private Curve parseLineString(ByteBuffer data, boolean haveZ, boolean haveM) throws CreateGeometryException {
366
                Point[] points = parsePointArray(data, haveZ, haveM);
367
                Curve curve = (Curve) geomManager.create(TYPES.CURVE, getSubType(haveZ, haveM));    
368
                curve.addMoveToVertex(points[0]);
369
                for (int i = 1; i< points.length; i++) {
370
                        curve.addVertex(points[i]);
371
                }
372
                return curve;
373
        }
374

    
375
        /**
376
         * Parse an Array of "slim" Points (without endianness and type, part of
377
         * LinearRing and Linestring, but not MultiPoint!
378
         * 
379
         * @param haveZ
380
         * @param haveM
381
         * @throws CreateGeometryException
382
         */
383
        private Point[] parsePointArray(ByteBuffer data, boolean haveZ, boolean haveM) 
384
        throws CreateGeometryException {
385
                int count = data.getInt();
386
                Point[] result = new Point[count];
387
                for (int i = 0; i < count; i++) {
388
                        result[i] = parsePoint(data, haveZ, haveM);
389
                }
390
                return result;
391
        }
392

    
393

    
394
        private Surface parsePolygon(ByteBuffer data, boolean haveZ, boolean haveM) throws CreateGeometryException {
395
                int count = data.getInt();
396
                int subType = getSubType(haveZ, haveM);        
397

    
398
                Surface surface = (Surface) geomManager.create(TYPES.SURFACE, subType);
399

    
400
                for (int i = 0; i < count; i++) {
401
                        fillLinearRing(data, surface, haveZ, haveM); 
402
                }
403

    
404
                surface.closePrimitive();                
405

    
406
                return surface;
407
        }
408

    
409
        private void fillLinearRing(ByteBuffer data, OrientablePrimitive orientablePrimitive, boolean haveZ, boolean haveM) throws CreateGeometryException {
410
                Point[] points = parsePointArray(data, haveZ, haveM);
411

    
412
                orientablePrimitive.addMoveToVertex(points[0]);
413
                int lastPoint = points.length - 1;
414
                for (int i = 1; i< lastPoint; i++) {
415
                        orientablePrimitive.addVertex(points[i]);
416
                }        
417
        }
418

    
419
        private MultiPoint parseMultiPoint(ByteBuffer data) throws CreateGeometryException {
420
                MultiPoint multipoint = (MultiPoint) geomManager.create(TYPES.MULTIPOINT, SUBTYPES.GEOM2D);
421
                Point2D[] points = new Point2D[data.getInt()];
422
                for (int i = 0; i < points.length; i++) {
423
                        parseTypeAndSRID(data);
424
                        multipoint.addPoint(parsePoint(data, gHaveZ, gHaveM));
425
                }
426
                return multipoint;
427
        }
428

    
429
}