Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_geometries / src / org / gvsig / fmap / geom / operation / towkb / WKBEncoder.java @ 34899

History | View | Annotate | Download (14.7 KB)

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

    
23
/*
24
* AUTHORS (In addition to CIT):
25
* 2009 IVER T.I   {{Task}}
26
*/
27

    
28
package org.gvsig.fmap.geom.operation.towkb;
29

    
30
import java.awt.geom.PathIterator;
31
import java.io.ByteArrayOutputStream;
32
import java.io.DataOutputStream;
33
import java.io.IOException;
34
import java.util.ArrayList;
35
import java.util.List;
36

    
37
import org.gvsig.fmap.geom.Geometry;
38
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
39
import org.gvsig.fmap.geom.Geometry.TYPES;
40
import org.gvsig.fmap.geom.aggregate.Aggregate;
41
import org.gvsig.fmap.geom.aggregate.MultiCurve;
42
import org.gvsig.fmap.geom.aggregate.MultiPoint;
43
import org.gvsig.fmap.geom.aggregate.MultiSurface;
44
import org.gvsig.fmap.geom.primitive.Curve;
45
import org.gvsig.fmap.geom.primitive.Point;
46
import org.gvsig.fmap.geom.primitive.Surface;
47
import org.gvsig.fmap.geom.type.GeometryType;
48
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
49

    
50

    
51

    
52
public class WKBEncoder {
53

    
54
        public interface wkbGeometryType {
55
                public final static int wkbPoint = 1;
56
                public final static int wkbLineString = 2;
57
                public final static int wkbPolygon = 3;
58
                public final static int wkbTriangle = 17;
59
                public final static int wkbMultiPoint = 4;
60
                public final static int wkbMultiLineString = 5;
61
                public final static int wkbMultiPolygon = 6;
62
                public final static int wkbGeometryCollection = 7;
63
                public final static int wkbPolyhedralSurface = 15;
64
                public final static int wkbTIN = 16;
65

    
66
                public final static int wkbPointZ = 1001;
67
                public final static int wkbLineStringZ = 1002;
68
                public final static int wkbPolygonZ = 1003;
69
                public final static int wkbTrianglez = 1017;
70
                public final static int wkbMultiPointZ = 1004;
71
                public final static int wkbMultiLineStringZ = 1005;
72
                public final static int wkbMultiPolygonZ = 1006;
73
                public final static int wkbGeometryCollectionZ = 1007;
74
                public final static int wkbPolyhedralSurfaceZ = 1015;
75
                public final static int wkbTINZ = 1016;
76

    
77
                public final static int wkbPointM = 2001;
78
                public final static int wkbLineStringM = 2002;
79
                public final static int wkbPolygonM = 2003;
80
                public final static int wkbTriangleM = 2017;
81
                public final static int wkbMultiPointM = 2004;
82
                public final static int wkbMultiLineStringM = 2005;
83
                public final static int wkbMultiPolygonM = 2006;
84
                public final static int wkbGeometryCollectionM = 2007;
85
                public final static int wkbPolyhedralSurfaceM = 2015;
86
                public final static int wkbTINM = 2016;
87

    
88
                public final static int wkbPointZM = 3001;
89
                public final static int wkbLineStringZM = 3002;
90
                public final static int wkbPolygonZM = 3003;
91
                public final static int wkbTriangleZM = 3017;
92
                public final static int wkbMultiPointZM = 3004;
93
                public final static int wkbMultiLineStringZM = 3005;
94
                public final static int wkbMultiPolygonZM = 3006;
95
                public final static int wkbGeometryCollectionZM = 3007;
96
                public final static int wkbPolyhedralSurfaceZM = 3015;
97
                public final static int wkbTinZM = 3016;
98

    
99
                public final static int wkb_baseToZ = wkbPointZ - wkbPoint;
100
                public final static int wkb_baseToM = wkbPointM - wkbPoint;
101
                public final static int wkb_baseToZM = wkbPointZM - wkbPoint;
102
        }
103

    
104
        public interface wkbByteOrder {
105
                public final static byte wkbXDR = 0;                // Big Endian
106
                public final static byte wkbNDR = 1;                // Little Endian
107
        }
108

    
109

    
110
        public byte[] encode(Geometry geometry)
111
                        throws GeometryTypeNotSupportedException,
112
                        WKBEncodingException,
113
                        IOException {
114
                ByteArrayOutputStream stream;
115

    
116
                if (geometry.getType() == TYPES.POINT) {
117
                        stream = new ByteArrayOutputStream(50);
118
                } else {
119
                        stream = new ByteArrayOutputStream(512);
120
                }
121

    
122
                encode(geometry, stream);
123
                return stream.toByteArray();
124

    
125
        }
126
        public void encode(Geometry geometry, ByteArrayOutputStream stream)
127
                        throws GeometryTypeNotSupportedException, WKBEncodingException,
128
                        IOException {
129
                encode(geometry, new DataOutputStream(stream));
130
        }
131

    
132
        public void encode(Geometry geometry, DataOutputStream stream)
133
                        throws GeometryTypeNotSupportedException,
134
                        WKBEncodingException,
135
                        IOException {
136
                switch (geometry.getType()) {
137
                        case TYPES.POINT:
138
                                encodePoint(geometry, stream);
139
                                break;
140
                        case TYPES.MULTIPOINT:
141
                                encodeMultiPoint(geometry, stream);
142
                                break;
143

    
144
                        case TYPES.ARC:
145
                        case TYPES.CURVE:
146
                        case TYPES.CIRCLE:
147
                        case TYPES.ELLIPSE:
148
                        case TYPES.ELLIPTICARC:
149
                                encodeLineString(geometry, stream);
150
                                break;
151

    
152
                        case TYPES.MULTICURVE:
153
                                encodeMultiLineString(geometry, stream);
154
                                break;
155

    
156
                        case TYPES.SURFACE:
157
                                encodePolygon(geometry, stream);
158
                                break;
159

    
160
                        case TYPES.MULTISURFACE:
161
                                encodeMultiPolygon(geometry, stream);
162
                                break;
163

    
164
                        case TYPES.AGGREGATE:
165
                                encodeCollection(geometry, stream);
166
                                break;
167

    
168
                        default:
169
                                throw new GeometryTypeNotSupportedException(geometry.getType(),
170
                                        geometry.getGeometryType().getSubType());
171
                }
172

    
173
                // FIXME geom.subtype != SUBTYPES.GEOM2D NOT SUPPORTED !!!!
174
                if (geometry.getGeometryType().getSubType() != SUBTYPES.GEOM2D) {
175
                        throw new GeometryTypeNotSupportedException(geometry.getType(),
176
                                        geometry.getGeometryType().getSubType());
177
                }
178
        }
179

    
180

    
181
        private void encodeCollection(Geometry geometry, DataOutputStream stream)
182
                        throws GeometryTypeNotSupportedException,
183
                        WKBEncodingException,
184
                        IOException {
185
                GeometryType geometryType = geometry.getGeometryType();
186
                encodeWKBGeomHead(wkbGeometryType.wkbGeometryCollection, geometryType,
187
                                stream);
188

    
189
                Aggregate collection = (Aggregate) geometry;
190

    
191
                int nGeometries = collection.getPrimitivesNumber();
192
                stream.writeInt(nGeometries);
193
                for (int i = 0; i < nGeometries; i++) {
194
                        encode(collection.getPrimitiveAt(i), stream);
195
                }
196
        }
197

    
198
        private void encodeMultiPolygon(Geometry geometry, DataOutputStream stream)
199
                        throws GeometryTypeNotSupportedException,
200
                        WKBPolygonNotClosedException, IOException {
201
                GeometryType geometryType = geometry.getGeometryType();
202
                encodeWKBGeomHead(wkbGeometryType.wkbMultiPolygon, geometryType, stream);
203

    
204
                MultiSurface surfaces = (MultiSurface) geometry;
205

    
206
                int nGeometries = surfaces.getPrimitivesNumber();
207
                stream.writeInt(nGeometries);
208
                for (int i = 0; i < nGeometries; i++) {
209
                        encodePolygon(surfaces.getPrimitiveAt(i), stream);
210
                }
211
        }
212

    
213
        private void checkLinearRingIsClosed(Geometry geom, List linearRing)
214
                        throws WKBPolygonNotClosedException {
215
                double[] first = (double[]) linearRing.get(0);
216
                double[] last = (double[]) linearRing.get(linearRing.size() - 1);
217

    
218
                for (int i = 0; i < first.length; i++) {
219
                        if (Math.abs(first[i] - last[i]) > 0.000001) {
220
                                throw new WKBPolygonNotClosedException(geom);
221
                        }
222
                }
223

    
224
        }
225

    
226
        private List getLinearRings(Surface surface)
227
                        throws WKBPolygonNotClosedException {
228
                PathIterator theIterator = surface.getPathIterator(null);
229
                List linearRings = new ArrayList();
230
                List curlinearRing = new ArrayList();
231
                int theType;
232
                double[] theData = new double[6];
233

    
234
                while (!theIterator.isDone()) {
235
                        // while not done
236
                        theType = theIterator.currentSegment(theData);
237

    
238
                        // Populate a segment of the new
239
                        // GeneralPathX object.
240
                        // Process the current segment to populate a new
241
                        // segment of the new GeneralPathX object.
242
                        switch (theType) {
243
                        case PathIterator.SEG_MOVETO:
244
                                if (curlinearRing.size() != 0) {
245
                                        if (curlinearRing.size() < 4) {
246
                                                // FIXME exception
247
                                                throw new WKBPolygonNotClosedException(surface);
248
                                        }
249
                                        checkLinearRingIsClosed(surface, curlinearRing);
250
                                        linearRings.add(curlinearRing);
251
                                        curlinearRing = new ArrayList();
252

    
253
                                }
254
                                curlinearRing.add(new double[] { theData[0], theData[1] });
255
                                break;
256

    
257
                        case PathIterator.SEG_LINETO:
258
                                curlinearRing.add(new double[] { theData[0], theData[1] });
259
                                break;
260

    
261
                        case PathIterator.SEG_QUADTO:
262
                                // TODO transform to linear segments
263
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
264

    
265
                                // shape.quadTo(theData[0], theData[1], theData[2], theData[3]);
266

    
267
                                // break;
268

    
269
                        case PathIterator.SEG_CUBICTO:
270
                                // TODO transform to linear segments
271
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
272
                                // shape.curveTo(theData[0], theData[1], theData[2], theData[3],
273
                                // theData[4], theData[5]);
274

    
275
                                // break;
276

    
277
                        case PathIterator.SEG_CLOSE:
278
                                curlinearRing.add(curlinearRing.get(0));
279
                                linearRings.add(curlinearRing);
280
                                curlinearRing = new ArrayList();
281
                                break;
282
                        } // end switch
283

    
284
                        theIterator.next();
285
                }
286

    
287
                if (curlinearRing.size() != 0) {
288
                        if (curlinearRing.size() < 4) {
289
                                // FIXME exception
290
                                throw new WKBPolygonNotClosedException(surface);
291
                        }
292
                        checkLinearRingIsClosed(surface, curlinearRing);
293
                        linearRings.add(curlinearRing);
294
                }
295
                return linearRings;
296
        }
297

    
298
        private List getLines(Curve curve) throws WKBEncodingException {
299
                List lines = new ArrayList();
300
                PathIterator theIterator = curve.getPathIterator(null);
301
                List curlinearRing = new ArrayList();
302
                int theType;
303
                double[] theData = new double[6];
304

    
305
                while (!theIterator.isDone()) {
306
                        // while not done
307
                        theType = theIterator.currentSegment(theData);
308

    
309
                        // Populate a segment of the new
310
                        // GeneralPathX object.
311
                        // Process the current segment to populate a new
312
                        // segment of the new GeneralPathX object.
313
                        switch (theType) {
314
                        case PathIterator.SEG_MOVETO:
315
                                if (curlinearRing.size() != 0) {
316
                                        if (curlinearRing.size() < 2) {
317
                                                throw new WKBOnePointLineException(curve);
318
                                        }
319
                                        lines.add(curlinearRing);
320
                                        curlinearRing = new ArrayList();
321
                                }
322
                                curlinearRing.add(new double[] { theData[0], theData[1] });
323

    
324
                                break;
325

    
326
                        case PathIterator.SEG_LINETO:
327
                                curlinearRing.add(new double[] { theData[0], theData[1] });
328
                                break;
329

    
330
                        case PathIterator.SEG_QUADTO:
331
                                // TODO transform to linear segments
332
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
333

    
334
                                // shape.quadTo(theData[0], theData[1], theData[2], theData[3]);
335

    
336
                                // break;
337

    
338
                        case PathIterator.SEG_CUBICTO:
339
                                // TODO transform to linear segments
340
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
341
                                // shape.curveTo(theData[0], theData[1], theData[2], theData[3],
342
                                // theData[4], theData[5]);
343

    
344
                                // break;
345

    
346
                        case PathIterator.SEG_CLOSE:
347
                                curlinearRing.add(curlinearRing.get(0));
348
                                break;
349
                        } // end switch
350

    
351
                        theIterator.next();
352
                }
353

    
354
                if (curlinearRing.size() != 0) {
355
                        if (curlinearRing.size() < 2) {
356
                                throw new WKBOnePointLineException(curve);
357
                        }
358
                        lines.add(curlinearRing);
359
                }
360
                return lines;
361
        }
362

    
363

    
364
        private void encodePolygon(Geometry geometry, DataOutputStream stream)
365
                        throws GeometryTypeNotSupportedException,
366
                        WKBPolygonNotClosedException, IOException {
367
                GeometryType geometryType = geometry.getGeometryType();
368
                encodeWKBGeomHead(wkbGeometryType.wkbPolygon, geometryType, stream);
369

    
370
                Surface surface = (Surface) geometry;
371

    
372
                List linearRings = getLinearRings(surface);
373
                stream.writeInt(linearRings.size());
374
                for (int i = 0; i < linearRings.size(); i++) {
375
                        encodeLinearRing((List) linearRings.get(i), stream);
376
                }
377

    
378
        }
379

    
380
        private void encodeLinearRing(List linearRing, DataOutputStream stream)
381
                        throws IOException {
382
                stream.writeInt(linearRing.size());
383
                for (int i = 0; i < linearRing.size(); i++) {
384
                        encodeCoordinates((double[]) linearRing.get(i), stream);
385
                }
386
        }
387

    
388
        private void encodeMultiLineString(Geometry geometry,
389
                        DataOutputStream stream)
390
                        throws GeometryTypeNotSupportedException,
391
                        WKBEncodingException, IOException {
392
                GeometryType geometryType = geometry.getGeometryType();
393
                encodeWKBGeomHead(wkbGeometryType.wkbMultiLineString, geometryType,
394
                                stream);
395

    
396
                MultiCurve curves = (MultiCurve) geometry;
397

    
398
                int nGeometries = curves.getPrimitivesNumber();
399
                stream.writeInt(nGeometries);
400
                for (int i = 0; i < nGeometries; i++) {
401
                        encodeLineString(curves.getPrimitiveAt(i), stream);
402
                }
403
        }
404

    
405
        private void encodeLineString(Geometry geometry, DataOutputStream stream)
406
                        throws GeometryTypeNotSupportedException, WKBEncodingException,
407
                        IOException {
408
                GeometryType geometryType = geometry.getGeometryType();
409
                encodeWKBGeomHead(wkbGeometryType.wkbLineString, geometryType,
410
                                 stream);
411

    
412
                Curve curve = (Curve) geometry;
413

    
414
                List lines = getLines(curve);
415
                if (lines.size() != 1) {
416
                        throw new WKBMultyLineInLineDefinitionException(curve);
417
                }
418

    
419
                List line = (List) lines.get(0);
420
                int nVertices = line.size();
421
                stream.writeInt(nVertices);
422
                for (int i = 0; i < nVertices; i++) {
423
                        encodeCoordinates((double[]) line.get(i), stream);
424
                }
425

    
426
        }
427

    
428

    
429
        private void encodeCoordinates(double[] coordinates, DataOutputStream stream)
430
                        throws IOException {
431
                for (int i = 0; i < coordinates.length; i++) {
432
                        stream.writeDouble(coordinates[i]);
433
                }
434
        }
435

    
436
        private void encodeWKBGeomHead(int wkbBaseType, GeometryType geometryType,
437
                        DataOutputStream stream) throws GeometryTypeNotSupportedException,
438
                        IOException {
439

    
440
                stream.writeByte(wkbByteOrder.wkbXDR);
441

    
442
                int finalType = wkbBaseType % wkbGeometryType.wkb_baseToZ;
443

    
444
                switch (geometryType.getSubType()) {
445
                case SUBTYPES.GEOM2D:
446
                        break;
447
                case SUBTYPES.GEOM2DM:
448
                        finalType = finalType + wkbGeometryType.wkb_baseToM;
449
                        break;
450
                
451
                case SUBTYPES.GEOM3D:
452
                        finalType = finalType + wkbGeometryType.wkb_baseToZ;
453
                        break;
454

    
455
                case SUBTYPES.GEOM3DM:
456
                        finalType = finalType + wkbGeometryType.wkb_baseToZM;
457
                        break;
458

    
459

    
460
                default:
461
                        throw new GeometryTypeNotSupportedException(geometryType.getType(),
462
                                        geometryType.getSubType());
463

    
464
                }
465

    
466
                stream.writeInt(finalType);
467

    
468

    
469
        }
470

    
471

    
472
        private void encodePoint(Geometry geometry, DataOutputStream stream)
473
                        throws GeometryTypeNotSupportedException, IOException {
474
                GeometryType geometryType = geometry.getGeometryType();
475
                encodeWKBGeomHead(wkbGeometryType.wkbPoint, geometryType,
476
                                stream);
477

    
478
                Point point = (Point) geometry;
479
                double[] coords = point.getCoordinates();
480
                for (int i = 0; i < coords.length; i++) {
481
                        stream.writeDouble(coords[i]);
482
                }
483

    
484
        }
485

    
486
        private void encodeMultiPoint(Geometry geometry, DataOutputStream stream)
487
                        throws GeometryTypeNotSupportedException, IOException {
488
                GeometryType geometryType = geometry.getGeometryType();
489
                encodeWKBGeomHead(wkbGeometryType.wkbMultiPoint, geometryType, stream);
490

    
491
                MultiPoint points = (MultiPoint) geometry;
492

    
493
                int nGeometries = points.getPrimitivesNumber();
494
                stream.writeInt(nGeometries);
495
                for (int i=0;i<nGeometries;i++) {
496
                        encodePoint(points.getPrimitiveAt(i), stream);
497
                }
498
        }
499

    
500

    
501

    
502
}