Statistics
| Revision:

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

History | View | Annotate | Download (11 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.SHP;
26
import com.iver.cit.gvsig.fmap.drivers.shp.write.SHPFileWrite;
27
import com.iver.cit.gvsig.fmap.drivers.shp.write.ShapefileException;
28
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
29
import com.iver.cit.gvsig.fmap.edition.ISpatialWriter;
30
import com.iver.cit.gvsig.fmap.edition.writers.AbstractWriter;
31
import com.iver.cit.gvsig.fmap.layers.FBitSet;
32
import com.iver.cit.gvsig.fmap.layers.FLayer;
33
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
34
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
35

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

    
41
        private File shpFile;
42

    
43
        private SHPFileWrite shpWrite;
44
        private DbaseFileWriterNIO dbfWrite;
45

    
46
        private DbaseFileHeaderNIO myHeader;
47

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

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

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

    
76
                shxPath = SHP.getShxFile(f).getAbsolutePath();
77

    
78
                dbfPath = SHP.getDbfFile(f).getAbsolutePath();
79

    
80
                shpFile = f;
81
        }
82

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

    
88
                File f = new File(path);
89

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

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

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

    
103
                return channel;
104
        }
105

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

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

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

    
171

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

    
178

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

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

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

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

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

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

    
231
                                dbfWrite.setCharset(charset);
232

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

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

    
242

    
243
        }
244

    
245
        public void process(IRowEdited row) throws ProcessWriterVisitorException {
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
                        throw new ProcessWriterVisitorException(getName(),e);
286
                } catch (ShapefileException e) {
287
                        throw new ProcessWriterVisitorException(getName(),e);
288
                }
289

    
290
        }
291

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

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

    
306

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

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

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

    
371
                }
372

    
373
                return false;
374
        }
375

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

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

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

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

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

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

    
414
}