bandraster.py 11 KB
Newer Older
1
2
3
from .const import Const, constants as const
from .raster import Raster
from .gridenvelope2d import GridEnvelope2D
Hoek, Steven's avatar
Hoek, Steven committed
4
5
6
import os.path
from math import fabs

7
8
__author__ = "Steven B. Hoek"

Hoek, Steven's avatar
Hoek, Steven committed
9
# Abstract class
10
11
12
class BandRaster(Raster, GridEnvelope2D):
    # Attributes
    _const = None
Hoek, Steven's avatar
Hoek, Steven committed
13
14
15
16
17
18
    
    # Data attributes
    nbands = 3 #default
    nbits = 8  #default
    nodatavalue = 256; #default
    dataformat = "h" # Default data format (2-byte signed short int)
19
    folder = os.getcwd();
Hoek, Steven's avatar
Hoek, Steven committed
20
21

    def __init__(self, filepath, *dataformat):
22
23
24
25
26
27
28
29
        # Class and subclass wide constants
        self._const = Const()
        self._const.INTEL = 'I'; # Least significant byte first
        self._const.UNSIGNEDINT = 'UNSIGNEDINT'
        self._const.PIXELTYPE = 'PIXELTYPE'
        self._const.NODATA = 'NODATA'
        
        # Initialise
Hoek, Steven's avatar
Hoek, Steven committed
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
        Raster.__init__(self, filepath)
        # Retrieve the name from the filepath and assign - incl. extension
        self.name = os.path.basename(filepath);
        # Also derive the folder
        self.folder = os.path.dirname(filepath);
        # Finally set the dataformat
        # TODO: get this from the header file?
        if len(dataformat) > 0:
            self.dataformat = dataformat[0]
    
    def open(self, mode, ncols=1, nrows=1, nbands=1, xll=0.0, yll=0.0, cellsize=1.0, nodatavalue=-9999.0):
        super(BandRaster, self).open(mode);
        # If file does not exist and mode[0] = 'w', create it!
        if (mode[0] == 'w'):
            # Set data attributes and write header file anyhow
            self.nbands = nbands;
            self.cellsize = cellsize
            self.nodatavalue = nodatavalue
            self.envelope = GridEnvelope2D.__init__(self, ncols, nrows, xll, yll, cellsize, cellsize)
            self.writeheader()
50
51
            if not self.file_exists:
                self.datafile = open(os.path.join(self.folder, self.name), 'w')
Hoek, Steven's avatar
Hoek, Steven committed
52
            else:
53
                self.datafile = open(os.path.join(self.folder, self.name), mode[0] + 'b') 
Hoek, Steven's avatar
Hoek, Steven committed
54
55
56
            return True
        else:    
            # Open the file
57
            if self.file_exists:            
Hoek, Steven's avatar
Hoek, Steven committed
58
                # Open the file and retrieve the data attributes from the header file
59
                self.datafile = open(os.path.join(self.folder, self.name), mode[0] + 'b'); 
Hoek, Steven's avatar
Hoek, Steven committed
60
61
                self.readheader();
                self.xll = self.xul;
62
                if self.ycoords_sort == const.DESC:
Hoek, Steven's avatar
Hoek, Steven committed
63
64
65
66
67
68
69
70
71
72
                    self.yll = self.yul - self.nrows * self.dy;
                else:
                    self.yll = self.yul + self.nrows * self.dy;
                self.envelope = GridEnvelope2D.__init__(self, self.ncols, self.nrows, self.xll, self.yll, self.dx, self.dy)
                return True
            else: return False
            
    def readheader(self):
        # See if we can find the header file to use. Then read it and assign all attributes
        hdrFilename = ""
73
74
        if os.path.isfile(os.path.join(self.folder, self.name + "." + const.HEADEREXT)): #@UndefinedVariable
            hdrFilename = os.path.join(self.folder, self.name + "." + const.HEADEREXT) #@UndefinedVariable
Hoek, Steven's avatar
Hoek, Steven committed
75
76
        else:
            name_wo_ext = os.path.splitext(os.path.join(self.folder, self.name))[0]
77
78
            if os.path.isfile(name_wo_ext + "." + const.HEADEREXT ): #@UndefinedVariable
                hdrFilename = os.path.join(name_wo_ext + "." + const.HEADEREXT) #@UndefinedVariable
Hoek, Steven's avatar
Hoek, Steven committed
79
80
81
82
83
84
85
86
        if hdrFilename == "":
            raise ValueError("Not sure about name of header file: " + hdrFilename + "?");
        hdrFilename = os.path.normpath(hdrFilename)
        if not os.path.exists(hdrFilename):  
            raise ValueError("Header file not found: " + hdrFilename);
        hf = open(hdrFilename, 'r');     
        if (hf != None):           
            hl = hf.readline();
87
88
            self.byteorder = str(hl.replace(const.BYTEORDER, '').strip()); 
            if self.byteorder != self._const.INTEL:
Hoek, Steven's avatar
Hoek, Steven committed
89
90
91
                raise ValueError("Unsupported byte order")
            hl = hf.readline();
            layout = str(hl.replace('LAYOUT', '').strip());
92
            extuc = self._const.DATAFILEXT.upper() 
Hoek, Steven's avatar
Hoek, Steven committed
93
94
95
            if layout != extuc:
                raise ValueError("Incorrect layout in header - apparently not a " + extuc + " file");
            hl = hf.readline();
96
            self.nrows = int(hl.replace(const.NROWS.upper(), ''));
Hoek, Steven's avatar
Hoek, Steven committed
97
            hl = hf.readline();
98
            self.ncols = int(hl.replace(const.NCOLS.upper(), ''));                
Hoek, Steven's avatar
Hoek, Steven committed
99
100
101
102
103
104
105
106
107
108
109
110
111
            hl = hf.readline();
            self.nbands = int(hl.replace('NBANDS', ''));
            hl = hf.readline();
            self.nbits = int(hl.replace('NBITS', ''));
            hl = hf.readline();
            bandrowbytes = int(hl.replace('BANDROWBYTES', ''));
            if self.nbits * self.ncols / 8 != bandrowbytes:
                raise ValueError("Incorrect number of bytes per band row in header");
            hl = hf.readline();
            totalrowbytes = int(hl.replace('TOTALROWBYTES', ''));
            if self.nbands * bandrowbytes != totalrowbytes:
                raise ValueError("Incorrect total bytes per row in header");
            hl = hf.readline();
112
            if hl.find(self._const.PIXELTYPE) != -1:
Hoek, Steven's avatar
Hoek, Steven committed
113
                # Assume ESRI style header
114
                self.pixeltype = str(hl.replace(self._const.PIXELTYPE, '').strip());
Hoek, Steven's avatar
Hoek, Steven committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
                hl = hf.readline();
                ulxmap = float(hl.replace('ULXMAP', ''));         
                hl = hf.readline();
                ulymap = float(hl.replace('ULYMAP', ''));        
                hl = hf.readline();
                self.dx = float(hl.replace('XDIM', ''));        
                hl = hf.readline();
                self.dy = float(hl.replace('YDIM', ''));  
                
                # ulxmap - The x-axis map coordinate of the center of the upper left pixel
                # ulymap - The y-axis map coordinate of the center of the upper left pixel
                self.xul = ulxmap - 0.5*self.dx
                self.yul = ulymap + 0.5*self.dy 
                hl = hf.readline();
129
                if self.dataformat in ['f', 'd']:
130
                    self.nodatavalue = float(hl.replace(self._const.NODATA, '').strip());
131
                else:
132
                    self.nodatavalue = int(hl.replace(self._const.NODATA, '').strip());
Hoek, Steven's avatar
Hoek, Steven committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
                hf.close()
            else:
                # Assume that the rest of the information has to be read from a world file
                name_wo_ext = os.path.splitext(os.path.join(self.folder, self.name))[0]
                if os.path.isfile(name_wo_ext + "." + self.WORLDEXT):
                    # TODO: Adapt the following so that it accounts also for rotated mapsheets
                    sign = lambda x: (1, -1)[x<0];
                    hdrFilename = os.path.normpath(os.path.join(name_wo_ext + "." + self.WORLDEXT))
                    hf = open(hdrFilename, 'r')
                    hl = hf.readline();
                    self.dx = float(hl.strip());
                    hl = hf.readline();
                    self.roty = float(hl.strip());
                    hl = hf.readline();
                    self.rotx = float(hl.strip());
                    eps = 0.0001;
                    if abs(self.rotx)>eps or abs(self.roty)>eps:
                        raise NotImplementedError("Cannot handle rotated mapsheets yet!")
                    hl = hf.readline();            
                    self.dy = fabs(float(hl.strip()));
                    if sign(float(hl.strip())) == 1.0: self.ycoords_sort = 'ASC';
                    hl = hf.readline();
                    self.xul = float(hl.strip()) - 0.5 * self.dx;
                    hl = hf.readline();
                    self.yul = float(hl.strip()) + 0.5 * self.dy;
                    hf.close();
            self.cellsize = (self.dx + self.dy) / 2
        else: 
            msg = "Unable to open header file " + hdrFilename + " in folder " + self.folder;
            raise IOError(msg);

    def writeheader(self):
        # TODO: test!
Hoek, Steven's avatar
Hoek, Steven committed
166
        # TODO rather use class WorldFile 
Hoek, Steven's avatar
Hoek, Steven committed
167
        # Write header file with all attributes
168
        hdrFilename = os.path.join(self.folder, self.name + "." + const.HEADEREXT) #@UndefinedVariable
Hoek, Steven's avatar
Hoek, Steven committed
169
170
171
172
173
174
        hdrFilename = os.path.normpath(hdrFilename)
        try:
            # Open the file if it exists, otherwise create it
            if os.path.exists(hdrFilename):
                hf = open(hdrFilename, 'w');
            else:
175
                hf = open(hdrFilename, 'w');
Hoek, Steven's avatar
Hoek, Steven committed
176
177

            # Now write all the attributes
178
179
180
181
            hf.write(const.BYTEORDER + "     " + str(self.byteorder) + "\n")
            hf.write("LAYOUT        " + self._const.DATAFILEXT.upper() + "\n")
            hf.write(const.NROWS.upper() + "         " + str(self.nrows) + "\n")
            hf.write(const.NCOLS.upper() + "         " + str(self.ncols) + "\n")
Hoek, Steven's avatar
Hoek, Steven committed
182
183
            hf.write("NBANDS        " + str(self.nbands) + "\n")
            hf.write("NBITS         " + str(self.nbits) + "\n") 
184
            bandrowbytes = int(self.nbits * self.ncols / 8)
Hoek, Steven's avatar
Hoek, Steven committed
185
186
187
            hf.write("BANDROWBYTES  " + str(bandrowbytes) + "\n")
            hf.write("TOTALROWBYTES " + str(self.nbands * bandrowbytes) + "\n")
            if self.dataformat.lower() == 'i':
188
189
190
                if self.dataformat.isupper(): hf.write(self._const.PIXELTYPE + "     UNSIGNEDINT\n") 
                else: hf.write(self._const.PIXELTYPE + "     SIGNEDINT\n")
            else: hf.write(self._const.PIXELTYPE + "     FLOAT\n")
Hoek, Steven's avatar
Hoek, Steven committed
191
192
193
194
195
196
197
198
199
                
            # ulxmap - The x-axis map coordinate of the center of the upper left pixel
            ulxmap = self.xll + 0.5*self.dx
            hf.write("ULXMAP        " + str(ulxmap) + "\n");
            # ulymap - The y-axis map coordinate of the center of the upper left pixel
            ulymap = self.yll + self.nrows*self.dy - 0.5*self.dy # Check this!!!
            hf.write("ULYMAP        " + str(ulymap) + "\n");
            hf.write("XDIM          " + str(self.dx) + "\n");
            hf.write("YDIM          " + str(self.dy) + "\n");
200
201
            hf.write(self._const.NODATA + "  " + str(self.nodatavalue) + "\n");
        except Exception as e:
Hoek, Steven's avatar
Hoek, Steven committed
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
            msg = "Header file " + hdrFilename + " could not be written in folder " + self.folder;
            raise IOError(msg + "(" + str(e) + ")");
        
    def _is_sequence(self, arg):
        return (not hasattr(arg, "strip") and hasattr(arg, "__getitem__") or hasattr(arg, "__iter__"))
    
    def next(self, parseLine=True):
        pass

    def writenext(self, sequence_with_data):
        # input is sequence type - e.g. list, array.array or numpy.array
        pass
    
    @staticmethod
    def getDataFileExt(self):
        return self.DATAFILEXT;
    
    @staticmethod
    def getHeaderFileExt():
221
        return const.HEADEREXT 
Hoek, Steven's avatar
Hoek, Steven committed
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    
    def close(self):
        if self.datafile:
            if not self.datafile.closed:
                self.datafile.close(); 

    def reset(self):
        self.currow = 0; 
        self.datafile.seek(0);
        
    def __exit__(self, exception_type, exception_value, traceback):
        self.close()
        
    def __enter__(self):
        return self