Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / org.gvsig.desktop.compat.cdc / org.gvsig.basicformats / src / main / java / org / gvsig / basicformats / impl / DefaultHDRFile.java @ 43876

History | View | Annotate | Download (18.8 KB)

1
package org.gvsig.basicformats.impl;
2

    
3

    
4
import java.io.File;
5
import java.io.IOException;
6
import java.nio.ByteOrder;
7
import java.util.List;
8
import org.apache.commons.io.FileUtils;
9
import org.apache.commons.io.FilenameUtils;
10
import org.apache.commons.lang3.StringUtils;
11
import org.gvsig.basicformats.HDRFile;
12
import org.gvsig.fmap.geom.Geometry;
13
import org.gvsig.fmap.geom.GeometryLocator;
14
import org.gvsig.fmap.geom.primitive.Envelope;
15
import org.gvsig.fmap.geom.primitive.Point;
16
import org.gvsig.raster.lib.buffer.api.BufferManager;
17
import org.slf4j.Logger;
18
import org.slf4j.LoggerFactory;
19

    
20
public class DefaultHDRFile implements HDRFile {
21

    
22
    // http://resources.esri.com/help/9.3/arcgisdesktop/com/gp_toolref/spatial_analyst_tools/esri_ascii_raster_format.htm
23
    private static final Logger logger = LoggerFactory.getLogger(DefaultHDRFile.class);
24

    
25
    private File source;
26
    private String comments;
27

    
28
    private int nrows = NONE;
29
    private int ncols = NONE;
30
    private int nbands = 1;
31
    private int nbits = 8;
32
    private String pixeltype;
33
    private String byteorder_word;
34
    private ByteOrder byteorder = ByteOrder.nativeOrder();
35
    private String layout = LAYOUT_BIL;
36
    private int skipbytes = 0;
37
    private double ulxmax = Double.NaN;
38
    private double ulymax = Double.NaN;
39
    private double xdim = Double.NaN;
40
    private double ydim = Double.NaN;
41
    private int bandrowbytes = NONE;
42
    private int totalrowbytes = NONE;
43
    private int bandgapbytes = 0;
44
    private boolean valid = false;
45
    private double nodata_value = Double.NaN;
46

    
47
    // X coordinate of the origin (by center or lower left corner of the cell).
48
    private double xllcorner = Double.NaN;
49

    
50
    // Y coordinate of the origin (by center or lower left corner of the cell).
51
    private double yllcorner = Double.NaN;
52

    
53
    private int cellsize = NONE;
54

    
55
    public DefaultHDRFile() {
56
        this.source = null;
57
    }
58

    
59
    @Override
60
    public File getFile(File file) {
61
        File f = new File(FilenameUtils.removeExtension(file.getAbsolutePath()) + "." + FILE_EXTENSION);
62
        return f;
63
    }
64

    
65
    @Override
66
    public File getFile() {
67
        return source;
68
    }
69

    
70
    @Override
71
    public void read(File file) throws IOException {
72
        File f = this.getFile(file);
73
        if (f.exists()) {
74
            try {
75
                List<String> lines = FileUtils.readLines(f);
76
                if (lines != null) {
77
                    this.source = f.getAbsoluteFile();
78
                    int lineno = 1;
79
                    for (String line : lines) {
80
                        String[] words = StringUtils.split(line.trim().toLowerCase());
81
                        try {
82
                            switch (words[0]) {
83
                                case "nrows":
84
                                    this.nrows = Integer.parseInt(words[1]);
85
                                    break;
86
                                case "ncols":
87
                                    this.ncols = Integer.parseInt(words[1]);
88
                                    break;
89
                                case "nbands":
90
                                    this.nbands = Integer.parseInt(words[1]);
91
                                    break;
92
                                case "nbits":
93
                                    this.nbits = Integer.parseInt(words[1]);
94
                                    break;
95
                                case "pixeltype":
96
                                    this.pixeltype = words[1];
97
                                    break;
98
                                case "byteorder":
99
                                    this.byteorder_word = words[1];
100
                                    break;
101
                                case "layout":
102
                                    this.layout = words[1];
103
                                    break;
104
                                case "skipbytes":
105
                                    this.skipbytes = Integer.parseInt(words[1]);
106
                                    break;
107
                                case "nodata_value":
108
                                    this.nodata_value = Double.parseDouble(words[1]);
109
                                    break;
110
                                case "cellsize":
111
                                    this.cellsize = Integer.parseInt(words[1]);
112
                                    break;
113
                                case "xllcorner":
114
                                case "xllcenter":
115
                                    this.xllcorner = Double.parseDouble(words[1]);
116
                                    break;
117
                                case "yllcorner":
118
                                case "yllcenter":
119
                                    this.yllcorner = Double.parseDouble(words[1]);
120
                                    break;
121
                                case "ulxmax":
122
                                    this.ulxmax = Double.parseDouble(words[1]);
123
                                    break;
124
                                case "ulymax":
125
                                    this.ulymax = Double.parseDouble(words[1]);
126
                                    break;
127
                                case "xdim":
128
                                    this.xdim = Double.parseDouble(words[1]);
129
                                    break;
130
                                case "ydim":
131
                                    this.ydim = Double.parseDouble(words[1]);
132
                                    break;
133
                                case "bandrowbytes":
134
                                    this.bandrowbytes = Integer.parseInt(words[1]);
135
                                    break;
136
                                case "totalrowbytes":
137
                                    this.totalrowbytes = Integer.parseInt(words[1]);
138
                                    break;
139
                                case "bandgapbytes":
140
                                    this.bandgapbytes = Integer.parseInt(words[1]);
141
                                    break;
142
                            }
143
                        } catch (NumberFormatException e) {
144
                            logger.warn("Can't parse keyword '" + words[0]
145
                                    + "' (value='" + words[1]
146
                                    + "', lineno=+" + lineno
147
                                    + ", file=" + f.getAbsoluteFile()
148
                                    + ").", e);
149
                        }
150
                        lineno++;
151
                    }
152
                    this.fixValues();
153
                }
154

    
155
            } catch (IOException e) {
156
                logger.warn("Couldn't read " + FILE_EXTENSION + " file (" + f.getAbsoluteFile() + ")", e);
157
                throw e;
158
            } catch (Exception e) {
159
                String msg = "Couldn't read " + FILE_EXTENSION + " file (" + f.getAbsoluteFile() + ")";
160
                logger.warn(msg, e);
161
                throw new IOException(msg, e);
162
            }
163
        }
164
    }
165

    
166
    private void fixValues() {
167
        @SuppressWarnings("LocalVariableHidesMemberVariable")
168
        boolean valid = true;
169

    
170
        if (this.pixeltype != null) {
171
            switch (this.pixeltype) {
172
                case "signedint":
173
                    this.nbits = 32;
174
                    break;
175
                case "byte_unsigned":
176
                    this.nbits = 8;
177
                    break;
178
            }
179
        }
180

    
181
        switch (this.getNbits()) {
182
            case 1:
183
            case 4:
184
                logger.warn("nbits keyword has a non supported value of " + this.getNbits() + " (" + this.source.getAbsolutePath() + ").");
185
                valid = false;
186
                break;
187
            case 8:
188
            case 16:
189
            case 32:
190
            case 64:
191
                break;
192
            default:
193
                logger.warn("nbits keyword has an invalid value of " + this.getNbits() + " (" + this.source.getAbsolutePath() + ").");
194
                this.nbits = 1;
195
                valid = false;
196
                break;
197
        }
198

    
199
        switch (this.getLayout()) {
200
            case LAYOUT_BIL:
201
            case LAYOUT_BIP:
202
            case LAYOUT_BSQ:
203
                break;
204
            default:
205
                logger.warn("layout keyword has an invalid value of '" + this.getLayout() + "' (" + this.source.getAbsolutePath() + ").");
206
                this.layout = LAYOUT_BIL;
207
                valid = false;
208
                break;
209
        }
210

    
211
        if( StringUtils.isEmpty(this.byteorder_word) ) {
212
            this.byteorder = ByteOrder.nativeOrder();
213
            if( this.byteorder == ByteOrder.BIG_ENDIAN ) {
214
                this.byteorder_word = "msbfirst";
215
            } else {
216
                this.byteorder_word = "lsbfirst";
217
            }
218
        } else {
219
            switch(this.byteorder_word) {
220
                case "lsbfirst":
221
                case "little_endian":
222
                case "littleendian":
223
                case "intel":
224
                case "i":
225
                    this.byteorder = ByteOrder.LITTLE_ENDIAN;
226
                    break;
227
                case "motorola":
228
                case "m":
229
                case "msbfirst":
230
                case "big_endian":
231
                case "bigendian":
232
                    this.byteorder = ByteOrder.BIG_ENDIAN;
233
                    break;
234
                default:
235
                    logger.warn("byteorder keyword has an invalid value of '" + this.byteorder_word + "' (" + this.source.getAbsolutePath() + ").");
236
                    this.byteorder = ByteOrder.nativeOrder();
237
            }
238
        }
239
        if (this.getNrows() == NONE || this.getNcols() == NONE) {
240
            logger.warn("nrows/ncols keywords has an invalid value of '" + this.getNrows() + "/" + this.getNcols() + "' (" + this.source.getAbsolutePath() + ").");
241
            valid = false;
242
        }
243
        if (this.getUlymax() == NONE) {
244
            this.ulymax = this.getNrows() - 1;
245
        }
246
        if (this.getBandrowbytes() == NONE) {
247
            this.bandrowbytes = (this.getNcols() * this.getNbits()) / 8;
248
        }
249
        switch (this.getLayout()) {
250
            case LAYOUT_BIL:
251
                if (this.getTotalrowbytes() == NONE) {
252
                    this.totalrowbytes = this.getNbands() * this.getBandrowbytes();
253
                }
254
                this.bandgapbytes = 0;
255
                break;
256
            case LAYOUT_BIP:
257
                if (this.getTotalrowbytes() == NONE) {
258
                    this.totalrowbytes = (this.getNcols() * this.getNbands() * this.getNbits()) / 8;
259
                }
260
                this.bandgapbytes = 0;
261
                break;
262
            case LAYOUT_BSQ:
263
                if (this.getTotalrowbytes() == NONE) {
264
                    this.totalrowbytes = 0;
265
                }
266
                if (this.getBandgapbytes() == NONE) {
267
                    this.bandgapbytes = 0;
268
                }
269
                break;
270
        }
271
        this.valid = valid;
272
    }
273

    
274
    @Override
275
    public int getDataType() {
276
        if (this.pixeltype != null) {
277
            switch (this.pixeltype) {
278
                case "signedint":
279
                    return BufferManager.TYPE_INT;
280
                case "byte_unsigned":
281
                    return BufferManager.TYPE_BYTE;
282
            }
283
        }
284
        switch (this.getNbits()) {
285
            case 1:
286
            case 4:
287
            default:
288
                return BufferManager.TYPE_UNDEFINED;
289
            case 8:
290
                return BufferManager.TYPE_BYTE;
291
            case 16:
292
                return BufferManager.TYPE_USHORT;
293
            case 32:
294
                return BufferManager.TYPE_INT;
295
            case 64:
296
                return BufferManager.TYPE_DOUBLE;
297
        }
298
    }
299

    
300
    @Override
301
    public void write(File file) throws IOException {
302
        File f = this.getFile(file);
303
        StringBuilder builder = new StringBuilder();
304
        builder.append("; ").append(this.comments).append("\n");
305
        builder.append("nrows ").append(this.nrows).append("\n");
306
        builder.append("ncols ").append(this.ncols).append("\n");
307
        builder.append("nbands ").append(this.nbands).append("\n");
308
        builder.append("nbits ").append(this.nbits).append("\n");
309
        builder.append("layout ").append(LAYOUT_BSQ).append("\n");
310
        builder.append("byteorder ").append(this.byteorder_word).append("\n");
311
        builder.append("ulxmax ").append(this.ulxmax).append("\n");
312
        builder.append("ulymax ").append(this.ulymax).append("\n");
313
        builder.append("ydim ").append(this.ydim).append("\n");
314
        builder.append("xdim ").append(this.xdim).append("\n");
315
        
316
        FileUtils.write(file, builder.toString());
317
    }
318
    
319
    @Override
320
    public void setByteOrder(ByteOrder order) {
321
        this.byteorder = order;
322
        if( order == ByteOrder.BIG_ENDIAN ) {
323
            this.byteorder_word = "msbfirst";
324
        } else {
325
            this.byteorder_word = "lsbfirst";
326
        }
327
    }
328
    
329
    @Override
330
    public void setNBands(int nbands) {
331
        this.nbands = nbands;
332
    }
333
    
334
    @Override
335
    public void setDataType(int dataType) {
336
        switch(dataType) {
337
            case BufferManager.TYPE_BYTE:
338
                this.nbits = 8;
339
                break;
340
            case BufferManager.TYPE_USHORT:
341
                this.nbits = 16;
342
                break;
343
            case BufferManager.TYPE_INT:
344
                this.nbits = 32;
345
                break;
346
            case BufferManager.TYPE_DOUBLE:
347
                this.nbits = 64;
348
                break;
349
            default:
350
                throw new IllegalArgumentException("The data type "+dataType +" is not supported");
351
        }
352
        
353
    }
354
    
355
    @Override
356
    public void setDimensions(int nrows, int ncols, Envelope envelope) {
357
        this.ncols = ncols;
358
        this.nrows = nrows;
359

    
360
        Point min = envelope.getLowerCorner();
361
        Point max = envelope.getUpperCorner();
362
        
363
        this.ulxmax = min.getX();
364
        this.ulymax = max.getY();
365
        this.ydim = (min.getY() - max.getY()) / this.nrows;
366
        this.xdim = (max.getX() - min.getX()) / this.ncols;
367
    }
368
    
369
    @Override
370
    public Envelope getEnvelope() {
371
        Envelope envelope = null;
372
        try {
373
            if (!Double.isNaN(this.xllcorner)
374
                    && !Double.isNaN(this.yllcorner)
375
                    && this.cellsize > 0) {
376
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
377
                        this.xllcorner,
378
                        this.yllcorner,
379
                        this.xllcorner + (this.ncols * this.cellsize),
380
                        this.yllcorner + (this.nrows * this.cellsize),
381
                        Geometry.SUBTYPES.GEOM2D);
382
            }
383
            if (envelope == null && !Double.isNaN(this.ulxmax)
384
                    && !Double.isNaN(this.ulymax)
385
                    && !Double.isNaN(this.xdim)
386
                    && !Double.isNaN(this.ydim)) {
387
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
388
                        this.ulxmax,
389
                        this.ulymax - (this.nrows * this.ydim),
390
                        this.ulxmax + (this.ncols * this.xdim),
391
                        this.ulymax,
392
                        Geometry.SUBTYPES.GEOM2D);
393
            }
394
            if (envelope == null && !Double.isNaN(this.xdim)
395
                    && !Double.isNaN(this.ydim)) {
396
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
397
                        0,
398
                        0,
399
                        this.ncols * this.xdim,
400
                        this.nrows * this.ydim,
401
                        Geometry.SUBTYPES.GEOM2D);
402
            }
403
            if (envelope == null && this.cellsize > 0) {
404
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
405
                        0,
406
                        0,
407
                        this.ncols * this.cellsize,
408
                        this.nrows * this.cellsize,
409
                        Geometry.SUBTYPES.GEOM2D);
410
            }
411
            if (envelope == null) {
412
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
413
                        0,
414
                        0,
415
                        this.ncols,
416
                        this.nrows,
417
                        Geometry.SUBTYPES.GEOM2D);
418
            }
419
        } catch (Exception ex) {
420
            logger.debug("Can't calculate envelope.", ex);
421
        }
422
        return envelope;
423
    }
424

    
425
    /**
426
     * @return the nrows
427
     */
428
    @Override
429
    public int getNrows() {
430
        return nrows;
431
    }
432

    
433
    /**
434
     * @return the ncols
435
     */
436
    @Override
437
    public int getNcols() {
438
        return ncols;
439
    }
440

    
441
    /**
442
     * @return the nbands
443
     */
444
    @Override
445
    public int getNbands() {
446
        return nbands;
447
    }
448

    
449
    /**
450
     * @return the nbits
451
     */
452
    @Override
453
    public int getNbits() {
454
        return nbits;
455
    }
456

    
457
    /**
458
     * @return the byteorder
459
     */
460
    @Override
461
    public ByteOrder getByteorder() {
462
        return byteorder;
463
    }
464

    
465
    /**
466
     * @return the layout
467
     */
468
    @Override
469
    public String getLayout() {
470
        return layout;
471
    }
472

    
473
    /**
474
     * @return the skipbytes
475
     */
476
    @Override
477
    public int getSkipbytes() {
478
        return skipbytes;
479
    }
480

    
481
    /**
482
     * @return the ulxmax
483
     */
484
    @Override
485
    public double getUlxmax() {
486
        return ulxmax;
487
    }
488

    
489
    /**
490
     * @return the ulymax
491
     */
492
    @Override
493
    public double getUlymax() {
494
        return ulymax;
495
    }
496

    
497
    /**
498
     * @return the xdim
499
     */
500
    @Override
501
    public double getXdim() {
502
        return xdim;
503
    }
504

    
505
    /**
506
     * @return the ydim
507
     */
508
    @Override
509
    public double getYdim() {
510
        return ydim;
511
    }
512

    
513
    /**
514
     * @return the bandrowbytes
515
     */
516
    @Override
517
    public int getBandrowbytes() {
518
        return bandrowbytes;
519
    }
520

    
521
    /**
522
     * @return the totalrowbytes
523
     */
524
    @Override
525
    public int getTotalrowbytes() {
526
        return totalrowbytes;
527
    }
528

    
529
    /**
530
     * @return the bandgapbytes
531
     */
532
    @Override
533
    public int getBandgapbytes() {
534
        return bandgapbytes;
535
    }
536

    
537
    /**
538
     * @return the isValid
539
     */
540
    @Override
541
    public boolean isValid() {
542
        return valid;
543
    }
544

    
545
    /**
546
     * @return the comments
547
     */
548
    @Override
549
    public String getComments() {
550
        return comments;
551
    }
552

    
553
    /**
554
     * @param comments the comments to set
555
     */
556
    @Override
557
    public void setComments(String comments) {
558
        this.comments = comments;
559
    }
560

    
561
    /**
562
     * @return the nodata_value
563
     */
564
    @Override
565
    public double getNodata_value() {
566
        return nodata_value;
567
    }
568

    
569
    /**
570
     * @return the xllcorner
571
     */
572
    @Override
573
    public double getXllcorner() {
574
        return xllcorner;
575
    }
576

    
577
    /**
578
     * @return the yllcorner
579
     */
580
    @Override
581
    public double getYllcorner() {
582
        return yllcorner;
583
    }
584

    
585
    /**
586
     * @return the cellsize
587
     */
588
    @Override
589
    public int getCellsize() {
590
        return cellsize;
591
    }
592

    
593
    @Override
594
    public int getBandSize() {
595
        return (this.nrows * this.ncols * this.nbits) + this.bandgapbytes;
596
    }
597

    
598
}