Revision 21365

View differences:

branches/v2_0_0_prep/libraries/libFMap_geometries/src/org/gvsig/fmap/geom/operation/fromwkb/WKBParser2.java
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
import java.util.ArrayList;
35

  
36
import org.gvsig.fmap.geom.Geometry;
37
import org.gvsig.fmap.geom.GeometryManager;
38
import org.gvsig.fmap.geom.aggregate.BaseMultiPrimitive;
39
import org.gvsig.fmap.geom.aggregate.MultiPoint2D;
40
import org.gvsig.fmap.geom.primitive.Curve2D;
41
import org.gvsig.fmap.geom.primitive.FShape;
42
import org.gvsig.fmap.geom.primitive.GeneralPathX;
43
import org.gvsig.fmap.geom.primitive.Point2D;
44
import org.gvsig.fmap.geom.primitive.Point2DZ;
45
import org.gvsig.fmap.geom.primitive.Surface2D;
46

  
47
import com.vividsolutions.jts.io.WKBConstants;
48

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

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

  
68

  
69
    /**
70
     * Parse a binary encoded geometry.
71
     *
72
     * Is synchronized to protect offset counter. (Unfortunately, Java does not
73
     * have neither call by reference nor multiple return values.)
74
     */
75
    public synchronized Geometry parse(byte[] value) {
76
        // BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value);
77
        ByteBuffer buf = ByteBuffer.wrap(value);
78
        return parseGeometry(buf);
79
    }
80

  
81
    protected void parseTypeAndSRID(ByteBuffer data)
82
    {
83
        byte endian = data.get(); //skip and test endian flag
84
        /* if (endian != data.endian) {
85
            throw new IllegalArgumentException("Endian inconsistency!");
86
        } */
87
        int typeword = data.getInt();
88

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

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

  
95
        int srid = -1;
96

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

  
101
    }
102

  
103

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

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

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

  
122
        int srid = -1;
123

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

  
154
        /*Geometry result = result1;
155

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

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

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

  
179
        return result;
180
    }
181

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

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

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

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

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

  
237
    private Surface2D parsePolygon(ByteBuffer data, boolean haveZ, boolean haveM) {
238
	        int count = data.getInt();
239
	        Surface2D[] rings = new Surface2D[count];
240
	        for (int i = 0; i < count; i++) {
241
	            rings[i] = parseLinearRing(data, haveZ, haveM);
242

  
243
	        }
244
	        GeneralPathX shape=(GeneralPathX)getGeneralPathX(rings);
245
	        shape.closePath();
246
			return new Surface2D(shape);
247
	 }
248
    private Curve2D parseMultiLineString(ByteBuffer data) {
249
        GeneralPathX gp = parseGeneralPath(data);
250
        // GeneralPathX shape=getGeneralPathX(strings);
251

  
252
        // parseGeometryArray(data, strings);
253
        return new Curve2D(gp);//strings[0]; //new MultiLineString(strings);
254
    }
255

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

  
281
            gp.moveTo(points[0].getX(), points[0].getY());
282
            for (int j = 1; j< points.length; j++)
283
            {
284
                gp.lineTo(points[j].getX(), points[j].getY());
285
            }
286

  
287
            // strings[i] = parseLineString(data, gHaveZ, gHaveM);
288
        }
289
		return gp;
290
	}
291

  
292
    private Surface2D parseMultiPolygon(ByteBuffer data) {
293
        int count = data.getInt();
294
        // FPolygon2D[] polys = new FPolygon2D[count];
295
        GeneralPathX gp = new GeneralPathX();
296
        for (int i=0; i < count; i++)
297
        {
298
            parseTypeAndSRID(data);
299
            // polys[i] = parsePolygon(data, gHaveZ, gHaveM);
300
	        int countRings = data.getInt();
301
	        // FPolygon2D[] rings = new FPolygon2D[countRings];
302
	        for (int j = 0; j < countRings; j++) {
303
	            // rings[j] = parseLinearRing(data, gHaveZ, gHaveM);
304
	            Point2D[] points = parsePointArray(data, gHaveZ, gHaveM);
305

  
306
	            gp.moveTo(points[0].getX(), points[0].getY());
307
	            for (int k = 1; k< points.length; k++)
308
	            {
309
	            	if (k==points.length-1){
310
	            		gp.closePath();
311
	            	}else{
312
	            		gp.lineTo(points[k].getX(), points[k].getY());
313
	            	}
314

  
315
	            }
316

  
317
	        }
318
	        // GeneralPathX shape=(GeneralPathX)getGeneralPathX(rings);
319

  
320
        }
321
		 // GeneralPathX shape=getGeneralPathX(polys);
322

  
323
        return new Surface2D(gp);
324
    	// return new FPolygon2D(parseGeneralPath(data));
325
    }
326

  
327
    private BaseMultiPrimitive parseCollection(ByteBuffer data) {
328
        int count = data.getInt();
329
        Geometry[] geoms = new Geometry[count];
330
        parseGeometryArray(data, geoms);
331
        return new BaseMultiPrimitive(geoms);
332
    }
333
	/**
334
	 * Devuelve el GeneralPathX compuesto por todos los GeneralPath de todas
335
	 * las geometr?as que componen el elemento.
336
	 *
337
	 * @param geometries Lista de geometr?as.
338
	 *
339
	 * @return GeneralPath completo.
340
	 */
341
	private GeneralPathX getGeneralPathX(FShape[] geometries) {
342
		GeneralPathX shape = new GeneralPathX();
343

  
344
		for (int i = 0; i < geometries.length; i++) {
345
			FShape shp = (FShape) geometries[i];
346
			PathIterator theIterator = shp.getPathIterator(null); //, flatness);
347
			double[] theData = new double[6];
348
			int theType;
349
			ArrayList arrayCoords;
350

  
351
			while (!theIterator.isDone()) {
352
				//while not done
353
				theType = theIterator.currentSegment(theData);
354

  
355
				//Populate a segment of the new
356
				// GeneralPathX object.
357
				//Process the current segment to populate a new
358
				// segment of the new GeneralPathX object.
359
				switch (theType) {
360
					case PathIterator.SEG_MOVETO:
361
						shape.moveTo(theData[0], theData[1]);
362

  
363
						break;
364

  
365
					case PathIterator.SEG_LINETO:
366
						shape.lineTo(theData[0], theData[1]);
367

  
368
						break;
369

  
370
					case PathIterator.SEG_QUADTO:
371
						shape.quadTo(theData[0], theData[1], theData[2],
372
							theData[3]);
373

  
374
						break;
375

  
376
					case PathIterator.SEG_CUBICTO:
377
						shape.curveTo(theData[0], theData[1], theData[2],
378
							theData[3], theData[4], theData[5]);
379

  
380
						break;
381

  
382
					case PathIterator.SEG_CLOSE:
383

  
384
						if (i == (geometries.length - 1)) {
385
							shape.closePath();
386
						}
387

  
388
						break;
389
				} //end switch
390

  
391
				theIterator.next();
392
			} //end while loop
393
		}
394

  
395
		return shape;
396
	}
397
}
branches/v2_0_0_prep/libraries/libFMap_geometries/src/org/gvsig/fmap/geom/operation/fromwkb/FromWKB.java
1

  
2
/* gvSIG. Geographic Information System of the Valencian Government
3
*
4
* Copyright (C) 2007-2008 Infrastructures and Transports Department
5
* of the Valencian Government (CIT)
6
*
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
* MA  02110-1301, USA.
21
*
22
*/
23

  
24
/*
25
* AUTHORS (In addition to CIT):
26
* ${year} IVER T.I. S.A.   {{Task}}
27
*/
28

  
29
package org.gvsig.fmap.geom.operation.fromwkb;
30

  
31
import org.gvsig.fmap.geom.Geometry;
32
import org.gvsig.fmap.geom.GeometryManager;
33
import org.gvsig.fmap.geom.operation.GeometryOperation;
34
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
35
import org.gvsig.fmap.geom.operation.GeometryOperationException;
36

  
37

  
38
/**
39
 * DOCUMENT ME!
40
 *
41
 * @author Vicente Caballero Navarro
42
 */
43
public class FromWKB extends GeometryOperation {
44
    private static WKBParser2 wkbParser = new WKBParser2();
45
    public static final int CODE = GeometryManager.getInstance()
46
                                                  .registerGeometryOperation("fromWKB",
47
            new FromWKB());
48

  
49
    /* (non-Javadoc)
50
     * @see org.gvsig.fmap.geom.operation.GeometryOperation#invoke(org.gvsig.fmap.geom.Geometry, org.gvsig.fmap.geom.operation.GeometryOperationContext)
51
     */
52
    public Object invoke(Geometry geom, GeometryOperationContext ctx)
53
        throws GeometryOperationException {
54
        byte[] data = ((FromWKBGeometryOperationContext) ctx).getData();
55

  
56
        return geom = wkbParser.parse(data);
57
    }
58

  
59
    /* (non-Javadoc)
60
     * @see org.gvsig.fmap.geom.operation.GeometryOperation#getOperationIndex()
61
     */
62
    public int getOperationIndex() {
63
        return CODE;
64
    }
65
}
branches/v2_0_0_prep/libraries/libFMap_geometries/src/org/gvsig/fmap/geom/operation/fromwkb/FromWKBGeometryOperationContext.java
1
package org.gvsig.fmap.geom.operation.fromwkb;
2

  
3
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
4

  
5
public class FromWKBGeometryOperationContext extends GeometryOperationContext{
6
	private byte[] data=null;
7

  
8
	public byte[] getData() {
9
		return data;
10
	}
11

  
12
	public void setData(byte[] data) {
13
		this.data = data;
14
	}
15
}

Also available in: Unified diff