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 @ 40559

History | View | Annotate | Download (15.6 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
/* gvSIG. Geographic Information System of the Valencian Government
25
*
26
* Copyright (C) 2007-2008 Infrastructures and Transports Department
27
* of the Valencian Government (CIT)
28
*
29
* This program is free software; you can redistribute it and/or
30
* modify it under the terms of the GNU General Public License
31
* as published by the Free Software Foundation; either version 2
32
* of the License, or (at your option) any later version.
33
*
34
* This program is distributed in the hope that it will be useful,
35
* but WITHOUT ANY WARRANTY; without even the implied warranty of
36
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37
* GNU General Public License for more details.
38
*
39
* You should have received a copy of the GNU General Public License
40
* along with this program; if not, write to the Free Software
41
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42
* MA  02110-1301, USA.
43
*
44
*/
45

    
46
/*
47
* AUTHORS (In addition to CIT):
48
* 2009 IVER T.I   {{Task}}
49
*/
50

    
51
package org.gvsig.fmap.geom.operation.towkb;
52

    
53
import java.awt.geom.PathIterator;
54
import java.io.ByteArrayOutputStream;
55
import java.io.DataOutputStream;
56
import java.io.IOException;
57
import java.util.ArrayList;
58
import java.util.List;
59

    
60
import org.gvsig.fmap.geom.Geometry;
61
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
62
import org.gvsig.fmap.geom.Geometry.TYPES;
63
import org.gvsig.fmap.geom.aggregate.Aggregate;
64
import org.gvsig.fmap.geom.aggregate.MultiCurve;
65
import org.gvsig.fmap.geom.aggregate.MultiPoint;
66
import org.gvsig.fmap.geom.aggregate.MultiSurface;
67
import org.gvsig.fmap.geom.primitive.Curve;
68
import org.gvsig.fmap.geom.primitive.Point;
69
import org.gvsig.fmap.geom.primitive.Surface;
70
import org.gvsig.fmap.geom.type.GeometryType;
71
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
72

    
73

    
74

    
75
public class WKBEncoder {
76

    
77
        public interface wkbGeometryType {
78
                public final static int wkbPoint = 1;
79
                public final static int wkbLineString = 2;
80
                public final static int wkbPolygon = 3;
81
                public final static int wkbTriangle = 17;
82
                public final static int wkbMultiPoint = 4;
83
                public final static int wkbMultiLineString = 5;
84
                public final static int wkbMultiPolygon = 6;
85
                public final static int wkbGeometryCollection = 7;
86
                public final static int wkbPolyhedralSurface = 15;
87
                public final static int wkbTIN = 16;
88

    
89
                public final static int wkbPointZ = 1001;
90
                public final static int wkbLineStringZ = 1002;
91
                public final static int wkbPolygonZ = 1003;
92
                public final static int wkbTrianglez = 1017;
93
                public final static int wkbMultiPointZ = 1004;
94
                public final static int wkbMultiLineStringZ = 1005;
95
                public final static int wkbMultiPolygonZ = 1006;
96
                public final static int wkbGeometryCollectionZ = 1007;
97
                public final static int wkbPolyhedralSurfaceZ = 1015;
98
                public final static int wkbTINZ = 1016;
99

    
100
                public final static int wkbPointM = 2001;
101
                public final static int wkbLineStringM = 2002;
102
                public final static int wkbPolygonM = 2003;
103
                public final static int wkbTriangleM = 2017;
104
                public final static int wkbMultiPointM = 2004;
105
                public final static int wkbMultiLineStringM = 2005;
106
                public final static int wkbMultiPolygonM = 2006;
107
                public final static int wkbGeometryCollectionM = 2007;
108
                public final static int wkbPolyhedralSurfaceM = 2015;
109
                public final static int wkbTINM = 2016;
110

    
111
                public final static int wkbPointZM = 3001;
112
                public final static int wkbLineStringZM = 3002;
113
                public final static int wkbPolygonZM = 3003;
114
                public final static int wkbTriangleZM = 3017;
115
                public final static int wkbMultiPointZM = 3004;
116
                public final static int wkbMultiLineStringZM = 3005;
117
                public final static int wkbMultiPolygonZM = 3006;
118
                public final static int wkbGeometryCollectionZM = 3007;
119
                public final static int wkbPolyhedralSurfaceZM = 3015;
120
                public final static int wkbTinZM = 3016;
121

    
122
                public final static int wkb_baseToZ = wkbPointZ - wkbPoint;
123
                public final static int wkb_baseToM = wkbPointM - wkbPoint;
124
                public final static int wkb_baseToZM = wkbPointZM - wkbPoint;
125
        }
126

    
127
        public interface wkbByteOrder {
128
                public final static byte wkbXDR = 0;                // Big Endian
129
                public final static byte wkbNDR = 1;                // Little Endian
130
        }
131

    
132

    
133
        public byte[] encode(Geometry geometry)
134
                        throws GeometryTypeNotSupportedException,
135
                        WKBEncodingException,
136
                        IOException {
137
                ByteArrayOutputStream stream;
138

    
139
                if (geometry.getType() == TYPES.POINT) {
140
                        stream = new ByteArrayOutputStream(50);
141
                } else {
142
                        stream = new ByteArrayOutputStream(512);
143
                }
144

    
145
                encode(geometry, stream);
146
                return stream.toByteArray();
147

    
148
        }
149
        public void encode(Geometry geometry, ByteArrayOutputStream stream)
150
                        throws GeometryTypeNotSupportedException, WKBEncodingException,
151
                        IOException {
152
                encode(geometry, new DataOutputStream(stream));
153
        }
154

    
155
        public void encode(Geometry geometry, DataOutputStream stream)
156
                        throws GeometryTypeNotSupportedException,
157
                        WKBEncodingException,
158
                        IOException {
159
                switch (geometry.getType()) {
160
                        case TYPES.POINT:
161
                                encodePoint(geometry, stream);
162
                                break;
163
                        case TYPES.MULTIPOINT:
164
                                encodeMultiPoint(geometry, stream);
165
                                break;
166

    
167
                        case TYPES.ARC:
168
                        case TYPES.CURVE:
169
                        case TYPES.CIRCLE:
170
                        case TYPES.ELLIPSE:
171
                        case TYPES.ELLIPTICARC:
172
                                encodeLineString(geometry, stream);
173
                                break;
174

    
175
                        case TYPES.MULTICURVE:
176
                                encodeMultiLineString(geometry, stream);
177
                                break;
178

    
179
                        case TYPES.SURFACE:
180
                                encodePolygon(geometry, stream);
181
                                break;
182

    
183
                        case TYPES.MULTISURFACE:
184
                                encodeMultiPolygon(geometry, stream);
185
                                break;
186

    
187
                        case TYPES.AGGREGATE:
188
                                encodeCollection(geometry, stream);
189
                                break;
190

    
191
                        default:
192
                                throw new GeometryTypeNotSupportedException(geometry.getType(),
193
                                        geometry.getGeometryType().getSubType());
194
                }
195

    
196
                // FIXME geom.subtype != SUBTYPES.GEOM2D NOT SUPPORTED !!!!
197
                if (geometry.getGeometryType().getSubType() != SUBTYPES.GEOM2D) {
198
                        throw new GeometryTypeNotSupportedException(geometry.getType(),
199
                                        geometry.getGeometryType().getSubType());
200
                }
201
        }
202

    
203

    
204
        private void encodeCollection(Geometry geometry, DataOutputStream stream)
205
                        throws GeometryTypeNotSupportedException,
206
                        WKBEncodingException,
207
                        IOException {
208
                GeometryType geometryType = geometry.getGeometryType();
209
                encodeWKBGeomHead(wkbGeometryType.wkbGeometryCollection, geometryType,
210
                                stream);
211

    
212
                Aggregate collection = (Aggregate) geometry;
213

    
214
                int nGeometries = collection.getPrimitivesNumber();
215
                stream.writeInt(nGeometries);
216
                for (int i = 0; i < nGeometries; i++) {
217
                        encode(collection.getPrimitiveAt(i), stream);
218
                }
219
        }
220

    
221
        private void encodeMultiPolygon(Geometry geometry, DataOutputStream stream)
222
                        throws GeometryTypeNotSupportedException,
223
                        WKBPolygonNotClosedException, IOException {
224
                GeometryType geometryType = geometry.getGeometryType();
225
                encodeWKBGeomHead(wkbGeometryType.wkbMultiPolygon, geometryType, stream);
226

    
227
                MultiSurface surfaces = (MultiSurface) geometry;
228

    
229
                int nGeometries = surfaces.getPrimitivesNumber();
230
                stream.writeInt(nGeometries);
231
                for (int i = 0; i < nGeometries; i++) {
232
                        encodePolygon(surfaces.getPrimitiveAt(i), stream);
233
                }
234
        }
235

    
236
        private void checkLinearRingIsClosed(Geometry geom, List linearRing)
237
                        throws WKBPolygonNotClosedException {
238
                double[] first = (double[]) linearRing.get(0);
239
                double[] last = (double[]) linearRing.get(linearRing.size() - 1);
240

    
241
                for (int i = 0; i < first.length; i++) {
242
                        if (Math.abs(first[i] - last[i]) > 0.000001) {
243
                                throw new WKBPolygonNotClosedException(geom);
244
                        }
245
                }
246

    
247
        }
248

    
249
        private List getLinearRings(Surface surface)
250
                        throws WKBPolygonNotClosedException {
251
                PathIterator theIterator = surface.getPathIterator(null);
252
                List linearRings = new ArrayList();
253
                List curlinearRing = new ArrayList();
254
                int theType;
255
                double[] theData = new double[6];
256

    
257
                while (!theIterator.isDone()) {
258
                        // while not done
259
                        theType = theIterator.currentSegment(theData);
260

    
261
                        // Populate a segment of the new
262
                        // GeneralPathX object.
263
                        // Process the current segment to populate a new
264
                        // segment of the new GeneralPathX object.
265
                        switch (theType) {
266
                        case PathIterator.SEG_MOVETO:
267
                                if (curlinearRing.size() != 0) {
268
                                        if (curlinearRing.size() < 4) {
269
                                                // FIXME exception
270
                                                throw new WKBPolygonNotClosedException(surface);
271
                                        }
272
                                        checkLinearRingIsClosed(surface, curlinearRing);
273
                                        linearRings.add(curlinearRing);
274
                                        curlinearRing = new ArrayList();
275

    
276
                                }
277
                                curlinearRing.add(new double[] { theData[0], theData[1] });
278
                                break;
279

    
280
                        case PathIterator.SEG_LINETO:
281
                                curlinearRing.add(new double[] { theData[0], theData[1] });
282
                                break;
283

    
284
                        case PathIterator.SEG_QUADTO:
285
                                // TODO transform to linear segments
286
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
287

    
288
                                // shape.quadTo(theData[0], theData[1], theData[2], theData[3]);
289

    
290
                                // break;
291

    
292
                        case PathIterator.SEG_CUBICTO:
293
                                // TODO transform to linear segments
294
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
295
                                // shape.curveTo(theData[0], theData[1], theData[2], theData[3],
296
                                // theData[4], theData[5]);
297

    
298
                                // break;
299

    
300
                        case PathIterator.SEG_CLOSE:
301
                                curlinearRing.add(curlinearRing.get(0));
302
                                linearRings.add(curlinearRing);
303
                                curlinearRing = new ArrayList();
304
                                break;
305
                        } // end switch
306

    
307
                        theIterator.next();
308
                }
309

    
310
                if (curlinearRing.size() != 0) {
311
                        if (curlinearRing.size() < 4) {
312
                                // FIXME exception
313
                                throw new WKBPolygonNotClosedException(surface);
314
                        }
315
                        checkLinearRingIsClosed(surface, curlinearRing);
316
                        linearRings.add(curlinearRing);
317
                }
318
                return linearRings;
319
        }
320

    
321
        private List getLines(Curve curve) throws WKBEncodingException {
322
                List lines = new ArrayList();
323
                PathIterator theIterator = curve.getPathIterator(null);
324
                List curlinearRing = new ArrayList();
325
                int theType;
326
                double[] theData = new double[6];
327

    
328
                while (!theIterator.isDone()) {
329
                        // while not done
330
                        theType = theIterator.currentSegment(theData);
331

    
332
                        // Populate a segment of the new
333
                        // GeneralPathX object.
334
                        // Process the current segment to populate a new
335
                        // segment of the new GeneralPathX object.
336
                        switch (theType) {
337
                        case PathIterator.SEG_MOVETO:
338
                                if (curlinearRing.size() != 0) {
339
                                        if (curlinearRing.size() < 2) {
340
                                                throw new WKBOnePointLineException(curve);
341
                                        }
342
                                        lines.add(curlinearRing);
343
                                        curlinearRing = new ArrayList();
344
                                }
345
                                curlinearRing.add(new double[] { theData[0], theData[1] });
346

    
347
                                break;
348

    
349
                        case PathIterator.SEG_LINETO:
350
                                curlinearRing.add(new double[] { theData[0], theData[1] });
351
                                break;
352

    
353
                        case PathIterator.SEG_QUADTO:
354
                                // TODO transform to linear segments
355
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
356

    
357
                                // shape.quadTo(theData[0], theData[1], theData[2], theData[3]);
358

    
359
                                // break;
360

    
361
                        case PathIterator.SEG_CUBICTO:
362
                                // TODO transform to linear segments
363
                                throw new IllegalArgumentException("SEG_QUADTO unsupported");
364
                                // shape.curveTo(theData[0], theData[1], theData[2], theData[3],
365
                                // theData[4], theData[5]);
366

    
367
                                // break;
368

    
369
                        case PathIterator.SEG_CLOSE:
370
                                curlinearRing.add(curlinearRing.get(0));
371
                                break;
372
                        } // end switch
373

    
374
                        theIterator.next();
375
                }
376

    
377
                if (curlinearRing.size() != 0) {
378
                        if (curlinearRing.size() < 2) {
379
                                throw new WKBOnePointLineException(curve);
380
                        }
381
                        lines.add(curlinearRing);
382
                }
383
                return lines;
384
        }
385

    
386

    
387
        private void encodePolygon(Geometry geometry, DataOutputStream stream)
388
                        throws GeometryTypeNotSupportedException,
389
                        WKBPolygonNotClosedException, IOException {
390
                GeometryType geometryType = geometry.getGeometryType();
391
                encodeWKBGeomHead(wkbGeometryType.wkbPolygon, geometryType, stream);
392

    
393
                Surface surface = (Surface) geometry;
394

    
395
                List linearRings = getLinearRings(surface);
396
                stream.writeInt(linearRings.size());
397
                for (int i = 0; i < linearRings.size(); i++) {
398
                        encodeLinearRing((List) linearRings.get(i), stream);
399
                }
400

    
401
        }
402

    
403
        private void encodeLinearRing(List linearRing, DataOutputStream stream)
404
                        throws IOException {
405
                stream.writeInt(linearRing.size());
406
                for (int i = 0; i < linearRing.size(); i++) {
407
                        encodeCoordinates((double[]) linearRing.get(i), stream);
408
                }
409
        }
410

    
411
        private void encodeMultiLineString(Geometry geometry,
412
                        DataOutputStream stream)
413
                        throws GeometryTypeNotSupportedException,
414
                        WKBEncodingException, IOException {
415
                GeometryType geometryType = geometry.getGeometryType();
416
                encodeWKBGeomHead(wkbGeometryType.wkbMultiLineString, geometryType,
417
                                stream);
418

    
419
                MultiCurve curves = (MultiCurve) geometry;
420

    
421
                int nGeometries = curves.getPrimitivesNumber();
422
                stream.writeInt(nGeometries);
423
                for (int i = 0; i < nGeometries; i++) {
424
                        encodeLineString(curves.getPrimitiveAt(i), stream);
425
                }
426
        }
427

    
428
        private void encodeLineString(Geometry geometry, DataOutputStream stream)
429
                        throws GeometryTypeNotSupportedException, WKBEncodingException,
430
                        IOException {
431
                GeometryType geometryType = geometry.getGeometryType();
432
                encodeWKBGeomHead(wkbGeometryType.wkbLineString, geometryType,
433
                                 stream);
434

    
435
                Curve curve = (Curve) geometry;
436

    
437
                List lines = getLines(curve);
438
                if (lines.size() != 1) {
439
                        throw new WKBMultyLineInLineDefinitionException(curve);
440
                }
441

    
442
                List line = (List) lines.get(0);
443
                int nVertices = line.size();
444
                stream.writeInt(nVertices);
445
                for (int i = 0; i < nVertices; i++) {
446
                        encodeCoordinates((double[]) line.get(i), stream);
447
                }
448

    
449
        }
450

    
451

    
452
        private void encodeCoordinates(double[] coordinates, DataOutputStream stream)
453
                        throws IOException {
454
                for (int i = 0; i < coordinates.length; i++) {
455
                        stream.writeDouble(coordinates[i]);
456
                }
457
        }
458

    
459
        private void encodeWKBGeomHead(int wkbBaseType, GeometryType geometryType,
460
                        DataOutputStream stream) throws GeometryTypeNotSupportedException,
461
                        IOException {
462

    
463
                stream.writeByte(wkbByteOrder.wkbXDR);
464

    
465
                int finalType = wkbBaseType % wkbGeometryType.wkb_baseToZ;
466

    
467
                switch (geometryType.getSubType()) {
468
                case SUBTYPES.GEOM2D:
469
                        break;
470
                case SUBTYPES.GEOM2DM:
471
                        finalType = finalType + wkbGeometryType.wkb_baseToM;
472
                        break;
473
                
474
                case SUBTYPES.GEOM3D:
475
                        finalType = finalType + wkbGeometryType.wkb_baseToZ;
476
                        break;
477

    
478
                case SUBTYPES.GEOM3DM:
479
                        finalType = finalType + wkbGeometryType.wkb_baseToZM;
480
                        break;
481

    
482

    
483
                default:
484
                        throw new GeometryTypeNotSupportedException(geometryType.getType(),
485
                                        geometryType.getSubType());
486

    
487
                }
488

    
489
                stream.writeInt(finalType);
490

    
491

    
492
        }
493

    
494

    
495
        private void encodePoint(Geometry geometry, DataOutputStream stream)
496
                        throws GeometryTypeNotSupportedException, IOException {
497
                GeometryType geometryType = geometry.getGeometryType();
498
                encodeWKBGeomHead(wkbGeometryType.wkbPoint, geometryType,
499
                                stream);
500

    
501
                Point point = (Point) geometry;
502
                double[] coords = point.getCoordinates();
503
                for (int i = 0; i < coords.length; i++) {
504
                        stream.writeDouble(coords[i]);
505
                }
506

    
507
        }
508

    
509
        private void encodeMultiPoint(Geometry geometry, DataOutputStream stream)
510
                        throws GeometryTypeNotSupportedException, IOException {
511
                GeometryType geometryType = geometry.getGeometryType();
512
                encodeWKBGeomHead(wkbGeometryType.wkbMultiPoint, geometryType, stream);
513

    
514
                MultiPoint points = (MultiPoint) geometry;
515

    
516
                int nGeometries = points.getPrimitivesNumber();
517
                stream.writeInt(nGeometries);
518
                for (int i=0;i<nGeometries;i++) {
519
                        encodePoint(points.getPrimitiveAt(i), stream);
520
                }
521
        }
522

    
523

    
524

    
525
}