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

History | View | Annotate | Download (13.3 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 org.gvsig.fmap.dal.store.dbf.utils.LogUtils;
27
import java.io.IOException;
28
import java.nio.Buffer;
29
import java.nio.ByteBuffer;
30
import java.nio.ByteOrder;
31
import java.nio.channels.FileChannel;
32

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

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

    
45
public class SHPFileWrite {
46

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

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

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

    
75
    private void position(int index) throws WriteException {
76
        LogUtils.log(this, "begin position "+index);
77
        try {
78
            LogUtils.log(this, "shpChannel.position(index)");
79
            shpChannel.position(index);
80
            LogUtils.log(this, "shxChannel.position(index)");
81
            shxChannel.position(index);
82
        } catch (IOException e) {
83
            throw new WriteException("SHP File Write Headers", e);
84
        } finally {
85
            LogUtils.log(this, "end position "+index);
86
        }
87
    }
88
    
89
    /**
90
     * Drain internal buffers into underlying channels.
91
     *
92
     * @throws WriteException
93
     *
94
     */
95
    private void drain() throws WriteException {
96
        m_bb.flip();
97
        m_indexBuffer.flip();
98
        try {
99
            LogUtils.log(this, "begin drain");
100
            while ( m_bb.remaining() > 0 ) {
101
                LogUtils.log(this, "shpChannel.write(m_bb)");
102
                shpChannel.write(m_bb);
103
            }
104

    
105
            while ( m_indexBuffer.remaining() > 0 ) {
106
                LogUtils.log(this, "shxChannel.write(m_indexBuffer)");
107
                shxChannel.write(m_indexBuffer);
108
            }
109
        } catch (IOException e) {
110
            throw new WriteException("SHP File Write Drain", e);
111
        } finally {
112
            LogUtils.log(this, "end drain");
113
        }
114
        m_bb.flip().limit(m_bb.capacity());
115
        m_indexBuffer.flip().limit(m_indexBuffer.capacity());
116
    }
117

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

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

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

    
147
        m_indexBuffer = null;
148
        m_bb = null;
149
        LogUtils.log(this, "end close");
150
    }
151

    
152
    private void allocateBuffers() {
153
        m_bb = ByteBuffer.allocateDirect(16 * 1024);
154
        m_indexBuffer = ByteBuffer.allocateDirect(100);
155
    }
156

    
157
    private void writeHeaders(Geometry[] geometries, int type)
158
            throws WriteException {
159
        this.m_type = type;
160
        this.inconsistenciesInGeometryTypeCounter = 0;
161

    
162
        int fileLength = 100;
163
        Envelope envelope = null;
164
        try {
165
            envelope = geomManager.createEnvelope(SUBTYPES.GEOM2D);
166
        } catch (CreateEnvelopeException e) {
167
            logger.error("Error creating the envelope", e);
168
        }
169

    
170
        for ( int i = geometries.length - 1; i >= 0; i-- ) {
171
            Geometry fgeometry = geometries[i];
172
            try {
173
                m_shape.initialize(fgeometry);
174
            } catch (BaseException e) {
175
                throw new WriteException("SHPFileWrite write headers", e);
176
            }
177
            int size = m_shape.getLength() + 8;
178
            fileLength += size;
179
            envelope.add(fgeometry.getEnvelope());
180
        }
181

    
182
        writeHeaders(envelope, type, geometries.length, fileLength);
183

    
184
    }
185

    
186
    /**
187
     * Writes shape header (100 bytes)
188
     */
189
    public void writeHeaders(Envelope bounds, int type,
190
            int numberOfGeometries,
191
            int fileLength) throws WriteException {
192

    
193
        this.m_type = type;
194
        this.inconsistenciesInGeometryTypeCounter = 0;
195

    
196
        if ( m_bb == null ) {
197
            allocateBuffers();
198
        }
199
        // Posicionamos al principio.
200
        ((Buffer)m_bb).position(0);
201
        ((Buffer)m_indexBuffer).position(0);
202

    
203
        ShapeFileHeader2 header = new ShapeFileHeader2();
204

    
205
        header.write(m_bb, type, numberOfGeometries, fileLength, // / 2,
206
                bounds
207
                .getMinimum(0), bounds.getMinimum(1), bounds.getMaximum(0),
208
                bounds.getMaximum(1), 0, 0, 0, 0);
209

    
210
        header.write(m_indexBuffer, type, numberOfGeometries,
211
                50 + (4 * numberOfGeometries), bounds.getMinimum(0), bounds.getMinimum(1),
212
                bounds.getMaximum(0), bounds.getMaximum(1), 0, 0, 0, 0);
213

    
214
        m_offset = 50;
215
        m_cnt = 0;
216

    
217
        position(0);
218
        drain();
219
    }
220

    
221
    public int writeIGeometry(Geometry g) throws WriteException {
222
        if ( g == null ) {
223
            m_shape = SHP.create(0);
224
        } else {
225
            int shapeType = getShapeType(g.getType(), g.getGeometryType().getSubType());
226
            m_shape = SHP.create(shapeType);
227
        }
228
        return writeGeometry(g);
229
    }
230

    
231
    /**
232
     * Writes a single Geometry.
233
     *
234
     * @param g
235
     * @return the position of buffer (after the last geometry, it will allow
236
     * you to write the file size in the header.
237
     */
238
    public synchronized int writeGeometry(Geometry g)
239
            throws WriteException {
240
        if ( m_shape.getShapeType() != this.m_type ) {
241
            if ( this.inconsistenciesInGeometryTypeCounter < 10 ) {
242
                logger.warn("Saving a geometry of type '" + SHP.getTypeName(m_shape.getShapeType()) + "' in a shape of type '" + SHP.getTypeName(this.m_type) + "'.");
243
            } else if ( this.inconsistenciesInGeometryTypeCounter < 11 ) {
244
                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) + "'.");
245
            }
246
            this.inconsistenciesInGeometryTypeCounter++;
247
        }
248

    
249
        if ( m_bb == null ) {
250
            allocateBuffers();
251
            m_offset = 50;
252
            m_cnt = 0;
253

    
254
            position(0);
255
        }
256

    
257
        m_pos = ((Buffer)m_bb).position();
258
        try {
259
            m_shape.initialize(g);
260
        } catch (BaseException e) {
261
            throw new WriteException("SHPFileWrite write geometry", e);
262
        }
263
        int length = m_shape.getLength();
264

    
265
        // must allocate enough for shape + header (2 ints)
266
        checkShapeBuffer(length + 8);
267

    
268
        length /= 2;
269

    
270
        m_bb.order(ByteOrder.BIG_ENDIAN);
271
        m_bb.putInt(++m_cnt);
272
        m_bb.putInt(length);
273
        m_bb.order(ByteOrder.LITTLE_ENDIAN);
274
        m_bb.putInt(m_shape.getShapeType());
275
        m_shape.write(m_bb);
276

    
277
        m_pos = ((Buffer)m_bb).position();
278

    
279
        // write to the shx
280
        m_indexBuffer.putInt(m_offset);
281
        m_indexBuffer.putInt(length);
282
        m_offset += (length + 4);
283
        drain();
284

    
285
        return m_pos; // Devolvemos hasta donde hemos escrito
286
    }
287

    
288
    /**
289
     * Returns a shapeType compatible with shapeFile constants from a gvSIG's
290
     * IGeometry type
291
     *
292
     * @param geometryType
293
     * @return a shapeType compatible with shapeFile constants from a gvSIG's
294
     * IGeometry type
295
     */
296
    public int getShapeType(int geometryType, int geometrySubType) {
297
        if ( geometrySubType == Geometry.SUBTYPES.GEOM3D ||  geometrySubType == Geometry.SUBTYPES.GEOM3DM  ) {
298
            switch (geometryType) {
299
            case Geometry.TYPES.NULL:
300
                return SHP.NULL;
301

    
302
            case Geometry.TYPES.POINT:
303
                return SHP.POINT3D;
304

    
305
            case Geometry.TYPES.CURVE:
306
            case Geometry.TYPES.LINE:
307
            case Geometry.TYPES.MULTICURVE:
308
            case Geometry.TYPES.MULTILINE:
309
            case Geometry.TYPES.ARC:
310
            case Geometry.TYPES.SPLINE:
311
            case Geometry.TYPES.CIRCUMFERENCE:
312
            case Geometry.TYPES.PERIELLIPSE:
313
                return SHP.POLYLINE3D;
314

    
315
            case Geometry.TYPES.SURFACE:
316
            case Geometry.TYPES.POLYGON:
317
            case Geometry.TYPES.MULTISURFACE:
318
            case Geometry.TYPES.MULTIPOLYGON:
319
            case Geometry.TYPES.CIRCLE:
320
            case Geometry.TYPES.ELLIPSE:
321
            case Geometry.TYPES.ELLIPTICARC:
322
            case Geometry.TYPES.FILLEDSPLINE:
323
                return SHP.POLYGON3D;
324

    
325
            case Geometry.TYPES.MULTIPOINT:
326
                return SHP.MULTIPOINT3D; //TODO falta aclarar cosas aqu?.
327
            }
328

    
329
        } else if ( geometrySubType == Geometry.SUBTYPES.GEOM2DM  ) {
330
            switch (geometryType) {
331
            case Geometry.TYPES.NULL:
332
                return SHP.NULL;
333

    
334
            case Geometry.TYPES.POINT:
335
                return SHP.POINTM;
336

    
337
            case Geometry.TYPES.CURVE:
338
            case Geometry.TYPES.LINE:
339
            case Geometry.TYPES.MULTICURVE:
340
            case Geometry.TYPES.MULTILINE:
341
            case Geometry.TYPES.ARC:
342
            case Geometry.TYPES.SPLINE:
343
            case Geometry.TYPES.CIRCUMFERENCE:
344
            case Geometry.TYPES.PERIELLIPSE:
345
                return SHP.POLYLINEM;
346

    
347
            case Geometry.TYPES.SURFACE:
348
            case Geometry.TYPES.POLYGON:
349
            case Geometry.TYPES.MULTISURFACE:
350
            case Geometry.TYPES.MULTIPOLYGON:
351
            case Geometry.TYPES.CIRCLE:
352
            case Geometry.TYPES.ELLIPSE:
353
            case Geometry.TYPES.ELLIPTICARC:
354
            case Geometry.TYPES.FILLEDSPLINE:
355
                return SHP.POLYGONM;
356

    
357
            case Geometry.TYPES.MULTIPOINT:
358
                return SHP.MULTIPOINTM; //TODO falta aclarar cosas aqu?.
359
            }
360

    
361
        } else {
362
            switch (geometryType) {
363
            case Geometry.TYPES.POINT:
364
                return SHP.POINT2D;
365

    
366
            case Geometry.TYPES.CURVE:
367
            case Geometry.TYPES.LINE:
368
            case Geometry.TYPES.MULTICURVE:
369
            case Geometry.TYPES.MULTILINE:
370
            case Geometry.TYPES.ARC:
371
            case Geometry.TYPES.SPLINE:
372
            case Geometry.TYPES.CIRCUMFERENCE:
373
            case Geometry.TYPES.PERIELLIPSE:
374
                return SHP.POLYLINE2D;
375

    
376
            case Geometry.TYPES.SURFACE:
377
            case Geometry.TYPES.POLYGON:
378
            case Geometry.TYPES.MULTISURFACE:
379
            case Geometry.TYPES.MULTIPOLYGON:
380
            case Geometry.TYPES.CIRCLE:
381
            case Geometry.TYPES.ELLIPSE:
382
            case Geometry.TYPES.ELLIPTICARC:
383
            case Geometry.TYPES.FILLEDSPLINE:
384
                return SHP.POLYGON2D;
385

    
386
            case Geometry.TYPES.MULTIPOINT:
387
                return SHP.MULTIPOINT2D; //TODO falta aclarar cosas aqu?.
388
            }
389
        }
390
        return SHP.NULL;
391
    }
392
    
393
    public int size() throws IOException {
394
        return (int) this.shpChannel.size();
395
    }
396

    
397
}