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

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

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

    
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
34

    
35
import org.gvsig.fmap.dal.exception.WriteException;
36
import org.gvsig.fmap.geom.Geometry;
37
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
38
import org.gvsig.fmap.geom.GeometryLocator;
39
import org.gvsig.fmap.geom.GeometryManager;
40
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
41
import org.gvsig.fmap.geom.primitive.Envelope;
42
import org.gvsig.tools.exception.BaseException;
43

    
44
public class SHPFileWrite {
45

    
46
    private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
47
    private static final Logger logger = LoggerFactory.getLogger(SHPFileWrite.class);
48
    private SHPShapeWriter m_shape = null;
49
    private ByteBuffer m_bb = null;
50
    private ByteBuffer m_indexBuffer = null;
51
    private int m_pos = 0;
52
    private int m_offset;
53
    private int m_type = SHP.NULL;
54
    private int m_cnt;
55
    private FileChannel shpChannel;
56
    private FileChannel shxChannel;
57
    private int inconsistenciesInGeometryTypeCounter = 0;
58

    
59
    public SHPFileWrite(FileChannel shpChannel, FileChannel shxChannel) {
60
        this.shpChannel = shpChannel;
61
        this.shxChannel = shxChannel;
62
    }
63

    
64
    /**
65
     * Make sure our buffer is of size.
66
     *
67
     */
68
    private void checkShapeBuffer(int size) {
69
        if ( m_bb.capacity() < size ) {
70
            m_bb = ByteBuffer.allocateDirect(size);
71
        }
72
    }
73

    
74
    /**
75
     * Drain internal buffers into underlying channels.
76
     *
77
     * @throws WriteException
78
     *
79
     */
80
    private void drain() throws WriteException {
81
        m_bb.flip();
82
        m_indexBuffer.flip();
83
        try {
84
            while ( m_bb.remaining() > 0 ) {
85
                shpChannel.write(m_bb);
86
            }
87

    
88
            while ( m_indexBuffer.remaining() > 0 ) {
89
                shxChannel.write(m_indexBuffer);
90
            }
91
        } catch (IOException e) {
92
            throw new WriteException("SHP File Write Drain", e);
93
        }
94
        m_bb.flip().limit(m_bb.capacity());
95
        m_indexBuffer.flip().limit(m_indexBuffer.capacity());
96
    }
97

    
98
    private void allocateBuffers() {
99
        m_bb = ByteBuffer.allocateDirect(16 * 1024);
100
        m_indexBuffer = ByteBuffer.allocateDirect(100);
101
    }
102

    
103
    /**
104
     * Close the underlying Channels.
105
     */
106
    public void close() throws WriteException {
107
        try {
108
            shpChannel.close();
109
            shxChannel.close();
110
        } catch (IOException e) {
111
            throw new WriteException("SHP File Write Close", e);
112
        }
113
        shpChannel = null;
114
        shxChannel = null;
115
        m_shape = null;
116

    
117
        if ( m_indexBuffer instanceof ByteBuffer ) {
118
            if ( m_indexBuffer != null ) {
119
                ///NIOUtilities.clean(m_indexBuffer);
120
            }
121
        }
122

    
123
        if ( m_indexBuffer instanceof ByteBuffer ) {
124
            if ( m_indexBuffer != null ) {
125
                ///NIOUtilities.clean(m_bb);
126
            }
127
        }
128

    
129
        m_indexBuffer = null;
130
        m_bb = null;
131
    }
132

    
133
    private void writeHeaders(Geometry[] geometries, int type)
134
            throws WriteException {
135
        this.m_type = type;
136
        this.inconsistenciesInGeometryTypeCounter = 0;
137

    
138
        int fileLength = 100;
139
        Envelope envelope = null;
140
        try {
141
            envelope = geomManager.createEnvelope(SUBTYPES.GEOM2D);
142
        } catch (CreateEnvelopeException e) {
143
            logger.error("Error creating the envelope", e);
144
        }
145

    
146
        for ( int i = geometries.length - 1; i >= 0; i-- ) {
147
            Geometry fgeometry = geometries[i];
148
            try {
149
                m_shape.initialize(fgeometry);
150
            } catch (BaseException e) {
151
                throw new WriteException("SHPFileWrite write headers", e);
152
            }
153
            int size = m_shape.getLength() + 8;
154
            fileLength += size;
155
            envelope.add(fgeometry.getEnvelope());
156
        }
157

    
158
        writeHeaders(envelope, type, geometries.length, fileLength);
159

    
160
    }
161

    
162
    /**
163
     * Writes shape header (100 bytes)
164
     */
165
    public void writeHeaders(Envelope bounds, int type,
166
            int numberOfGeometries,
167
            int fileLength) throws WriteException {
168

    
169
        this.m_type = type;
170
        this.inconsistenciesInGeometryTypeCounter = 0;
171

    
172
        if ( m_bb == null ) {
173
            allocateBuffers();
174
        }
175
        // Posicionamos al principio.
176
        ((Buffer)m_bb).position(0);
177
        ((Buffer)m_indexBuffer).position(0);
178

    
179
        ShapeFileHeader2 header = new ShapeFileHeader2();
180

    
181
        header.write(m_bb, type, numberOfGeometries, fileLength / 2,
182
                bounds
183
                .getMinimum(0), bounds.getMinimum(1), bounds.getMaximum(0),
184
                bounds.getMaximum(1), 0, 0, 0, 0);
185

    
186
        header.write(m_indexBuffer, type, numberOfGeometries,
187
                50 + (4 * numberOfGeometries), bounds.getMinimum(0), bounds.getMinimum(1),
188
                bounds.getMaximum(0), bounds.getMaximum(1), 0, 0, 0, 0);
189

    
190
        m_offset = 50;
191
        m_cnt = 0;
192

    
193
        try {
194
            shpChannel.position(0);
195
            shxChannel.position(0);
196
        } catch (IOException e) {
197
            throw new WriteException("SHP File Write Headers", e);
198
        }
199
        drain();
200
    }
201

    
202
    public int writeIGeometry(Geometry g) throws WriteException {
203
        if ( g == null ) {
204
            m_shape = SHP.create(0);
205
        } else {
206
            int shapeType = getShapeType(g.getType(), g.getGeometryType().getSubType());
207
            m_shape = SHP.create(shapeType);
208
        }
209
        return writeGeometry(g);
210
    }
211

    
212
    /**
213
     * Writes a single Geometry.
214
     *
215
     * @param g
216
     * @return the position of buffer (after the last geometry, it will allow
217
     * you to write the file size in the header.
218
     */
219
    public synchronized int writeGeometry(Geometry g)
220
            throws WriteException {
221
        if ( m_shape.getShapeType() != this.m_type ) {
222
            if ( this.inconsistenciesInGeometryTypeCounter < 10 ) {
223
                logger.warn("Saving a geometry of type '" + SHP.getTypeName(m_shape.getShapeType()) + "' in a shape of type '" + SHP.getTypeName(this.m_type) + "'.");
224
            } else if ( this.inconsistenciesInGeometryTypeCounter < 11 ) {
225
                logger.warn("Too many warnings. Saving a geometry of type '" + SHP.getTypeName(m_shape.getShapeType()) + "' in a shape of type '" + SHP.getTypeName(this.m_type) + "'.");
226
            }
227
            this.inconsistenciesInGeometryTypeCounter++;
228
        }
229

    
230
        if ( m_bb == null ) {
231
            allocateBuffers();
232
            m_offset = 50;
233
            m_cnt = 0;
234

    
235
            try {
236
                shpChannel.position(0);
237
                shxChannel.position(0);
238
            } catch (IOException e) {
239
                throw new WriteException("SHP File Write", e);
240
            }
241
        }
242

    
243
        m_pos = ((Buffer)m_bb).position();
244
        try {
245
            m_shape.initialize(g);
246
        } catch (BaseException e) {
247
            throw new WriteException("SHPFileWrite write geometry", e);
248
        }
249
        int length = m_shape.getLength();
250

    
251
        // must allocate enough for shape + header (2 ints)
252
        checkShapeBuffer(length + 8);
253

    
254
        length /= 2;
255

    
256
        m_bb.order(ByteOrder.BIG_ENDIAN);
257
        m_bb.putInt(++m_cnt);
258
        m_bb.putInt(length);
259
        m_bb.order(ByteOrder.LITTLE_ENDIAN);
260
        m_bb.putInt(m_shape.getShapeType());
261
        m_shape.write(m_bb);
262

    
263
        m_pos = ((Buffer)m_bb).position();
264

    
265
        // write to the shx
266
        m_indexBuffer.putInt(m_offset);
267
        m_indexBuffer.putInt(length);
268
        m_offset += (length + 4);
269
        drain();
270

    
271
        return m_pos; // Devolvemos hasta donde hemos escrito
272
    }
273

    
274
    /**
275
     * Returns a shapeType compatible with shapeFile constants from a gvSIG's
276
     * IGeometry type
277
     *
278
     * @param geometryType
279
     * @return a shapeType compatible with shapeFile constants from a gvSIG's
280
     * IGeometry type
281
     */
282
    public int getShapeType(int geometryType, int geometrySubType) {
283
        if ( geometrySubType == Geometry.SUBTYPES.GEOM3D ||  geometrySubType == Geometry.SUBTYPES.GEOM3DM  ) {
284
            switch (geometryType) {
285
            case Geometry.TYPES.NULL:
286
                return SHP.NULL;
287

    
288
            case Geometry.TYPES.POINT:
289
                return SHP.POINT3D;
290

    
291
            case Geometry.TYPES.CURVE:
292
            case Geometry.TYPES.LINE:
293
            case Geometry.TYPES.MULTICURVE:
294
            case Geometry.TYPES.MULTILINE:
295
            case Geometry.TYPES.ARC:
296
            case Geometry.TYPES.SPLINE:
297
            case Geometry.TYPES.CIRCUMFERENCE:
298
            case Geometry.TYPES.PERIELLIPSE:
299
                return SHP.POLYLINE3D;
300

    
301
            case Geometry.TYPES.SURFACE:
302
            case Geometry.TYPES.POLYGON:
303
            case Geometry.TYPES.MULTISURFACE:
304
            case Geometry.TYPES.MULTIPOLYGON:
305
            case Geometry.TYPES.CIRCLE:
306
            case Geometry.TYPES.ELLIPSE:
307
            case Geometry.TYPES.ELLIPTICARC:
308
            case Geometry.TYPES.FILLEDSPLINE:
309
                return SHP.POLYGON3D;
310

    
311
            case Geometry.TYPES.MULTIPOINT:
312
                return SHP.MULTIPOINT3D; //TODO falta aclarar cosas aqu?.
313
            }
314

    
315
        } else if ( geometrySubType == Geometry.SUBTYPES.GEOM2DM  ) {
316
            switch (geometryType) {
317
            case Geometry.TYPES.NULL:
318
                return SHP.NULL;
319

    
320
            case Geometry.TYPES.POINT:
321
                return SHP.POINTM;
322

    
323
            case Geometry.TYPES.CURVE:
324
            case Geometry.TYPES.LINE:
325
            case Geometry.TYPES.MULTICURVE:
326
            case Geometry.TYPES.MULTILINE:
327
            case Geometry.TYPES.ARC:
328
            case Geometry.TYPES.SPLINE:
329
            case Geometry.TYPES.CIRCUMFERENCE:
330
            case Geometry.TYPES.PERIELLIPSE:
331
                return SHP.POLYLINEM;
332

    
333
            case Geometry.TYPES.SURFACE:
334
            case Geometry.TYPES.POLYGON:
335
            case Geometry.TYPES.MULTISURFACE:
336
            case Geometry.TYPES.MULTIPOLYGON:
337
            case Geometry.TYPES.CIRCLE:
338
            case Geometry.TYPES.ELLIPSE:
339
            case Geometry.TYPES.ELLIPTICARC:
340
            case Geometry.TYPES.FILLEDSPLINE:
341
                return SHP.POLYGONM;
342

    
343
            case Geometry.TYPES.MULTIPOINT:
344
                return SHP.MULTIPOINTM; //TODO falta aclarar cosas aqu?.
345
            }
346

    
347
        } else {
348
            switch (geometryType) {
349
            case Geometry.TYPES.POINT:
350
                return SHP.POINT2D;
351

    
352
            case Geometry.TYPES.CURVE:
353
            case Geometry.TYPES.LINE:
354
            case Geometry.TYPES.MULTICURVE:
355
            case Geometry.TYPES.MULTILINE:
356
            case Geometry.TYPES.ARC:
357
            case Geometry.TYPES.SPLINE:
358
            case Geometry.TYPES.CIRCUMFERENCE:
359
            case Geometry.TYPES.PERIELLIPSE:
360
                return SHP.POLYLINE2D;
361

    
362
            case Geometry.TYPES.SURFACE:
363
            case Geometry.TYPES.POLYGON:
364
            case Geometry.TYPES.MULTISURFACE:
365
            case Geometry.TYPES.MULTIPOLYGON:
366
            case Geometry.TYPES.CIRCLE:
367
            case Geometry.TYPES.ELLIPSE:
368
            case Geometry.TYPES.ELLIPTICARC:
369
            case Geometry.TYPES.FILLEDSPLINE:
370
                return SHP.POLYGON2D;
371

    
372
            case Geometry.TYPES.MULTIPOINT:
373
                return SHP.MULTIPOINT2D; //TODO falta aclarar cosas aqu?.
374
            }
375
        }
376
        return SHP.NULL;
377
    }
378
}