vector.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. """!@package grass.script.vector
  2. @brief GRASS Python scripting module (vector functions)
  3. Vector related functions to be used in Python scripts.
  4. Usage:
  5. @code
  6. from grass.script import vector as grass
  7. grass.vector_db(map)
  8. ...
  9. @endcode
  10. (C) 2008-2010 by the GRASS Development Team
  11. This program is free software under the GNU General Public
  12. License (>=v2). Read the file COPYING that comes with GRASS
  13. for details.
  14. @author Glynn Clements
  15. @author Martin Landa <landa.martin gmail.com>
  16. """
  17. import os
  18. import types
  19. import __builtin__
  20. from core import *
  21. # run "v.db.connect -g ..." and parse output
  22. def vector_db(map, **args):
  23. """!Return the database connection details for a vector map
  24. (interface to `v.db.connect -g'). Example:
  25. \code
  26. >>> grass.vector_db('lakes')
  27. {1: {'layer': 1, 'name': '',
  28. 'database': '/home/martin/grassdata/nc_spm_08/PERMANENT/dbf/',
  29. 'driver': 'dbf', 'key': 'cat', 'table': 'lakes'}}
  30. \endcode
  31. @param map vector map
  32. @param args other v.db.connect's arguments
  33. @return dictionary
  34. """
  35. s = read_command('v.db.connect', flags = 'g', map = map, fs = ';', **args)
  36. result = {}
  37. for l in s.splitlines():
  38. f = l.split(';')
  39. if len(f) != 5:
  40. continue
  41. if '/' in f[0]:
  42. f1 = f[0].split('/')
  43. layer = f1[0]
  44. name = f1[1]
  45. else:
  46. layer = f[0]
  47. name = ''
  48. result[int(layer)] = {
  49. 'layer' : int(layer),
  50. 'name' : name,
  51. 'table' : f[1],
  52. 'key' : f[2],
  53. 'database' : f[3],
  54. 'driver' : f[4] }
  55. return result
  56. def vector_layer_db(map, layer):
  57. """!Return the database connection details for a vector map layer.
  58. If db connection for given layer is not defined, fatal() is called.
  59. @param map map name
  60. @param layer layer number
  61. @return parsed output
  62. """
  63. try:
  64. f = vector_db(map)[int(layer)]
  65. except KeyError:
  66. fatal(_("Database connection not defined for layer %s") % layer)
  67. return f
  68. # run "v.info -c ..." and parse output
  69. def vector_columns(map, layer = None, getDict = True, **args):
  70. """!Return a dictionary (or a list) of the columns for the
  71. database table connected to a vector map (interface to `v.info
  72. -c').
  73. @code
  74. >>> vector_columns(urbanarea, getDict = True)
  75. {'UA_TYPE': {'index': 4, 'type': 'CHARACTER'}, 'UA': {'index': 2, 'type': 'CHARACTER'}, 'NAME': {'index': 3, 'type': 'CHARACTER'}, 'OBJECTID': {'index': 1, 'type': 'INTEGER'}, 'cat': {'index': 0, 'type': 'INTEGER'}}
  76. >>> vector_columns(urbanarea, getDict = False)
  77. ['cat', 'OBJECTID', 'UA', 'NAME', 'UA_TYPE']
  78. @endcode
  79. @param map map name
  80. @param layer layer number or name (None for all layers)
  81. @param getDict True to return dictionary of columns otherwise list of column names is returned
  82. @param args (v.info's arguments)
  83. @return dictionary/list of columns
  84. """
  85. s = read_command('v.info', flags = 'c', map = map, layer = layer, quiet = True, **args)
  86. if getDict:
  87. result = dict()
  88. else:
  89. result = list()
  90. i = 0
  91. for line in s.splitlines():
  92. ctype, cname = line.split('|')
  93. if getDict:
  94. result[cname] = { 'type' : ctype,
  95. 'index' : i }
  96. else:
  97. result.append(cname)
  98. i+=1
  99. return result
  100. # add vector history
  101. def vector_history(map):
  102. """!Set the command history for a vector map to the command used to
  103. invoke the script (interface to `v.support').
  104. @param map mapname
  105. @return v.support output
  106. """
  107. run_command('v.support', map = map, cmdhist = os.environ['CMDLINE'])
  108. # run "v.info -t" and parse output
  109. def vector_info_topo(map):
  110. """!Return information about a vector map (interface to `v.info
  111. -t'). Example:
  112. \code
  113. >>> grass.vector_info_topo('lakes')
  114. {'kernels': 0, 'lines': 0, 'centroids': 15279,
  115. 'boundaries': 27764, 'points': 0, 'faces': 0,
  116. 'primitives': 43043, 'islands': 7470, 'nodes': 35234, 'map3d': False, 'areas': 15279}
  117. \endcode
  118. @param map map name
  119. @return parsed output
  120. """
  121. s = read_command('v.info', flags = 't', map = map)
  122. ret = parse_key_val(s, val_type = int)
  123. if 'map3d' in ret:
  124. ret['map3d'] = bool(ret['map3d'])
  125. return ret
  126. # run "v.info -get ..." and parse output
  127. def vector_info(map):
  128. """!Return information about a vector map (interface to
  129. `v.info'). Example:
  130. \code
  131. >>> grass.vector_info('random_points')
  132. {'comment': '', 'projection': 'x,y', 'creator': 'soeren', 'holes': 0,
  133. 'primitives': 20, 'kernels': 0, 'scale': '1:1', 'title': '',
  134. 'west': 0.046125489999999998, 'top': 2376.133159, 'boundaries': 0,
  135. 'location': 'XYLocation', 'nodes': 0, 'east': 0.97305646000000001,
  136. 'source_date': 'Mon Aug 29 10:55:57 2011', 'north': 0.9589993,
  137. 'format': 'native', 'faces': 0, 'centroids': 0,
  138. 'digitization_threshold': '0.000000', 'islands': 0, 'level': 2,
  139. 'mapset': 'test', 'areas': 0, 'name': 'random_points',
  140. 'database': '/home/soeren/grassdata', 'bottom': 22.186596999999999,
  141. 'lines': 0, 'points': 20, 'map3d': True, 'volumes': 0, 'num_dblinks': 0,
  142. 'organization': '', 'south': 0.066047099999999997}
  143. \endcode
  144. @param map map name
  145. @return parsed vector info
  146. """
  147. s = read_command('v.info', flags = 'get', map = map)
  148. kv = parse_key_val(s)
  149. for k in ['north', 'south', 'east', 'west', 'top', 'bottom']:
  150. kv[k] = float(kv[k])
  151. for k in ['level', 'num_dblinks']:
  152. kv[k] = int(kv[k])
  153. for k in ['nodes', 'points', 'lines', 'boundaries', 'centroids', 'areas', 'islands', 'primitives']:
  154. kv[k] = int(kv[k])
  155. if 'map3d' in kv:
  156. kv['map3d'] = bool(int(kv['map3d']))
  157. if kv['map3d']:
  158. for k in ['faces', 'kernels', 'volumes', 'holes']:
  159. kv[k] = int(kv[k])
  160. return kv
  161. # interface for v.db.select
  162. def vector_db_select(map, layer = 1, **kwargs):
  163. """!Get attribute data of selected vector map layer.
  164. Function returns list of columns and dictionary of values ordered by
  165. key column value. Example:
  166. \code
  167. >>> print grass.vector_db_select('lakes')['columns']
  168. ['cat', 'AREA', 'PERIMETER', 'FULL_HYDRO', 'FULL_HYDR2', 'FTYPE', 'FCODE', 'NAME']
  169. >>> print grass.vector_db_select('lakes')['values'][3]
  170. ['3', '19512.86146', '708.44683', '4', '55652', 'LAKE/POND', '39000', '']
  171. >>> print grass.vector_db_select('lakes', columns = 'FTYPE')['values'][3]
  172. ['LAKE/POND']
  173. \endcode
  174. @param map map name
  175. @param layer layer number
  176. @param kwargs v.db.select options
  177. @return dictionary ('columns' and 'values')
  178. """
  179. try:
  180. key = vector_db(map = map)[layer]['key']
  181. except KeyError:
  182. error(_('Missing layer %(layer)d in vector map <%(map)s>') % \
  183. { 'layer' : layer, 'map' : map })
  184. return { 'columns' : [], 'values' : {} }
  185. if 'columns' in kwargs:
  186. if key not in kwargs['columns'].split(','):
  187. # add key column if missing
  188. debug("Adding key column to the output")
  189. kwargs['columns'] += ',' + key
  190. ret = read_command('v.db.select',
  191. map = map,
  192. layer = layer,
  193. **kwargs)
  194. if not ret:
  195. error(_('vector_db_select() failed'))
  196. return { 'columns' : [], 'values' : {} }
  197. columns = []
  198. values = {}
  199. for line in ret.splitlines():
  200. if not columns:
  201. columns = line.split('|')
  202. key_index = columns.index(key)
  203. continue
  204. value = line.split('|')
  205. key_value = int(value[key_index])
  206. values[key_value] = line.split('|')
  207. return { 'columns' : columns,
  208. 'values' : values }
  209. # interface to v.what
  210. def vector_what(map, coord, distance = 0.0, ttype = None):
  211. """!Query vector map at given locations
  212. To query one vector map at one location
  213. @code
  214. print grass.vector_what(map = 'archsites', coord = (595743, 4925281), distance = 250)
  215. [{'Category': 8, 'Map': 'archsites', 'Layer': 1, 'Key_column': 'cat',
  216. 'Database': '/home/martin/grassdata/spearfish60/PERMANENT/dbf/',
  217. 'Mapset': 'PERMANENT', 'Driver': 'dbf',
  218. 'Attributes': {'str1': 'No_Name', 'cat': '8'},
  219. 'Table': 'archsites', 'Type': 'Point', 'Id': 8}]
  220. @endcode
  221. To query one vector map at more locations
  222. @code
  223. for q in grass.vector_what(map = ('archsites', 'roads'), coord = (595743, 4925281),
  224. distance = 250):
  225. print q['Map'], q['Attributes']
  226. archsites {'str1': 'No_Name', 'cat': '8'}
  227. roads {'label': 'interstate', 'cat': '1'}
  228. @endcode
  229. To query more vector maps at one location
  230. @code
  231. for q in grass.vector_what(map = 'archsites', coord = [(595743, 4925281), (597950, 4918898)],
  232. distance = 250):
  233. print q['Map'], q['Attributes']
  234. archsites {'str1': 'No_Name', 'cat': '8'}
  235. archsites {'str1': 'Bob_Miller', 'cat': '22'}
  236. @endcode
  237. @param map vector map(s) to query given as string or list/tuple
  238. @param coord coordinates of query given as tuple (easting, northing) or list of tuples
  239. @param distance query threshold distance (in map units)
  240. @param ttype list of topology types (default of v.what are point, line, area, face)
  241. @return parsed list
  242. """
  243. if "LC_ALL" in os.environ:
  244. locale = os.environ["LC_ALL"]
  245. os.environ["LC_ALL"] = "C"
  246. if type(map) in (types.StringType, types.UnicodeType):
  247. map_list = [map]
  248. else:
  249. map_list = map
  250. layer_list = ['-1'] * len(map_list)
  251. coord_list = list()
  252. if type(coord) is types.TupleType:
  253. coord_list.append('%f,%f' % (coord[0], coord[1]))
  254. else:
  255. for e, n in coord:
  256. coord_list.append('%f,%f' % (e, n))
  257. cmdParams = dict(quiet = True,
  258. flags = 'ag',
  259. map = ','.join(map_list),
  260. layer = ','.join(layer_list),
  261. coordinates = ','.join(coord_list),
  262. distance = float(distance))
  263. if ttype:
  264. cmdParams['type'] = ','.join(ttype)
  265. ret = read_command('v.what',
  266. **cmdParams)
  267. if "LC_ALL" in os.environ:
  268. os.environ["LC_ALL"] = locale
  269. data = list()
  270. if not ret:
  271. return data
  272. dict_attrb = None
  273. for item in ret.splitlines():
  274. try:
  275. key, value = __builtin__.map(lambda x: x.strip(), item.split('=', 1))
  276. except ValueError:
  277. continue
  278. if key in ('East', 'North'):
  279. continue
  280. if key == 'Map':
  281. dict_main = { 'Map' : value }
  282. dict_attrb = None
  283. data.append(dict_main)
  284. continue
  285. else:
  286. if dict_attrb is not None:
  287. dict_attrb[key] = value
  288. else:
  289. if key in ('Category', 'Layer', 'Id'):
  290. dict_main[key] = int(value)
  291. else:
  292. dict_main[key] = value
  293. if key == 'Key_column':
  294. # skip attributes
  295. dict_attrb = dict()
  296. dict_main['Attributes'] = dict_attrb
  297. return data