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