source: issm/trunk-jpl/src/m/shp/shpread.py

Last change on this file was 27458, checked in by jdquinn, 2 years ago

CHG: MATLAB > Python translation; cleanup

File size: 5.5 KB
Line 
1import numpy as np
2from collections import OrderedDict
3from os import path
4try:
5 import shapefile
6except ImportError:
7 print("could not import shapefile, PyShp has not been installed, no shapefile reading capabilities enabled")
8
9from pairoptions import pairoptions
10
11
12def shpread(filename, *args): # {{{
13 """SHPREAD - read a shapefile and build a list of shapes
14
15 This routine reads a shapefile and builds a list of OrderedDict objects
16 containing the fields x and y corresponding to the coordinates, one for the
17 filename of the shp file, for the density, for the nodes, and a field
18 closed to indicate if the domain is closed. If this initial shapefile is
19 point only, the fields closed and points are ommitted. The first argument
20 is the shapefile to be read and the second argument (optional) indicates if
21 the last point shall be read (1 to read it, 0 not to).
22
23 The current implementation of shpread depends on PyShp.
24
25 Usage:
26 list = shpread(filename)
27
28 Example:
29 From underling PyShp implementation, "The shapefile format is actually
30 a collection of three files. You specify the base filename of the
31 shapefile or the complete filename of any of the shapefile component
32 files."
33
34 list = shpread('domainoutline.shp')
35 OR
36 list = shpread('domainoutline.dbf')
37 OR
38 list = shpread('domainoutline')
39
40 "OR any of the other 5+ formats which are potentially part of a
41 shapefile. The library does not care about file extensions". We do,
42 however, check that a file with the base filename or base filename with
43 .shp extension exists.
44
45 Sources:
46 - https://github.com/GeospatialPython/pyshp
47
48 NOTE:
49 - OrderedDict objects are used instead of OrderedStruct objects (although
50 addressing in the latter case is closer to the MATLAB struct type) in order
51 to remain consistent with the pattern established by src/m/exp/expread.py.
52
53 TODO:
54 - Create class that can be used to store and pretty print shape structs
55 (ala OrderedStruct from src/m/qmu/helpers.py).
56 - Convert returned data structure from list of OrderedDict objects to list
57 of OrderedStruct objects and remove corresponding note (see also
58 src/m/exp/expread.py). Also, modify handling of returned data structure in,
59 - src/m/classes/basin.py
60 - src/m/classes/boundary.py
61 - src/m/modules/ExpToLevelSet.py
62 - src/m/mesh/bamg.py
63 May also need to modify addressing in corresponding FetchData function, or
64 create new one, in src/wrappers/ContoursToNodes/ContoursToNodes.cpp.
65 """
66
67 #recover options
68 options = pairoptions(*args)
69
70 #some checks
71 if not (path.isfile(filename) or path.isfile(filename + '.shp')):
72 raise RuntimeError('shpread error message: file {} or {}.shp not found!'.format(filename, filename))
73
74 #read shapefile
75 sf = shapefile.Reader(filename)
76
77 Structs = []
78 shapes = sf.shapes()
79 for i, shape in enumerate(shapes):
80 Struct = OrderedDict()
81 if shape.shapeType == shapefile.POINT:
82 Struct['x'] = shape.points[0][0]
83 Struct['y'] = shape.points[0][1]
84 Struct['density'] = 1
85 Struct['Geometry'] = 'Point'
86 elif shape.shapeType == shapefile.POLYLINE:
87 num_points = len(shape.points)
88 x = []
89 y = []
90 for j, point in enumerate(shape.points):
91 x.append(point[0])
92 y.append(point[1])
93 Struct['x'] = x
94 Struct['y'] = y
95 Struct['nods'] = num_points
96 Struct['density'] = 1
97 Struct['closed'] = 1
98 Struct['BoundingBox'] = shape.bbox
99 Struct['Geometry'] = 'Line'
100 elif shape.shapeType == shapefile.POLYGON:
101 num_points = len(shape.points)
102 x = []
103 y = []
104 for j, point in enumerate(shape.points):
105 x.append(point[0])
106 y.append(point[1])
107 Struct['x'] = x
108 Struct['y'] = y
109 Struct['nods'] = num_points
110 Struct['density'] = 1
111 Struct['closed'] = 1
112 Struct['BoundingBox'] = shape.bbox
113 Struct['Geometry'] = 'Polygon'
114 else:
115 # NOTE: We could do this once before looping over shapes as all
116 # shapes in the file must be of the same type, but we would
117 # need to have a second check anyway in order to know how to
118 # parse the points. So, let's just assume the file is not
119 # malformed.
120 #
121 raise Exception('shpread error: geometry {} is not currently supported'.format(shape.shapeTypeName))
122
123 name = ''
124 fields = sf.fields
125 for j in range(1, len(fields)): # skip over first field, which is "DeletionFlag"
126 fieldname = fields[j][0]
127 # 'id' field gets special treatment
128 if fieldname in ['id', 'fid']:
129 name = str(sf.record(i)[j - 1]) # record index is offset by one, again, because of "DeletionFlag"
130 else:
131 setattr(Struct, str(fieldname), sf.record(i)[j - 1]) # cast to string removes "u" from "u'fieldname'"
132 Struct['name'] = name
133 Structs.append(Struct)
134
135 invert = options.getfieldvalue('invert', 0)
136 if invert:
137 for i in range(len(Structs)):
138 Structs[i]['x'] = np.flipud(Structs[i]['x'])
139 Structs[i]['y'] = np.flipud(Structs[i]['y'])
140
141 return Structs
142# }}}
Note: See TracBrowser for help on using the repository browser.