Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_1006 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / writers / shp / ShpWriter.java @ 12458

History | View | Annotate | Download (10.7 KB)

1
package com.iver.cit.gvsig.fmap.edition.writers.shp;
2

    
3
import java.awt.geom.Rectangle2D;
4
import java.io.File;
5
import java.io.IOException;
6
import java.io.RandomAccessFile;
7
import java.nio.channels.FileChannel;
8
import java.nio.channels.WritableByteChannel;
9
import java.nio.charset.Charset;
10
import java.sql.Types;
11

    
12
import com.iver.cit.gvsig.fmap.DriverException;
13
import com.iver.cit.gvsig.fmap.core.FShape;
14
import com.iver.cit.gvsig.fmap.core.IFeature;
15
import com.iver.cit.gvsig.fmap.core.IGeometry;
16
import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition;
17
import com.iver.cit.gvsig.fmap.drivers.ITableDefinition;
18
import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileHeaderNIO;
19
import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileWriterNIO;
20
import com.iver.cit.gvsig.fmap.drivers.shp.write.SHPFileWrite;
21
import com.iver.cit.gvsig.fmap.drivers.shp.write.ShapefileException;
22
import com.iver.cit.gvsig.fmap.edition.EditionException;
23
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
24
import com.iver.cit.gvsig.fmap.edition.ISpatialWriter;
25
import com.iver.cit.gvsig.fmap.edition.writers.AbstractWriter;
26
import com.iver.cit.gvsig.fmap.layers.FBitSet;
27
import com.iver.cit.gvsig.fmap.layers.FLayer;
28
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
29
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
30

    
31
public class ShpWriter extends AbstractWriter implements ISpatialWriter {
32
        private String shpPath;
33
        private String shxPath;
34
        private String dbfPath;
35

    
36
        private File shpFile;
37

    
38
        private SHPFileWrite shpWrite;
39
        private DbaseFileWriterNIO dbfWrite;
40

    
41
        private DbaseFileHeaderNIO myHeader;
42

    
43
        private int shapeType;
44
        private int numRows;
45
        private int fileSize;
46
        private Rectangle2D fullExtent;
47
        private Object[] record;
48

    
49
        // private FLyrVect lyrVect;
50
        private FBitSet selection = null;
51
        private boolean bWriteHeaders = true;
52
        private int gvSIG_geometryType;
53
        private int[] supportedGeometryTypes = {FShape.POINT,
54
                                                                                        FShape.LINE,
55
                                                                                        FShape.MULTIPOINT,
56
                                                                                        FShape.ARC,
57
                                                                                        FShape.CIRCLE,
58
                                                                                        FShape.POLYGON,
59
                                                                                        FShape.TEXT
60
                                                                                        };
61
        private Charset charset = Charset.forName("ISO-8859-1");
62

    
63
        public ShpWriter() {
64
                super();
65
                this.capabilities.setProperty("FieldNameMaxLength","10");
66
        }
67
        public void setFile(File f)
68
        {
69
                shpPath = f.getAbsolutePath();
70

    
71
                String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx");
72
                shxPath = strFichshx.replaceAll("\\.SHP", ".SHX");
73

    
74
                String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf");
75
                dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF");
76

    
77
                shpFile = f;
78
        }
79

    
80
        private WritableByteChannel getWriteChannel(String path)
81
                                throws IOException
82
        {
83
                WritableByteChannel channel;
84

    
85
                File f = new File(path);
86

    
87
                if (!f.exists()) {
88
                        System.out.println("Creando fichero " + f.getAbsolutePath());
89

    
90
                        if (!f.createNewFile()) {
91
                                System.err.print("Error al crear el fichero " +
92
                                        f.getAbsolutePath());
93
                                throw new IOException("Cannot create file " + f);
94
                        }
95
                }
96

    
97
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
98
                channel = raf.getChannel();
99

    
100
                return channel;
101
        }
102

    
103
        /**
104
         * Util para crear un fichero .shp desde cero.
105
         * @param lyrDef
106
         * @throws IOException
107
         * @throws DriverException
108
         */
109
        /*public ShpWriter(File shpFile, LayerDefinition lyrDef) throws IOException, DriverException
110
        {
111
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc());
112
                initialize(shpFile, lyrDef.getShapeType());
113
        }
114

115
        public ShpWriter(File shpFile, FLyrVect lyrVect) throws IOException, DriverException
116
        {
117
                SelectableDataSource sds = lyrVect.getRecordset();
118
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
119

120
                initialize(shpFile, lyrVect.getShapeType());
121
        }
122
        */
123
        /**
124
         * Use this function first of all, when you need to prepare a writer
125
         * having a FLayer as model.
126
         * IMPORTANT: Call setFile before calling this function.
127
         * @param lyrVect
128
         * @throws IOException
129
         * @throws DriverException
130
         */
131
        public void initialize(FLayer layer) throws EditionException{
132
                if (layer instanceof FLyrVect)
133
                {
134
                        FLyrVect lyrVect = (FLyrVect) layer;
135
                        try {
136
                                SelectableDataSource sds = lyrVect.getRecordset();
137
                                myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
138
                                initialize(shpFile, lyrVect.getShapeType());
139
                        } catch (IOException e) {
140
                                e.printStackTrace();
141
                                throw new EditionException(e);
142
                        } catch (DriverException e) {
143
                                e.printStackTrace();
144
                                throw new EditionException(e);
145
                        }
146
                }
147
                else
148
                {
149
                        throw new EditionException("No se puede usar una capa que no es vectorial como modelo para escribir un shp.");
150
                }
151
        }
152
        /**
153
         * Useful to create a layer from scratch
154
         * Call setFile before using this function
155
         * @param lyrDef
156
         * @throws EditionException
157
         */
158
        public void initialize(ITableDefinition lyrDef) throws EditionException
159
        {
160
                super.initialize(lyrDef);
161
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc());
162
                try {
163
                        initialize(shpFile, ((ILayerDefinition)lyrDef).getShapeType());
164
                } catch (IOException e) {
165
                        e.printStackTrace();
166
                        throw new EditionException(e);
167
                }
168
        }
169

    
170

    
171
        private void initialize(File shpFile, int typeFShape) throws IOException //, FLyrVect lyrVect, FBitSet selection) throws IOException, DriverException
172
        {
173
                // this.lyrVect = lyrVect;
174
                // this.selection = selection;
175
                setFile(shpFile);
176

    
177

    
178
                shpWrite = new SHPFileWrite((FileChannel) getWriteChannel(shpPath),
179
                                (FileChannel) getWriteChannel(shxPath));
180
                shapeType = shpWrite.getShapeType(typeFShape);
181
                gvSIG_geometryType = typeFShape;
182
                setSupportedGeometryTypes();
183
        }
184

    
185
        /**
186
         *
187
         */
188
        private void setSupportedGeometryTypes() {
189
                switch (gvSIG_geometryType)
190
                {
191
                case FShape.POINT:
192
                        supportedGeometryTypes = new int[] {FShape.POINT};
193
                        break;
194
                case FShape.MULTIPOINT:
195
                        supportedGeometryTypes = new int[] {FShape.MULTIPOINT};
196
                        break;
197
                case FShape.LINE:
198
                        supportedGeometryTypes = new int[] {FShape.LINE, FShape.ELLIPSE,
199
                                                        FShape.ARC, FShape.CIRCLE, FShape.POLYGON};
200
                        break;
201
                case FShape.POLYGON:
202
                        supportedGeometryTypes = new int[] {FShape.ELLIPSE,
203
                                FShape.CIRCLE, FShape.POLYGON};
204
                        break;
205

    
206
                default:
207
                        supportedGeometryTypes = new int[] {};
208
                }
209
        }
210

    
211
        public void preProcess() throws EditionException {
212
                // Por ahora solo escribimos los primeros bytes
213
                // de las cabeceras. Luego en el postprocess los escribiremos
214
                // correctamente, con el fullExtent y el numero de
215
                // registros que tocan.
216
                if (selection == null)
217
                {
218

    
219
                        try {
220
                                if (bWriteHeaders)
221
                                {
222
                                        shpWrite.writeHeaders(new Rectangle2D.Double(),
223
                                                shapeType, 0, 0);
224

    
225
                                }
226
                                myHeader.setNumRecords(0);
227
                                dbfWrite = new DbaseFileWriterNIO(myHeader,
228
                                        (FileChannel) getWriteChannel(dbfPath));
229

    
230
                                dbfWrite.setCharset(charset);
231

    
232
                                record = new Object[myHeader.getNumFields()];
233
                                numRows = 0;
234
                                fullExtent = null;
235

    
236
                        } catch (IOException e) {
237
                                e.printStackTrace();
238
                                throw new EditionException(e);
239
                        }
240
                }
241

    
242

    
243
        }
244

    
245
        public void process(IRowEdited row) throws EditionException {
246

    
247
                if (row.getStatus() == IRowEdited.STATUS_DELETED) return;
248

    
249
                IFeature feat = (IFeature) row.getLinkedRow();
250

    
251
                try {
252
                        /* System.out.println("Intento escribir el registro " +
253
                                        numRows + " de la capa " + lyrVect.getName()); */
254
                        IGeometry theGeom = feat.getGeometry();
255
                        // Revisamos que podemos escribir esa entidad
256
                        // En un shpFile, podemos meter pol?gonos, pero que sean como
257
                        // lineas. En cambio, en uno de puntos solo se pueden meter puntos
258
                        // Con capas de anotaciones ?nicamente se pueden salvar los puntos,
259
                        // de momento no hay problema porque est? limitado
260
                        // y no se puede tener anotaciones de otro tipo de shape.
261
                        if (canWriteGeometry(theGeom.getGeometryType()))// || canWriteGeometry(gvSIG_geometryType))
262
                        {
263
                                for (int i=0; i < record.length; i++)
264
                                        record[i] = feat.getAttribute(i);
265

    
266
                                fileSize = shpWrite.writeIGeometry(theGeom);
267
                                Rectangle2D boundsShp = theGeom.getBounds2D();
268

    
269
                                if (fullExtent == null) {
270
                                        fullExtent = boundsShp;
271
                                } else {
272
                                        fullExtent.add(boundsShp);
273
                                }
274

    
275
                                dbfWrite.write(record);
276
                                numRows++;
277
                        }
278
                        else
279
                        {
280
                                System.out.println("No se ha escrito la geometr?a "
281
                                                + row.getIndex() + " geomType=" + theGeom.getGeometryType());
282
                        }
283

    
284
                } catch (IOException e) {
285
                        e.printStackTrace();
286
                        throw new EditionException(e);
287
                } catch (ShapefileException e) {
288
                        e.printStackTrace();
289
                        throw new EditionException(e);
290
                }
291

    
292
        }
293

    
294
        public void postProcess() throws EditionException {
295
                try {
296
                        myHeader.setNumRecords(numRows);
297
                        if (fullExtent == null)
298
                                fullExtent = new Rectangle2D.Double();
299
                        shpWrite.writeHeaders(fullExtent,
300
                                        shapeType, numRows, fileSize);
301

    
302
                        dbfWrite = new DbaseFileWriterNIO(myHeader,
303
                                        (FileChannel) getWriteChannel(dbfPath));
304
                } catch (IOException e) {
305
                        e.printStackTrace();
306
                        throw new EditionException(e);
307
                }
308

    
309

    
310
        }
311
        /**
312
         * Devuelve el path del fichero Shp.
313
         *
314
         * @author azabala
315
         * @return shp path
316
         */
317
        public String getShpPath(){
318
                //Lo necesito para que el ShpSchemaManager sepa
319
                //como "construir" el esquema del fichero SHP/DBF
320
                //adem?s del ShpLayerDefinition
321
                //TODO hacer que ShpWriter implemente ISchemaManager
322
                return this.shpPath;
323
        }
324

    
325
        public String getName() {
326
                return "Shape Writer";
327
        }
328
        public boolean canWriteGeometry(int gvSIGgeometryType) {
329
                /* switch (gvSIGgeometryType)
330
                {
331
                case FShape.POINT:
332
                        return true;
333
                case FShape.LINE:
334
                        return true;
335
                case FShape.POLYGON:
336
                        return true;
337
                case FShape.ARC:
338
                        return true; // Pero convirtiendo a segmentos peque?os
339
                case FShape.ELLIPSE:
340
                        return true; // Pero convirtiendo a segmentos peque?os
341
                case FShape.MULTIPOINT:
342
                        return true;
343
                case FShape.TEXT:
344
                        return false;
345
                } */
346
                for (int i=0; i < supportedGeometryTypes.length; i++)
347
                {
348
                        if (gvSIGgeometryType == supportedGeometryTypes[i] ||
349
                                gvSIGgeometryType == (supportedGeometryTypes[i] | FShape.Z))
350
                                return true;
351
                }
352
                return false;
353
        }
354

    
355
        public boolean canWriteAttribute(int sqlType) {
356
                switch (sqlType)
357
                {
358
                case Types.DOUBLE:
359
                case Types.FLOAT:
360
                case Types.INTEGER:
361
                case Types.BIGINT:
362
                        return true;
363
                case Types.DATE:
364
                        return true;
365
                case Types.BIT:
366
                case Types.BOOLEAN:
367
                        return true;
368
                case Types.VARCHAR:
369
                case Types.CHAR:
370
                case Types.LONGVARCHAR:
371
                        return true; // TODO: Revisar esto, porque no creo que admita campos muy grandes
372

    
373
                }
374

    
375
                return false;
376
        }
377

    
378
        /**
379
         * @param dontWriteHeaders The bDontWriteHeaders to set.
380
         */
381
        public void setWriteHeaders(boolean bWriteHeaders) {
382
                this.bWriteHeaders = bWriteHeaders;
383
        }
384

    
385
//        public void setFlatness(double flatness) {
386
//                shpWrite.setFlatness(flatness);
387
//
388
//        }
389

    
390
        public boolean canAlterTable() {
391
                return true;
392
        }
393

    
394
        public boolean canSaveEdits() {
395
                if (shpFile.canWrite())
396
                {
397
                        File auxShx = new File(shxPath);
398
                        if (auxShx.canWrite())
399
                        {
400
                                File auxDbf = new File(dbfPath);
401
                                if (auxDbf.canWrite())
402
                                        return true;
403
                        }
404
                }
405
                return false;
406
        }
407

    
408
        public void setCharsetForWriting(Charset charset) {
409
                this.charset = charset;
410
        }
411

    
412
        public Charset getCharsetForWriting() {
413
                return charset;
414
        }
415

    
416
}