svn-gvsig-desktop / tags / v1_1_Build_1010 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / writers / shp / ShpWriter.java @ 12804
History | View | Annotate | Download (10.7 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 | 8765 | jjdelcerro | import java.nio.charset.Charset; |
10 | 4328 | fjp | import java.sql.Types; |
11 | 3653 | fjp | |
12 | 3672 | fjp | import com.iver.cit.gvsig.fmap.DriverException; |
13 | 4328 | fjp | import com.iver.cit.gvsig.fmap.core.FShape; |
14 | 3672 | fjp | import com.iver.cit.gvsig.fmap.core.IFeature; |
15 | 4564 | fjp | import com.iver.cit.gvsig.fmap.core.IGeometry; |
16 | 4937 | fjp | import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition; |
17 | 5558 | fjp | import com.iver.cit.gvsig.fmap.drivers.ITableDefinition; |
18 | 3672 | fjp | import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileHeaderNIO; |
19 | import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileWriterNIO; |
||
20 | 3653 | fjp | import com.iver.cit.gvsig.fmap.drivers.shp.write.SHPFileWrite; |
21 | 3686 | fjp | import com.iver.cit.gvsig.fmap.drivers.shp.write.ShapefileException; |
22 | 3672 | fjp | import com.iver.cit.gvsig.fmap.edition.EditionException; |
23 | 3653 | fjp | import com.iver.cit.gvsig.fmap.edition.IRowEdited; |
24 | 4380 | fjp | import com.iver.cit.gvsig.fmap.edition.ISpatialWriter; |
25 | 4328 | fjp | import com.iver.cit.gvsig.fmap.edition.writers.AbstractWriter; |
26 | 3653 | fjp | import com.iver.cit.gvsig.fmap.layers.FBitSet; |
27 | 4440 | fjp | import com.iver.cit.gvsig.fmap.layers.FLayer; |
28 | 3672 | fjp | import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
29 | import com.iver.cit.gvsig.fmap.layers.SelectableDataSource; |
||
30 | 3653 | fjp | |
31 | 4380 | fjp | public class ShpWriter extends AbstractWriter implements ISpatialWriter { |
32 | 3653 | fjp | private String shpPath; |
33 | private String shxPath; |
||
34 | private String dbfPath; |
||
35 | 5389 | caballero | |
36 | 4430 | fjp | private File shpFile; |
37 | 3963 | caballero | |
38 | 3672 | fjp | private SHPFileWrite shpWrite;
|
39 | private DbaseFileWriterNIO dbfWrite;
|
||
40 | 4143 | caballero | |
41 | 3977 | fjp | private DbaseFileHeaderNIO myHeader;
|
42 | 3963 | caballero | |
43 | 3672 | fjp | private int shapeType; |
44 | private int numRows; |
||
45 | 3686 | fjp | private int fileSize; |
46 | 3672 | fjp | private Rectangle2D fullExtent; |
47 | private Object[] record; |
||
48 | 3963 | caballero | |
49 | 3977 | fjp | // private FLyrVect lyrVect;
|
50 | 3672 | fjp | private FBitSet selection = null; |
51 | 4535 | fjp | private boolean bWriteHeaders = true; |
52 | 5268 | fjp | private int gvSIG_geometryType; |
53 | private int[] supportedGeometryTypes = {FShape.POINT, |
||
54 | FShape.LINE, |
||
55 | FShape.MULTIPOINT, |
||
56 | FShape.ARC, |
||
57 | FShape.CIRCLE, |
||
58 | FShape.POLYGON, |
||
59 | FShape.TEXT |
||
60 | 5389 | caballero | }; |
61 | 8765 | jjdelcerro | private Charset charset = Charset.forName("ISO-8859-1"); |
62 | 3963 | caballero | |
63 | 10046 | jmvivo | public ShpWriter() {
|
64 | super();
|
||
65 | this.capabilities.setProperty("FieldNameMaxLength","10"); |
||
66 | } |
||
67 | 4430 | fjp | public void setFile(File f) |
68 | 3653 | fjp | { |
69 | shpPath = f.getAbsolutePath(); |
||
70 | |||
71 | String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx"); |
||
72 | shxPath = strFichshx.replaceAll("\\.SHP", ".SHX"); |
||
73 | 3963 | caballero | |
74 | 3653 | fjp | String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf"); |
75 | dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF"); |
||
76 | 5389 | caballero | |
77 | 4430 | fjp | shpFile = f; |
78 | 3653 | fjp | } |
79 | 3963 | caballero | |
80 | 3653 | fjp | private WritableByteChannel getWriteChannel(String path) |
81 | throws IOException |
||
82 | { |
||
83 | WritableByteChannel channel;
|
||
84 | 3963 | caballero | |
85 | 3653 | fjp | File f = new File(path); |
86 | 3963 | caballero | |
87 | 3653 | fjp | if (!f.exists()) {
|
88 | System.out.println("Creando fichero " + f.getAbsolutePath()); |
||
89 | 3963 | caballero | |
90 | 3653 | fjp | if (!f.createNewFile()) {
|
91 | System.err.print("Error al crear el fichero " + |
||
92 | f.getAbsolutePath()); |
||
93 | throw new IOException("Cannot create file " + f); |
||
94 | } |
||
95 | } |
||
96 | 3963 | caballero | |
97 | 3653 | fjp | RandomAccessFile raf = new RandomAccessFile(f, "rw"); |
98 | channel = raf.getChannel(); |
||
99 | 3963 | caballero | |
100 | 3653 | fjp | return channel;
|
101 | } |
||
102 | 3963 | caballero | |
103 | 3977 | fjp | /**
|
104 | * Util para crear un fichero .shp desde cero.
|
||
105 | * @param lyrDef
|
||
106 | * @throws IOException
|
||
107 | * @throws DriverException
|
||
108 | */
|
||
109 | 4143 | caballero | /*public ShpWriter(File shpFile, LayerDefinition lyrDef) throws IOException, DriverException
|
110 | 3977 | fjp | {
|
111 | 4084 | azabala | myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc());
|
112 | 4078 | azabala | initialize(shpFile, lyrDef.getShapeType());
|
113 | 3977 | fjp | }
|
114 | 3963 | caballero | |
115 | 3686 | fjp | public ShpWriter(File shpFile, FLyrVect lyrVect) throws IOException, DriverException
|
116 | 3653 | fjp | {
|
117 | 3977 | fjp | SelectableDataSource sds = lyrVect.getRecordset();
|
118 | myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
|
||
119 | |||
120 | initialize(shpFile, lyrVect.getShapeType());
|
||
121 | 3653 | fjp | }
|
122 | 4143 | caballero | */
|
123 | 4440 | fjp | /**
|
124 | * Use this function first of all, when you need to prepare a writer
|
||
125 | * having a FLayer as model.
|
||
126 | * IMPORTANT: Call setFile before calling this function.
|
||
127 | * @param lyrVect
|
||
128 | * @throws IOException
|
||
129 | * @throws DriverException
|
||
130 | */
|
||
131 | public void initialize(FLayer layer) throws EditionException{ |
||
132 | if (layer instanceof FLyrVect) |
||
133 | { |
||
134 | 5389 | caballero | FLyrVect lyrVect = (FLyrVect) layer; |
135 | 4440 | fjp | try {
|
136 | 4455 | fjp | SelectableDataSource sds = lyrVect.getRecordset(); |
137 | 4440 | fjp | myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds); |
138 | initialize(shpFile, lyrVect.getShapeType()); |
||
139 | } catch (IOException e) { |
||
140 | e.printStackTrace(); |
||
141 | throw new EditionException(e); |
||
142 | } catch (DriverException e) {
|
||
143 | e.printStackTrace(); |
||
144 | throw new EditionException(e); |
||
145 | 5389 | caballero | } |
146 | 4440 | fjp | } |
147 | else
|
||
148 | { |
||
149 | throw new EditionException("No se puede usar una capa que no es vectorial como modelo para escribir un shp."); |
||
150 | } |
||
151 | 4143 | caballero | } |
152 | 4430 | fjp | /**
|
153 | 4440 | fjp | * Useful to create a layer from scratch
|
154 | * Call setFile before using this function
|
||
155 | * @param lyrDef
|
||
156 | 4740 | fjp | * @throws EditionException
|
157 | 4430 | fjp | */
|
158 | 5558 | fjp | public void initialize(ITableDefinition lyrDef) throws EditionException |
159 | 4430 | fjp | { |
160 | 6259 | fjp | super.initialize(lyrDef);
|
161 | 4440 | fjp | myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc()); |
162 | 4740 | fjp | try {
|
163 | 5558 | fjp | initialize(shpFile, ((ILayerDefinition)lyrDef).getShapeType()); |
164 | 4740 | fjp | } catch (IOException e) { |
165 | e.printStackTrace(); |
||
166 | throw new EditionException(e); |
||
167 | } |
||
168 | 4440 | fjp | } |
169 | 3977 | fjp | |
170 | 5389 | caballero | |
171 | 3977 | fjp | private void initialize(File shpFile, int typeFShape) throws IOException //, FLyrVect lyrVect, FBitSet selection) throws IOException, DriverException |
172 | 3686 | fjp | { |
173 | 3977 | fjp | // this.lyrVect = lyrVect;
|
174 | // this.selection = selection;
|
||
175 | 3653 | fjp | setFile(shpFile); |
176 | |||
177 | 3963 | caballero | |
178 | 3686 | fjp | shpWrite = new SHPFileWrite((FileChannel) getWriteChannel(shpPath), |
179 | (FileChannel) getWriteChannel(shxPath));
|
||
180 | 3977 | fjp | shapeType = shpWrite.getShapeType(typeFShape); |
181 | 5268 | fjp | gvSIG_geometryType = typeFShape; |
182 | setSupportedGeometryTypes(); |
||
183 | 3653 | fjp | } |
184 | 3963 | caballero | |
185 | 5268 | fjp | /**
|
186 | 5389 | caballero | *
|
187 | 5268 | fjp | */
|
188 | private void setSupportedGeometryTypes() { |
||
189 | 12594 | caballero | switch (gvSIG_geometryType % FShape.Z)
|
190 | 5268 | fjp | { |
191 | case FShape.POINT:
|
||
192 | supportedGeometryTypes = new int[] {FShape.POINT}; |
||
193 | break;
|
||
194 | 6026 | caballero | case FShape.MULTIPOINT:
|
195 | supportedGeometryTypes = new int[] {FShape.MULTIPOINT}; |
||
196 | break;
|
||
197 | 5268 | fjp | case FShape.LINE:
|
198 | supportedGeometryTypes = new int[] {FShape.LINE, FShape.ELLIPSE, |
||
199 | FShape.ARC, FShape.CIRCLE, FShape.POLYGON}; |
||
200 | break;
|
||
201 | case FShape.POLYGON:
|
||
202 | supportedGeometryTypes = new int[] {FShape.ELLIPSE, |
||
203 | FShape.CIRCLE, FShape.POLYGON}; |
||
204 | break;
|
||
205 | 5389 | caballero | |
206 | 5268 | fjp | default:
|
207 | supportedGeometryTypes = new int[] {}; |
||
208 | } |
||
209 | } |
||
210 | |||
211 | 3672 | fjp | public void preProcess() throws EditionException { |
212 | // Por ahora solo escribimos los primeros bytes
|
||
213 | // de las cabeceras. Luego en el postprocess los escribiremos
|
||
214 | 3963 | caballero | // correctamente, con el fullExtent y el numero de
|
215 | 3672 | fjp | // registros que tocan.
|
216 | if (selection == null) |
||
217 | { |
||
218 | 3963 | caballero | |
219 | 3672 | fjp | try {
|
220 | 4535 | fjp | if (bWriteHeaders)
|
221 | { |
||
222 | shpWrite.writeHeaders(new Rectangle2D.Double(), |
||
223 | 3686 | fjp | shapeType, 0, 0); |
224 | 3963 | caballero | |
225 | 4535 | fjp | } |
226 | 3672 | fjp | myHeader.setNumRecords(0);
|
227 | dbfWrite = new DbaseFileWriterNIO(myHeader,
|
||
228 | 4535 | fjp | (FileChannel) getWriteChannel(dbfPath));
|
229 | 9394 | caballero | |
230 | 8765 | jjdelcerro | dbfWrite.setCharset(charset); |
231 | 4535 | fjp | |
232 | 3977 | fjp | record = new Object[myHeader.getNumFields()]; |
233 | 3672 | fjp | numRows = 0;
|
234 | fullExtent = null;
|
||
235 | 3963 | caballero | |
236 | 3672 | fjp | } catch (IOException e) { |
237 | e.printStackTrace(); |
||
238 | throw new EditionException(e); |
||
239 | } |
||
240 | } |
||
241 | 3653 | fjp | |
242 | 3963 | caballero | |
243 | 3653 | fjp | } |
244 | |||
245 | 3672 | fjp | public void process(IRowEdited row) throws EditionException { |
246 | 5389 | caballero | |
247 | 4937 | fjp | if (row.getStatus() == IRowEdited.STATUS_DELETED) return; |
248 | 5389 | caballero | |
249 | 3963 | caballero | IFeature feat = (IFeature) row.getLinkedRow(); |
250 | |||
251 | 3672 | fjp | try {
|
252 | 3977 | fjp | /* System.out.println("Intento escribir el registro " +
|
253 | numRows + " de la capa " + lyrVect.getName()); */
|
||
254 | 4564 | fjp | IGeometry theGeom = feat.getGeometry(); |
255 | 5268 | fjp | // 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 | 11086 | fdiaz | // 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 | 5268 | fjp | { |
263 | for (int i=0; i < record.length; i++) |
||
264 | record[i] = feat.getAttribute(i); |
||
265 | 5389 | caballero | |
266 | 5268 | fjp | fileSize = shpWrite.writeIGeometry(theGeom); |
267 | Rectangle2D boundsShp = theGeom.getBounds2D();
|
||
268 | 5389 | caballero | |
269 | 5268 | fjp | if (fullExtent == null) { |
270 | fullExtent = boundsShp; |
||
271 | } else {
|
||
272 | fullExtent.add(boundsShp); |
||
273 | } |
||
274 | 5389 | caballero | |
275 | 5268 | fjp | dbfWrite.write(record); |
276 | numRows++; |
||
277 | 3672 | fjp | } |
278 | 5268 | fjp | else
|
279 | { |
||
280 | 5389 | caballero | System.out.println("No se ha escrito la geometr?a " |
281 | 5268 | fjp | + row.getIndex() + " geomType=" + theGeom.getGeometryType());
|
282 | } |
||
283 | 3963 | caballero | |
284 | 3672 | fjp | } catch (IOException e) { |
285 | e.printStackTrace(); |
||
286 | throw new EditionException(e); |
||
287 | 3686 | fjp | } catch (ShapefileException e) {
|
288 | e.printStackTrace(); |
||
289 | throw new EditionException(e); |
||
290 | 3672 | fjp | } |
291 | |||
292 | 3653 | fjp | } |
293 | |||
294 | 3672 | fjp | public void postProcess() throws EditionException { |
295 | 4143 | caballero | try {
|
296 | 3672 | fjp | myHeader.setNumRecords(numRows); |
297 | 4416 | fjp | if (fullExtent == null) |
298 | fullExtent = new Rectangle2D.Double(); |
||
299 | 3963 | caballero | shpWrite.writeHeaders(fullExtent, |
300 | 3686 | fjp | shapeType, numRows, fileSize); |
301 | 3963 | caballero | |
302 | 3672 | fjp | dbfWrite = new DbaseFileWriterNIO(myHeader,
|
303 | (FileChannel) getWriteChannel(dbfPath));
|
||
304 | } catch (IOException e) { |
||
305 | e.printStackTrace(); |
||
306 | throw new EditionException(e); |
||
307 | } |
||
308 | 3653 | fjp | |
309 | 3672 | fjp | |
310 | 3653 | fjp | } |
311 | 3973 | azabala | /**
|
312 | * Devuelve el path del fichero Shp.
|
||
313 | 4143 | caballero | *
|
314 | 3973 | azabala | * @author azabala
|
315 | * @return shp path
|
||
316 | */
|
||
317 | public String getShpPath(){ |
||
318 | //Lo necesito para que el ShpSchemaManager sepa
|
||
319 | //como "construir" el esquema del fichero SHP/DBF
|
||
320 | //adem?s del ShpLayerDefinition
|
||
321 | //TODO hacer que ShpWriter implemente ISchemaManager
|
||
322 | return this.shpPath; |
||
323 | } |
||
324 | 3653 | fjp | |
325 | 4143 | caballero | public String getName() { |
326 | return "Shape Writer"; |
||
327 | } |
||
328 | 4328 | fjp | public boolean canWriteGeometry(int gvSIGgeometryType) { |
329 | 5268 | fjp | /* switch (gvSIGgeometryType)
|
330 | 4328 | fjp | {
|
331 | case FShape.POINT:
|
||
332 | return true;
|
||
333 | case FShape.LINE:
|
||
334 | return true;
|
||
335 | case FShape.POLYGON:
|
||
336 | return true;
|
||
337 | case FShape.ARC:
|
||
338 | 5268 | fjp | return true; // Pero convirtiendo a segmentos peque?os
|
339 | 4328 | fjp | case FShape.ELLIPSE:
|
340 | 5268 | fjp | return true; // Pero convirtiendo a segmentos peque?os
|
341 | 4328 | fjp | case FShape.MULTIPOINT:
|
342 | 5389 | caballero | return true;
|
343 | 4328 | fjp | case FShape.TEXT:
|
344 | 5389 | caballero | return false;
|
345 | 5268 | fjp | } */
|
346 | for (int i=0; i < supportedGeometryTypes.length; i++) |
||
347 | { |
||
348 | 7247 | jaume | if (gvSIGgeometryType == supportedGeometryTypes[i] ||
|
349 | 12594 | caballero | gvSIGgeometryType == (supportedGeometryTypes[i] | FShape.Z)) |
350 | 5268 | fjp | return true; |
351 | 4328 | fjp | } |
352 | return false; |
||
353 | } |
||
354 | 4143 | caballero | |
355 | 4328 | fjp | public boolean canWriteAttribute(int sqlType) { |
356 | switch (sqlType)
|
||
357 | { |
||
358 | case Types.DOUBLE: |
||
359 | 5389 | caballero | case Types.FLOAT: |
360 | 4328 | fjp | case Types.INTEGER: |
361 | case Types.BIGINT: |
||
362 | return true; |
||
363 | case Types.DATE: |
||
364 | return true; |
||
365 | case Types.BIT: |
||
366 | case Types.BOOLEAN: |
||
367 | 5389 | caballero | return true; |
368 | 4328 | fjp | case Types.VARCHAR: |
369 | 5389 | caballero | case Types.CHAR: |
370 | 4328 | fjp | case Types.LONGVARCHAR: |
371 | return true; // TODO: Revisar esto, porque no creo que admita campos muy grandes |
||
372 | |||
373 | } |
||
374 | 5389 | caballero | |
375 | 4328 | fjp | return false; |
376 | } |
||
377 | |||
378 | 4535 | fjp | /**
|
379 | * @param dontWriteHeaders The bDontWriteHeaders to set.
|
||
380 | */
|
||
381 | public void setWriteHeaders(boolean bWriteHeaders) { |
||
382 | this.bWriteHeaders = bWriteHeaders;
|
||
383 | } |
||
384 | |||
385 | 6714 | caballero | // public void setFlatness(double flatness) {
|
386 | // shpWrite.setFlatness(flatness);
|
||
387 | //
|
||
388 | // }
|
||
389 | 5389 | caballero | |
390 | 6621 | fjp | public boolean canAlterTable() { |
391 | return true; |
||
392 | } |
||
393 | |||
394 | 6856 | fjp | public boolean canSaveEdits() { |
395 | if (shpFile.canWrite())
|
||
396 | { |
||
397 | File auxShx = new File(shxPath); |
||
398 | if (auxShx.canWrite())
|
||
399 | { |
||
400 | File auxDbf = new File(dbfPath); |
||
401 | if (auxDbf.canWrite())
|
||
402 | return true; |
||
403 | } |
||
404 | } |
||
405 | return false; |
||
406 | } |
||
407 | 9394 | caballero | |
408 | 8765 | jjdelcerro | public void setCharsetForWriting(Charset charset) { |
409 | this.charset = charset;
|
||
410 | } |
||
411 | 6856 | fjp | |
412 | 8765 | jjdelcerro | public Charset getCharsetForWriting() { |
413 | return charset;
|
||
414 | } |
||
415 | |||
416 | 3653 | fjp | } |