Statistics
| Revision:

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

History | View | Annotate | Download (10.2 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.sql.Types;
10

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

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

    
35
        private File shpFile;
36

    
37
        private SHPFileWrite shpWrite;
38
        private DbaseFileWriterNIO dbfWrite;
39

    
40
        private DbaseFileHeaderNIO myHeader;
41

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

    
48
        // private FLyrVect lyrVect;
49
        private FBitSet selection = null;
50
        private boolean bWriteHeaders = true;
51
        private int gvSIG_geometryType;
52
        private int[] supportedGeometryTypes = {FShape.POINT,
53
                                                                                        FShape.LINE,
54
                                                                                        FShape.MULTIPOINT,
55
                                                                                        FShape.ARC,
56
                                                                                        FShape.CIRCLE,
57
                                                                                        FShape.POLYGON,
58
                                                                                        FShape.TEXT
59
                                                                                        };
60

    
61
        public void setFile(File f)
62
        {
63
                shpPath = f.getAbsolutePath();
64

    
65
                String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx");
66
                shxPath = strFichshx.replaceAll("\\.SHP", ".SHX");
67

    
68
                String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf");
69
                dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF");
70

    
71
                shpFile = f;
72
        }
73

    
74
        private WritableByteChannel getWriteChannel(String path)
75
                                throws IOException
76
        {
77
                WritableByteChannel channel;
78

    
79
                File f = new File(path);
80

    
81
                if (!f.exists()) {
82
                        System.out.println("Creando fichero " + f.getAbsolutePath());
83

    
84
                        if (!f.createNewFile()) {
85
                                System.err.print("Error al crear el fichero " +
86
                                        f.getAbsolutePath());
87
                                throw new IOException("Cannot create file " + f);
88
                        }
89
                }
90

    
91
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
92
                channel = raf.getChannel();
93

    
94
                return channel;
95
        }
96

    
97
        /**
98
         * Util para crear un fichero .shp desde cero.
99
         * @param lyrDef
100
         * @throws IOException
101
         * @throws DriverException
102
         */
103
        /*public ShpWriter(File shpFile, LayerDefinition lyrDef) throws IOException, DriverException
104
        {
105
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc());
106
                initialize(shpFile, lyrDef.getShapeType());
107
        }
108

109
        public ShpWriter(File shpFile, FLyrVect lyrVect) throws IOException, DriverException
110
        {
111
                SelectableDataSource sds = lyrVect.getRecordset();
112
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
113

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

    
164

    
165
        private void initialize(File shpFile, int typeFShape) throws IOException //, FLyrVect lyrVect, FBitSet selection) throws IOException, DriverException
166
        {
167
                // this.lyrVect = lyrVect;
168
                // this.selection = selection;
169
                setFile(shpFile);
170

    
171

    
172
                shpWrite = new SHPFileWrite((FileChannel) getWriteChannel(shpPath),
173
                                (FileChannel) getWriteChannel(shxPath));
174
                shapeType = shpWrite.getShapeType(typeFShape);
175
                gvSIG_geometryType = typeFShape;
176
                setSupportedGeometryTypes();
177
        }
178

    
179
        /**
180
         *
181
         */
182
        private void setSupportedGeometryTypes() {
183
                switch (gvSIG_geometryType)
184
                {
185
                case FShape.POINT:
186
                        supportedGeometryTypes = new int[] {FShape.POINT};
187
                        break;
188
                case FShape.MULTIPOINT:
189
                        supportedGeometryTypes = new int[] {FShape.MULTIPOINT};
190
                        break;
191
                case FShape.LINE:
192
                        supportedGeometryTypes = new int[] {FShape.LINE, FShape.ELLIPSE,
193
                                                        FShape.ARC, FShape.CIRCLE, FShape.POLYGON};
194
                        break;
195
                case FShape.POLYGON:
196
                        supportedGeometryTypes = new int[] {FShape.ELLIPSE,
197
                                FShape.CIRCLE, FShape.POLYGON};
198
                        break;
199

    
200
                default:
201
                        supportedGeometryTypes = new int[] {};
202
                }
203
        }
204

    
205
        public void preProcess() throws EditionException {
206
                // Por ahora solo escribimos los primeros bytes
207
                // de las cabeceras. Luego en el postprocess los escribiremos
208
                // correctamente, con el fullExtent y el numero de
209
                // registros que tocan.
210
                if (selection == null)
211
                {
212

    
213
                        try {
214
                                if (bWriteHeaders)
215
                                {
216
                                        shpWrite.writeHeaders(new Rectangle2D.Double(),
217
                                                shapeType, 0, 0);
218

    
219
                                }
220
                                myHeader.setNumRecords(0);
221
                                dbfWrite = new DbaseFileWriterNIO(myHeader,
222
                                        (FileChannel) getWriteChannel(dbfPath));
223

    
224
                                record = new Object[myHeader.getNumFields()];
225
                                numRows = 0;
226
                                fullExtent = null;
227

    
228
                        } catch (IOException e) {
229
                                e.printStackTrace();
230
                                throw new EditionException(e);
231
                        }
232
                }
233

    
234

    
235
        }
236

    
237
        public void process(IRowEdited row) throws EditionException {
238

    
239
                if (row.getStatus() == IRowEdited.STATUS_DELETED) return;
240

    
241
                IFeature feat = (IFeature) row.getLinkedRow();
242

    
243
                try {
244
                        /* System.out.println("Intento escribir el registro " +
245
                                        numRows + " de la capa " + lyrVect.getName()); */
246
                        IGeometry theGeom = feat.getGeometry();
247
                        // Revisamos que podemos escribir esa entidad
248
                        // En un shpFile, podemos meter pol?gonos, pero que sean como
249
                        // lineas. En cambio, en uno de puntos solo se pueden meter puntos
250
                        if (canWriteGeometry(theGeom.getGeometryType()))
251
                        {
252
                                for (int i=0; i < record.length; i++)
253
                                        record[i] = feat.getAttribute(i);
254

    
255
                                fileSize = shpWrite.writeIGeometry(theGeom);
256
                                Rectangle2D boundsShp = theGeom.getBounds2D();
257

    
258
                                if (fullExtent == null) {
259
                                        fullExtent = boundsShp;
260
                                } else {
261
                                        fullExtent.add(boundsShp);
262
                                }
263

    
264
                                dbfWrite.write(record);
265
                                numRows++;
266
                        }
267
                        else
268
                        {
269
                                System.out.println("No se ha escrito la geometr?a "
270
                                                + row.getIndex() + " geomType=" + theGeom.getGeometryType());
271
                        }
272

    
273
                } catch (IOException e) {
274
                        e.printStackTrace();
275
                        throw new EditionException(e);
276
                } catch (ShapefileException e) {
277
                        e.printStackTrace();
278
                        throw new EditionException(e);
279
                }
280

    
281
        }
282

    
283
        public void postProcess() throws EditionException {
284
                try {
285
                        myHeader.setNumRecords(numRows);
286
                        if (fullExtent == null)
287
                                fullExtent = new Rectangle2D.Double();
288
                        shpWrite.writeHeaders(fullExtent,
289
                                        shapeType, numRows, fileSize);
290

    
291
                        dbfWrite = new DbaseFileWriterNIO(myHeader,
292
                                        (FileChannel) getWriteChannel(dbfPath));
293
                } catch (IOException e) {
294
                        e.printStackTrace();
295
                        throw new EditionException(e);
296
                }
297

    
298

    
299
        }
300
        /**
301
         * Devuelve el path del fichero Shp.
302
         *
303
         * @author azabala
304
         * @return shp path
305
         */
306
        public String getShpPath(){
307
                //Lo necesito para que el ShpSchemaManager sepa
308
                //como "construir" el esquema del fichero SHP/DBF
309
                //adem?s del ShpLayerDefinition
310
                //TODO hacer que ShpWriter implemente ISchemaManager
311
                return this.shpPath;
312
        }
313

    
314
        public String getName() {
315
                return "Shape Writer";
316
        }
317
        public boolean canWriteGeometry(int gvSIGgeometryType) {
318
                /* switch (gvSIGgeometryType)
319
                {
320
                case FShape.POINT:
321
                        return true;
322
                case FShape.LINE:
323
                        return true;
324
                case FShape.POLYGON:
325
                        return true;
326
                case FShape.ARC:
327
                        return true; // Pero convirtiendo a segmentos peque?os
328
                case FShape.ELLIPSE:
329
                        return true; // Pero convirtiendo a segmentos peque?os
330
                case FShape.MULTIPOINT:
331
                        return true;
332
                case FShape.TEXT:
333
                        return false;
334
                } */
335
                for (int i=0; i < supportedGeometryTypes.length; i++)
336
                {
337
                        if (gvSIGgeometryType == supportedGeometryTypes[i] ||
338
                                gvSIGgeometryType == (supportedGeometryTypes[i] | FShape.Z)) // Jaume: support for 3D geometries
339
                                return true;
340
                }
341
                return false;
342
        }
343

    
344
        public boolean canWriteAttribute(int sqlType) {
345
                switch (sqlType)
346
                {
347
                case Types.DOUBLE:
348
                case Types.FLOAT:
349
                case Types.INTEGER:
350
                case Types.BIGINT:
351
                        return true;
352
                case Types.DATE:
353
                        return true;
354
                case Types.BIT:
355
                case Types.BOOLEAN:
356
                        return true;
357
                case Types.VARCHAR:
358
                case Types.CHAR:
359
                case Types.LONGVARCHAR:
360
                        return true; // TODO: Revisar esto, porque no creo que admita campos muy grandes
361

    
362
                }
363

    
364
                return false;
365
        }
366

    
367
        /**
368
         * @param dontWriteHeaders The bDontWriteHeaders to set.
369
         */
370
        public void setWriteHeaders(boolean bWriteHeaders) {
371
                this.bWriteHeaders = bWriteHeaders;
372
        }
373

    
374
//        public void setFlatness(double flatness) {
375
//                shpWrite.setFlatness(flatness);
376
//
377
//        }
378

    
379
        public boolean canAlterTable() {
380
                return true;
381
        }
382

    
383
        public boolean canSaveEdits() {
384
                if (shpFile.canWrite())
385
                {
386
                        File auxShx = new File(shxPath);
387
                        if (auxShx.canWrite())
388
                        {
389
                                File auxDbf = new File(dbfPath);
390
                                if (auxDbf.canWrite())
391
                                        return true;
392
                        }
393
                }
394
                return false;
395
        }
396

    
397
}