Statistics
| Revision:

root / branches / simbologia / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / writers / shp / ShpWriter.java @ 10450

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
import com.iver.utiles.xmlEntity.generate.Property;
31

    
32
/**
33
 * @author   jaume dominguez faus - jaume.dominguez@iver.es
34
 */
35
public class ShpWriter extends AbstractWriter implements ISpatialWriter {
36
        /**
37
         * @uml.property  name="shpPath"
38
         */
39
        private String shpPath;
40
        private String shxPath;
41
        private String dbfPath;
42

    
43
        private File shpFile;
44

    
45
        private SHPFileWrite shpWrite;
46
        private DbaseFileWriterNIO dbfWrite;
47

    
48
        private DbaseFileHeaderNIO myHeader;
49

    
50
        private int shapeType;
51
        private int numRows;
52
        private int fileSize;
53
        private Rectangle2D fullExtent;
54
        private Object[] record;
55

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

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

    
78
                String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx");
79
                shxPath = strFichshx.replaceAll("\\.SHP", ".SHX");
80

    
81
                String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf");
82
                dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF");
83

    
84
                shpFile = f;
85
        }
86

    
87
        private WritableByteChannel getWriteChannel(String path)
88
                                throws IOException
89
        {
90
                WritableByteChannel channel;
91

    
92
                File f = new File(path);
93

    
94
                if (!f.exists()) {
95
                        System.out.println("Creando fichero " + f.getAbsolutePath());
96

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

    
104
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
105
                channel = raf.getChannel();
106

    
107
                return channel;
108
        }
109

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

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

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

    
177

    
178
        private void initialize(File shpFile, int typeFShape) throws IOException //, FLyrVect lyrVect, FBitSet selection) throws IOException, DriverException
179
        {
180
                // this.lyrVect = lyrVect;
181
                // this.selection = selection;
182
                setFile(shpFile);
183

    
184

    
185
                shpWrite = new SHPFileWrite((FileChannel) getWriteChannel(shpPath),
186
                                (FileChannel) getWriteChannel(shxPath));
187
                shapeType = shpWrite.getShapeType(typeFShape);
188
                gvSIG_geometryType = typeFShape;
189
                setSupportedGeometryTypes();
190
        }
191

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

    
213
                default:
214
                        supportedGeometryTypes = new int[] {};
215
                }
216
        }
217

    
218
        public void preProcess() throws EditionException {
219
                // Por ahora solo escribimos los primeros bytes
220
                // de las cabeceras. Luego en el postprocess los escribiremos
221
                // correctamente, con el fullExtent y el numero de
222
                // registros que tocan.
223
                if (selection == null)
224
                {
225

    
226
                        try {
227
                                if (bWriteHeaders)
228
                                {
229
                                        shpWrite.writeHeaders(new Rectangle2D.Double(),
230
                                                shapeType, 0, 0);
231

    
232
                                }
233
                                myHeader.setNumRecords(0);
234
                                dbfWrite = new DbaseFileWriterNIO(myHeader,
235
                                        (FileChannel) getWriteChannel(dbfPath));
236

    
237
                                dbfWrite.setCharset(charset);
238

    
239
                                record = new Object[myHeader.getNumFields()];
240
                                numRows = 0;
241
                                fullExtent = null;
242

    
243
                        } catch (IOException e) {
244
                                e.printStackTrace();
245
                                throw new EditionException(e);
246
                        }
247
                }
248

    
249

    
250
        }
251

    
252
        public void process(IRowEdited row) throws EditionException {
253

    
254
                if (row.getStatus() == IRowEdited.STATUS_DELETED) return;
255

    
256
                IFeature feat = (IFeature) row.getLinkedRow();
257

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

    
270
                                fileSize = shpWrite.writeIGeometry(theGeom);
271
                                Rectangle2D boundsShp = theGeom.getBounds2D();
272

    
273
                                if (fullExtent == null) {
274
                                        fullExtent = boundsShp;
275
                                } else {
276
                                        fullExtent.add(boundsShp);
277
                                }
278

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

    
288
                } catch (IOException e) {
289
                        e.printStackTrace();
290
                        throw new EditionException(e);
291
                } catch (ShapefileException e) {
292
                        e.printStackTrace();
293
                        throw new EditionException(e);
294
                }
295

    
296
        }
297

    
298
        public void postProcess() throws EditionException {
299
                try {
300
                        myHeader.setNumRecords(numRows);
301
                        if (fullExtent == null)
302
                                fullExtent = new Rectangle2D.Double();
303
                        shpWrite.writeHeaders(fullExtent,
304
                                        shapeType, numRows, fileSize);
305

    
306
                        dbfWrite = new DbaseFileWriterNIO(myHeader,
307
                                        (FileChannel) getWriteChannel(dbfPath));
308
                } catch (IOException e) {
309
                        e.printStackTrace();
310
                        throw new EditionException(e);
311
                }
312

    
313

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

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

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

    
377
                }
378

    
379
                return false;
380
        }
381

    
382
        /**
383
         * @param dontWriteHeaders The bDontWriteHeaders to set.
384
         */
385
        public void setWriteHeaders(boolean bWriteHeaders) {
386
                this.bWriteHeaders = bWriteHeaders;
387
        }
388

    
389
//        public void setFlatness(double flatness) {
390
//                shpWrite.setFlatness(flatness);
391
//
392
//        }
393

    
394
        public boolean canAlterTable() {
395
                return true;
396
        }
397

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

    
412
        public void setCharsetForWriting(Charset charset) {
413
                this.charset = charset;
414
        }
415

    
416
        public Charset getCharsetForWriting() {
417
                return charset;
418
        }
419

    
420
}