Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.shp / src / main / java / org / gvsig / fmap / dal / store / shp / utils / SHPFileWrite.java @ 40559

History | View | Annotate | Download (9.33 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
package org.gvsig.fmap.dal.store.shp.utils;
25

    
26
import java.io.IOException;
27
import java.nio.ByteBuffer;
28
import java.nio.ByteOrder;
29
import java.nio.channels.FileChannel;
30

    
31
import org.gvsig.fmap.dal.exception.WriteException;
32
import org.gvsig.fmap.geom.Geometry;
33
import org.gvsig.fmap.geom.GeometryLocator;
34
import org.gvsig.fmap.geom.GeometryManager;
35
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
36
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
37
import org.gvsig.fmap.geom.primitive.Envelope;
38
import org.slf4j.Logger;
39
import org.slf4j.LoggerFactory;
40

    
41

    
42

    
43
/**
44
 * DOCUMENT ME!
45
 *
46
 * @author Vicente Caballero Navarro
47
 */
48
public class SHPFileWrite {
49
        private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
50
        private static final Logger logger = LoggerFactory.getLogger(SHPFileWrite.class);
51
        private SHPShape m_shape = null;
52
        private ByteBuffer m_bb = null;
53
        private ByteBuffer m_indexBuffer = null;
54
        private int m_pos = 0;
55
        private int m_offset;
56
        //        private int m_type;
57
        private int m_cnt;
58
        private FileChannel shpChannel;
59
        private FileChannel shxChannel;
60
//        private double flatness;
61

    
62
        /**
63
         * Crea un nuevo SHPFileWrite.
64
         *
65
         * @param shpChannel DOCUMENT ME!
66
         * @param shxChannel DOCUMENT ME!
67
         */
68
        public SHPFileWrite(FileChannel shpChannel, FileChannel shxChannel) {
69
                this.shpChannel = shpChannel;
70
                this.shxChannel = shxChannel;
71
        }
72

    
73
        /**
74
         * Make sure our buffer is of size.
75
         *
76
         * @param size DOCUMENT ME!
77
         */
78
        private void checkShapeBuffer(int size) {
79
                if (m_bb.capacity() < size) {
80
                        m_bb = ByteBuffer.allocateDirect(size);
81
                }
82
        }
83

    
84
        /**
85
         * Drain internal buffers into underlying channels.
86
         * @throws WriteException
87
         *
88
         * @throws IOException DOCUMENT ME!
89
         */
90
        private void drain() throws WriteException {
91
                m_bb.flip();
92
                m_indexBuffer.flip();
93
                try{
94
                while (m_bb.remaining() > 0) {
95
                        shpChannel.write(m_bb);
96
                }
97

    
98
                while (m_indexBuffer.remaining() > 0) {
99
                        shxChannel.write(m_indexBuffer);
100
                }
101
                }catch (IOException e) {
102
                        throw new WriteException("SHP File Write Drain", e);
103
                }
104
                m_bb.flip().limit(m_bb.capacity());
105
                m_indexBuffer.flip().limit(m_indexBuffer.capacity());
106
        }
107

    
108
        /**
109
         * DOCUMENT ME!
110
         */
111
        private void allocateBuffers() {
112
                m_bb = ByteBuffer.allocateDirect(16 * 1024);
113
                m_indexBuffer = ByteBuffer.allocateDirect(100);
114
        }
115

    
116
        /**
117
         * Close the underlying Channels.
118
         */
119
        public void close() throws WriteException {
120
                try {
121
                        shpChannel.close();
122
                        shxChannel.close();
123
                } catch (IOException e) {
124
                        throw new WriteException("SHP File Write Close", e);
125
                }
126
                shpChannel = null;
127
                shxChannel = null;
128
                m_shape = null;
129

    
130
                if (m_indexBuffer instanceof ByteBuffer) {
131
                        if (m_indexBuffer != null) {
132
                                ///NIOUtilities.clean(m_indexBuffer);
133
                        }
134
                }
135

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

    
142
                m_indexBuffer = null;
143
                m_bb = null;
144
        }
145

    
146
        /**
147
         * DOCUMENT ME!
148
         *
149
         * @param geometries DOCUMENT ME!
150
         * @param type DOCUMENT ME!
151
         *
152
         */
153
        public void write(Geometry[] geometries, int type)
154
                        throws WriteException {
155
                m_shape = SHP.create(type);
156
//                m_shape.setFlatness(flatness);
157
                writeHeaders(geometries, type);
158

    
159
                m_pos = m_bb.position();
160

    
161
                for (int i = 0, ii = geometries.length; i < ii; i++) {
162
                        writeGeometry(geometries[i]);
163
                }
164

    
165
                close();
166
        }
167

    
168
        /**
169
         * DOCUMENT ME!
170
         *
171
         * @param geometries DOCUMENT ME!
172
         * @param type DOCUMENT ME!
173
         * @throws WriteException
174
         *
175
         */
176
        private void writeHeaders(Geometry[] geometries, int type)
177
                        throws WriteException {
178
                int fileLength = 100;                
179
                Envelope envelope = null;
180
                try {
181
                    envelope = geomManager.createEnvelope(SUBTYPES.GEOM2D);
182
        } catch (CreateEnvelopeException e) {
183
            logger.error("Error creating the envelope", e);
184
        }
185

    
186
                for (int i = geometries.length - 1; i >= 0; i--) {
187
                        Geometry fgeometry = geometries[i];
188
                        m_shape.obtainsPoints(fgeometry);
189
                        int size = m_shape.getLength(fgeometry) + 8;
190
                        fileLength += size;
191
                        envelope.add(fgeometry.getEnvelope());                        
192
                }
193

    
194
                writeHeaders(envelope, type, geometries.length, fileLength);
195
        }
196

    
197
        /**
198
         * Writes shape header (100 bytes)
199
         *
200
         * @param bounds DOCUMENT ME!
201
         * @param type DOCUMENT ME!
202
         * @param numberOfGeometries DOCUMENT ME!
203
         * @param fileLength DOCUMENT ME!
204
         */
205
        public void writeHeaders(Envelope bounds, int type,
206
                int numberOfGeometries,
207
                        int fileLength) throws WriteException {
208
                /*try {
209
                   handler = type.getShapeHandler();
210
                   } catch (ShapefileException se) {
211
                     throw new RuntimeException("unexpected Exception",se);
212
                   }
213
                 */
214
                if (m_bb == null) {
215
                        allocateBuffers();
216
                }
217
                // Posicionamos al principio.
218
                m_bb.position(0);
219
                m_indexBuffer.position(0);
220

    
221
                ShapeFileHeader2 header = new ShapeFileHeader2();
222

    
223
                header.write(m_bb, type, numberOfGeometries, fileLength / 2,
224
                        bounds
225
                                .getMinimum(0), bounds.getMinimum(1), bounds.getMaximum(0),
226
                        bounds.getMaximum(1), 0, 0, 0, 0);
227

    
228
                header.write(m_indexBuffer, type, numberOfGeometries,
229
                        50 + (4 * numberOfGeometries), bounds.getMinimum(0), bounds.getMinimum(1),
230
                        bounds.getMaximum(0), bounds.getMaximum(1), 0, 0, 0, 0);
231

    
232
                m_offset = 50;
233
//                m_type = type;
234
                m_cnt = 0;
235

    
236
                try {
237
                        shpChannel.position(0);
238
                        shxChannel.position(0);
239
                } catch (IOException e) {
240
                        throw new WriteException("SHP File Write Headers", e);
241
                }
242
                drain();
243
        }
244
        public int writeIGeometry(Geometry g) throws WriteException {
245
                int shapeType = getShapeType(g.getType(), g.getGeometryType().getSubType());
246
                m_shape = SHP.create(shapeType);
247
//                m_shape.setFlatness(flatness);
248
                // System.out.println("writeIGeometry: type="+ g.getType());
249
                return writeGeometry(g);
250
        }
251

    
252
        /**
253
         * Writes a single Geometry.
254
         *
255
         * @param g
256
         * @return the position of buffer (after the last geometry, it will allow you to
257
         * write the file size in the header.
258
         */
259
        public synchronized int writeGeometry(Geometry g)
260
                        throws WriteException {
261
                if (m_bb == null) {
262
                        allocateBuffers();
263
                        m_offset = 50;
264
                        m_cnt = 0;
265

    
266
                        try {
267
                                shpChannel.position(0);
268
                                shxChannel.position(0);
269
                        } catch (IOException e) {
270
                                throw new WriteException("SHP File Write", e);
271
                        }
272
                        // throw new IOException("Must write headers first");
273
                }
274

    
275
                m_pos = m_bb.position();
276
                m_shape.obtainsPoints(g);
277
                int length = m_shape.getLength(g);
278

    
279
                // must allocate enough for shape + header (2 ints)
280
                checkShapeBuffer(length + 8);
281

    
282
                length /= 2;
283

    
284
                m_bb.order(ByteOrder.BIG_ENDIAN);
285
                m_bb.putInt(++m_cnt);
286
                m_bb.putInt(length);
287
                m_bb.order(ByteOrder.LITTLE_ENDIAN);
288
                m_bb.putInt(m_shape.getShapeType());
289
                m_shape.write(m_bb, g);
290

    
291
                ///assert (length * 2 == (m_bb.position() - m_pos) - 8);
292
                m_pos = m_bb.position();
293

    
294
                // write to the shx
295
                m_indexBuffer.putInt(m_offset);
296
                m_indexBuffer.putInt(length);
297
                m_offset += (length + 4);
298
                drain();
299

    
300
                ///assert(m_bb.position() == 0);
301
                return m_pos; // Devolvemos hasta donde hemos escrito
302
        }
303

    
304
        /**
305
         * Returns a shapeType compatible with shapeFile constants from a gvSIG's IGeometry type
306
         * @param geometryType
307
         * @return a shapeType compatible with shapeFile constants from a gvSIG's IGeometry type
308
         */
309
        public int getShapeType(int geometryType, int geometrySubType) {
310

    
311
                if (geometrySubType == Geometry.SUBTYPES.GEOM3D){
312
                        switch (geometryType) {
313
                        case Geometry.TYPES.POINT:
314
                                return SHP.POINT3D;
315

    
316
                        case Geometry.TYPES.CURVE:
317
                        case Geometry.TYPES.MULTICURVE:
318
                        case Geometry.TYPES.ELLIPSE:
319
                        case Geometry.TYPES.CIRCLE:
320
                        case Geometry.TYPES.ARC:
321
                        case Geometry.TYPES.SPLINE: 
322
                                return SHP.POLYLINE3D;
323

    
324
                        case Geometry.TYPES.SURFACE:
325
                        case Geometry.TYPES.MULTISURFACE:
326
                                return SHP.POLYGON3D;
327

    
328
                        case Geometry.TYPES.MULTIPOINT:
329
                                return SHP.MULTIPOINT3D; //TODO falta aclarar cosas aqu?.
330
                }
331

    
332
                }else{
333
                        switch (geometryType) {
334
                                case Geometry.TYPES.POINT:
335
                                        return SHP.POINT2D;
336

    
337
                                case Geometry.TYPES.CURVE:
338
                                case Geometry.TYPES.MULTICURVE:
339
                                case Geometry.TYPES.ELLIPSE:
340
                                case Geometry.TYPES.CIRCLE:
341
                                case Geometry.TYPES.ARC:
342
                                case Geometry.TYPES.SPLINE: 
343
                                        return SHP.POLYLINE2D;
344

    
345
                                case Geometry.TYPES.SURFACE:
346
                                case Geometry.TYPES.MULTISURFACE:
347
                                        return SHP.POLYGON2D;
348

    
349
                                case Geometry.TYPES.MULTIPOINT:
350
                                        return SHP.MULTIPOINT2D; //TODO falta aclarar cosas aqu?.
351
                        }
352
                }
353
                        return SHP.NULL;
354
                }
355
}