Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / writers / shp / ShpWriter.java @ 10627

History | View | Annotate | Download (10.9 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.hardcode.gdbms.driver.exceptions.InitializeWriterException;
13
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
14
import com.hardcode.gdbms.engine.data.driver.DriverException;
15
import com.iver.cit.gvsig.exceptions.visitors.ProcessWriterVisitorException;
16
import com.iver.cit.gvsig.exceptions.visitors.StartWriterVisitorException;
17
import com.iver.cit.gvsig.exceptions.visitors.StopWriterVisitorException;
18
import com.iver.cit.gvsig.fmap.core.FShape;
19
import com.iver.cit.gvsig.fmap.core.IFeature;
20
import com.iver.cit.gvsig.fmap.core.IGeometry;
21
import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition;
22
import com.iver.cit.gvsig.fmap.drivers.ITableDefinition;
23
import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileHeaderNIO;
24
import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileWriterNIO;
25
import com.iver.cit.gvsig.fmap.drivers.shp.write.SHPFileWrite;
26
import com.iver.cit.gvsig.fmap.drivers.shp.write.ShapefileException;
27
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
28
import com.iver.cit.gvsig.fmap.edition.ISpatialWriter;
29
import com.iver.cit.gvsig.fmap.edition.writers.AbstractWriter;
30
import com.iver.cit.gvsig.fmap.layers.FBitSet;
31
import com.iver.cit.gvsig.fmap.layers.FLayer;
32
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
33
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
34

    
35
public class ShpWriter extends AbstractWriter implements ISpatialWriter {
36
        private String shpPath;
37
        private String shxPath;
38
        private String dbfPath;
39

    
40
        private File shpFile;
41

    
42
        private SHPFileWrite shpWrite;
43
        private DbaseFileWriterNIO dbfWrite;
44

    
45
        private DbaseFileHeaderNIO myHeader;
46

    
47
        private int shapeType;
48
        private int numRows;
49
        private int fileSize;
50
        private Rectangle2D fullExtent;
51
        private Object[] record;
52

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

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

    
75
                String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx");
76
                shxPath = strFichshx.replaceAll("\\.SHP", ".SHX");
77

    
78
                String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf");
79
                dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF");
80

    
81
                shpFile = f;
82
        }
83

    
84
        private WritableByteChannel getWriteChannel(String path)
85
                                throws IOException
86
        {
87
                WritableByteChannel channel;
88

    
89
                File f = new File(path);
90

    
91
                if (!f.exists()) {
92
                        System.out.println("Creando fichero " + f.getAbsolutePath());
93

    
94
                        if (!f.createNewFile()) {
95
                                System.err.print("Error al crear el fichero " +
96
                                        f.getAbsolutePath());
97
                                throw new IOException("Cannot create file " + f);
98
                        }
99
                }
100

    
101
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
102
                channel = raf.getChannel();
103

    
104
                return channel;
105
        }
106

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

119
        public ShpWriter(File shpFile, FLyrVect lyrVect) throws IOException, DriverException
120
        {
121
                SelectableDataSource sds = lyrVect.getRecordset();
122
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
123

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

    
172

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

    
179

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

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

    
208
                default:
209
                        supportedGeometryTypes = new int[] {};
210
                }
211
        }
212

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

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

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

    
232
                                dbfWrite.setCharset(charset);
233

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

    
238
                        } catch (IOException e) {
239
                                throw new StartWriterVisitorException(getName(),e);
240
                        }
241
                }
242

    
243

    
244
        }
245

    
246
        public void process(IRowEdited row) throws ProcessWriterVisitorException {
247

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

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

    
252
                try {
253
                        /* System.out.println("Intento escribir el registro " +
254
                                        numRows + " de la capa " + lyrVect.getName()); */
255
                        IGeometry theGeom = feat.getGeometry();
256
                        // Revisamos que podemos escribir esa entidad
257
                        // En un shpFile, podemos meter pol?gonos, pero que sean como
258
                        // lineas. En cambio, en uno de puntos solo se pueden meter puntos
259
                                if (canWriteGeometry(theGeom.getGeometryType()) || canWriteGeometry(gvSIG_geometryType))
260
                        {
261
                                for (int i=0; i < record.length; i++)
262
                                        record[i] = feat.getAttribute(i);
263

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

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

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

    
282
                } catch (IOException e) {
283
                        throw new ProcessWriterVisitorException(getName(),e);
284
                } catch (ShapefileException e) {
285
                        throw new ProcessWriterVisitorException(getName(),e);
286
                }
287

    
288
        }
289

    
290
        public void postProcess() throws StopWriterVisitorException {
291
                try {
292
                        myHeader.setNumRecords(numRows);
293
                        if (fullExtent == null)
294
                                fullExtent = new Rectangle2D.Double();
295
                        shpWrite.writeHeaders(fullExtent,
296
                                        shapeType, numRows, fileSize);
297

    
298
                        dbfWrite = new DbaseFileWriterNIO(myHeader,
299
                                        (FileChannel) getWriteChannel(dbfPath));
300
                } catch (IOException e) {
301
                        throw new StopWriterVisitorException(getName(),e);
302
                }
303

    
304

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

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

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

    
368
                }
369

    
370
                return false;
371
        }
372

    
373
        /**
374
         * @param dontWriteHeaders The bDontWriteHeaders to set.
375
         */
376
        public void setWriteHeaders(boolean bWriteHeaders) {
377
                this.bWriteHeaders = bWriteHeaders;
378
        }
379

    
380
//        public void setFlatness(double flatness) {
381
//                shpWrite.setFlatness(flatness);
382
//
383
//        }
384

    
385
        public boolean canAlterTable() {
386
                return true;
387
        }
388

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

    
403
        public void setCharsetForWriting(Charset charset) {
404
                this.charset = charset;
405
        }
406

    
407
        public Charset getCharsetForWriting() {
408
                return charset;
409
        }
410

    
411
}