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 | 3653 | fjp | package com.iver.cit.gvsig.fmap.edition.writers.shp; |
---|---|---|---|
2 | |||
3 | 3672 | fjp | import java.awt.geom.Rectangle2D; |
4 | 3653 | fjp | 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 | 4328 | fjp | import java.sql.Types; |
10 | 3653 | fjp | |
11 | 3672 | fjp | import com.iver.cit.gvsig.fmap.DriverException; |
12 | 4328 | fjp | import com.iver.cit.gvsig.fmap.core.FShape; |
13 | 3672 | fjp | import com.iver.cit.gvsig.fmap.core.IFeature; |
14 | 4564 | fjp | import com.iver.cit.gvsig.fmap.core.IGeometry; |
15 | 4937 | fjp | import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition; |
16 | 5558 | fjp | import com.iver.cit.gvsig.fmap.drivers.ITableDefinition; |
17 | 3672 | fjp | import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileHeaderNIO; |
18 | import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileWriterNIO; |
||
19 | 3653 | fjp | import com.iver.cit.gvsig.fmap.drivers.shp.write.SHPFileWrite; |
20 | 3686 | fjp | import com.iver.cit.gvsig.fmap.drivers.shp.write.ShapefileException; |
21 | 3672 | fjp | import com.iver.cit.gvsig.fmap.edition.EditionException; |
22 | 3653 | fjp | import com.iver.cit.gvsig.fmap.edition.IRowEdited; |
23 | 4380 | fjp | import com.iver.cit.gvsig.fmap.edition.ISpatialWriter; |
24 | 4328 | fjp | import com.iver.cit.gvsig.fmap.edition.writers.AbstractWriter; |
25 | 3653 | fjp | import com.iver.cit.gvsig.fmap.layers.FBitSet; |
26 | 4440 | fjp | import com.iver.cit.gvsig.fmap.layers.FLayer; |
27 | 3672 | fjp | import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
28 | import com.iver.cit.gvsig.fmap.layers.SelectableDataSource; |
||
29 | 3653 | fjp | |
30 | 4380 | fjp | public class ShpWriter extends AbstractWriter implements ISpatialWriter { |
31 | 3653 | fjp | private String shpPath; |
32 | private String shxPath; |
||
33 | private String dbfPath; |
||
34 | 5389 | caballero | |
35 | 4430 | fjp | private File shpFile; |
36 | 3963 | caballero | |
37 | 3672 | fjp | private SHPFileWrite shpWrite;
|
38 | private DbaseFileWriterNIO dbfWrite;
|
||
39 | 4143 | caballero | |
40 | 3977 | fjp | private DbaseFileHeaderNIO myHeader;
|
41 | 3963 | caballero | |
42 | 3672 | fjp | private int shapeType; |
43 | private int numRows; |
||
44 | 3686 | fjp | private int fileSize; |
45 | 3672 | fjp | private Rectangle2D fullExtent; |
46 | private Object[] record; |
||
47 | 3963 | caballero | |
48 | 3977 | fjp | // private FLyrVect lyrVect;
|
49 | 3672 | fjp | private FBitSet selection = null; |
50 | 4535 | fjp | private boolean bWriteHeaders = true; |
51 | 5268 | fjp | 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 | 5389 | caballero | }; |
60 | 3963 | caballero | |
61 | 4430 | fjp | public void setFile(File f) |
62 | 3653 | fjp | { |
63 | shpPath = f.getAbsolutePath(); |
||
64 | |||
65 | String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx"); |
||
66 | shxPath = strFichshx.replaceAll("\\.SHP", ".SHX"); |
||
67 | 3963 | caballero | |
68 | 3653 | fjp | String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf"); |
69 | dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF"); |
||
70 | 5389 | caballero | |
71 | 4430 | fjp | shpFile = f; |
72 | 3653 | fjp | } |
73 | 3963 | caballero | |
74 | 3653 | fjp | private WritableByteChannel getWriteChannel(String path) |
75 | throws IOException |
||
76 | { |
||
77 | WritableByteChannel channel;
|
||
78 | 3963 | caballero | |
79 | 3653 | fjp | File f = new File(path); |
80 | 3963 | caballero | |
81 | 3653 | fjp | if (!f.exists()) {
|
82 | System.out.println("Creando fichero " + f.getAbsolutePath()); |
||
83 | 3963 | caballero | |
84 | 3653 | fjp | 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 | 3963 | caballero | |
91 | 3653 | fjp | RandomAccessFile raf = new RandomAccessFile(f, "rw"); |
92 | channel = raf.getChannel(); |
||
93 | 3963 | caballero | |
94 | 3653 | fjp | return channel;
|
95 | } |
||
96 | 3963 | caballero | |
97 | 3977 | fjp | /**
|
98 | * Util para crear un fichero .shp desde cero.
|
||
99 | * @param lyrDef
|
||
100 | * @throws IOException
|
||
101 | * @throws DriverException
|
||
102 | */
|
||
103 | 4143 | caballero | /*public ShpWriter(File shpFile, LayerDefinition lyrDef) throws IOException, DriverException
|
104 | 3977 | fjp | {
|
105 | 4084 | azabala | myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc());
|
106 | 4078 | azabala | initialize(shpFile, lyrDef.getShapeType());
|
107 | 3977 | fjp | }
|
108 | 3963 | caballero | |
109 | 3686 | fjp | public ShpWriter(File shpFile, FLyrVect lyrVect) throws IOException, DriverException
|
110 | 3653 | fjp | {
|
111 | 3977 | fjp | SelectableDataSource sds = lyrVect.getRecordset();
|
112 | myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
|
||
113 | |||
114 | initialize(shpFile, lyrVect.getShapeType());
|
||
115 | 3653 | fjp | }
|
116 | 4143 | caballero | */
|
117 | 4440 | fjp | /**
|
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 | 5389 | caballero | FLyrVect lyrVect = (FLyrVect) layer; |
129 | 4440 | fjp | try {
|
130 | 4455 | fjp | SelectableDataSource sds = lyrVect.getRecordset(); |
131 | 4440 | fjp | 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 | 5389 | caballero | } |
140 | 4440 | fjp | } |
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 | 4143 | caballero | } |
146 | 4430 | fjp | /**
|
147 | 4440 | fjp | * Useful to create a layer from scratch
|
148 | * Call setFile before using this function
|
||
149 | * @param lyrDef
|
||
150 | 4740 | fjp | * @throws EditionException
|
151 | 4430 | fjp | */
|
152 | 5558 | fjp | public void initialize(ITableDefinition lyrDef) throws EditionException |
153 | 4430 | fjp | { |
154 | 6259 | fjp | super.initialize(lyrDef);
|
155 | 4440 | fjp | myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc()); |
156 | 4740 | fjp | try {
|
157 | 5558 | fjp | initialize(shpFile, ((ILayerDefinition)lyrDef).getShapeType()); |
158 | 4740 | fjp | } catch (IOException e) { |
159 | e.printStackTrace(); |
||
160 | throw new EditionException(e); |
||
161 | } |
||
162 | 4440 | fjp | } |
163 | 3977 | fjp | |
164 | 5389 | caballero | |
165 | 3977 | fjp | private void initialize(File shpFile, int typeFShape) throws IOException //, FLyrVect lyrVect, FBitSet selection) throws IOException, DriverException |
166 | 3686 | fjp | { |
167 | 3977 | fjp | // this.lyrVect = lyrVect;
|
168 | // this.selection = selection;
|
||
169 | 3653 | fjp | setFile(shpFile); |
170 | |||
171 | 3963 | caballero | |
172 | 3686 | fjp | shpWrite = new SHPFileWrite((FileChannel) getWriteChannel(shpPath), |
173 | (FileChannel) getWriteChannel(shxPath));
|
||
174 | 3977 | fjp | shapeType = shpWrite.getShapeType(typeFShape); |
175 | 5268 | fjp | gvSIG_geometryType = typeFShape; |
176 | setSupportedGeometryTypes(); |
||
177 | 3653 | fjp | } |
178 | 3963 | caballero | |
179 | 5268 | fjp | /**
|
180 | 5389 | caballero | *
|
181 | 5268 | fjp | */
|
182 | private void setSupportedGeometryTypes() { |
||
183 | switch (gvSIG_geometryType)
|
||
184 | { |
||
185 | case FShape.POINT:
|
||
186 | supportedGeometryTypes = new int[] {FShape.POINT}; |
||
187 | break;
|
||
188 | 6026 | caballero | case FShape.MULTIPOINT:
|
189 | supportedGeometryTypes = new int[] {FShape.MULTIPOINT}; |
||
190 | break;
|
||
191 | 5268 | fjp | 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 | 5389 | caballero | |
200 | 5268 | fjp | default:
|
201 | supportedGeometryTypes = new int[] {}; |
||
202 | } |
||
203 | } |
||
204 | |||
205 | 3672 | fjp | public void preProcess() throws EditionException { |
206 | // Por ahora solo escribimos los primeros bytes
|
||
207 | // de las cabeceras. Luego en el postprocess los escribiremos
|
||
208 | 3963 | caballero | // correctamente, con el fullExtent y el numero de
|
209 | 3672 | fjp | // registros que tocan.
|
210 | if (selection == null) |
||
211 | { |
||
212 | 3963 | caballero | |
213 | 3672 | fjp | try {
|
214 | 4535 | fjp | if (bWriteHeaders)
|
215 | { |
||
216 | shpWrite.writeHeaders(new Rectangle2D.Double(), |
||
217 | 3686 | fjp | shapeType, 0, 0); |
218 | 3963 | caballero | |
219 | 4535 | fjp | } |
220 | 3672 | fjp | myHeader.setNumRecords(0);
|
221 | dbfWrite = new DbaseFileWriterNIO(myHeader,
|
||
222 | 4535 | fjp | (FileChannel) getWriteChannel(dbfPath));
|
223 | |||
224 | 3977 | fjp | record = new Object[myHeader.getNumFields()]; |
225 | 3672 | fjp | numRows = 0;
|
226 | fullExtent = null;
|
||
227 | 3963 | caballero | |
228 | 3672 | fjp | } catch (IOException e) { |
229 | e.printStackTrace(); |
||
230 | throw new EditionException(e); |
||
231 | } |
||
232 | } |
||
233 | 3653 | fjp | |
234 | 3963 | caballero | |
235 | 3653 | fjp | } |
236 | |||
237 | 3672 | fjp | public void process(IRowEdited row) throws EditionException { |
238 | 5389 | caballero | |
239 | 4937 | fjp | if (row.getStatus() == IRowEdited.STATUS_DELETED) return; |
240 | 5389 | caballero | |
241 | 3963 | caballero | IFeature feat = (IFeature) row.getLinkedRow(); |
242 | |||
243 | 3672 | fjp | try {
|
244 | 3977 | fjp | /* System.out.println("Intento escribir el registro " +
|
245 | numRows + " de la capa " + lyrVect.getName()); */
|
||
246 | 4564 | fjp | IGeometry theGeom = feat.getGeometry(); |
247 | 5268 | fjp | // 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 | 5389 | caballero | |
255 | 5268 | fjp | fileSize = shpWrite.writeIGeometry(theGeom); |
256 | Rectangle2D boundsShp = theGeom.getBounds2D();
|
||
257 | 5389 | caballero | |
258 | 5268 | fjp | if (fullExtent == null) { |
259 | fullExtent = boundsShp; |
||
260 | } else {
|
||
261 | fullExtent.add(boundsShp); |
||
262 | } |
||
263 | 5389 | caballero | |
264 | 5268 | fjp | dbfWrite.write(record); |
265 | numRows++; |
||
266 | 3672 | fjp | } |
267 | 5268 | fjp | else
|
268 | { |
||
269 | 5389 | caballero | System.out.println("No se ha escrito la geometr?a " |
270 | 5268 | fjp | + row.getIndex() + " geomType=" + theGeom.getGeometryType());
|
271 | } |
||
272 | 3963 | caballero | |
273 | 3672 | fjp | } catch (IOException e) { |
274 | e.printStackTrace(); |
||
275 | throw new EditionException(e); |
||
276 | 3686 | fjp | } catch (ShapefileException e) {
|
277 | e.printStackTrace(); |
||
278 | throw new EditionException(e); |
||
279 | 3672 | fjp | } |
280 | |||
281 | 3653 | fjp | } |
282 | |||
283 | 3672 | fjp | public void postProcess() throws EditionException { |
284 | 4143 | caballero | try {
|
285 | 3672 | fjp | myHeader.setNumRecords(numRows); |
286 | 4416 | fjp | if (fullExtent == null) |
287 | fullExtent = new Rectangle2D.Double(); |
||
288 | 3963 | caballero | shpWrite.writeHeaders(fullExtent, |
289 | 3686 | fjp | shapeType, numRows, fileSize); |
290 | 3963 | caballero | |
291 | 3672 | fjp | dbfWrite = new DbaseFileWriterNIO(myHeader,
|
292 | (FileChannel) getWriteChannel(dbfPath));
|
||
293 | } catch (IOException e) { |
||
294 | e.printStackTrace(); |
||
295 | throw new EditionException(e); |
||
296 | } |
||
297 | 3653 | fjp | |
298 | 3672 | fjp | |
299 | 3653 | fjp | } |
300 | 3973 | azabala | /**
|
301 | * Devuelve el path del fichero Shp.
|
||
302 | 4143 | caballero | *
|
303 | 3973 | azabala | * @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 | 3653 | fjp | |
314 | 4143 | caballero | public String getName() { |
315 | return "Shape Writer"; |
||
316 | } |
||
317 | 4328 | fjp | public boolean canWriteGeometry(int gvSIGgeometryType) { |
318 | 5268 | fjp | /* switch (gvSIGgeometryType)
|
319 | 4328 | fjp | {
|
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 | 5268 | fjp | return true; // Pero convirtiendo a segmentos peque?os
|
328 | 4328 | fjp | case FShape.ELLIPSE:
|
329 | 5268 | fjp | return true; // Pero convirtiendo a segmentos peque?os
|
330 | 4328 | fjp | case FShape.MULTIPOINT:
|
331 | 5389 | caballero | return true;
|
332 | 4328 | fjp | case FShape.TEXT:
|
333 | 5389 | caballero | return false;
|
334 | 5268 | fjp | } */
|
335 | for (int i=0; i < supportedGeometryTypes.length; i++) |
||
336 | { |
||
337 | 7247 | jaume | if (gvSIGgeometryType == supportedGeometryTypes[i] ||
|
338 | gvSIGgeometryType == (supportedGeometryTypes[i] | FShape.Z)) // Jaume: support for 3D geometries
|
||
339 | 5268 | fjp | return true; |
340 | 4328 | fjp | } |
341 | return false; |
||
342 | } |
||
343 | 4143 | caballero | |
344 | 4328 | fjp | public boolean canWriteAttribute(int sqlType) { |
345 | switch (sqlType)
|
||
346 | { |
||
347 | case Types.DOUBLE: |
||
348 | 5389 | caballero | case Types.FLOAT: |
349 | 4328 | fjp | 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 | 5389 | caballero | return true; |
357 | 4328 | fjp | case Types.VARCHAR: |
358 | 5389 | caballero | case Types.CHAR: |
359 | 4328 | fjp | case Types.LONGVARCHAR: |
360 | return true; // TODO: Revisar esto, porque no creo que admita campos muy grandes |
||
361 | |||
362 | } |
||
363 | 5389 | caballero | |
364 | 4328 | fjp | return false; |
365 | } |
||
366 | |||
367 | 4535 | fjp | /**
|
368 | * @param dontWriteHeaders The bDontWriteHeaders to set.
|
||
369 | */
|
||
370 | public void setWriteHeaders(boolean bWriteHeaders) { |
||
371 | this.bWriteHeaders = bWriteHeaders;
|
||
372 | } |
||
373 | |||
374 | 6714 | caballero | // public void setFlatness(double flatness) {
|
375 | // shpWrite.setFlatness(flatness);
|
||
376 | //
|
||
377 | // }
|
||
378 | 5389 | caballero | |
379 | 6621 | fjp | public boolean canAlterTable() { |
380 | return true; |
||
381 | } |
||
382 | |||
383 | 6856 | fjp | 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 | 3653 | fjp | } |