Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.geometry / org.gvsig.fmap.geometry.operation / src / main / java / org / gvsig / fmap / geom / operation / towkb / WKBEncoder.java @ 40596

History | View | Annotate | Download (14.7 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
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 3
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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

    
25
package org.gvsig.fmap.geom.operation.towkb;
26

    
27
import java.awt.geom.PathIterator;
28
import java.io.ByteArrayOutputStream;
29
import java.io.DataOutputStream;
30
import java.io.IOException;
31
import java.util.ArrayList;
32
import java.util.List;
33

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

    
47

    
48

    
49
public class WKBEncoder {
50

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

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

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

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

    
96
                public final static int wkb_baseToZ = wkbPointZ - wkbPoint;
97
                public final static int wkb_baseToM = wkbPointM - wkbPoint;
98
                public final static int wkb_baseToZM = wkbPointZM - wkbPoint;
99
        }
100

    
101
        public interface wkbByteOrder {
102
                public final static byte wkbXDR = 0;                // Big Endian
103
                public final static byte wkbNDR = 1;                // Little Endian
104
        }
105

    
106

    
107
        public byte[] encode(Geometry geometry)
108
                        throws GeometryTypeNotSupportedException,
109
                        WKBEncodingException,
110
                        IOException {
111
                ByteArrayOutputStream stream;
112

    
113
                if (geometry.getType() == TYPES.POINT) {
114
                        stream = new ByteArrayOutputStream(50);
115
                } else {
116
                        stream = new ByteArrayOutputStream(512);
117
                }
118

    
119
                encode(geometry, stream);
120
                return stream.toByteArray();
121

    
122
        }
123
        public void encode(Geometry geometry, ByteArrayOutputStream stream)
124
                        throws GeometryTypeNotSupportedException, WKBEncodingException,
125
                        IOException {
126
                encode(geometry, new DataOutputStream(stream));
127
        }
128

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

    
141
                        case TYPES.ARC:
142
                        case TYPES.CURVE:
143
                        case TYPES.CIRCLE:
144
                        case TYPES.ELLIPSE:
145
                        case TYPES.ELLIPTICARC:
146
                                encodeLineString(geometry, stream);
147
                                break;
148

    
149
                        case TYPES.MULTICURVE:
150
                                encodeMultiLineString(geometry, stream);
151
                                break;
152

    
153
                        case TYPES.SURFACE:
154
                                encodePolygon(geometry, stream);
155
                                break;
156

    
157
                        case TYPES.MULTISURFACE:
158
                                encodeMultiPolygon(geometry, stream);
159
                                break;
160

    
161
                        case TYPES.AGGREGATE:
162
                                encodeCollection(geometry, stream);
163
                                break;
164

    
165
                        default:
166
                                throw new GeometryTypeNotSupportedException(geometry.getType(),
167
                                        geometry.getGeometryType().getSubType());
168
                }
169

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

    
177

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

    
186
                Aggregate collection = (Aggregate) geometry;
187

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

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

    
201
                MultiSurface surfaces = (MultiSurface) geometry;
202

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

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

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

    
221
        }
222

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

    
231
                while (!theIterator.isDone()) {
232
                        // while not done
233
                        theType = theIterator.currentSegment(theData);
234

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

    
250
                                }
251
                                curlinearRing.add(new double[] { theData[0], theData[1] });
252
                                break;
253

    
254
                        case PathIterator.SEG_LINETO:
255
                                curlinearRing.add(new double[] { theData[0], theData[1] });
256
                                break;
257

    
258
                        case PathIterator.SEG_QUADTO:
259
                                // TODO transform to linear segments
260
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
261

    
262
                                // shape.quadTo(theData[0], theData[1], theData[2], theData[3]);
263

    
264
                                // break;
265

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

    
272
                                // break;
273

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

    
281
                        theIterator.next();
282
                }
283

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

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

    
302
                while (!theIterator.isDone()) {
303
                        // while not done
304
                        theType = theIterator.currentSegment(theData);
305

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

    
321
                                break;
322

    
323
                        case PathIterator.SEG_LINETO:
324
                                curlinearRing.add(new double[] { theData[0], theData[1] });
325
                                break;
326

    
327
                        case PathIterator.SEG_QUADTO:
328
                                // TODO transform to linear segments
329
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
330

    
331
                                // shape.quadTo(theData[0], theData[1], theData[2], theData[3]);
332

    
333
                                // break;
334

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

    
341
                                // break;
342

    
343
                        case PathIterator.SEG_CLOSE:
344
                                curlinearRing.add(curlinearRing.get(0));
345
                                break;
346
                        } // end switch
347

    
348
                        theIterator.next();
349
                }
350

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

    
360

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

    
367
                Surface surface = (Surface) geometry;
368

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

    
375
        }
376

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

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

    
393
                MultiCurve curves = (MultiCurve) geometry;
394

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

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

    
409
                Curve curve = (Curve) geometry;
410

    
411
                List lines = getLines(curve);
412
                if (lines.size() != 1) {
413
                        throw new WKBMultyLineInLineDefinitionException(curve);
414
                }
415

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

    
423
        }
424

    
425

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

    
433
        private void encodeWKBGeomHead(int wkbBaseType, GeometryType geometryType,
434
                        DataOutputStream stream) throws GeometryTypeNotSupportedException,
435
                        IOException {
436

    
437
                stream.writeByte(wkbByteOrder.wkbXDR);
438

    
439
                int finalType = wkbBaseType % wkbGeometryType.wkb_baseToZ;
440

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

    
452
                case SUBTYPES.GEOM3DM:
453
                        finalType = finalType + wkbGeometryType.wkb_baseToZM;
454
                        break;
455

    
456

    
457
                default:
458
                        throw new GeometryTypeNotSupportedException(geometryType.getType(),
459
                                        geometryType.getSubType());
460

    
461
                }
462

    
463
                stream.writeInt(finalType);
464

    
465

    
466
        }
467

    
468

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

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

    
481
        }
482

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

    
488
                MultiPoint points = (MultiPoint) geometry;
489

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

    
497

    
498

    
499
}