svn-gvsig-desktop / tags / v1_1_Build_1013 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / WKBParser2.java @ 13521
History | View | Annotate | Download (12.6 KB)
1 | 5634 | fjp | /*
|
---|---|---|---|
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$
|
||
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 | 8765 | jjdelcerro | points[i] = parsePoint(data, gHaveZ, gHaveM); |
210 | 5634 | fjp | } |
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 | } |