4 @brief Misc utilities for wxGUI
6 (C) 2007-2009, 2011 by the GRASS Development Team
8 This program is free software under the GNU General Public License
9 (>=v2). Read the file COPYING that comes with GRASS for details.
11 @author Martin Landa <landa.martin gmail.com>
12 @author Jachym Cepicky
24 sys.path.append(os.path.join(globalvar.ETCDIR,
"python"))
30 from debug
import Debug
33 """!Remove redundant whitespace from a string"""
34 return string.join(string.split(text),
' ')
37 """!Platform spefic shlex.split"""
38 if sys.version_info >= (2, 6):
39 return shlex.split(s, posix = (sys.platform !=
"win32"))
40 elif sys.platform ==
"win32":
41 return shlex.split(s.replace(
'\\',
r'\\'))
46 """!Creates GRASS temporary file using defined prefix.
48 @todo Fix path on MS Windows/MSYS
50 @param pref prefer the given path
52 @return Path to file name (string) or None
56 ret = gcmd.RunCommand(
'g.tempfile',
60 tempfile = ret.splitlines()[0].strip()
64 if platform.system() ==
'Windows':
65 tempfile = tempfile.replace(
"/",
"\\")
67 path, file = os.path.split(tempfile)
69 return os.path.join(pref, file)
77 """!Get map name from GRASS command
79 Parameter dcmd can be modified when first parameter is not
82 @param dcmd GRASS command (given as list)
83 @param fullyQualified change map name to be fully qualified
84 @param param params directory
85 @param layerType check also layer type ('raster', 'vector', '3d-raster', ...)
87 @return tuple (name, found)
95 if 'd.grid' == dcmd[0]:
97 elif 'd.geodesic' in dcmd[0]:
99 elif 'd.rhumbline' in dcmd[0]:
101 elif 'labels=' in dcmd[0]:
102 mapname = dcmd[idx].
split(
'=')[1] +
' labels'
105 for idx
in range(len(dcmd)):
107 p, v = dcmd[idx].
split(
'=', 1)
112 params = [(idx, p, v)]
115 if p
in (
'map',
'input',
116 'red',
'blue',
'green',
117 'h_map',
's_map',
'i_map',
118 'reliefmap',
'labels'):
119 params.append((idx, p, v))
122 if len(dcmd) > 1
and '=' not in dcmd[1]:
123 task = gtask.parse_interface(dcmd[0])
124 p = task.get_options()[
'params'][0].get(
'name',
'')
125 params.append((1, p, dcmd[1]))
127 return mapname,
False
129 mapname = params[0][2]
131 if fullyQualified
and '@' not in mapname:
132 if layerType
in (
'raster',
'vector',
'3d-raster',
'rgb',
'his'):
134 if layerType
in (
'raster',
'rgb',
'his'):
138 mapset = grass.find_file(mapname, element = findType)[
'mapset']
139 except AttributeError, e:
144 mapset = grass.gisenv()[
'MAPSET']
147 for i, p, v
in params:
149 dcmd[i] = p +
'=' + v
153 dcmd[i] +=
'@' + mapset
156 for i, p, v
in params:
160 maps.append(dcmd[i].
split(
'=', 1)[1])
161 mapname =
'\n'.join(maps)
163 return mapname, found
166 """!Make layer name SQL compliant, based on G_str_to_sql()
168 @todo: Better use directly GRASS Python SWIG...
170 retName = str(name).strip()
174 retName, mapset = retName.split(
'@')
179 retNameList = list(retName)
180 for c
in retNameList:
181 if not (c >=
'A' and c <=
'Z')
and \
182 not (c >=
'a' and c <=
'z')
and \
183 not (c >=
'0' and c <=
'9'):
184 retNameList[cIdx] =
'_'
186 retName =
''.join(retNameList)
188 if not (retName[0] >=
'A' and retName[0] <=
'Z')
and \
189 not (retName[0] >=
'a' and retName[0] <=
'z'):
190 retName =
'x' + retName[1:]
193 retName = retName +
'@' + mapset
198 """!Convert list of category number to range(s)
200 Used for example for d.vect cats=[range]
202 @param cats category list
204 @return category range string
211 cats =
map(int, cats)
220 if cats[i + next] == cats[j] - 1:
227 catstr +=
'%d-%d,' % (cats[i], cats[i + next])
230 catstr +=
'%d,' % (cats[i])
233 return catstr.strip(
',')
236 """!Get list of available/accessible mapsets
238 @param get method ('all', 'accessible', 'ordered')
240 @return list of mapsets
241 @return None on error
245 if get ==
'all' or get ==
'ordered':
246 ret = gcmd.RunCommand(
'g.mapsets',
253 mapsets = ret.replace(
'\n',
'').strip().
split(
';')
258 if get ==
'accessible' or get ==
'ordered':
259 ret = gcmd.RunCommand(
'g.mapsets',
265 if get ==
'accessible':
266 mapsets = ret.replace(
'\n',
'').strip().
split(
';')
268 mapsets_accessible = ret.replace(
'\n',
'').strip().
split(
';')
269 for mapset
in mapsets_accessible:
270 mapsets.remove(mapset)
271 mapsets = mapsets_accessible + mapsets
278 """!Sort list items (not case-sensitive)"""
279 list.sort(cmp=
lambda x, y: cmp(x.lower(), y.lower()))
282 """!Get list of vector layers
284 @param vector name of vector map
285 @param parent parent window (to show dialog) or None
291 fullname = grass.find_file(name = vector, element =
'vector')[
'fullname']
293 Debug.msg(5,
"utils.GetVectorNumberOfLayers(): vector map '%s' not found" % vector)
296 ret, out, msg = gcmd.RunCommand(
'v.db.connect',
303 sys.stderr.write(_(
"Vector map <%(map)s>: %(msg)s\n") % {
'map' : fullname,
'msg' : msg })
306 Debug.msg(1,
"GetVectorNumberOfLayers(): ret %s" % ret)
308 for line
in out.splitlines():
310 layer = line.split(
';')[0]
312 layer = layer.split(
'/')[0]
317 Debug.msg(3,
"utils.GetVectorNumberOfLayers(): vector=%s -> %s" % \
318 (fullname,
','.join(layers)))
322 def Deg2DMS(lon, lat, string = True, hemisphere = True, precision = 3):
323 """!Convert deg value to dms string
325 @param lon longitude (x)
326 @param lat latitude (y)
327 @param string True to return string otherwise tuple
328 @param hemisphere print hemisphere
329 @param precision seconds precision
331 @return DMS string or tuple of values
332 @return empty string on error
368 slat = __ll_parts(flat, precision = precision)
369 slon = __ll_parts(flon, precision = precision)
372 return slon + hlon +
'; ' + slat + hlat
374 return (slon + hlon, slat + hlat)
377 """!Convert dms value to deg
379 @param lon longitude (x)
380 @param lat latitude (y)
382 @return tuple of converted values
383 @return ValueError on error
385 x = __ll_parts(lon, reverse =
True)
386 y = __ll_parts(lat, reverse =
True)
390 def __ll_parts(value, reverse = False, precision = 3):
391 """!Converts deg to d:m:s string
393 @param value value to be converted
394 @param reverse True to convert from d:m:s to deg
395 @param precision seconds precision (ignored if reverse is True)
397 @return converted value (string/float)
398 @return ValueError on error (reverse == True)
402 return '%s%.*f' % (
'00:00:0', precision, 0.0)
405 m = int((value - d) * 60)
406 s = ((value - d) * 60 - m) * 60
416 s =
'0%.*f' % (precision, s)
418 s =
'%.*f' % (precision, s)
420 return str(d) +
':' + m +
':' + s
423 d, m, s = value.split(
':')
428 d, m = value.split(
':')
442 if hs
not in (
'N',
'S',
'E',
'W'):
450 fs = float(s) / (60 * 60)
452 return coef * (float(d) + fm + fs)
456 Get GRASS command as string.
458 @param cmd GRASS command given as dictionary
460 @return command string
468 if 'flags' in cmd[1]:
469 for flag
in cmd[1][
'flags']:
471 for flag
in (
'verbose',
'quiet',
'overwrite'):
472 if flag
in cmd[1]
and cmd[1][flag]
is True:
475 for k, v
in cmd[1].iteritems():
476 if k
in (
'flags',
'verbose',
'quiet',
'overwrite'):
478 scmd +=
' %s=%s' % (k, v)
483 """!Convert command list to tuple for gcmd.RunCommand()"""
490 key, value = item.split(
'=', 1)
491 dcmd[str(key)] = str(value)
492 elif item[:2] ==
'--':
494 if flag
in (
'verbose',
'quiet',
'overwrite'):
495 dcmd[str(flag)] =
True
497 if 'flags' not in dcmd:
499 dcmd[
'flags'] += item.replace(
'-',
'')
505 """!Check path created by os.path.join"""
506 path = os.path.join(*args)
507 if platform.system() ==
'Windows' and \
509 return path[1].upper() +
':\\' + path[3:].replace(
'/',
'\\')
514 """!Read EPSG code from the file
516 @param path full path to the file with EPSG codes
518 @return dictionary of EPSG code
519 @return string on error
521 epsgCodeDict = dict()
526 return _(
"failed to open '%s'" % path)
530 for line
in f.readlines():
536 descr = line[1:].strip()
538 code, params = line.split(
" ", 1)
540 code = int(code.replace(
'<',
'').replace(
'>',
''))
545 epsgCodeDict[code] = (descr, params)
550 except StandardError, e:
556 """!Reproject coordinates
558 @param coord coordinates given as tuple
559 @param projOut output projection
560 @param projIn input projection (use location projection settings)
562 @return reprojected coordinates (returned as tuple)
565 projIn = gcmd.RunCommand(
'g.proj',
568 coors = gcmd.RunCommand(
'm.proj',
572 stdin =
'%f|%f' % (coord[0], coord[1]),
575 coors = coors.split(
'\t')
577 n = coors[1].
split(
' ')[0].strip()
579 proj = projOut.split(
' ')[0].
split(
'=')[1]
582 if proj
in (
'll',
'latlong',
'longlat')
and 'd' not in flags:
583 return (proj, (e, n))
586 return (proj, (float(e), float(n)))
593 """!Get list of GRASS locations in given dbase
595 @param dbase GRASS database path
597 @return list of locations (sorted)
599 listOfLocations = list()
602 for location
in glob.glob(os.path.join(dbase,
"*")):
604 if os.path.join(location,
"PERMANENT")
in glob.glob(os.path.join(location,
"*")):
605 listOfLocations.append(os.path.basename(location))
608 except UnicodeEncodeError, e:
613 return listOfLocations
616 """!Get list of mapsets in given GRASS location
618 @param dbase GRASS database path
619 @param location GRASS location
620 @param selectable True to get list of selectable mapsets, otherwise all
622 @return list of mapsets - sorted (PERMANENT first)
624 listOfMapsets = list()
627 ret = gcmd.RunCommand(
'g.mapset',
636 for line
in ret.rstrip().splitlines():
637 listOfMapsets += line.split(
' ')
639 for mapset
in glob.glob(os.path.join(dbase, location,
"*")):
640 if os.path.isdir(mapset)
and \
641 os.path.isfile(os.path.join(dbase, location, mapset,
"WIND")):
642 listOfMapsets.append(os.path.basename(mapset))
648 """!Get list of color tables"""
649 ret = gcmd.RunCommand(
'r.colors',
655 return ret.splitlines()
658 """!Decode string using system encoding
660 @param string string to be decoded
662 @return decoded string
667 enc = locale.getdefaultlocale()[1]
669 Debug.msg(5,
"DecodeString(): enc=%s" % enc)
670 return string.decode(enc)
675 """!Return encoded string using system locales
677 @param string string to be encoded
679 @return encoded string
683 enc = locale.getdefaultlocale()[1]
685 Debug.msg(5,
"EncodeString(): enc=%s" % enc)
686 return string.encode(enc)
691 """!Return unicode string
693 @param string string to be converted
695 @return unicode string
697 if isinstance(string, unicode):
700 enc = locale.getdefaultlocale()[1]
702 return unicode(string, enc)
706 def _getGDALFormats():
707 """!Get dictionary of avaialble GDAL drivers"""
708 ret = grass.read_command(
'r.in.gdal',
712 return _parseFormats(ret)
714 def _getOGRFormats():
715 """!Get dictionary of avaialble OGR drivers"""
716 ret = grass.read_command(
'v.in.ogr',
720 return _parseFormats(ret)
722 def _parseFormats(output):
723 """!Parse r.in.gdal/v.in.ogr -f output"""
724 formats = {
'file' : list(),
732 for line
in output.splitlines():
733 format = line.strip().rsplit(
':', -1)[1].strip()
734 if format
in (
'Memory',
'Virtual Raster',
'In Memory Raster'):
736 if format
in (
'PostgreSQL',
'SQLite',
737 'ODBC',
'ESRI Personal GeoDatabase',
739 'PostGIS WKT Raster driver'):
740 formats[
'database'].append(format)
741 elif format
in (
'GeoJSON',
742 'OGC Web Coverage Service',
743 'OGC Web Map Service',
744 'HTTP Fetching Wrapper'):
745 formats[
'protocol'].append(format)
747 formats[
'file'].append(format)
749 for items
in formats.itervalues():
757 """!Get GDAL/OGR formats"""
761 'gdal' : _getGDALFormats(),
762 'ogr' : _getOGRFormats()
768 """!Get full path to the settings directory
771 verFd = open(os.path.join(globalvar.ETCDIR,
"VERSIONNUMBER"))
772 version = int(verFd.readlines()[0].
split(
' ')[0].
split(
'.')[0])
773 except (IOError, ValueError, TypeError, IndexError), e:
774 sys.exit(_(
"ERROR: Unable to determine GRASS version. Details: %s") % e)
778 if sys.platform ==
'win32':
779 return os.path.join(os.getenv(
'APPDATA'),
'.grass%d' % version)
781 return os.path.join(os.getenv(
'HOME'),
'.grass%d' % version)