Statistics
| Revision:

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

History | View | Annotate | Download (10.6 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.SHP;
21
import com.iver.cit.gvsig.fmap.drivers.shp.write.SHPFileWrite;
22
import com.iver.cit.gvsig.fmap.drivers.shp.write.ShapefileException;
23
import com.iver.cit.gvsig.fmap.edition.EditionException;
24
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
25
import com.iver.cit.gvsig.fmap.edition.ISpatialWriter;
26
import com.iver.cit.gvsig.fmap.edition.writers.AbstractWriter;
27
import com.iver.cit.gvsig.fmap.layers.FBitSet;
28
import com.iver.cit.gvsig.fmap.layers.FLayer;
29
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
30
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
31

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

    
37
        private File shpFile;
38

    
39
        private SHPFileWrite shpWrite;
40
        private DbaseFileWriterNIO dbfWrite;
41

    
42
        private DbaseFileHeaderNIO myHeader;
43

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

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

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

    
72
                shxPath = SHP.getShxFile(f).getAbsolutePath();
73

    
74
                dbfPath = SHP.getDbfFile(f).getAbsolutePath();
75

    
76
                shpFile = f;
77
        }
78

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

    
84
                File f = new File(path);
85

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

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

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

    
99
                return channel;
100
        }
101

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

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

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

    
169

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

    
176

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

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

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

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

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

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

    
229
                                dbfWrite.setCharset(charset);
230

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

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

    
241

    
242
        }
243

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

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

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

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

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

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

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

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

    
291
        }
292

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

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

    
308

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

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

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

    
372
                }
373

    
374
                return false;
375
        }
376

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

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

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

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

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

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

    
415
}