Statistics
| Revision:

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

History | View | Annotate | Download (14.4 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 15669 2007-10-30 16:19:37Z vcaballero $
28
 */
29
package org.gvsig.fmap.geom.operation.fromwkb;
30

    
31
import java.awt.geom.PathIterator;
32
import java.nio.ByteBuffer;
33
import java.nio.ByteOrder;
34

    
35
import org.geotools.xml.gml.GMLComplexTypes.MultiGeometryPropertyType;
36
import org.gvsig.fmap.geom.Geometry;
37
import org.gvsig.fmap.geom.GeometryLocator;
38
import org.gvsig.fmap.geom.GeometryManager;
39
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
40
import org.gvsig.fmap.geom.Geometry.TYPES;
41
import org.gvsig.fmap.geom.aggregate.Aggregate;
42
import org.gvsig.fmap.geom.aggregate.MultiPoint;
43
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
44
import org.gvsig.fmap.geom.aggregate.impl.BaseMultiPrimitive;
45
import org.gvsig.fmap.geom.aggregate.impl.BaseMultiPrimitive2D;
46
import org.gvsig.fmap.geom.exception.CreateGeometryException;
47
import org.gvsig.fmap.geom.primitive.Curve;
48
import org.gvsig.fmap.geom.primitive.GeneralPathX;
49
import org.gvsig.fmap.geom.primitive.Primitive;
50
import org.gvsig.fmap.geom.primitive.Surface;
51
import org.gvsig.fmap.geom.primitive.impl.Curve2D;
52
import org.gvsig.fmap.geom.primitive.impl.Point2D;
53
import org.gvsig.fmap.geom.primitive.impl.Point2DZ;
54
import org.gvsig.fmap.geom.primitive.impl.Surface2D;
55

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

    
58
/**
59
 * Parse binary representation of geometries. Currently, only text rep (hexed)
60
 * implementation is tested.
61
 *
62
 * It should be easy to add char[] and CharSequence ByteGetter instances,
63
 * although the latter one is not compatible with older jdks.
64
 *
65
 * I did not implement real unsigned 32-bit integers or emulate them with long,
66
 * as both java Arrays and Strings currently can have only 2^31-1 elements
67
 * (bytes), so we cannot even get or build Geometries with more than approx.
68
 * 2^28 coordinates (8 bytes each).
69
 *
70
 * @author markus.schaber@logi-track.com
71
 *
72
 */
73
public class WKBParser2 {
74
        private GeometryManager geomManager = GeometryLocator.getGeometryManager();
75
    private boolean gHaveM, gHaveZ, gHaveS; // M, Z y SRID
76

    
77

    
78
    /**
79
     * Parse a binary encoded geometry.
80
     *
81
     * Is synchronized to protect offset counter. (Unfortunately, Java does not
82
     * have neither call by reference nor multiple return values.)
83
     * @throws CreateGeometryException 
84
     */
85
    public synchronized Geometry parse(byte[] value) throws CreateGeometryException {
86
        // BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value);
87
        ByteBuffer buf = ByteBuffer.wrap(value);
88
        return parseGeometry(buf);
89
    }
90

    
91
    protected void parseTypeAndSRID(ByteBuffer data)
92
    {
93
        byte endian = data.get(); //skip and test endian flag
94
        /* if (endian != data.endian) {
95
            throw new IllegalArgumentException("Endian inconsistency!");
96
        } */
97
        int typeword = data.getInt();
98

    
99
        int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits
100

    
101
        gHaveZ = (typeword & 0x80000000) != 0;
102
        gHaveM = (typeword & 0x40000000) != 0;
103
        gHaveS = (typeword & 0x20000000) != 0;
104

    
105
        int srid = -1;
106

    
107
        if (gHaveS) {
108
            srid = data.getInt();
109
        }
110

    
111
    }
112

    
113

    
114
    /** Parse a geometry starting at offset. 
115
     * @throws CreateGeometryException */
116
    protected Geometry parseGeometry(ByteBuffer data) throws CreateGeometryException {
117
        byte endian = data.get(); //skip and test endian flag
118
        if (endian == 1)
119
        {
120
                data.order(ByteOrder.LITTLE_ENDIAN);
121
        }
122
        /* if (endian != data.endian) {
123
            throw new IllegalArgumentException("Endian inconsistency!");
124
        } */
125
        int typeword = data.getInt();
126

    
127
        int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits
128

    
129
        boolean haveZ = (typeword & 0x80000000) != 0;
130
        boolean haveM = (typeword & 0x40000000) != 0;
131
        boolean haveS = (typeword & 0x20000000) != 0;
132

    
133
        int srid = -1;
134

    
135
        if (haveS) {
136
            srid = data.getInt();
137
        }
138
        Geometry result1;
139
        switch (realtype) {
140
        case WKBConstants.wkbPoint :
141
                result1 = parsePoint(data, haveZ, haveM);
142
            break;
143
        case WKBConstants.wkbLineString :
144
            result1 = parseLineString(data, haveZ, haveM);
145
            break;
146
        case WKBConstants.wkbPolygon :
147
            result1 = parsePolygon(data, haveZ, haveM);
148
            break;
149
        case WKBConstants.wkbMultiPoint:
150
            result1 = parseMultiPoint(data);
151
            break;
152
        case WKBConstants.wkbMultiLineString:
153
            result1 = parseMultiLineString(data);
154
            break;
155
        case WKBConstants.wkbMultiPolygon:
156
            result1 = parseMultiPolygon(data);
157
            break;
158
        case WKBConstants.wkbGeometryCollection :
159
            result1 = parseCollection(data);
160
            break;
161
        default :
162
            throw new IllegalArgumentException("Unknown Geometry Type!");
163
        }
164

    
165
        /*Geometry result = result1;
166

167
        if (haveS) {
168
            result.setSrid(srid);
169
        } */
170
        return result1;
171
    }
172

    
173
    private Point2D parsePoint(ByteBuffer data, boolean haveZ, boolean haveM) {
174
        double X = data.getDouble();
175
        double Y = data.getDouble();
176
        Point2D result;
177
        if (haveZ) {
178
            double Z = data.getDouble();
179
            result = new Point2DZ(X, Y, Z);
180
        } else {
181
            result = new Point2D(X, Y);
182
        }
183

    
184
        if (haveM) {
185
            System.err.println("M no soportado. (WKBParser de gvSIG, dentro de parsePoint)");
186
            double m = data.getDouble();
187
            // result.setM(m);
188
        }
189

    
190
        return result;
191
    }
192

    
193
    /** Parse an Array of "full" Geometries 
194
     * @throws CreateGeometryException */
195
    private void parseGeometryArray(ByteBuffer data, Geometry[] container) throws CreateGeometryException {
196
        for (int i = 0; i < container.length; i++) {
197
            container[i] = parseGeometry(data);
198
        }
199
    }
200

    
201
    /**
202
     * Parse an Array of "slim" Points (without endianness and type, part of
203
     * LinearRing and Linestring, but not MultiPoint!
204
     *
205
     * @param haveZ
206
     * @param haveM
207
     */
208
    private Point2D[] parsePointArray(ByteBuffer data, boolean haveZ, boolean haveM) {
209
        int count = data.getInt();
210
        Point2D[] result = new Point2D[count];
211
        for (int i = 0; i < count; i++) {
212
            result[i] = parsePoint(data, haveZ, haveM);
213
        }
214
        return result;
215
    }
216

    
217
    private MultiPoint parseMultiPoint(ByteBuffer data) throws CreateGeometryException {
218
            MultiPoint multipoint = (MultiPoint) geomManager.create(TYPES.MULTIPOINT, SUBTYPES.GEOM2D);
219
            Point2D[] points = new Point2D[data.getInt()];
220
        for (int i=0; i < points.length; i++)
221
        {
222
                parseTypeAndSRID(data);
223
                multipoint.addPoint(parsePoint(data, gHaveZ, gHaveM));
224
        }
225
        return multipoint;
226
    }
227

    
228
    private Curve parseLineString(ByteBuffer data, boolean haveZ, boolean haveM) throws CreateGeometryException {
229
        Point2D[] points = parsePointArray(data, haveZ, haveM);
230
        GeneralPathX gp = new GeneralPathX();
231
        gp.moveTo(points[0].getX(), points[0].getY());
232
        for (int i = 1; i< points.length; i++)
233
        {
234
            gp.lineTo(points[i].getX(), points[i].getY());
235
        }
236
        return (Curve) geomManager.createCurve(gp, SUBTYPES.GEOM2D);
237
    }
238

    
239
    private Surface parseLinearRing(ByteBuffer data, boolean haveZ, boolean haveM) throws CreateGeometryException {
240
        Point2D[] points = parsePointArray(data, haveZ, haveM);
241
        GeneralPathX gp = new GeneralPathX();
242
        gp.moveTo(points[0].getX(), points[0].getY());
243
        for (int i = 1; i< points.length; i++)
244
        {
245
            gp.lineTo(points[i].getX(), points[i].getY());
246
        }
247
        return (Surface) geomManager.createSurface(gp, SUBTYPES.GEOM2D);
248
    }
249

    
250
    private Surface parsePolygon(ByteBuffer data, boolean haveZ, boolean haveM) throws CreateGeometryException {
251
                int count = data.getInt();
252
                Surface[] rings = new Surface2D[count];
253
                for (int i = 0; i < count; i++) {
254
                    rings[i] = parseLinearRing(data, haveZ, haveM);
255

    
256
                }
257
                GeneralPathX shape=getGeneralPathX(rings);
258
                if (!shape.isClosed()) {
259
                        shape.closePath();
260
                }
261
                        return (Surface) geomManager.createSurface(shape, SUBTYPES.GEOM2D);
262
         }
263
    private Curve parseMultiLineString(ByteBuffer data) throws CreateGeometryException {
264
        GeneralPathX gp = parseGeneralPath(data);
265
        // GeneralPathX shape=getGeneralPathX(strings);
266

    
267
        // parseGeometryArray(data, strings);
268
        return (Curve) geomManager.createCurve(gp, SUBTYPES.GEOM2D);//strings[0]; //new MultiLineString(strings);
269
    }
270

    
271
        /**
272
         * @param data
273
         * @return
274
         */
275
        private GeneralPathX parseGeneralPath(ByteBuffer data) {
276
                int count = data.getInt();
277
        // FPolyline2D[] strings = new FPolyline2D[count];
278
        GeneralPathX gp = new GeneralPathX();
279
        for (int i=0; i < count; i++)
280
        {
281
            parseTypeAndSRID(data);
282
            Point2D[] points = parsePointArray(data, gHaveZ, gHaveM);
283
            // int count2 = data.getInt();
284
            /* FPoint2D[] result = new FPoint2D[count2];
285
            for (int i = 0; i < count; i++) {
286
                result[i] = parsePoint(data, haveZ, haveM);
287
            }
288
            return result; */
289
            /* FPoint2D p = parsePoint(data, gHaveZ, gHaveM);
290
            gp.moveTo(p.getX(), p.getY());
291
            for (int j = 1; j < count2; j++) {
292
                p = parsePoint(data, gHaveZ, gHaveM);
293
                gp.lineTo(p.getX(), p.getY());
294
            } */
295

    
296
            gp.moveTo(points[0].getX(), points[0].getY());
297
            for (int j = 1; j< points.length; j++)
298
            {
299
                gp.lineTo(points[j].getX(), points[j].getY());
300
            }
301

    
302
            // strings[i] = parseLineString(data, gHaveZ, gHaveM);
303
        }
304
                return gp;
305
        }
306

    
307
    private Surface parseMultiPolygon(ByteBuffer data) throws CreateGeometryException {
308
        int count = data.getInt();
309
        // FPolygon2D[] polys = new FPolygon2D[count];
310
        GeneralPathX gp = new GeneralPathX();
311
        for (int i=0; i < count; i++)
312
        {
313
            parseTypeAndSRID(data);
314
            // polys[i] = parsePolygon(data, gHaveZ, gHaveM);
315
                int countRings = data.getInt();
316
                // FPolygon2D[] rings = new FPolygon2D[countRings];
317
                for (int j = 0; j < countRings; j++) {
318
                    // rings[j] = parseLinearRing(data, gHaveZ, gHaveM);
319
                    Point2D[] points = parsePointArray(data, gHaveZ, gHaveM);
320

    
321
                    gp.moveTo(points[0].getX(), points[0].getY());
322
                    for (int k = 1; k< points.length; k++)
323
                    {
324
                            if (k==points.length-1){
325
                                    gp.closePath();
326
                            }else{
327
                                    gp.lineTo(points[k].getX(), points[k].getY());
328
                            }
329

    
330
                    }
331

    
332
                }
333
                // GeneralPathX shape=(GeneralPathX)getGeneralPathX(rings);
334

    
335
        }
336
                 // GeneralPathX shape=getGeneralPathX(polys);
337

    
338
        return (Surface) geomManager.createSurface(gp, SUBTYPES.GEOM2D);
339
            // return new FPolygon2D(parseGeneralPath(data));
340
    }
341

    
342
    private MultiPrimitive parseCollection(ByteBuffer data) throws CreateGeometryException {
343
        int count = data.getInt();
344
        Geometry[] geoms = new Geometry[count];
345
        parseGeometryArray(data, geoms);
346
        MultiPrimitive multiPrimitive = (MultiPrimitive) geomManager.create(TYPES.AGGREGATE, SUBTYPES.GEOM2D);
347
        for (int i=0 ; i<geoms.length ; i++){
348
                multiPrimitive.addPrimitive((Primitive) geoms[i]);
349
        }
350
        return multiPrimitive;
351
    }
352
        /**
353
         * Devuelve el GeneralPathX compuesto por todos los GeneralPath de todas
354
         * las geometr?as que componen el elemento.
355
         *
356
         * @param geometries Lista de geometr?as.
357
         *
358
         * @return GeneralPath completo.
359
         */
360
        private GeneralPathX getGeneralPathX(Geometry[] geometries) {
361
                GeneralPathX shape = new GeneralPathX();
362

    
363
                for (int i = 0; i < geometries.length; i++) {
364
                        Geometry shp = geometries[i];
365
                        PathIterator theIterator = shp.getPathIterator(null); //, flatness);
366
                        double[] theData = new double[6];
367
                        int theType;
368
//                        ArrayList arrayCoords;
369

    
370
                        while (!theIterator.isDone()) {
371
                                //while not done
372
                                theType = theIterator.currentSegment(theData);
373

    
374
                                //Populate a segment of the new
375
                                // GeneralPathX object.
376
                                //Process the current segment to populate a new
377
                                // segment of the new GeneralPathX object.
378
                                switch (theType) {
379
                                        case PathIterator.SEG_MOVETO:
380
                                                shape.moveTo(theData[0], theData[1]);
381

    
382
                                                break;
383

    
384
                                        case PathIterator.SEG_LINETO:
385
                                                shape.lineTo(theData[0], theData[1]);
386

    
387
                                                break;
388

    
389
                                        case PathIterator.SEG_QUADTO:
390
                                                shape.quadTo(theData[0], theData[1], theData[2],
391
                                                        theData[3]);
392

    
393
                                                break;
394

    
395
                                        case PathIterator.SEG_CUBICTO:
396
                                                shape.curveTo(theData[0], theData[1], theData[2],
397
                                                        theData[3], theData[4], theData[5]);
398

    
399
                                                break;
400

    
401
                                        case PathIterator.SEG_CLOSE:
402

    
403
                                                if (i == (geometries.length - 1)) {
404
                                                        shape.closePath();
405
                                                }
406

    
407
                                                break;
408
                                } //end switch
409

    
410
                                theIterator.next();
411
                        } //end while loop
412
                }
413

    
414
                return shape;
415
        }
416
}