1 | """Class Geospatial_data - Manipulation of locations on the planet and |
---|
2 | associated attributes. |
---|
3 | |
---|
4 | """ |
---|
5 | |
---|
6 | |
---|
7 | from anuga.utilities.numerical_tools import ensure_numeric |
---|
8 | |
---|
9 | from numpy import concatenate |
---|
10 | |
---|
11 | from coordinate_transforms.geo_reference import Geo_reference |
---|
12 | |
---|
13 | class Geospatial_data: |
---|
14 | |
---|
15 | def __init__(self, |
---|
16 | data_points, |
---|
17 | attributes = None, |
---|
18 | geo_reference = None, |
---|
19 | default_attribute_name = None): |
---|
20 | |
---|
21 | """Create instance from data points and associated attributes |
---|
22 | |
---|
23 | |
---|
24 | data_points: x,y coordinates in meters. Type must be either a |
---|
25 | sequence of 2-tuples or an Mx2 Numeric array of floats. |
---|
26 | |
---|
27 | attributes: Associated values for each data point. The type |
---|
28 | must be either a list or an array of length M or a dictionary |
---|
29 | of lists (or arrays) of length M. In the latter case the keys |
---|
30 | in the dictionary represent the attribute names, in the former |
---|
31 | the attribute will get the default name 'attribute'. |
---|
32 | |
---|
33 | geo_reference: Object representing the origin of the data |
---|
34 | points. It contains UTM zone, easting and northing and data |
---|
35 | points are assumed to be relative to this origin. |
---|
36 | If geo_reference is None, the default geo ref object is used |
---|
37 | |
---|
38 | default_attribute_name: Name of default attribute to be used with |
---|
39 | get_attribute_values. The idea is that the dataset can be |
---|
40 | equipped with information about which attribute to return. |
---|
41 | If None, the default is the 'first' |
---|
42 | |
---|
43 | """ |
---|
44 | |
---|
45 | self.data_points = ensure_numeric(data_points) |
---|
46 | self.set_attributes(attributes) |
---|
47 | self.set_geo_reference(geo_reference) |
---|
48 | self.set_default_attribute_name(default_attribute_name) |
---|
49 | |
---|
50 | |
---|
51 | |
---|
52 | |
---|
53 | def set_attributes(self, attributes): |
---|
54 | """Check and assign attributes dictionary |
---|
55 | """ |
---|
56 | |
---|
57 | from types import DictType |
---|
58 | |
---|
59 | if attributes is None: |
---|
60 | self.attributes = None |
---|
61 | return |
---|
62 | |
---|
63 | if not isinstance(attributes, DictType): |
---|
64 | #Convert single attribute into dictionary |
---|
65 | attributes = {'attribute': attributes} |
---|
66 | |
---|
67 | #Check input attributes |
---|
68 | for key in attributes.keys(): |
---|
69 | try: |
---|
70 | attributes[key] = ensure_numeric(attributes[key]) |
---|
71 | except: |
---|
72 | msg = 'Attribute %s could not be converted' %key |
---|
73 | msg += 'to a numeric vector' |
---|
74 | raise msg |
---|
75 | |
---|
76 | self.attributes = attributes |
---|
77 | |
---|
78 | |
---|
79 | def set_geo_reference(self, geo_reference): |
---|
80 | |
---|
81 | from coordinate_transforms.geo_reference import Geo_reference |
---|
82 | |
---|
83 | |
---|
84 | if geo_reference is None: |
---|
85 | self.geo_reference = Geo_reference() # Use default |
---|
86 | elif isinstance(geo_reference, Geo_reference): |
---|
87 | self.geo_reference = geo_reference |
---|
88 | else: |
---|
89 | msg = 'Argument geo_reference must be a valid Geo_reference \n' |
---|
90 | msg += 'object or None.' |
---|
91 | raise msg |
---|
92 | |
---|
93 | |
---|
94 | def set_default_attribute_name(self, default_attribute_name): |
---|
95 | self.default_attribute_name = default_attribute_name |
---|
96 | |
---|
97 | |
---|
98 | def get_geo_reference(self): |
---|
99 | return self.geo_reference |
---|
100 | |
---|
101 | def get_data_points(self, absolute = True): |
---|
102 | if absolute is True: |
---|
103 | xll = self.geo_reference.xllcorner |
---|
104 | yll = self.geo_reference.yllcorner |
---|
105 | return self.data_points + [xll, yll] |
---|
106 | |
---|
107 | else: |
---|
108 | return self.data_points |
---|
109 | |
---|
110 | def get_attributes(self, attribute_name = None): |
---|
111 | """Return values for one named attribute. |
---|
112 | |
---|
113 | If attribute_name is None, default_attribute_name is used |
---|
114 | """ |
---|
115 | |
---|
116 | if attribute_name is None: |
---|
117 | if self.default_attribute_name is not None: |
---|
118 | attribute_name = self.default_attribute_name |
---|
119 | else: |
---|
120 | attribute_name = self.attributes.keys()[0] |
---|
121 | # above line takes the first one from keys |
---|
122 | |
---|
123 | |
---|
124 | msg = 'Attribute name %s does not exist in data set' %attribute_name |
---|
125 | assert self.attributes.has_key(attribute_name), msg |
---|
126 | |
---|
127 | return self.attributes[attribute_name] |
---|
128 | |
---|
129 | def __add__(self,other): |
---|
130 | """ |
---|
131 | returns the addition of 2 geospatical objects, |
---|
132 | objects are concatencated to the end of each other |
---|
133 | |
---|
134 | NOTE: doesn't add if objects contain different |
---|
135 | attributes |
---|
136 | """ |
---|
137 | |
---|
138 | # sets xll and yll as the smallest from self and other |
---|
139 | if self.geo_reference.xllcorner <= other.geo_reference.xllcorner: |
---|
140 | xll = self.geo_reference.xllcorner |
---|
141 | else: |
---|
142 | xll = other.geo_reference.xllcorner |
---|
143 | |
---|
144 | if self.geo_reference.yllcorner <= other.geo_reference.yllcorner: |
---|
145 | yll = self.geo_reference.yllcorner |
---|
146 | else: |
---|
147 | yll = other.geo_reference.yllcorner |
---|
148 | |
---|
149 | # find objects zone and checks if the same |
---|
150 | geo_ref1 = self.get_geo_reference() |
---|
151 | zone1 = geo_ref1.get_zone() |
---|
152 | |
---|
153 | geo_ref2 = other.get_geo_reference() |
---|
154 | zone2 = geo_ref2.get_zone() |
---|
155 | |
---|
156 | geo_ref = Geo_reference(zone1, xll, yll) |
---|
157 | |
---|
158 | if zone1 == zone2: |
---|
159 | a_rel_points = self.get_data_points() |
---|
160 | b_rel_points = other.get_data_points() |
---|
161 | |
---|
162 | # subtracts xll and yll from self's and other's |
---|
163 | # reletive data point and concatenates |
---|
164 | c_points = concatenate((a_rel_points-[xll, yll], |
---|
165 | b_rel_points-[xll, yll]), axis = 0) |
---|
166 | |
---|
167 | new_dictionary = {} |
---|
168 | for x in self.attributes.keys(): |
---|
169 | if other.attributes.has_key(x): |
---|
170 | |
---|
171 | a_attrib = self.attributes[x] |
---|
172 | b_attrib = other.attributes[x] |
---|
173 | new_dictionary[x] = concatenate((a_attrib, b_attrib)) |
---|
174 | |
---|
175 | else: |
---|
176 | msg = 'Both geospatial_data objects must have the same \n' |
---|
177 | msg += 'attributes to allow addition.' |
---|
178 | raise msg |
---|
179 | |
---|
180 | return Geospatial_data(c_points, new_dictionary, geo_ref) |
---|
181 | |
---|
182 | else: |
---|
183 | msg = 'Both geospatial_data objects must be in the same \ |
---|
184 | ZONE to allow addition.' |
---|
185 | raise msg |
---|
186 | |
---|
187 | |
---|
188 | |
---|
189 | def geospatial_data2points_dictionary(geospatial_data): |
---|
190 | """Convert geospatial data to points_dictionary |
---|
191 | """ |
---|
192 | |
---|
193 | points_dictionary = {} |
---|
194 | points_dictionary['pointlist'] = geospatial_data.data_points |
---|
195 | |
---|
196 | points_dictionary['attributelist'] = {} |
---|
197 | |
---|
198 | for attribute_name in geospatial_data.attributes.keys(): |
---|
199 | val = geospatial_data.attributes[attribute_name] |
---|
200 | points_dictionary['attributelist'][attribute_name] = val |
---|
201 | |
---|
202 | points_dictionary['geo_reference'] = geospatial_data.geo_reference |
---|
203 | |
---|
204 | return points_dictionary |
---|
205 | |
---|
206 | |
---|
207 | |
---|
208 | |
---|
209 | |
---|
210 | |
---|
211 | |
---|
212 | def points_dictionary2geospatial_data(points_dictionary): |
---|
213 | """Convert points_dictionary to geospatial data object |
---|
214 | """ |
---|
215 | |
---|
216 | msg = 'Points dictionary must have key pointlist' |
---|
217 | assert points_dictionary.has_key('pointlist'), msg |
---|
218 | |
---|
219 | msg = 'Points dictionary must have key attributelist' |
---|
220 | assert points_dictionary.has_key('attributelist'), msg |
---|
221 | |
---|
222 | if points_dictionary.has_key('geo_reference'): |
---|
223 | geo = points_dictionary['geo_reference'] |
---|
224 | else: |
---|
225 | geo = None |
---|
226 | |
---|
227 | return Geospatial_data(points_dictionary['pointlist'], |
---|
228 | points_dictionary['attributelist'], |
---|
229 | geo_reference = geo) |
---|
230 | |
---|
231 | |
---|
232 | |
---|
233 | |
---|
234 | |
---|