Changeset 9212
- Timestamp:
- Jun 23, 2014, 6:14:01 PM (10 years ago)
- Location:
- trunk/anuga_core/source/anuga
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/anuga_core/source/anuga/shallow_water/shallow_water_domain.py
r9171 r9212 692 692 """ 693 693 694 self. discontinuous_elevation = flag694 self.using_discontinuous_elevation = flag 695 695 696 696 def get_using_discontinuous_elevation(self): 697 697 698 return self. discontinuous_elevation698 return self.using_discontinuous_elevation 699 699 700 700 def set_flow_algorithm(self, flag=1.5): -
trunk/anuga_core/source/anuga/utilities/plot_utils.py
r9200 r9212 761 761 NOTE: proj4string is used in preference to EPSG_CODE if available 762 762 """ 763 763 764 try: 764 765 import gdal 765 766 import osr 766 except: 767 raise Exception, 'Cannot find gdal and/or osr python modules' 767 except ImportError, e: 768 msg='Failed to import gdal/ogr modules --'\ 769 + 'perhaps gdal python interface is not installed.' 770 raise ImportError, msg 771 772 768 773 769 774 xres = lons[1] - lons[0] … … 849 854 #pdb.set_trace() 850 855 856 import scipy.io 857 import scipy.interpolate 858 import anuga 859 from anuga.utilities import plot_utils as util 860 import os 861 851 862 try: 852 863 import gdal 853 864 import osr 854 import scipy.io855 import scipy.interpolate856 import anuga857 from anuga.utilities import plot_utils as util858 import os 859 #from matplotlib import nxutils 860 except:861 raise Exception, 'Required modules not installed for Make_Geotif' 865 except ImportError, e: 866 msg='Failed to import gdal/ogr modules --'\ 867 + 'perhaps gdal python interface is not installed.' 868 raise ImportError, msg 869 870 871 872 862 873 863 874 -
trunk/anuga_core/source/anuga/utilities/spatialInputUtil.py
r9203 r9212 49 49 import gdal 50 50 import ogr 51 gdal_available = True 51 52 #import osr # Not needed here but important in general 52 except Exception, err: 53 msg='Failed to import gdal/ogr modules --'\ 54 + 'perhaps gdal python interface is not installed. See error below:' 55 print msg 56 raise Exception, err 57 58 ##################################### 59 60 def readShp_1PolyGeo(shapefile, dropLast=True): 61 """ 62 Read a "single polygon" shapefile into an ANUGA_polygon object 63 (a list of lists, each containing a polygon coordinate) 64 65 The attribute table is ignored, and there can only be a single geometry in the shapefile 66 67 INPUTS: shapefile -- full path to shapefile name 68 dropLast -- Logical. If so, cut the last point (which closes 69 the polygon). ANUGA uses this by default for e.g. 70 bounding polygons 71 """ 72 73 # Get the data 74 driver=ogr.GetDriverByName("ESRI Shapefile") 75 dataSrc=driver.Open(shapefile, 0) 76 layer=dataSrc.GetLayer() 77 78 # Need a single polygon 79 try: 80 assert(len(layer)==1) 81 except: 82 print shapefile 83 84 boundary_poly=[] 85 for feature in layer: 86 #geom=feature.GetGeometryReg() 87 boundary=feature.GetGeometryRef().Boundary().GetPoints() 88 boundary=[list(pts) for pts in boundary] 89 boundary_poly.extend(boundary) 90 91 if(dropLast): 92 # Return a list of points, without last point [= first point] 93 return boundary_poly[:-1] 94 else: 95 return boundary_poly 96 97 #################### 98 99 def readShp_1LineGeo(shapefile): 100 """ 101 Read a "single-line" shapefile into a list of lists (each containing a point), 102 resembling an ANUGA polygon object 103 104 The attribute table is ignored, and there can only be a single geometry in the shapefile 105 106 INPUTS: shapefile -- full path to shapefile name 107 """ 108 109 driver=ogr.GetDriverByName("ESRI Shapefile") 110 dataSrc=driver.Open(shapefile, 0) 111 layer=dataSrc.GetLayer() 112 113 # Need a single line 114 try: 115 assert(len(layer)==1) 116 except: 117 print shapefile 118 119 line_all=[] 120 for feature in layer: 121 line=feature.GetGeometryRef().GetPoints() 122 line=[list(pts) for pts in line] 123 line_all.extend(line) 124 125 return line_all 53 except ImportError, err: 54 gdal_available = False 55 56 57 ##################################### 58 if gdal_available: 59 60 61 def readShp_1PolyGeo(shapefile, dropLast=True): 62 """ 63 Read a "single polygon" shapefile into an ANUGA_polygon object 64 (a list of lists, each containing a polygon coordinate) 65 66 The attribute table is ignored, and there can only be a single geometry in the shapefile 67 68 INPUTS: shapefile -- full path to shapefile name 69 dropLast -- Logical. If so, cut the last point (which closes 70 the polygon). ANUGA uses this by default for e.g. 71 bounding polygons 72 """ 73 74 # Get the data 75 driver=ogr.GetDriverByName("ESRI Shapefile") 76 dataSrc=driver.Open(shapefile, 0) 77 layer=dataSrc.GetLayer() 126 78 127 #################### 128 129 def readShpPtsAndAttributes(shapefile): 130 """ 131 Read a point shapefile with an attribute table into a list 132 133 INPUT: shapefile -- name of shapefile to read 134 135 OUTPUT: List with [ list_of_points, list_of_attributes, names_of_attributes] 136 """ 137 138 driver=ogr.GetDriverByName("ESRI Shapefile") 139 dataSrc=driver.Open(shapefile, 0) 140 layer=dataSrc.GetLayer() 141 142 pts=[] 143 attribute=[] 144 for i, feature in enumerate(layer): 145 if(i==0): 146 attributeNames=feature.keys() 147 pt=feature.GetGeometryRef().GetPoints() 148 pt=[list(p) for p in pt] 149 pts.extend(pt) 150 att=[feature[i] for i in attributeNames] 151 attribute.extend(att) 152 153 return [pts, attribute, attributeNames] 154 155 ######################################## 156 def ListPts2Wkb( ptsIn, geometry_type='line', appendFirstOnEnd=None): 157 """ 158 Convert list of points to a GDAl Wkb format 159 Can be either points, lines, or polygon 160 161 Purpose is that once data in in Wkb format, we can use GDAL's geometric operations 162 (e.g. to test for intersections, etc) 163 164 INPUT: ptsIn -- list of points in the format [[x0,y0], [x1, y1], ..., [xn, yn]] 165 Actually it is also ok if [x0,y0], .. is a tuple instead 166 geometry_type -- 'point' or 'line' or 'polygon' 167 168 appendFirstOnEnd -- logical. If true, add the first point to the 169 end. Probably wanted for polygons when they are unclosed in ANUGA 170 171 OUTPUT: 172 The points as a Wkb Geometry. 173 geometry_type='point' produces a MULTIPOINT Geometry 174 ='line' produces a LINESTRING Geometry 175 ='polygon' produces a POLYGON Geometry 176 177 FIXME: This might not sensibly-use the gdal geometry types (although it 178 passes our tests) -- consider revising 179 """ 180 # Avoid modifying ptsIn 181 pts=copy.copy(ptsIn) 182 183 if appendFirstOnEnd is None: 184 if(geometry_type=='polygon'): 185 appendFirstOnEnd=True 79 # Need a single polygon 80 try: 81 assert(len(layer)==1) 82 except: 83 print shapefile 84 85 boundary_poly=[] 86 for feature in layer: 87 #geom=feature.GetGeometryReg() 88 boundary=feature.GetGeometryRef().Boundary().GetPoints() 89 boundary=[list(pts) for pts in boundary] 90 boundary_poly.extend(boundary) 91 92 if(dropLast): 93 # Return a list of points, without last point [= first point] 94 return boundary_poly[:-1] 186 95 else: 187 appendFirstOnEnd=False 188 189 if appendFirstOnEnd: 190 pts.append(pts[0]) 191 192 if(geometry_type=='point'): 193 data=ogr.Geometry(ogr.wkbMultiPoint) 194 elif(geometry_type=='line'): 195 data=ogr.Geometry(ogr.wkbLineString) 196 elif(geometry_type=='polygon'): 197 data=ogr.Geometry(ogr.wkbLinearRing) 198 else: 199 raise Exception, "Type must be either 'point' or 'line' or 'polygon'" 200 201 for i in range(len(pts)): 202 if(len(pts[i])==2): 203 if(geometry_type=='point'): 204 newPt=ogr.Geometry(ogr.wkbPoint) 205 newPt.AddPoint(pts[i][0], pts[i][1]) 206 data.AddGeometryDirectly(newPt) 96 return boundary_poly 97 98 #################### 99 100 def readShp_1LineGeo(shapefile): 101 """ 102 Read a "single-line" shapefile into a list of lists (each containing a point), 103 resembling an ANUGA polygon object 104 105 The attribute table is ignored, and there can only be a single geometry in the shapefile 106 107 INPUTS: shapefile -- full path to shapefile name 108 """ 109 110 driver=ogr.GetDriverByName("ESRI Shapefile") 111 dataSrc=driver.Open(shapefile, 0) 112 layer=dataSrc.GetLayer() 113 114 # Need a single line 115 try: 116 assert(len(layer)==1) 117 except: 118 print shapefile 119 120 line_all=[] 121 for feature in layer: 122 line=feature.GetGeometryRef().GetPoints() 123 line=[list(pts) for pts in line] 124 line_all.extend(line) 125 126 return line_all 127 128 #################### 129 130 def readShpPtsAndAttributes(shapefile): 131 """ 132 Read a point shapefile with an attribute table into a list 133 134 INPUT: shapefile -- name of shapefile to read 135 136 OUTPUT: List with [ list_of_points, list_of_attributes, names_of_attributes] 137 """ 138 139 driver=ogr.GetDriverByName("ESRI Shapefile") 140 dataSrc=driver.Open(shapefile, 0) 141 layer=dataSrc.GetLayer() 142 143 pts=[] 144 attribute=[] 145 for i, feature in enumerate(layer): 146 if(i==0): 147 attributeNames=feature.keys() 148 pt=feature.GetGeometryRef().GetPoints() 149 pt=[list(p) for p in pt] 150 pts.extend(pt) 151 att=[feature[i] for i in attributeNames] 152 attribute.extend(att) 153 154 return [pts, attribute, attributeNames] 155 156 ######################################## 157 def ListPts2Wkb( ptsIn, geometry_type='line', appendFirstOnEnd=None): 158 """ 159 Convert list of points to a GDAl Wkb format 160 Can be either points, lines, or polygon 161 162 Purpose is that once data in in Wkb format, we can use GDAL's geometric operations 163 (e.g. to test for intersections, etc) 164 165 INPUT: ptsIn -- list of points in the format [[x0,y0], [x1, y1], ..., [xn, yn]] 166 Actually it is also ok if [x0,y0], .. is a tuple instead 167 geometry_type -- 'point' or 'line' or 'polygon' 168 169 appendFirstOnEnd -- logical. If true, add the first point to the 170 end. Probably wanted for polygons when they are unclosed in ANUGA 171 172 OUTPUT: 173 The points as a Wkb Geometry. 174 geometry_type='point' produces a MULTIPOINT Geometry 175 ='line' produces a LINESTRING Geometry 176 ='polygon' produces a POLYGON Geometry 177 178 FIXME: This might not sensibly-use the gdal geometry types (although it 179 passes our tests) -- consider revising 180 """ 181 # Avoid modifying ptsIn 182 pts=copy.copy(ptsIn) 183 184 if appendFirstOnEnd is None: 185 if(geometry_type=='polygon'): 186 appendFirstOnEnd=True 207 187 else: 208 data.AddPoint(pts[i][0], pts[i][1]) 209 elif(len(pts[i])==3): 210 if(geometry_type=='point'): 211 newPt=ogr.Geometry(ogr.wkbPoint) 212 newPt.AddPoint(pts[i][0], pts[i][1], pts[i][2]) 213 data.AddGeometryDirectly(newPt) 188 appendFirstOnEnd=False 189 190 if appendFirstOnEnd: 191 pts.append(pts[0]) 192 193 if(geometry_type=='point'): 194 data=ogr.Geometry(ogr.wkbMultiPoint) 195 elif(geometry_type=='line'): 196 data=ogr.Geometry(ogr.wkbLineString) 197 elif(geometry_type=='polygon'): 198 data=ogr.Geometry(ogr.wkbLinearRing) 199 else: 200 raise Exception, "Type must be either 'point' or 'line' or 'polygon'" 201 202 for i in range(len(pts)): 203 if(len(pts[i])==2): 204 if(geometry_type=='point'): 205 newPt=ogr.Geometry(ogr.wkbPoint) 206 newPt.AddPoint(pts[i][0], pts[i][1]) 207 data.AddGeometryDirectly(newPt) 208 else: 209 data.AddPoint(pts[i][0], pts[i][1]) 210 elif(len(pts[i])==3): 211 if(geometry_type=='point'): 212 newPt=ogr.Geometry(ogr.wkbPoint) 213 newPt.AddPoint(pts[i][0], pts[i][1], pts[i][2]) 214 data.AddGeometryDirectly(newPt) 215 else: 216 data.AddPoint(pts[i][0], pts[i][1], pts[i][2]) 214 217 else: 215 data.AddPoint(pts[i][0], pts[i][1], pts[i][2]) 218 raise Exception, 'Points must be either 2 or 3 dimensional' 219 220 if(geometry_type=='polygon'): 221 poly = ogr.Geometry(ogr.wkbPolygon) 222 poly.AddGeometry(data) 223 data=poly 224 225 return(data) 226 227 ############################################################################ 228 def Wkb2ListPts(wkb_geo, removeLast=False, drop_third_dimension=False): 229 """ 230 Reverse of ListPts2Wkb 231 """ 232 if(wkb_geo.GetGeometryName()=='POLYGON'): 233 X=wkb_geo.GetBoundary() 234 new=[ list(X.GetPoints()[i]) for i in range(len(X.GetPoints())) ] 235 elif(wkb_geo.GetGeometryName()=='MULTIPOINT'): 236 new=[ [feature.GetX(), feature.GetY(),feature.GetZ()] for feature in wkb_geo] 237 elif(wkb_geo.GetGeometryName()=='LINESTRING'): 238 new=[ list(wkb_geo.GetPoints()[i]) for i in range(len(wkb_geo.GetPoints())) ] 216 239 else: 217 raise Exception, 'Points must be either 2 or 3 dimensional' 218 219 if(geometry_type=='polygon'): 220 poly = ogr.Geometry(ogr.wkbPolygon) 221 poly.AddGeometry(data) 222 data=poly 223 224 return(data) 225 226 ############################################################################ 227 def Wkb2ListPts(wkb_geo, removeLast=False, drop_third_dimension=False): 228 """ 229 Reverse of ListPts2Wkb 230 """ 231 if(wkb_geo.GetGeometryName()=='POLYGON'): 232 X=wkb_geo.GetBoundary() 233 new=[ list(X.GetPoints()[i]) for i in range(len(X.GetPoints())) ] 234 elif(wkb_geo.GetGeometryName()=='MULTIPOINT'): 235 new=[ [feature.GetX(), feature.GetY(),feature.GetZ()] for feature in wkb_geo] 236 elif(wkb_geo.GetGeometryName()=='LINESTRING'): 237 new=[ list(wkb_geo.GetPoints()[i]) for i in range(len(wkb_geo.GetPoints())) ] 238 else: 239 raise Exception, 'Geometry type not supported' 240 241 if(removeLast): 242 new=new[:-1] 243 if(drop_third_dimension): 244 new = [new[i][0:2] for i in range(len(new))] 245 return new 246 247 ############################################################################ 248 def compute_squared_distance_to_segment(pt, line): 249 """ 250 Compute the squared distance between a point and a [finite] line segment 251 252 INPUT: pt -- [x,y] 253 line -- [[x0,y0],[x1,y1]] -- 2 points defining a line segment 254 255 OUTPUT: The distance^2 of pt to the line segment 256 257 """ 258 p0 = line[0] 259 p1 = line[1] 240 raise Exception, 'Geometry type not supported' 241 242 if(removeLast): 243 new=new[:-1] 244 if(drop_third_dimension): 245 new = [new[i][0:2] for i in range(len(new))] 246 return new 247 248 ############################################################################ 249 def compute_squared_distance_to_segment(pt, line): 250 """ 251 Compute the squared distance between a point and a [finite] line segment 252 253 INPUT: pt -- [x,y] 254 line -- [[x0,y0],[x1,y1]] -- 2 points defining a line segment 255 256 OUTPUT: The distance^2 of pt to the line segment 257 258 """ 259 p0 = line[0] 260 p1 = line[1] 261 # 262 # Get unit vector along segment 263 seg_unitVec_x=float(p1[0]-p0[0]) 264 seg_unitVec_y=float(p1[1]-p0[1]) 265 segLen=(seg_unitVec_x**2+seg_unitVec_y**2)**0.5 266 if(segLen==0.): 267 #print line 268 #print 'Pt' 269 #print pt 270 raise Exception, 'Line has repeated points: Line %s Pt %s' % (str(line),str(pt)) 271 seg_unitVec_x=seg_unitVec_x/segLen 272 seg_unitVec_y=seg_unitVec_y/segLen 273 # 274 # Get vector from pt to p0 275 pt_p0_vec_x=float(pt[0]-p0[0]) 276 pt_p0_vec_y=float(pt[1]-p0[1]) 277 pt_p0_vec_len_squared=(pt_p0_vec_x**2 + pt_p0_vec_y**2) 278 # Get dot product of above vector with unit vector 279 pt_dot_segUnitVec=(pt_p0_vec_x)*seg_unitVec_x+(pt_p0_vec_y)*seg_unitVec_y 280 # 281 if( (pt_dot_segUnitVec<segLen) and (pt_dot_segUnitVec > 0.)): 282 # The nearest point on the line is actually between p0 and p1, so we have a 'real' candidate 283 # Get distance^2 284 output = pt_p0_vec_len_squared - pt_dot_segUnitVec**2. 285 else: 286 # Distance is the min distance from p0 and p1. 287 output = min( pt_p0_vec_len_squared, (float(pt[0]-p1[0])**2+float(pt[1]-p1[1])**2)) 288 if(output < -1.0e-06): 289 raise Exception, 'round-off in compute_squared_distance_to_segment' 290 if(output < 0.): 291 output=0. 292 return output 293 294 ############################################################################ 295 296 def find_nearest_segment(pt, segments): 297 """ 298 Given a point and a line, find the line segment nearest to the line 299 300 NOTE: The answer can be ambiguous if one of the segment endpoints is 301 the nearest point. In that case, the behaviour is determined by the behaviour 302 of numpy.argmin. Won't be a problem for this application 303 304 INPUT: pt -- [x,y] 305 segments -- [[x0,y0], [x1,y1], ...] 306 A list of points, consecutive points are interpreted 307 as joined and so defining line segments 308 309 OUTPUT: The squared distance, and the index i of the segment [x_i,y_i],[x_i+1,y_i+1] in segments which is closest to pt 310 """ 311 ll=len(segments) 312 if(ll<=1): 313 raise Exception, 'Segments must have length > 1 in find_nearest_segment' 314 315 ptDist_sq=numpy.zeros(ll-1) # Hold the squared distance from the point to the line segment 316 for i in range(len(segments)-1): 317 # Compute distance from segment 318 ptDist_sq[i]=compute_squared_distance_to_segment(pt, [segments[i],segments[i+1]]) 319 320 return [ptDist_sq.min(), ptDist_sq.argmin()] 321 322 ###################################################### 323 324 def shift_point_on_line(pt, lineIn, nearest_segment_index): 325 """ 326 Support pt is a point, which is near to the 'nearest_segment_index' segment of the line 'lineIn' 327 328 This routine moves the nearest end point of that segment on line to pt. 329 330 INPUTS: pt -- [x,y] point 331 lineIn -- [ [x0, y0], [x1, y1], ..., [xN,yN]] 332 nearest_segment_index = index where the distance of pt to the line from [x_i,y_i] to [x_i+1,y_i+1] is minimum 333 334 OUTPUT: The new line 335 """ 336 # Avoid Changing line 337 line=copy.copy(lineIn) 338 339 # Replace the nearest point on L1 with the intersection point 340 p0 = line[nearest_segment_index] 341 p1 = line[nearest_segment_index+1] 342 d_p0 = ( (pt[0]-p0[0])**2 + (pt[1]-p0[1])**2) 343 d_p1 = ( (pt[0]-p1[0])**2 + (pt[1]-p1[1])**2) 344 changeP1=(d_p1<d_p0) 345 line[nearest_segment_index+changeP1][0] = pt[0] 346 line[nearest_segment_index+changeP1][1] = pt[1] 347 348 return line 349 350 ################################################################################# 351 def insert_intersection_point(intersectionPt, line_pts, point_movement_threshold): 352 """ 353 Add intersectionPt to line_pts, either by inserting it, or if a point on line_pts is 354 closer than point_movement_threshold, then by moving that point to the intersection point 355 356 INPUTS: 357 intersectionPt -- the intersection point [known to lie on line_pts] 358 line_pts -- ordered list of [x,y] points making a line. 359 point_movement_threshold -- used to decide to move or add intersectionPt 360 361 OUTPUT: 362 new version of lint_pts with the point added 363 """ 364 # Avoid pointer/copy issues 365 L1_pts = copy.copy(line_pts) 366 iP=copy.copy(intersectionPt) 367 368 # Adjust L1 369 tmp = find_nearest_segment(intersectionPt, L1_pts) 370 # Compute the distance from the end points of the segment to the 371 # intersection point. Based on this we decide to add or move the point 372 p0 = L1_pts[tmp[1]] 373 p1 = L1_pts[tmp[1]+1] 374 endPt_Dist_Sq=min( ( (p0[0]-iP[0])**2 + (p0[1]-iP[1])**2), ( (p1[0]-iP[0])**2 + (p1[1]-iP[1])**2)) 375 # 376 if(endPt_Dist_Sq>point_movement_threshold**2): 377 # Insert the intersection point. We do this in a tricky way to 378 # account for the possibility of L1_pts having > 2 coordinates 379 # (riverWalls) 380 dummyPt=copy.copy(L1_pts[tmp[1]]) 381 L1_pts.insert(tmp[1]+1,dummyPt) 382 L1_pts[tmp[1]+1][0]=iP[0] 383 L1_pts[tmp[1]+1][1]=iP[1] 384 if(len(L1_pts[tmp[1]+1])==3): 385 # Treat 3rd coordinate 386 # Find distance of inserted point from neighbours, and 387 # Set 3rd coordinate as distance-weighted average of the others 388 d0=((L1_pts[tmp[1]][0]-L1_pts[tmp[1]+1][0])**2.+\ 389 (L1_pts[tmp[1]][0]-L1_pts[tmp[1]+1][1])**2.)**0.5 390 d1=((L1_pts[tmp[1]+2][0]-L1_pts[tmp[1]+1][0])**2.+\ 391 (L1_pts[tmp[1]+2][1]-L1_pts[tmp[1]+1][1])**2.)**0.5 392 L1_pts[tmp[1]+1][2] = (d0*L1_pts[tmp[1]+2][2] + d1*L1_pts[tmp[1]][2])/(d0+d1) 393 394 else: 395 # Move a point already on L1 396 L1_pts=shift_point_on_line(iP, L1_pts, tmp[1]) 397 398 return L1_pts 399 400 ####################################################################################################### 401 def check_polygon_is_small(intersection, buf, tol2=100.): 402 """ 403 404 Elsewhere in the code, we check whether lines intersect by buffering them 405 to polygons with a small buffer = buf, then getting the intersection. 406 [since intersection with polygons is supported by gdal, but apparently 407 not directly with lines]. 408 409 The logic of our code only works with point intersections, 410 and it will fails if 2 lines overlap in a line. 411 412 We crudely check for this situation here, by ensuring that the intersection polygon is 'small' 413 414 WARNING: The gdal geometry routines may be a bit rough (?) 415 Intersections not very precise, etc (?) 416 417 INPUT: intersection -- intersection of the 2 lines [gdal geometry] 418 buf -- a length scale giving the size of the intersection extent that we expect for a point 419 tol2 -- Throw an error if the x or y extent is greater than buf*tol2. Seems this needs to be 420 large sometimes -- this might reflect the stated weaknesses of GDALs geometry routines? 421 OUTPUT: True/False 422 False should suggest that the intersection is not describing a point 423 """ 424 425 extent=intersection.GetEnvelope() 426 assert(len(extent)==4) # Make sure this assumption is valid 427 if( (abs(extent[0]-extent[1])>buf*tol2) or (abs(extent[2]-extent[3]) > buf*tol2)): 428 return False 429 else: 430 return True 431 432 ####################################################################################################### 433 434 def addIntersectionPtsToLines(L1,L2, point_movement_threshold=0.0, buf=1.0e-06, tol2 = 100, 435 verbose=True, nameFlag=''): 436 """ 437 Add intersection points to lines L1 and L2 if they intersect each other 438 439 This is useful e.g. so that intersections can be exact (important for 440 mesh generation in ANUGA) 441 442 It currently only supports point intersection of 2 lines. 443 Line intersections should fail gracefully 444 445 INPUTS: L1, L2 = Wkb LineString geometries 446 447 point_movement_threshold -- if the distance from the nearest 448 point on L1 or L2 to the intersection is < point_movement_threshold, then the 449 nearest point has its coordinates replaced with the intersection point. This is 450 to prevent points being too close to each other 451 452 buf = tolerence that is used to buffer lines to find 453 intersections. Probably doesn't need modification 454 455 tol2 = [see check_polygon_is_small] Probably doesn't need to change 456 457 nameFlag = This will be printed if intersection occurs. Convenient way to display intersecting filenames 458 459 OUTPUTS: L1,L2 with intersection points added in the right places 460 """ 461 462 if(L1.Intersects(L2)): 463 # Get points on the lines 464 L1_pts=Wkb2ListPts(L1) #L1.GetPoints() 465 L2_pts=Wkb2ListPts(L2) #L2.GetPoints() 466 467 # Buffer lines by a small amount 468 L1_buf=L1.Buffer(buf) 469 L2_buf=L2.Buffer(buf) 470 471 # Get intersection point[s] 472 L1_L2_intersect=L1_buf.Intersection(L2_buf) 473 if(L1_L2_intersect.GetGeometryCount()==1): 474 if(not check_polygon_is_small(L1_L2_intersect, buf, tol2)): 475 #print L1_L2_intersect.GetEnvelope() 476 raise Exception, 'line intersection is not allowed. Envelope %s '% str(L1_L2_intersect.GetEnvelope()) 477 # Seems to need special treatment with only 1 intersection point 478 intersectionPts=[L1_L2_intersect.Centroid().GetPoint()] 479 else: 480 intersectionPts=[] 481 for feature in L1_L2_intersect: 482 if(not check_polygon_is_small(feature, buf, tol2)): 483 print feature.GetEnvelope() 484 raise Exception, 'line intersection is not allowed' 485 intersectionPts.append(feature.Centroid().GetPoint()) 486 487 if(verbose): 488 print nameFlag 489 print ' Treating intersections in ', len(intersectionPts) , ' locations' 490 print intersectionPts 491 492 # Insert the points into the line segments 493 for i in range(len(intersectionPts)): 494 L1_pts = insert_intersection_point(intersectionPts[i], L1_pts, point_movement_threshold) 495 L2_pts = insert_intersection_point(intersectionPts[i], L2_pts, point_movement_threshold) 496 497 # Convert to the input format 498 L1_pts=ListPts2Wkb(L1_pts,geometry_type='line') 499 L2_pts=ListPts2Wkb(L2_pts,geometry_type='line') 500 501 return [L1_pts, L2_pts] 502 else: 503 return [L1, L2] 504 505 ########################################################### 506 def rasterValuesAtPoints(xy, rasterFile, band=1): 507 """ 508 Get raster values at point locations. 509 Can be used to e.g. set quantity values 510 511 INPUT: 512 xy = numpy array with point locations 513 rasterFile = Filename of the gdal-compatible raster 514 band = band of the raster to get 515 516 OUTPUT: 517 1d numpy array with raster values at xy 518 519 """ 520 # Raster info 521 raster = gdal.Open(rasterFile) 522 rasterBand=raster.GetRasterBand(band) 523 rasterBandType=gdal.GetDataTypeName(rasterBand.DataType) 524 525 # Projection info 526 transform=raster.GetGeoTransform() 527 xOrigin = transform[0] 528 yOrigin = transform[3] 529 pixelWidth = transform[1] 530 pixelHeight = transform[5] # Negative 531 532 # Get coordinates in pixel values 533 px = ((xy[:,0] - xOrigin) / pixelWidth).astype(int) #x 534 py = ((xy[:,1] - yOrigin) / pixelHeight).astype(int) #y 535 536 # Hold elevation 537 elev=px*0. 538 539 # Get the right character for struct.unpack 540 if (rasterBandType == 'Int16'): 541 CtypeName='h' 542 elif (rasterBandType == 'Float32'): 543 CtypeName='f' 544 elif (rasterBandType == 'Byte'): 545 CtypeName='B' 546 else: 547 print 'unrecognized DataType:', gdal.GetDataTypeName(band.DataType) 548 print 'You might need to edit this code to read the data type' 549 raise Exception, 'Stopping' 550 551 # Get values -- seems we have to loop, but it is efficient enough 552 for i in range(len(px)): 553 xC=int(px[i]) 554 yC=int(py[i]) 555 structval=rasterBand.ReadRaster(xC,yC,1,1,buf_type=rasterBand.DataType) 556 elev[i] = struct.unpack(CtypeName, structval)[0] 557 558 return elev 559 560 561 def gridPointsInPolygon(polygon, approx_grid_spacing=[1.,1.], eps=1.0e-06): 562 """ 563 Get a 'grid' of points inside a polygon. Could be used with rasterValuesAtPoints to 564 get a range of raster values inside a polygon 565 566 Approach: A 'trial-grid' of points is created which is 'almost' covering the range of the polygon (xmin-xmax,ymin-ymax). 567 568 (Actually it is just inside this region, to avoid polygon-boundary issues, see below) 569 570 Then we find those points which are actually inside the polygon. 571 572 The x/y point spacing on the trial-grid will be close to 573 approx_grid_spacing, but we ensure there are at least 3x3 points on the trial grid. 574 Also, we reduce the spacing so that the min_x+R and max_x-R 575 are both similarly close to the polygon extents [see definition of R below] 576 577 INPUTS: 578 polygon -- the polygon in ANUGA format (list of lists of ordered xy points) 579 580 approx_grid_spacing -- the approximate x,y grid spacing 581 582 eps -- 'trial-grid' of points has x range from min_polygon_x+R to 583 max_polygon_x - R, where R = (max_polygon_x-min_polygon_x)*eps 584 ( and similarly for y). 585 586 This makes it more likely that points are inside the 587 polygon, not on the boundaries. Points on the boundaries can confuse the 588 point-in-polygon routine 589 590 OUTPUTS: A n x 2 numpy array of points in the polygon 591 """ 592 593 # Get polygon extent 594 polygonArr=numpy.array(polygon) 595 poly_xmin=polygonArr[:,0].min() 596 poly_xmax=polygonArr[:,0].max() 597 poly_ymin=polygonArr[:,1].min() 598 poly_ymax=polygonArr[:,1].max() 599 600 # Make a 'grid' of points which covers the polygon 601 xGridCount=max( numpy.ceil( (poly_xmax-poly_xmin)/approx_grid_spacing[0]+1. ).astype(int), 3) 602 R=(poly_xmax-poly_xmin)*eps 603 Xvals=numpy.linspace(poly_xmin+R,poly_xmax-R, xGridCount) 604 yGridCount=max( numpy.ceil( (poly_ymax-poly_ymin)/approx_grid_spacing[1]+1. ).astype(int), 3) 605 R=(poly_ymax-poly_ymin)*eps 606 Yvals=numpy.linspace(poly_ymin+R,poly_ymax-R, yGridCount) 607 608 xGrid,yGrid=numpy.meshgrid(Xvals,Yvals) 609 Grid=numpy.vstack([xGrid.flatten(),yGrid.flatten()]).transpose() 610 611 # Now find the xy values which are actually inside the polygon 612 polpath=path.Path(polygonArr) 613 keepers=[] 614 for i in range(len(Grid[:,0])): 615 if(polpath.contains_point(Grid[i,:])): 616 keepers=keepers+[i] 617 #import pdb 618 #pdb.set_trace() 619 xyInside=Grid[keepers,:] 620 621 return(xyInside) 622 623 ######################################################################### 624 # Function to search for pattern matches in a string (turns out to be useful) 625 def matchInds(pattern, stringList): 626 """ 627 Find indices in stringList which match pattern 628 """ 629 #matches=[ (pattern in stringList[i]) for i in range(len(stringList))] 630 matches=[] 631 for i in range(len(stringList)): 632 if pattern in stringList[i]: 633 matches.append(i) 634 return matches 635 636 637 ########################################################################### 260 638 # 261 # Get unit vector along segment 262 seg_unitVec_x=float(p1[0]-p0[0]) 263 seg_unitVec_y=float(p1[1]-p0[1]) 264 segLen=(seg_unitVec_x**2+seg_unitVec_y**2)**0.5 265 if(segLen==0.): 266 #print line 267 #print 'Pt' 268 #print pt 269 raise Exception, 'Line has repeated points: Line %s Pt %s' % (str(line),str(pt)) 270 seg_unitVec_x=seg_unitVec_x/segLen 271 seg_unitVec_y=seg_unitVec_y/segLen 639 # Less generic utilities below 640 # 641 # These are more 'anuga-specific' than above, aiming to make nice interfaces 642 # in ANUGA scripts 272 643 # 273 # Get vector from pt to p0 274 pt_p0_vec_x=float(pt[0]-p0[0]) 275 pt_p0_vec_y=float(pt[1]-p0[1]) 276 pt_p0_vec_len_squared=(pt_p0_vec_x**2 + pt_p0_vec_y**2) 277 # Get dot product of above vector with unit vector 278 pt_dot_segUnitVec=(pt_p0_vec_x)*seg_unitVec_x+(pt_p0_vec_y)*seg_unitVec_y 279 # 280 if( (pt_dot_segUnitVec<segLen) and (pt_dot_segUnitVec > 0.)): 281 # The nearest point on the line is actually between p0 and p1, so we have a 'real' candidate 282 # Get distance^2 283 output = pt_p0_vec_len_squared - pt_dot_segUnitVec**2. 284 else: 285 # Distance is the min distance from p0 and p1. 286 output = min( pt_p0_vec_len_squared, (float(pt[0]-p1[0])**2+float(pt[1]-p1[1])**2)) 287 if(output < -1.0e-06): 288 raise Exception, 'round-off in compute_squared_distance_to_segment' 289 if(output < 0.): 290 output=0. 291 return output 292 293 ############################################################################ 294 295 def find_nearest_segment(pt, segments): 296 """ 297 Given a point and a line, find the line segment nearest to the line 298 299 NOTE: The answer can be ambiguous if one of the segment endpoints is 300 the nearest point. In that case, the behaviour is determined by the behaviour 301 of numpy.argmin. Won't be a problem for this application 302 303 INPUT: pt -- [x,y] 304 segments -- [[x0,y0], [x1,y1], ...] 305 A list of points, consecutive points are interpreted 306 as joined and so defining line segments 307 308 OUTPUT: The squared distance, and the index i of the segment [x_i,y_i],[x_i+1,y_i+1] in segments which is closest to pt 309 """ 310 ll=len(segments) 311 if(ll<=1): 312 raise Exception, 'Segments must have length > 1 in find_nearest_segment' 313 314 ptDist_sq=numpy.zeros(ll-1) # Hold the squared distance from the point to the line segment 315 for i in range(len(segments)-1): 316 # Compute distance from segment 317 ptDist_sq[i]=compute_squared_distance_to_segment(pt, [segments[i],segments[i+1]]) 318 319 return [ptDist_sq.min(), ptDist_sq.argmin()] 320 321 ###################################################### 322 323 def shift_point_on_line(pt, lineIn, nearest_segment_index): 324 """ 325 Support pt is a point, which is near to the 'nearest_segment_index' segment of the line 'lineIn' 326 327 This routine moves the nearest end point of that segment on line to pt. 328 329 INPUTS: pt -- [x,y] point 330 lineIn -- [ [x0, y0], [x1, y1], ..., [xN,yN]] 331 nearest_segment_index = index where the distance of pt to the line from [x_i,y_i] to [x_i+1,y_i+1] is minimum 332 333 OUTPUT: The new line 334 """ 335 # Avoid Changing line 336 line=copy.copy(lineIn) 337 338 # Replace the nearest point on L1 with the intersection point 339 p0 = line[nearest_segment_index] 340 p1 = line[nearest_segment_index+1] 341 d_p0 = ( (pt[0]-p0[0])**2 + (pt[1]-p0[1])**2) 342 d_p1 = ( (pt[0]-p1[0])**2 + (pt[1]-p1[1])**2) 343 changeP1=(d_p1<d_p0) 344 line[nearest_segment_index+changeP1][0] = pt[0] 345 line[nearest_segment_index+changeP1][1] = pt[1] 346 347 return line 348 349 ################################################################################# 350 def insert_intersection_point(intersectionPt, line_pts, point_movement_threshold): 351 """ 352 Add intersectionPt to line_pts, either by inserting it, or if a point on line_pts is 353 closer than point_movement_threshold, then by moving that point to the intersection point 354 355 INPUTS: 356 intersectionPt -- the intersection point [known to lie on line_pts] 357 line_pts -- ordered list of [x,y] points making a line. 358 point_movement_threshold -- used to decide to move or add intersectionPt 359 360 OUTPUT: 361 new version of lint_pts with the point added 362 """ 363 # Avoid pointer/copy issues 364 L1_pts = copy.copy(line_pts) 365 iP=copy.copy(intersectionPt) 366 367 # Adjust L1 368 tmp = find_nearest_segment(intersectionPt, L1_pts) 369 # Compute the distance from the end points of the segment to the 370 # intersection point. Based on this we decide to add or move the point 371 p0 = L1_pts[tmp[1]] 372 p1 = L1_pts[tmp[1]+1] 373 endPt_Dist_Sq=min( ( (p0[0]-iP[0])**2 + (p0[1]-iP[1])**2), ( (p1[0]-iP[0])**2 + (p1[1]-iP[1])**2)) 374 # 375 if(endPt_Dist_Sq>point_movement_threshold**2): 376 # Insert the intersection point. We do this in a tricky way to 377 # account for the possibility of L1_pts having > 2 coordinates 378 # (riverWalls) 379 dummyPt=copy.copy(L1_pts[tmp[1]]) 380 L1_pts.insert(tmp[1]+1,dummyPt) 381 L1_pts[tmp[1]+1][0]=iP[0] 382 L1_pts[tmp[1]+1][1]=iP[1] 383 if(len(L1_pts[tmp[1]+1])==3): 384 # Treat 3rd coordinate 385 # Find distance of inserted point from neighbours, and 386 # Set 3rd coordinate as distance-weighted average of the others 387 d0=((L1_pts[tmp[1]][0]-L1_pts[tmp[1]+1][0])**2.+\ 388 (L1_pts[tmp[1]][0]-L1_pts[tmp[1]+1][1])**2.)**0.5 389 d1=((L1_pts[tmp[1]+2][0]-L1_pts[tmp[1]+1][0])**2.+\ 390 (L1_pts[tmp[1]+2][1]-L1_pts[tmp[1]+1][1])**2.)**0.5 391 L1_pts[tmp[1]+1][2] = (d0*L1_pts[tmp[1]+2][2] + d1*L1_pts[tmp[1]][2])/(d0+d1) 392 393 else: 394 # Move a point already on L1 395 L1_pts=shift_point_on_line(iP, L1_pts, tmp[1]) 396 397 return L1_pts 398 399 ####################################################################################################### 400 def check_polygon_is_small(intersection, buf, tol2=100.): 401 """ 402 403 Elsewhere in the code, we check whether lines intersect by buffering them 404 to polygons with a small buffer = buf, then getting the intersection. 405 [since intersection with polygons is supported by gdal, but apparently 406 not directly with lines]. 407 408 The logic of our code only works with point intersections, 409 and it will fails if 2 lines overlap in a line. 410 411 We crudely check for this situation here, by ensuring that the intersection polygon is 'small' 412 413 WARNING: The gdal geometry routines may be a bit rough (?) 414 Intersections not very precise, etc (?) 415 416 INPUT: intersection -- intersection of the 2 lines [gdal geometry] 417 buf -- a length scale giving the size of the intersection extent that we expect for a point 418 tol2 -- Throw an error if the x or y extent is greater than buf*tol2. Seems this needs to be 419 large sometimes -- this might reflect the stated weaknesses of GDALs geometry routines? 420 OUTPUT: True/False 421 False should suggest that the intersection is not describing a point 422 """ 423 424 extent=intersection.GetEnvelope() 425 assert(len(extent)==4) # Make sure this assumption is valid 426 if( (abs(extent[0]-extent[1])>buf*tol2) or (abs(extent[2]-extent[3]) > buf*tol2)): 427 return False 428 else: 429 return True 430 431 ####################################################################################################### 432 433 def addIntersectionPtsToLines(L1,L2, point_movement_threshold=0.0, buf=1.0e-06, tol2 = 100, 434 verbose=True, nameFlag=''): 435 """ 436 Add intersection points to lines L1 and L2 if they intersect each other 437 438 This is useful e.g. so that intersections can be exact (important for 439 mesh generation in ANUGA) 440 441 It currently only supports point intersection of 2 lines. 442 Line intersections should fail gracefully 443 444 INPUTS: L1, L2 = Wkb LineString geometries 445 446 point_movement_threshold -- if the distance from the nearest 447 point on L1 or L2 to the intersection is < point_movement_threshold, then the 448 nearest point has its coordinates replaced with the intersection point. This is 449 to prevent points being too close to each other 450 451 buf = tolerence that is used to buffer lines to find 452 intersections. Probably doesn't need modification 453 454 tol2 = [see check_polygon_is_small] Probably doesn't need to change 455 456 nameFlag = This will be printed if intersection occurs. Convenient way to display intersecting filenames 457 458 OUTPUTS: L1,L2 with intersection points added in the right places 459 """ 460 461 if(L1.Intersects(L2)): 462 # Get points on the lines 463 L1_pts=Wkb2ListPts(L1) #L1.GetPoints() 464 L2_pts=Wkb2ListPts(L2) #L2.GetPoints() 465 466 # Buffer lines by a small amount 467 L1_buf=L1.Buffer(buf) 468 L2_buf=L2.Buffer(buf) 469 470 # Get intersection point[s] 471 L1_L2_intersect=L1_buf.Intersection(L2_buf) 472 if(L1_L2_intersect.GetGeometryCount()==1): 473 if(not check_polygon_is_small(L1_L2_intersect, buf, tol2)): 474 #print L1_L2_intersect.GetEnvelope() 475 raise Exception, 'line intersection is not allowed. Envelope %s '% str(L1_L2_intersect.GetEnvelope()) 476 # Seems to need special treatment with only 1 intersection point 477 intersectionPts=[L1_L2_intersect.Centroid().GetPoint()] 478 else: 479 intersectionPts=[] 480 for feature in L1_L2_intersect: 481 if(not check_polygon_is_small(feature, buf, tol2)): 482 print feature.GetEnvelope() 483 raise Exception, 'line intersection is not allowed' 484 intersectionPts.append(feature.Centroid().GetPoint()) 485 644 ############################################################################ 645 646 647 def add_intersections_to_domain_features(bounding_polygonIn, 648 breakLinesIn={ }, riverWallsIn={ }, point_movement_threshold=0., 649 verbose=True): 650 """ 651 If bounding polygon / breaklines /riverwalls intersect with each other, then 652 add intersection points. 653 654 INPUTS: 655 bounding_polygonIn -- the bounding polygon in ANUGA format 656 breakLinesIn -- the breaklines dictionary 657 riverWallsIn -- the riverWalls dictionary 658 659 point_movement_threshold -- if points on lines are < this distance 660 from intersection points, then they are replaced with the intersection point. 661 This can prevent overly close points from breaking the mesh generation 662 663 OUTPUT: 664 List with bounding_polygon,breakLines,riverwalls 665 """ 666 667 bounding_polygon=copy.copy(bounding_polygonIn) 668 breakLines=copy.copy(breakLinesIn) 669 riverWalls=copy.copy(riverWallsIn) 670 671 # Clean intersections of breakLines with itself 672 if(verbose): 673 print 'Cleaning breakline intersections' 674 if(len(breakLines)>0): 675 kbl=breakLines.keys() 676 for i in range(len(kbl)): 677 n1=kbl[i] 678 for j in range(len(kbl)): 679 if(i>=j): 680 continue 681 n2=kbl[j] 682 # Convert breaklines to wkb format 683 bl1=ListPts2Wkb(breakLines[n1],geometry_type='line') 684 bl2=ListPts2Wkb(breakLines[n2],geometry_type='line') 685 # Add intersection points 686 bl1, bl2 =addIntersectionPtsToLines(bl1, bl2,\ 687 point_movement_threshold=point_movement_threshold, 688 verbose=verbose, nameFlag=n1+' intersects '+ n2) 689 breakLines[n1]=Wkb2ListPts(bl1) 690 breakLines[n2]=Wkb2ListPts(bl2) 691 692 693 # Clean intersections of riverWalls with itself 694 if(verbose): 695 print 'Cleaning riverWall intersections' 696 if(len(riverWalls)>0): 697 krw=riverWalls.keys() 698 for i in range(len(krw)): 699 n1=krw[i] 700 for j in range(len(krw)): 701 if(i>=j): 702 continue 703 n2=krw[j] 704 # Convert breaklines to wkb format 705 rw1=ListPts2Wkb(riverWalls[n1],geometry_type='line') 706 rw2=ListPts2Wkb(riverWalls[n2],geometry_type='line') 707 # Add intersection points 708 rw1, rw2 =addIntersectionPtsToLines(rw1, rw2,\ 709 point_movement_threshold=point_movement_threshold,\ 710 verbose=verbose, nameFlag=n1+' intersects '+ n2) 711 riverWalls[n1]=Wkb2ListPts(rw1) 712 riverWalls[n2]=Wkb2ListPts(rw2) 713 714 # Clean intersections of breaklines with riverwalls 715 if(verbose): 716 print 'Cleaning breakLine-riverWall intersections' 717 if( (len(riverWalls)>0) and (len(breakLines)>0)): 718 krw=riverWalls.keys() 719 kbl=breakLines.keys() 720 for i in range(len(krw)): 721 n1=krw[i] 722 for j in range(len(kbl)): 723 n2=kbl[j] 724 # Convert breaklines to wkb format 725 rw1=ListPts2Wkb(riverWalls[n1],geometry_type='line') 726 bw2=ListPts2Wkb(breakLines[n2],geometry_type='line') 727 # Add intersection points 728 rw1, bw2 =addIntersectionPtsToLines(rw1, bw2,\ 729 point_movement_threshold=point_movement_threshold,\ 730 verbose=verbose, nameFlag=n1+' intersects '+ n2) 731 riverWalls[n1]=Wkb2ListPts(rw1) 732 breakLines[n2]=Wkb2ListPts(bw2) 733 734 735 # Clean intersections of bounding polygon and riverwalls 736 if(verbose): 737 print 'Cleaning bounding_poly-riverWall intersections' 738 if( (len(riverWalls)>0)): 739 krw=riverWalls.keys() 740 for i in range(len(krw)): 741 n1=krw[i] 742 # Convert breaklines to wkb format 743 rw1=ListPts2Wkb(riverWalls[n1],geometry_type='line') 744 bp2=ListPts2Wkb(bounding_polygon,geometry_type='line', appendFirstOnEnd=True) 745 # Add intersection points 746 rw1, bp2 =addIntersectionPtsToLines(rw1, bp2,\ 747 point_movement_threshold=point_movement_threshold,\ 748 verbose=verbose, nameFlag='Bounding Pol intersects '+ n1) 749 riverWalls[n1]=Wkb2ListPts(rw1) 750 bounding_polygon=Wkb2ListPts(bp2,removeLast=True) 751 752 # Clean intersections of bounding polygon and breaklines 486 753 if(verbose): 487 print nameFlag 488 print ' Treating intersections in ', len(intersectionPts) , ' locations' 489 print intersectionPts 490 491 # Insert the points into the line segments 492 for i in range(len(intersectionPts)): 493 L1_pts = insert_intersection_point(intersectionPts[i], L1_pts, point_movement_threshold) 494 L2_pts = insert_intersection_point(intersectionPts[i], L2_pts, point_movement_threshold) 495 496 # Convert to the input format 497 L1_pts=ListPts2Wkb(L1_pts,geometry_type='line') 498 L2_pts=ListPts2Wkb(L2_pts,geometry_type='line') 499 500 return [L1_pts, L2_pts] 501 else: 502 return [L1, L2] 503 504 ########################################################### 505 def rasterValuesAtPoints(xy, rasterFile, band=1): 506 """ 507 Get raster values at point locations. 508 Can be used to e.g. set quantity values 509 510 INPUT: 511 xy = numpy array with point locations 512 rasterFile = Filename of the gdal-compatible raster 513 band = band of the raster to get 514 515 OUTPUT: 516 1d numpy array with raster values at xy 517 518 """ 519 # Raster info 520 raster = gdal.Open(rasterFile) 521 rasterBand=raster.GetRasterBand(band) 522 rasterBandType=gdal.GetDataTypeName(rasterBand.DataType) 523 524 # Projection info 525 transform=raster.GetGeoTransform() 526 xOrigin = transform[0] 527 yOrigin = transform[3] 528 pixelWidth = transform[1] 529 pixelHeight = transform[5] # Negative 530 531 # Get coordinates in pixel values 532 px = ((xy[:,0] - xOrigin) / pixelWidth).astype(int) #x 533 py = ((xy[:,1] - yOrigin) / pixelHeight).astype(int) #y 534 535 # Hold elevation 536 elev=px*0. 537 538 # Get the right character for struct.unpack 539 if (rasterBandType == 'Int16'): 540 CtypeName='h' 541 elif (rasterBandType == 'Float32'): 542 CtypeName='f' 543 elif (rasterBandType == 'Byte'): 544 CtypeName='B' 545 else: 546 print 'unrecognized DataType:', gdal.GetDataTypeName(band.DataType) 547 print 'You might need to edit this code to read the data type' 548 raise Exception, 'Stopping' 549 550 # Get values -- seems we have to loop, but it is efficient enough 551 for i in range(len(px)): 552 xC=int(px[i]) 553 yC=int(py[i]) 554 structval=rasterBand.ReadRaster(xC,yC,1,1,buf_type=rasterBand.DataType) 555 elev[i] = struct.unpack(CtypeName, structval)[0] 556 557 return elev 558 559 560 def gridPointsInPolygon(polygon, approx_grid_spacing=[1.,1.], eps=1.0e-06): 561 """ 562 Get a 'grid' of points inside a polygon. Could be used with rasterValuesAtPoints to 563 get a range of raster values inside a polygon 564 565 Approach: A 'trial-grid' of points is created which is 'almost' covering the range of the polygon (xmin-xmax,ymin-ymax). 566 567 (Actually it is just inside this region, to avoid polygon-boundary issues, see below) 568 569 Then we find those points which are actually inside the polygon. 570 571 The x/y point spacing on the trial-grid will be close to 572 approx_grid_spacing, but we ensure there are at least 3x3 points on the trial grid. 573 Also, we reduce the spacing so that the min_x+R and max_x-R 574 are both similarly close to the polygon extents [see definition of R below] 575 576 INPUTS: 577 polygon -- the polygon in ANUGA format (list of lists of ordered xy points) 578 579 approx_grid_spacing -- the approximate x,y grid spacing 580 581 eps -- 'trial-grid' of points has x range from min_polygon_x+R to 582 max_polygon_x - R, where R = (max_polygon_x-min_polygon_x)*eps 583 ( and similarly for y). 584 585 This makes it more likely that points are inside the 586 polygon, not on the boundaries. Points on the boundaries can confuse the 587 point-in-polygon routine 588 589 OUTPUTS: A n x 2 numpy array of points in the polygon 590 """ 591 592 # Get polygon extent 593 polygonArr=numpy.array(polygon) 594 poly_xmin=polygonArr[:,0].min() 595 poly_xmax=polygonArr[:,0].max() 596 poly_ymin=polygonArr[:,1].min() 597 poly_ymax=polygonArr[:,1].max() 598 599 # Make a 'grid' of points which covers the polygon 600 xGridCount=max( numpy.ceil( (poly_xmax-poly_xmin)/approx_grid_spacing[0]+1. ).astype(int), 3) 601 R=(poly_xmax-poly_xmin)*eps 602 Xvals=numpy.linspace(poly_xmin+R,poly_xmax-R, xGridCount) 603 yGridCount=max( numpy.ceil( (poly_ymax-poly_ymin)/approx_grid_spacing[1]+1. ).astype(int), 3) 604 R=(poly_ymax-poly_ymin)*eps 605 Yvals=numpy.linspace(poly_ymin+R,poly_ymax-R, yGridCount) 606 607 xGrid,yGrid=numpy.meshgrid(Xvals,Yvals) 608 Grid=numpy.vstack([xGrid.flatten(),yGrid.flatten()]).transpose() 609 610 # Now find the xy values which are actually inside the polygon 611 polpath=path.Path(polygonArr) 612 keepers=[] 613 for i in range(len(Grid[:,0])): 614 if(polpath.contains_point(Grid[i,:])): 615 keepers=keepers+[i] 616 #import pdb 617 #pdb.set_trace() 618 xyInside=Grid[keepers,:] 619 620 return(xyInside) 621 622 ######################################################################### 623 # Function to search for pattern matches in a string (turns out to be useful) 624 def matchInds(pattern, stringList): 625 """ 626 Find indices in stringList which match pattern 627 """ 628 #matches=[ (pattern in stringList[i]) for i in range(len(stringList))] 629 matches=[] 630 for i in range(len(stringList)): 631 if pattern in stringList[i]: 632 matches.append(i) 633 return matches 634 635 636 ########################################################################### 637 # 638 # Less generic utilities below 639 # 640 # These are more 'anuga-specific' than above, aiming to make nice interfaces 641 # in ANUGA scripts 642 # 643 ############################################################################ 644 645 646 def add_intersections_to_domain_features(bounding_polygonIn, 647 breakLinesIn={ }, riverWallsIn={ }, point_movement_threshold=0., 648 verbose=True): 649 """ 650 If bounding polygon / breaklines /riverwalls intersect with each other, then 651 add intersection points. 652 653 INPUTS: 654 bounding_polygonIn -- the bounding polygon in ANUGA format 655 breakLinesIn -- the breaklines dictionary 656 riverWallsIn -- the riverWalls dictionary 657 658 point_movement_threshold -- if points on lines are < this distance 659 from intersection points, then they are replaced with the intersection point. 660 This can prevent overly close points from breaking the mesh generation 661 662 OUTPUT: 663 List with bounding_polygon,breakLines,riverwalls 664 """ 665 666 bounding_polygon=copy.copy(bounding_polygonIn) 667 breakLines=copy.copy(breakLinesIn) 668 riverWalls=copy.copy(riverWallsIn) 669 670 # Clean intersections of breakLines with itself 671 if(verbose): 672 print 'Cleaning breakline intersections' 673 if(len(breakLines)>0): 674 kbl=breakLines.keys() 675 for i in range(len(kbl)): 676 n1=kbl[i] 677 for j in range(len(kbl)): 678 if(i>=j): 679 continue 680 n2=kbl[j] 754 print 'Cleaning bounding_poly-breaklines intersections' 755 if( (len(breakLines)>0)): 756 kbl=breakLines.keys() 757 for i in range(len(kbl)): 758 n1=kbl[i] 681 759 # Convert breaklines to wkb format 682 760 bl1=ListPts2Wkb(breakLines[n1],geometry_type='line') 683 b l2=ListPts2Wkb(breakLines[n2],geometry_type='line')761 bp2=ListPts2Wkb(bounding_polygon,geometry_type='line', appendFirstOnEnd=True) 684 762 # Add intersection points 685 bl1, b l2 =addIntersectionPtsToLines(bl1, bl2,\763 bl1, bp2 =addIntersectionPtsToLines(bl1, bp2,\ 686 764 point_movement_threshold=point_movement_threshold, 687 verbose=verbose, nameFlag= n1+' intersects '+ n2)765 verbose=verbose, nameFlag='Bounding Pol intersects '+n1) 688 766 breakLines[n1]=Wkb2ListPts(bl1) 689 breakLines[n2]=Wkb2ListPts(bl2) 690 691 692 # Clean intersections of riverWalls with itself 693 if(verbose): 694 print 'Cleaning riverWall intersections' 695 if(len(riverWalls)>0): 696 krw=riverWalls.keys() 697 for i in range(len(krw)): 698 n1=krw[i] 699 for j in range(len(krw)): 700 if(i>=j): 701 continue 702 n2=krw[j] 703 # Convert breaklines to wkb format 704 rw1=ListPts2Wkb(riverWalls[n1],geometry_type='line') 705 rw2=ListPts2Wkb(riverWalls[n2],geometry_type='line') 706 # Add intersection points 707 rw1, rw2 =addIntersectionPtsToLines(rw1, rw2,\ 708 point_movement_threshold=point_movement_threshold,\ 709 verbose=verbose, nameFlag=n1+' intersects '+ n2) 710 riverWalls[n1]=Wkb2ListPts(rw1) 711 riverWalls[n2]=Wkb2ListPts(rw2) 712 713 # Clean intersections of breaklines with riverwalls 714 if(verbose): 715 print 'Cleaning breakLine-riverWall intersections' 716 if( (len(riverWalls)>0) and (len(breakLines)>0)): 717 krw=riverWalls.keys() 718 kbl=breakLines.keys() 719 for i in range(len(krw)): 720 n1=krw[i] 721 for j in range(len(kbl)): 722 n2=kbl[j] 723 # Convert breaklines to wkb format 724 rw1=ListPts2Wkb(riverWalls[n1],geometry_type='line') 725 bw2=ListPts2Wkb(breakLines[n2],geometry_type='line') 726 # Add intersection points 727 rw1, bw2 =addIntersectionPtsToLines(rw1, bw2,\ 728 point_movement_threshold=point_movement_threshold,\ 729 verbose=verbose, nameFlag=n1+' intersects '+ n2) 730 riverWalls[n1]=Wkb2ListPts(rw1) 731 breakLines[n2]=Wkb2ListPts(bw2) 732 733 734 # Clean intersections of bounding polygon and riverwalls 735 if(verbose): 736 print 'Cleaning bounding_poly-riverWall intersections' 737 if( (len(riverWalls)>0)): 738 krw=riverWalls.keys() 739 for i in range(len(krw)): 740 n1=krw[i] 741 # Convert breaklines to wkb format 742 rw1=ListPts2Wkb(riverWalls[n1],geometry_type='line') 743 bp2=ListPts2Wkb(bounding_polygon,geometry_type='line', appendFirstOnEnd=True) 744 # Add intersection points 745 rw1, bp2 =addIntersectionPtsToLines(rw1, bp2,\ 746 point_movement_threshold=point_movement_threshold,\ 747 verbose=verbose, nameFlag='Bounding Pol intersects '+ n1) 748 riverWalls[n1]=Wkb2ListPts(rw1) 749 bounding_polygon=Wkb2ListPts(bp2,removeLast=True) 750 751 # Clean intersections of bounding polygon and breaklines 752 if(verbose): 753 print 'Cleaning bounding_poly-breaklines intersections' 754 if( (len(breakLines)>0)): 755 kbl=breakLines.keys() 756 for i in range(len(kbl)): 757 n1=kbl[i] 758 # Convert breaklines to wkb format 759 bl1=ListPts2Wkb(breakLines[n1],geometry_type='line') 760 bp2=ListPts2Wkb(bounding_polygon,geometry_type='line', appendFirstOnEnd=True) 761 # Add intersection points 762 bl1, bp2 =addIntersectionPtsToLines(bl1, bp2,\ 763 point_movement_threshold=point_movement_threshold, 764 verbose=verbose, nameFlag='Bounding Pol intersects '+n1) 765 breakLines[n1]=Wkb2ListPts(bl1) 766 bounding_polygon=Wkb2ListPts(bp2, removeLast=True) 767 768 # Remove the extra 0.0 from bounding polygon [this cannot have 3 coordinates] 769 bounding_polygon = [ bounding_polygon[i][0:2] for i in range(len(bounding_polygon))] 770 # Same for breaklines [although might not matter] 771 for n1 in breakLines.keys(): 772 breakLines[n1] = [breakLines[n1][i][0:2] for i in range(len(breakLines[n1]))] 773 774 return [bounding_polygon, breakLines, riverWalls] 775 776 ################################################################### 777 778 def readRegionPtAreas(shapefile, convert_length_to_area=False): 779 """ 780 Read a point shapefile to define the ANUGA mesh resoutions. 781 782 MUST HAVE A SINGLE ATTRIBUTE REPRESENTING THE LENGTHS OF TRIANGLES IN 783 REGIONS 784 785 INPUT: shapefile -- name of the input shapefile 786 convert_length_to_area -- if True, res values are assumed to 787 represent triangle side lengths, and are converted to areas with 0.5*res0*res0 788 Note that this might not ensure that the max triangle side length really is res0, but 789 it will be of similar magnitude 790 If False, attribute values are assumed to represent triangle areas 791 792 OUTPUT: list of the form [ [x0,y0,res0], [x1, y1, res1], ...] 793 """ 794 795 ptData=readShpPtsAndAttributes(shapefile) 796 797 # Must have only 1 attribute 798 assert len(ptData[2])==1 799 800 numPts=len(ptData[0]) 801 outData=[] 802 for i in range(numPts): 803 if(convert_length_to_area): 804 newDat=[ptData[0][i][0], ptData[0][i][1], 0.5*float(ptData[1][i])**2] 805 else: 806 newDat=[ptData[0][i][0], ptData[0][i][1], float(ptData[1][i])] 807 outData.append(newDat) 808 809 return outData 810 811 ######################################### 812 def readListOfBreakLines(shapefileList): 813 """ 814 Take a list with the names of shapefiles 815 816 They are assumed to be '2D breaklines', so we just read their 817 coordinates into a dict with their names 818 819 Read them in 820 821 INPUT: shapefileList -- a list of shapefile names [e.g. from glob.glob('GIS/Breaklines/*.shp')] 822 823 OUTPUT: dictionary with breaklines [filenames are keys] 824 """ 825 826 allBreakLines={} 827 for shapefile in shapefileList: 828 allBreakLines[shapefile]=readShp_1LineGeo(shapefile) 829 830 return allBreakLines 831 832 ############################################################################ 833 def polygon_from_matching_breaklines(pattern,breakLinesIn, reverse2nd=None): 834 """ 835 We sometimes have breaklines defining 2 edges of a channel, 836 and wish to make a polygon from them 837 838 Can do this with the current function 839 840 INPUTS: pattern == character string containing pattern which is inside exactly 2 keys in breaklines 841 842 breakLines = the breakLinesIn dictionary 843 844 reverse2nd = True/False or None. Reverse the order of the 2nd set of edges before making the polygon. 845 If None, then we compute the distance between the 846 first point on breakline1 and the first/last points on breakline2, and reverse2nd if 847 the 'distance from the first point' < 'distance from the last point' 848 849 OUTPUT: Polygon made with the 2 breaklines 850 """ 851 852 breakLines=copy.copy(breakLinesIn) 853 bk=breakLines.keys() 854 matchers=matchInds(pattern, bk) 855 856 if(len(matchers)==0): 857 msg = 'Cannot match ' + pattern + 'in breaklines file names' 858 raise Exception, msg 859 860 if(len(matchers)!=2): 861 print 'Need exactly 2 matches, but pattern matched these', bk[matchers] 862 863 # There are 2 matches 864 865 if(reverse2nd is None): 866 # Automatically compute whether we should reverse the 2nd breakline 867 bl1_0=breakLines[bk[matchers[0]]][0] 868 bl2_0=breakLines[bk[matchers[1]]][0] 869 bl2_N=breakLines[bk[matchers[1]]][-1] 870 d0 = ((bl1_0[0]-bl2_0[0])**2 + (bl1_0[1]-bl2_0[1])**2) 871 dN = ((bl1_0[0]-bl2_N[0])**2 + (bl1_0[1]-bl2_N[1])**2) 872 if(d0<dN): 873 reverse2nd = True 874 else: 875 reverse2nd = False 876 877 if(reverse2nd): 878 breakLines[bk[matchers[1]]].reverse() 879 polyOut=breakLines[bk[matchers[0]]] + breakLines[bk[matchers[1]]] 880 #polyOut=polyOut+[polyOut[0]] 881 return polyOut 882 ################### 883 884 767 bounding_polygon=Wkb2ListPts(bp2, removeLast=True) 768 769 # Remove the extra 0.0 from bounding polygon [this cannot have 3 coordinates] 770 bounding_polygon = [ bounding_polygon[i][0:2] for i in range(len(bounding_polygon))] 771 # Same for breaklines [although might not matter] 772 for n1 in breakLines.keys(): 773 breakLines[n1] = [breakLines[n1][i][0:2] for i in range(len(breakLines[n1]))] 774 775 return [bounding_polygon, breakLines, riverWalls] 776 777 ################################################################### 778 779 def readRegionPtAreas(shapefile, convert_length_to_area=False): 780 """ 781 Read a point shapefile to define the ANUGA mesh resoutions. 782 783 MUST HAVE A SINGLE ATTRIBUTE REPRESENTING THE LENGTHS OF TRIANGLES IN 784 REGIONS 785 786 INPUT: shapefile -- name of the input shapefile 787 convert_length_to_area -- if True, res values are assumed to 788 represent triangle side lengths, and are converted to areas with 0.5*res0*res0 789 Note that this might not ensure that the max triangle side length really is res0, but 790 it will be of similar magnitude 791 If False, attribute values are assumed to represent triangle areas 792 793 OUTPUT: list of the form [ [x0,y0,res0], [x1, y1, res1], ...] 794 """ 795 796 ptData=readShpPtsAndAttributes(shapefile) 797 798 # Must have only 1 attribute 799 assert len(ptData[2])==1 800 801 numPts=len(ptData[0]) 802 outData=[] 803 for i in range(numPts): 804 if(convert_length_to_area): 805 newDat=[ptData[0][i][0], ptData[0][i][1], 0.5*float(ptData[1][i])**2] 806 else: 807 newDat=[ptData[0][i][0], ptData[0][i][1], float(ptData[1][i])] 808 outData.append(newDat) 809 810 return outData 811 812 ######################################### 813 def readListOfBreakLines(shapefileList): 814 """ 815 Take a list with the names of shapefiles 816 817 They are assumed to be '2D breaklines', so we just read their 818 coordinates into a dict with their names 819 820 Read them in 821 822 INPUT: shapefileList -- a list of shapefile names [e.g. from glob.glob('GIS/Breaklines/*.shp')] 823 824 OUTPUT: dictionary with breaklines [filenames are keys] 825 """ 826 827 allBreakLines={} 828 for shapefile in shapefileList: 829 allBreakLines[shapefile]=readShp_1LineGeo(shapefile) 830 831 return allBreakLines 832 833 ############################################################################ 834 def polygon_from_matching_breaklines(pattern,breakLinesIn, reverse2nd=None): 835 """ 836 We sometimes have breaklines defining 2 edges of a channel, 837 and wish to make a polygon from them 838 839 Can do this with the current function 840 841 INPUTS: pattern == character string containing pattern which is inside exactly 2 keys in breaklines 842 843 breakLines = the breakLinesIn dictionary 844 845 reverse2nd = True/False or None. Reverse the order of the 2nd set of edges before making the polygon. 846 If None, then we compute the distance between the 847 first point on breakline1 and the first/last points on breakline2, and reverse2nd if 848 the 'distance from the first point' < 'distance from the last point' 849 850 OUTPUT: Polygon made with the 2 breaklines 851 """ 852 853 breakLines=copy.copy(breakLinesIn) 854 bk=breakLines.keys() 855 matchers=matchInds(pattern, bk) 856 857 if(len(matchers)==0): 858 msg = 'Cannot match ' + pattern + 'in breaklines file names' 859 raise Exception, msg 860 861 if(len(matchers)!=2): 862 print 'Need exactly 2 matches, but pattern matched these', bk[matchers] 863 864 # There are 2 matches 865 866 if(reverse2nd is None): 867 # Automatically compute whether we should reverse the 2nd breakline 868 bl1_0=breakLines[bk[matchers[0]]][0] 869 bl2_0=breakLines[bk[matchers[1]]][0] 870 bl2_N=breakLines[bk[matchers[1]]][-1] 871 d0 = ((bl1_0[0]-bl2_0[0])**2 + (bl1_0[1]-bl2_0[1])**2) 872 dN = ((bl1_0[0]-bl2_N[0])**2 + (bl1_0[1]-bl2_N[1])**2) 873 if(d0<dN): 874 reverse2nd = True 875 else: 876 reverse2nd = False 877 878 if(reverse2nd): 879 breakLines[bk[matchers[1]]].reverse() 880 polyOut=breakLines[bk[matchers[0]]] + breakLines[bk[matchers[1]]] 881 #polyOut=polyOut+[polyOut[0]] 882 return polyOut 883 ################### 884 885 else: # gdal_available == False 886 msg='Failed to import gdal/ogr modules --'\ 887 + 'perhaps gdal python interface is not installed.' 888 889 890 891 def readShp_1PolyGeo(shapefile, dropLast=True): 892 raise ImportError, msg 893 894 def readShp_1LineGeo(shapefile): 895 raise ImportError, msg 896 897 def readShpPtsAndAttributes(shapefile): 898 raise ImportError, msg 899 900 def ListPts2Wkb( ptsIn, geometry_type='line', appendFirstOnEnd=None): 901 raise ImportError, msg 902 903 def Wkb2ListPts(wkb_geo, removeLast=False, drop_third_dimension=False): 904 raise ImportError, msg 905 906 def compute_squared_distance_to_segment(pt, line): 907 raise ImportError, msg 908 909 def find_nearest_segment(pt, segments): 910 raise ImportError, msg 911 912 def shift_point_on_line(pt, lineIn, nearest_segment_index): 913 raise ImportError, msg 914 915 def insert_intersection_point(intersectionPt, line_pts, point_movement_threshold): 916 raise ImportError, msg 917 918 def check_polygon_is_small(intersection, buf, tol2=100.): 919 raise ImportError, msg 920 921 def addIntersectionPtsToLines(L1,L2, point_movement_threshold=0.0, buf=1.0e-06, tol2 = 100, 922 verbose=True, nameFlag=''): 923 raise ImportError, msg 924 925 926 def rasterValuesAtPoints(xy, rasterFile, band=1): 927 raise ImportError, msg 928 929 930 def gridPointsInPolygon(polygon, approx_grid_spacing=[1.,1.], eps=1.0e-06): 931 raise ImportError, msg 932 933 934 def matchInds(pattern, stringList): 935 raise ImportError, msg 936 937 938 def add_intersections_to_domain_features(bounding_polygonIn, 939 breakLinesIn={ }, riverWallsIn={ }, point_movement_threshold=0., 940 verbose=True): 941 raise ImportError, msg 942 943 944 def readRegionPtAreas(shapefile, convert_length_to_area=False): 945 raise ImportError, msg 946 947 def readListOfBreakLines(shapefileList): 948 raise ImportError, msg 949 950 def polygon_from_matching_breaklines(pattern,breakLinesIn, reverse2nd=None): 951 raise ImportError, msg 952 ################### 953 954 -
trunk/anuga_core/source/anuga/utilities/test_plot_utils.py
r9200 r9212 383 383 fakeZ=xG-min(xG)+yG -min(yG) 384 384 dataToGrid=np.vstack([xG,yG,fakeZ]).transpose() 385 try: 386 util.Make_Geotif(dataToGrid, output_quantities=['TestData'], 385 util.Make_Geotif(dataToGrid, output_quantities=['TestData'], 387 386 EPSG_CODE=32756, output_dir='.', CellSize=myCellSize) 388 except: 389 assert False 387 390 388 391 389 # Use gdal to check that at least the data extent is ok … … 395 393 assert(np.allclose(x.min()-myCellSize/2.0, rasterGeoTrans[0])) 396 394 assert(np.allclose(y.max()+myCellSize/2.0, rasterGeoTrans[3])) 395 #release data file 396 raster = None 397 397 # Delete tif made with Make_Geotif 398 398 os.remove('PointData_TestData.tif') -
trunk/anuga_core/source/anuga/utilities/test_spatialInputUtil.py
r9203 r9212 294 294 fakeZ=xG-min(xG)+yG -min(yG) 295 295 dataToGrid=numpy.vstack([xG,yG,fakeZ]).transpose() 296 try: 297 util.Make_Geotif(dataToGrid, output_quantities=['TestData'], 298 EPSG_CODE=32756, output_dir='.',CellSize=1.0) 299 except: 300 raise Exception, "Failed because util.Make_Geotif didn't work" 296 297 util.Make_Geotif(dataToGrid, output_quantities=['TestData'], 298 EPSG_CODE=32756, output_dir='.',CellSize=1.0) 299 301 300 302 301 # Now try to get some point values -- note they will be rounded to the
Note: See TracChangeset
for help on using the changeset viewer.