Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_1009 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / WKBParser2.java @ 12649

History | View | Annotate | Download (12.6 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 12649 2007-07-17 12:20:01Z  $
28
 */
29
package com.iver.cit.gvsig.fmap.drivers;
30

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

    
36
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
37
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
38
import com.iver.cit.gvsig.fmap.core.FPoint2D;
39
import com.iver.cit.gvsig.fmap.core.FPoint3D;
40
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
41
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
42
import com.iver.cit.gvsig.fmap.core.FShape;
43
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
44
import com.iver.cit.gvsig.fmap.core.IGeometry;
45
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
46
import com.vividsolutions.jts.io.WKBConstants;
47

    
48
/**
49
 * Parse binary representation of geometries. Currently, only text rep (hexed)
50
 * implementation is tested.
51
 * 
52
 * It should be easy to add char[] and CharSequence ByteGetter instances,
53
 * although the latter one is not compatible with older jdks.
54
 * 
55
 * I did not implement real unsigned 32-bit integers or emulate them with long,
56
 * as both java Arrays and Strings currently can have only 2^31-1 elements
57
 * (bytes), so we cannot even get or build Geometries with more than approx.
58
 * 2^28 coordinates (8 bytes each).
59
 * 
60
 * @author markus.schaber@logi-track.com
61
 *  
62
 */
63
public class WKBParser2 {
64

    
65
    private boolean gHaveM, gHaveZ, gHaveS; // M, Z y SRID
66

    
67

    
68
    /**
69
     * Parse a binary encoded geometry.
70
     * 
71
     * Is synchronized to protect offset counter. (Unfortunately, Java does not
72
     * have neither call by reference nor multiple return values.)
73
     */
74
    public synchronized IGeometry parse(byte[] value) {
75
        // BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value);
76
        ByteBuffer buf = ByteBuffer.wrap(value);
77
        return parseGeometry(buf);
78
    }
79
    
80
    protected void parseTypeAndSRID(ByteBuffer data)
81
    {
82
        byte endian = data.get(); //skip and test endian flag
83
        /* if (endian != data.endian) {
84
            throw new IllegalArgumentException("Endian inconsistency!");
85
        } */
86
        int typeword = data.getInt();
87

    
88
        int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits
89

    
90
        gHaveZ = (typeword & 0x80000000) != 0;
91
        gHaveM = (typeword & 0x40000000) != 0;
92
        gHaveS = (typeword & 0x20000000) != 0;
93

    
94
        int srid = -1;
95

    
96
        if (gHaveS) {
97
            srid = data.getInt();
98
        }
99
        
100
    }
101

    
102

    
103
    /** Parse a geometry starting at offset. */
104
    protected IGeometry parseGeometry(ByteBuffer data) {
105
        byte endian = data.get(); //skip and test endian flag
106
        if (endian == 1)
107
        {
108
                data.order(ByteOrder.LITTLE_ENDIAN);
109
        }
110
        /* if (endian != data.endian) {
111
            throw new IllegalArgumentException("Endian inconsistency!");
112
        } */
113
        int typeword = data.getInt();
114

    
115
        int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits
116

    
117
        boolean haveZ = (typeword & 0x80000000) != 0;
118
        boolean haveM = (typeword & 0x40000000) != 0;
119
        boolean haveS = (typeword & 0x20000000) != 0;
120

    
121
        int srid = -1;
122

    
123
        if (haveS) {
124
            srid = data.getInt();
125
        }
126
        IGeometry result1;
127
        switch (realtype) {
128
        case WKBConstants.wkbPoint :
129
            result1 = ShapeFactory.createPoint2D(parsePoint(data, haveZ, haveM));
130
            break;
131
        case WKBConstants.wkbLineString :
132
            result1 = ShapeFactory.createGeometry(parseLineString(data, haveZ, haveM));
133
            break;
134
        case WKBConstants.wkbPolygon :
135
            result1 = ShapeFactory.createGeometry(parsePolygon(data, haveZ, haveM));
136
            break;
137
        case WKBConstants.wkbMultiPoint:
138
            result1 = parseMultiPoint(data);
139
            break;
140
        case WKBConstants.wkbMultiLineString:
141
            result1 = ShapeFactory.createGeometry(parseMultiLineString(data));
142
            break;
143
        case WKBConstants.wkbMultiPolygon:
144
            result1 = ShapeFactory.createGeometry(parseMultiPolygon(data));
145
            break;
146
        case WKBConstants.wkbGeometryCollection :
147
            result1 = parseCollection(data);
148
            break;
149
        default :
150
            throw new IllegalArgumentException("Unknown Geometry Type!");
151
        }
152

    
153
        /*Geometry result = result1;
154

155
        if (haveS) {
156
            result.setSrid(srid);
157
        } */
158
        return result1;
159
    }
160

    
161
    private FPoint2D parsePoint(ByteBuffer data, boolean haveZ, boolean haveM) {
162
        double X = data.getDouble();
163
        double Y = data.getDouble();
164
        FPoint2D result;
165
        if (haveZ) {
166
            double Z = data.getDouble();
167
            result = new FPoint3D(X, Y, Z);
168
        } else {
169
            result = new FPoint2D(X, Y);
170
        }
171

    
172
        if (haveM) {
173
            System.err.println("M no soportado. (WKBParser de gvSIG, dentro de parsePoint)");
174
            double m = data.getDouble();
175
            // result.setM(m);
176
        }
177

    
178
        return result;
179
    }
180

    
181
    /** Parse an Array of "full" Geometries */
182
    private void parseGeometryArray(ByteBuffer data, IGeometry[] container) {
183
        for (int i = 0; i < container.length; i++) {
184
            container[i] = parseGeometry(data);
185
        }
186
    }
187

    
188
    /**
189
     * Parse an Array of "slim" Points (without endianness and type, part of
190
     * LinearRing and Linestring, but not MultiPoint!
191
     * 
192
     * @param haveZ
193
     * @param haveM
194
     */
195
    private FPoint2D[] parsePointArray(ByteBuffer data, boolean haveZ, boolean haveM) {
196
        int count = data.getInt();
197
        FPoint2D[] result = new FPoint2D[count];
198
        for (int i = 0; i < count; i++) {
199
            result[i] = parsePoint(data, haveZ, haveM);
200
        }
201
        return result;
202
    }
203

    
204
    private FMultiPoint2D parseMultiPoint(ByteBuffer data) {
205
        FPoint2D[] points = new FPoint2D[data.getInt()];
206
        for (int i=0; i < points.length; i++)
207
        {
208
                parseTypeAndSRID(data);
209
                points[i] = parsePoint(data, gHaveZ, gHaveM);
210
        }
211
        return new FMultiPoint2D(points);
212
    }
213

    
214
    private FPolyline2D parseLineString(ByteBuffer data, boolean haveZ, boolean haveM) {
215
        FPoint2D[] points = parsePointArray(data, haveZ, haveM);
216
        GeneralPathX gp = new GeneralPathX();
217
        gp.moveTo(points[0].getX(), points[0].getY());
218
        for (int i = 1; i< points.length; i++)
219
        {
220
            gp.lineTo(points[i].getX(), points[i].getY());
221
        }
222
        return new FPolyline2D(gp);
223
    }
224

    
225
    private FPolygon2D parseLinearRing(ByteBuffer data, boolean haveZ, boolean haveM) {
226
        FPoint2D[] points = parsePointArray(data, haveZ, haveM);
227
        GeneralPathX gp = new GeneralPathX();
228
        gp.moveTo(points[0].getX(), points[0].getY());
229
        for (int i = 1; i< points.length; i++)
230
        {
231
            gp.lineTo(points[i].getX(), points[i].getY());
232
        }
233
        return new FPolygon2D(gp);
234
    }
235

    
236
    private FPolygon2D parsePolygon(ByteBuffer data, boolean haveZ, boolean haveM) {
237
                int count = data.getInt();
238
                FPolygon2D[] rings = new FPolygon2D[count];
239
                for (int i = 0; i < count; i++) {
240
                    rings[i] = parseLinearRing(data, haveZ, haveM);
241
                                        
242
                }
243
                GeneralPathX shape=(GeneralPathX)getGeneralPathX(rings);
244
                        return new FPolygon2D(shape);
245
         }
246
    private FPolyline2D parseMultiLineString(ByteBuffer data) {
247
        GeneralPathX gp = parseGeneralPath(data);
248
        // GeneralPathX shape=getGeneralPathX(strings);
249
                
250
        // parseGeometryArray(data, strings);
251
        return new FPolyline2D(gp);//strings[0]; //new MultiLineString(strings);
252
    }
253

    
254
        /**
255
         * @param data
256
         * @return
257
         */
258
        private GeneralPathX parseGeneralPath(ByteBuffer data) {
259
                int count = data.getInt();
260
        // FPolyline2D[] strings = new FPolyline2D[count];
261
        GeneralPathX gp = new GeneralPathX();
262
        for (int i=0; i < count; i++)
263
        {
264
            parseTypeAndSRID(data);
265
            FPoint2D[] points = parsePointArray(data, gHaveZ, gHaveM);
266
            // int count2 = data.getInt();
267
            /* FPoint2D[] result = new FPoint2D[count2];
268
            for (int i = 0; i < count; i++) {
269
                result[i] = parsePoint(data, haveZ, haveM);
270
            }
271
            return result; */            
272
            /* FPoint2D p = parsePoint(data, gHaveZ, gHaveM);
273
            gp.moveTo(p.getX(), p.getY());
274
            for (int j = 1; j < count2; j++) {
275
                p = parsePoint(data, gHaveZ, gHaveM);
276
                gp.lineTo(p.getX(), p.getY());
277
            } */
278
            
279
            gp.moveTo(points[0].getX(), points[0].getY());
280
            for (int j = 1; j< points.length; j++)
281
            {
282
                gp.lineTo(points[j].getX(), points[j].getY());
283
            } 
284
            
285
            // strings[i] = parseLineString(data, gHaveZ, gHaveM);
286
        }
287
                return gp;
288
        }
289

    
290
    private FPolygon2D parseMultiPolygon(ByteBuffer data) {
291
        int count = data.getInt();
292
        // FPolygon2D[] polys = new FPolygon2D[count];
293
        GeneralPathX gp = new GeneralPathX();
294
        for (int i=0; i < count; i++)
295
        {
296
            parseTypeAndSRID(data);
297
            // polys[i] = parsePolygon(data, gHaveZ, gHaveM);
298
                int countRings = data.getInt();
299
                // FPolygon2D[] rings = new FPolygon2D[countRings];
300
                for (int j = 0; j < countRings; j++) {
301
                    // rings[j] = parseLinearRing(data, gHaveZ, gHaveM);
302
                    FPoint2D[] points = parsePointArray(data, gHaveZ, gHaveM);
303
                    
304
                    gp.moveTo(points[0].getX(), points[0].getY());
305
                    for (int k = 1; k< points.length; k++)
306
                    {
307
                            gp.lineTo(points[k].getX(), points[k].getY());
308
                    }
309
                    
310
                }
311
                // GeneralPathX shape=(GeneralPathX)getGeneralPathX(rings);
312
            
313
        }
314
                 // GeneralPathX shape=getGeneralPathX(polys);
315

    
316
        return new FPolygon2D(gp);
317
            // return new FPolygon2D(parseGeneralPath(data));
318
    }
319

    
320
    private FGeometryCollection parseCollection(ByteBuffer data) {
321
        int count = data.getInt();
322
        IGeometry[] geoms = new IGeometry[count];
323
        parseGeometryArray(data, geoms);
324
        return new FGeometryCollection(geoms);
325
    }
326
        /**
327
         * Devuelve el GeneralPathX compuesto por todos los GeneralPath de todas
328
         * las geometr?as que componen el elemento.
329
         *
330
         * @param geometries Lista de geometr?as.
331
         *
332
         * @return GeneralPath completo.
333
         */
334
        private GeneralPathX getGeneralPathX(FShape[] geometries) {
335
                GeneralPathX shape = new GeneralPathX();
336

    
337
                for (int i = 0; i < geometries.length; i++) {
338
                        FShape shp = (FShape) geometries[i];
339
                        PathIterator theIterator = shp.getPathIterator(null); //, flatness);
340
                        double[] theData = new double[6];
341
                        int theType;
342
                        ArrayList arrayCoords;
343

    
344
                        while (!theIterator.isDone()) {
345
                                //while not done
346
                                theType = theIterator.currentSegment(theData);
347

    
348
                                //Populate a segment of the new
349
                                // GeneralPathX object.
350
                                //Process the current segment to populate a new
351
                                // segment of the new GeneralPathX object.
352
                                switch (theType) {
353
                                        case PathIterator.SEG_MOVETO:
354
                                                shape.moveTo(theData[0], theData[1]);
355

    
356
                                                break;
357

    
358
                                        case PathIterator.SEG_LINETO:
359
                                                shape.lineTo(theData[0], theData[1]);
360

    
361
                                                break;
362

    
363
                                        case PathIterator.SEG_QUADTO:
364
                                                shape.quadTo(theData[0], theData[1], theData[2],
365
                                                        theData[3]);
366

    
367
                                                break;
368

    
369
                                        case PathIterator.SEG_CUBICTO:
370
                                                shape.curveTo(theData[0], theData[1], theData[2],
371
                                                        theData[3], theData[4], theData[5]);
372

    
373
                                                break;
374

    
375
                                        case PathIterator.SEG_CLOSE:
376

    
377
                                                if (i == (geometries.length - 1)) {
378
                                                        shape.closePath();
379
                                                }
380

    
381
                                                break;
382
                                } //end switch
383

    
384
                                theIterator.next();
385
                        } //end while loop
386
                }
387

    
388
                return shape;
389
        }
390
}