Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.geometry / org.gvsig.fmap.geometry.jts / src / main / java / org / gvsig / fmap / geom / jts / operation / towkb / OGCWKBEncoder.java @ 43020

History | View | Annotate | Download (14.8 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.jts.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 OGCWKBEncoder {
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
                        case TYPES.MULTILINE:
151
                                encodeMultiLineString(geometry, stream);
152
                                break;
153

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

    
159
                        case TYPES.MULTISURFACE:
160
                        case TYPES.MULTIPOLYGON:
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
}