Statistics
| Revision:

svn-gvsig-desktop / tags / Root_Fmap_GisPlanet / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / WKBParser.java @ 1826

History | View | Annotate | Download (10.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: WKBParser.java 1826 2005-04-21 09:41:04Z  $
28
 */
29
package com.iver.cit.gvsig.fmap.drivers;
30

    
31
import org.postgis.Geometry;
32
import org.postgis.GeometryCollection;
33
import org.postgis.LineString;
34
import org.postgis.LinearRing;
35
import org.postgis.MultiLineString;
36
import org.postgis.MultiPoint;
37
import org.postgis.MultiPolygon;
38
import org.postgis.Point;
39
import org.postgis.Polygon;
40
import org.postgis.binary.ByteGetter;
41
import org.postgis.binary.ValueGetter;
42
import org.postgis.binary.ByteGetter.BinaryByteGetter;
43
import org.postgis.binary.ByteGetter.StringByteGetter;
44

    
45
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
46
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
47
import com.iver.cit.gvsig.fmap.core.FPoint2D;
48
import com.iver.cit.gvsig.fmap.core.FPoint3D;
49
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
50
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
51
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
52
import com.iver.cit.gvsig.fmap.core.IGeometry;
53
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
54

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

    
72
    private boolean gHaveM, gHaveZ, gHaveS; // M, Z y SRID
73
    /**
74
     * Get the appropriate ValueGetter for my endianness
75
     * 
76
     * @param bytes The appropriate Byte Getter
77
     * 
78
     * @return the ValueGetter
79
     */    
80
    public static ValueGetter valueGetterForEndian(ByteGetter bytes) {
81
        if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR
82
            return new ValueGetter.XDR(bytes);
83
        } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) {
84
            return new ValueGetter.NDR(bytes);
85
        } else {
86
            throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0));
87
        }
88
    }
89

    
90
    /**
91
     * Parse a hex encoded geometry
92
     * 
93
     * Is synchronized to protect offset counter. (Unfortunately, Java does not
94
     * have neither call by reference nor multiple return values.)
95
     */
96
    public synchronized IGeometry parse(String value) {
97
        StringByteGetter bytes = new ByteGetter.StringByteGetter(value);
98
        return parseGeometry(valueGetterForEndian(bytes));
99
    }
100

    
101
    /**
102
     * Parse a binary encoded geometry.
103
     * 
104
     * Is synchronized to protect offset counter. (Unfortunately, Java does not
105
     * have neither call by reference nor multiple return values.)
106
     */
107
    public synchronized IGeometry parse(byte[] value) {
108
        BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value);
109
        return parseGeometry(valueGetterForEndian(bytes));
110
    }
111
    
112
    protected void parseTypeAndSRID(ValueGetter data)
113
    {
114
        byte endian = data.getByte(); //skip and test endian flag
115
        if (endian != data.endian) {
116
            throw new IllegalArgumentException("Endian inconsistency!");
117
        }
118
        int typeword = data.getInt();
119

    
120
        int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits
121

    
122
        gHaveZ = (typeword & 0x80000000) != 0;
123
        gHaveM = (typeword & 0x40000000) != 0;
124
        gHaveS = (typeword & 0x20000000) != 0;
125

    
126
        int srid = -1;
127

    
128
        if (gHaveS) {
129
            srid = data.getInt();
130
        }
131
        
132
    }
133

    
134
    /** Parse a geometry starting at offset. */
135
    protected IGeometry parseGeometry(ValueGetter data) {
136
        byte endian = data.getByte(); //skip and test endian flag
137
        if (endian != data.endian) {
138
            throw new IllegalArgumentException("Endian inconsistency!");
139
        }
140
        int typeword = data.getInt();
141

    
142
        int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits
143

    
144
        boolean haveZ = (typeword & 0x80000000) != 0;
145
        boolean haveM = (typeword & 0x40000000) != 0;
146
        boolean haveS = (typeword & 0x20000000) != 0;
147

    
148
        int srid = -1;
149

    
150
        if (haveS) {
151
            srid = data.getInt();
152
        }
153
        IGeometry result1;
154
        switch (realtype) {
155
        case Geometry.POINT :
156
            result1 = ShapeFactory.createPoint2D(parsePoint(data, haveZ, haveM));
157
            break;
158
        case Geometry.LINESTRING :
159
            result1 = ShapeFactory.createGeometry(parseLineString(data, haveZ, haveM));
160
            break;
161
        case Geometry.POLYGON :
162
            result1 = ShapeFactory.createGeometry(parsePolygon(data, haveZ, haveM));
163
            break;
164
        case Geometry.MULTIPOINT :
165
            result1 = parseMultiPoint(data);
166
            break;
167
        case Geometry.MULTILINESTRING :
168
            result1 = ShapeFactory.createGeometry(parseMultiLineString(data));
169
            break;
170
        case Geometry.MULTIPOLYGON :
171
            result1 = ShapeFactory.createGeometry(parseMultiPolygon(data));
172
            break;
173
        case Geometry.GEOMETRYCOLLECTION :
174
            result1 = parseCollection(data);
175
            break;
176
        default :
177
            throw new IllegalArgumentException("Unknown Geometry Type!");
178
        }
179

    
180
        /*Geometry result = result1;
181

182
        if (haveS) {
183
            result.setSrid(srid);
184
        } */
185
        return result1;
186
    }
187

    
188
    private FPoint2D parsePoint(ValueGetter data, boolean haveZ, boolean haveM) {
189
        double X = data.getDouble();
190
        double Y = data.getDouble();
191
        FPoint2D result;
192
        if (haveZ) {
193
            double Z = data.getDouble();
194
            result = new FPoint3D(X, Y, Z);
195
        } else {
196
            result = new FPoint2D(X, Y);
197
        }
198

    
199
        if (haveM) {
200
            System.err.println("M no soportado. (WKBParser de gvSIG, dentro de parsePoint)");
201
            double m = data.getDouble();
202
            // result.setM(m);
203
        }
204

    
205
        return result;
206
    }
207

    
208
    /** Parse an Array of "full" Geometries */
209
    private void parseGeometryArray(ValueGetter data, IGeometry[] container) {
210
        for (int i = 0; i < container.length; i++) {
211
            container[i] = parseGeometry(data);
212
        }
213
    }
214

    
215
    /**
216
     * Parse an Array of "slim" Points (without endianness and type, part of
217
     * LinearRing and Linestring, but not MultiPoint!
218
     * 
219
     * @param haveZ
220
     * @param haveM
221
     */
222
    private FPoint2D[] parsePointArray(ValueGetter data, boolean haveZ, boolean haveM) {
223
        int count = data.getInt();
224
        FPoint2D[] result = new FPoint2D[count];
225
        for (int i = 0; i < count; i++) {
226
            result[i] = parsePoint(data, haveZ, haveM);
227
        }
228
        return result;
229
    }
230

    
231
    private FMultiPoint2D parseMultiPoint(ValueGetter data) {
232
        FPoint2D[] points = new FPoint2D[data.getInt()];
233
        for (int i=0; i < points.length; i++)
234
        {
235
            parseTypeAndSRID(data);
236
            parsePoint(data, gHaveZ, gHaveM);
237
        }
238
        return new FMultiPoint2D(points);
239
    }
240

    
241
    private FPolyline2D parseLineString(ValueGetter data, boolean haveZ, boolean haveM) {
242
        FPoint2D[] points = parsePointArray(data, haveZ, haveM);
243
        GeneralPathX gp = new GeneralPathX();
244
        gp.moveTo(points[0].getX(), points[0].getY());
245
        for (int i = 1; i< points.length; i++)
246
        {
247
            gp.lineTo(points[i].getX(), points[i].getY());
248
        }
249
        return new FPolyline2D(gp);
250
    }
251

    
252
    private FPolygon2D parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) {
253
        FPoint2D[] points = parsePointArray(data, haveZ, haveM);
254
        GeneralPathX gp = new GeneralPathX();
255
        gp.moveTo(points[0].getX(), points[0].getY());
256
        for (int i = 1; i< points.length; i++)
257
        {
258
            gp.lineTo(points[i].getX(), points[i].getY());
259
        }
260
        return new FPolygon2D(gp);
261
    }
262

    
263
    private FPolygon2D parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) {
264
        int count = data.getInt();
265
        FPolygon2D[] rings = new FPolygon2D[count];
266
        for (int i = 0; i < count; i++) {
267
            rings[i] = parseLinearRing(data, haveZ, haveM);
268
        }
269
        return rings[0]; //new FPolygon2D(rings[0]);
270
    }
271

    
272
    private FPolyline2D parseMultiLineString(ValueGetter data) {
273
        int count = data.getInt();
274
        FPolyline2D[] strings = new FPolyline2D[count];   
275
        for (int i=0; i < strings.length; i++)
276
        {
277
            parseTypeAndSRID(data);
278
            strings[i] = parseLineString(data, gHaveZ, gHaveM);
279
        }
280
        
281
        // parseGeometryArray(data, strings);
282
        return strings[0]; //new MultiLineString(strings);
283
    }
284

    
285
    private FPolygon2D parseMultiPolygon(ValueGetter data) {
286
        int count = data.getInt();
287
        FPolygon2D[] polys = new FPolygon2D[count];
288
        for (int i=0; i < polys.length; i++)
289
        {
290
            parseTypeAndSRID(data);
291
            polys[i] = parsePolygon(data, gHaveZ, gHaveM);
292
        }
293
        
294
        // parseGeometryArray(data, polys);
295
        return polys[0]; //new MultiPolygon(polys);
296
    }
297

    
298
    private FGeometryCollection parseCollection(ValueGetter data) {
299
        int count = data.getInt();
300
        IGeometry[] geoms = new IGeometry[count];
301
        parseGeometryArray(data, geoms);
302
        return new FGeometryCollection(geoms);
303
    }
304
}