Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / shp / write / SHPFileWrite.java @ 24154

History | View | Annotate | Download (8.92 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package com.iver.cit.gvsig.fmap.drivers.shp.write;
42

    
43
import java.awt.geom.Rectangle2D;
44
import java.io.IOException;
45
import java.nio.ByteBuffer;
46
import java.nio.ByteOrder;
47
import java.nio.channels.FileChannel;
48

    
49
import com.iver.cit.gvsig.fmap.core.FShape;
50
import com.iver.cit.gvsig.fmap.core.IGeometry;
51
import com.iver.cit.gvsig.fmap.core.v02.FConstant;
52
import com.iver.cit.gvsig.fmap.drivers.shp.SHP;
53
import com.iver.cit.gvsig.fmap.drivers.shp.ShapeFileHeader;
54

    
55

    
56
/**
57
 * DOCUMENT ME!
58
 *
59
 * @author Vicente Caballero Navarro
60
 */
61
public class SHPFileWrite {
62
        private SHPShape m_shape = null;
63
        private ByteBuffer m_bb = null;
64
        private ByteBuffer m_indexBuffer = null;
65
        private int m_pos = 0;
66
        private int m_offset;
67
        private int m_type;
68
        private int m_cnt;
69
        private FileChannel shpChannel;
70
        private FileChannel shxChannel;
71
//        private double flatness;
72

    
73
        /**
74
         * Crea un nuevo SHPFileWrite.
75
         *
76
         * @param shpChannel DOCUMENT ME!
77
         * @param shxChannel DOCUMENT ME!
78
         */
79
        public SHPFileWrite(FileChannel shpChannel, FileChannel shxChannel) {
80
                this.shpChannel = shpChannel;
81
                this.shxChannel = shxChannel;
82
        }
83

    
84
        /**
85
         * Make sure our buffer is of size.
86
         *
87
         * @param size DOCUMENT ME!
88
         */
89
        private void checkShapeBuffer(int size) {
90
                if (m_bb.capacity() < size) {
91
                        m_bb = ByteBuffer.allocateDirect(size);
92
                }
93
        }
94

    
95
        /**
96
         * Drain internal buffers into underlying channels.
97
         *
98
         * @throws IOException DOCUMENT ME!
99
         */
100
        private void drain() throws IOException {
101
                m_bb.flip();
102
                m_indexBuffer.flip();
103

    
104
                while (m_bb.remaining() > 0)
105
                        shpChannel.write(m_bb);
106

    
107
                while (m_indexBuffer.remaining() > 0)
108
                        shxChannel.write(m_indexBuffer);
109

    
110
                m_bb.flip().limit(m_bb.capacity());
111
                m_indexBuffer.flip().limit(m_indexBuffer.capacity());
112
        }
113

    
114
        /**
115
         * DOCUMENT ME!
116
         */
117
        private void allocateBuffers() {
118
                m_bb = ByteBuffer.allocateDirect(16 * 1024);
119
                m_indexBuffer = ByteBuffer.allocateDirect(100);
120
        }
121

    
122
        /**
123
         * Close the underlying Channels.
124
         *
125
         * @throws IOException DOCUMENT ME!
126
         */
127
        public void close() throws IOException {
128
                shpChannel.close();
129
                shxChannel.close();
130
                shpChannel = null;
131
                shxChannel = null;
132
                m_shape = null;
133

    
134
                if (m_indexBuffer instanceof ByteBuffer) {
135
                        if (m_indexBuffer != null) {
136
                                ///NIOUtilities.clean(m_indexBuffer);
137
                        }
138
                }
139

    
140
                if (m_indexBuffer instanceof ByteBuffer) {
141
                        if (m_indexBuffer != null) {
142
                                ///NIOUtilities.clean(m_bb);
143
                        }
144
                }
145

    
146
                m_indexBuffer = null;
147
                m_bb = null;
148
        }
149

    
150
        /**
151
         * DOCUMENT ME!
152
         *
153
         * @param geometries DOCUMENT ME!
154
         * @param type DOCUMENT ME!
155
         *
156
         * @throws IOException DOCUMENT ME!
157
         * @throws ShapefileException DOCUMENT ME!
158
         */
159
        public void write(IGeometry[] geometries, int type)
160
                throws IOException, ShapefileException {
161
                m_shape = SHP.create(type);
162
//                m_shape.setFlatness(flatness);
163
                writeHeaders(geometries, type);
164

    
165
                m_pos = m_bb.position();
166

    
167
                for (int i = 0, ii = geometries.length; i < ii; i++) {
168
                        writeGeometry(geometries[i]);
169
                }
170

    
171
                close();
172
        }
173

    
174
        /**
175
         * DOCUMENT ME!
176
         *
177
         * @param geometries DOCUMENT ME!
178
         * @param type DOCUMENT ME!
179
         *
180
         * @throws IOException DOCUMENT ME!
181
         */
182
        private void writeHeaders(IGeometry[] geometries, int type)
183
                throws IOException {
184
                int fileLength = 100;
185
                Rectangle2D extent = null;
186

    
187
                for (int i = geometries.length - 1; i >= 0; i--) {
188
                        IGeometry fgeometry = geometries[i];
189
                        m_shape.obtainsPoints(fgeometry);
190
                        int size = m_shape.getLength(fgeometry) + 8;
191
                        fileLength += size;
192

    
193
                        if (extent == null) {
194
                                extent = new Rectangle2D.Double(fgeometry.getBounds2D().getMinX(),
195
                                                fgeometry.getBounds2D().getMinY(),
196
                                                fgeometry.getBounds2D().getWidth(),
197
                                                fgeometry.getBounds2D().getHeight());
198
                        } else {
199
                                extent.add(fgeometry.getBounds2D());
200
                        }
201
                }
202

    
203
                writeHeaders(extent, type, geometries.length, fileLength);
204
        }
205

    
206
        /**
207
         * Writes shape header (100 bytes)
208
         *
209
         * @param bounds DOCUMENT ME!
210
         * @param type DOCUMENT ME!
211
         * @param numberOfGeometries DOCUMENT ME!
212
         * @param fileLength DOCUMENT ME!
213
         *
214
         * @throws IOException DOCUMENT ME!
215
         */
216
        public void writeHeaders(Rectangle2D bounds, int type,
217
                int numberOfGeometries, int fileLength) throws IOException {
218
                /*try {
219
                   handler = type.getShapeHandler();
220
                   } catch (ShapefileException se) {
221
                     throw new RuntimeException("unexpected Exception",se);
222
                   }
223
                 */
224
                if (m_bb == null) {
225
                        allocateBuffers();
226
                }
227
                // Posicionamos al principio.
228
                m_bb.position(0);
229
                m_indexBuffer.position(0);
230

    
231
                ShapeFileHeader header = new ShapeFileHeader();
232

    
233
                header.write(m_bb, type, numberOfGeometries, fileLength / 2,
234
                        bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(),
235
                        bounds.getMaxY(), 0, 0, 0, 0);
236

    
237
                header.write(m_indexBuffer, type, numberOfGeometries,
238
                        50 + (4 * numberOfGeometries), bounds.getMinX(), bounds.getMinY(),
239
                        bounds.getMaxX(), bounds.getMaxY(), 0, 0, 0, 0);
240

    
241
                m_offset = 50;
242
                m_type = type;
243
                m_cnt = 0;
244

    
245
                shpChannel.position(0);
246
                shxChannel.position(0);
247
                drain();
248
        }
249
        public int writeIGeometry(IGeometry g) throws IOException, ShapefileException
250
        {
251
                int shapeType = getShapeType(g.getGeometryType());
252
                m_shape = SHP.create(shapeType);
253
//                m_shape.setFlatness(flatness);
254
                return writeGeometry(g);
255
        }
256

    
257

    
258

    
259
        /**
260
         * Writes a single Geometry.
261
         *
262
         * @param g
263
         * @return the position of buffer (after the last geometry, it will allow you to
264
         * write the file size in the header.
265
         * @throws IOException
266
         */
267
        public synchronized int writeGeometry(IGeometry g) throws IOException {
268
                if (m_bb == null) {
269
                        allocateBuffers();
270
                        m_offset = 50;
271
                        m_cnt = 0;
272

    
273
                        shpChannel.position(0);
274
                        shxChannel.position(0);
275

    
276
                        // throw new IOException("Must write headers first");
277
                }
278

    
279
                m_pos = m_bb.position();
280
                m_shape.obtainsPoints(g);
281
                int length = m_shape.getLength(g);
282

    
283
                // must allocate enough for shape + header (2 ints)
284
                checkShapeBuffer(length + 8);
285

    
286
                length /= 2;
287

    
288
                m_bb.order(ByteOrder.BIG_ENDIAN);
289
                m_bb.putInt(++m_cnt);
290
                m_bb.putInt(length);
291
                m_bb.order(ByteOrder.LITTLE_ENDIAN);
292
                m_bb.putInt(m_type);
293
                m_shape.write(m_bb, g);
294

    
295
                ///assert (length * 2 == (m_bb.position() - m_pos) - 8);
296
                m_pos = m_bb.position();
297

    
298
                // write to the shx
299
                m_indexBuffer.putInt(m_offset);
300
                m_indexBuffer.putInt(length);
301
                m_offset += (length + 4);
302
                drain();
303

    
304
                ///assert(m_bb.position() == 0);
305
                return m_pos; // Devolvemos hasta donde hemos escrito
306
        }
307

    
308
        /**
309
         * Returns a shapeType compatible with shapeFile constants from a gvSIG's IGeometry type
310
         * @param geometryType
311
         * @return a shapeType compatible with shapeFile constants from a gvSIG's IGeometry type
312
         */
313
        public int getShapeType(int geometryType) {
314
                int type=geometryType;
315
                if (geometryType>=FShape.M) {
316
                        type=geometryType-FShape.M;
317
                        switch (type) {
318
                        case (FShape.POINT):
319
                                return FConstant.SHAPE_TYPE_POINTM;
320

    
321
                        case (FShape.LINE):
322
                                return FConstant.SHAPE_TYPE_POLYLINEM;
323

    
324
                        case FShape.POLYGON:
325
                                return FConstant.SHAPE_TYPE_POLYGONM;
326

    
327
                        case FShape.MULTIPOINT:
328
                                return FConstant.SHAPE_TYPE_MULTIPOINTM; //TODO falta aclarar cosas aqu?.
329
                        }
330
                }else if (geometryType>=FShape.Z){
331
                        type=geometryType-FShape.Z;
332
                        switch (geometryType - FShape.Z) {
333
                        case (FShape.POINT):
334
                                return FConstant.SHAPE_TYPE_POINTZ;
335

    
336
                        case (FShape.LINE):
337
                                return FConstant.SHAPE_TYPE_POLYLINEZ;
338

    
339
                        case FShape.POLYGON:
340
                                return FConstant.SHAPE_TYPE_POLYGONZ;
341

    
342
                        case FShape.MULTIPOINT:
343
                                return FConstant.SHAPE_TYPE_MULTIPOINTZ; //TODO falta aclarar cosas aqu?.
344
                }
345

    
346
                }else{
347
                        switch (geometryType) {
348
                                case FShape.POINT:
349
                                        return FConstant.SHAPE_TYPE_POINT;
350

    
351
                                case FShape.LINE:
352
                                case FShape.ELLIPSE:
353
                                case FShape.CIRCLE:
354
                                case FShape.ARC:
355
                                        return FConstant.SHAPE_TYPE_POLYLINE;
356

    
357
                                case FShape.POLYGON:
358
                                        return FConstant.SHAPE_TYPE_POLYGON;
359

    
360
                                case FShape.MULTIPOINT:
361
                                        return FConstant.SHAPE_TYPE_MULTIPOINT; //TODO falta aclarar cosas aqu?.
362
                        }
363
                }
364
                        return FConstant.SHAPE_TYPE_NULL;
365
                }
366

    
367
//        public void setFlatness(double flatness) {
368
//                this.flatness=flatness;
369
//        }
370

    
371
}