123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- """
- @package core.units
- @brief Units management
- .. todo::
- Probably will be replaced by Python ctypes fns in the near future(?)
- Usage:
- from core.units import Units
- Classes:
- - units::BaseUnits
- (C) 2009, 2011 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Martin Landa <landa.martin gmail.com>
- """
- import math
- if __name__ == '__main__':
- import os
- import sys
- from core.utils import _
- class BaseUnits:
- def __init__(self):
- self._units = dict()
- self._units['length'] = { 0 : { 'key' : 'mu', 'label' : _('map units') },
- 1 : { 'key' : 'me', 'label' : _('meters') },
- 2 : { 'key' : 'km', 'label' : _('kilometers') },
- 3 : { 'key' : 'mi', 'label' : _('miles') },
- 4 : { 'key' : 'ft', 'label' : _('feet') } }
-
- self._units['area'] = { 0 : { 'key' : 'mu', 'label' : _('sq map units') },
- 1 : { 'key' : 'me', 'label' : _('sq meters') },
- 2 : { 'key' : 'km', 'label' : _('sq kilometers') },
- 3 : { 'key' : 'ar', 'label' : _('acres') },
- 4 : { 'key' : 'ht', 'label' : _('hectares') } }
- def GetUnitsList(self, type):
- """Get list of units (their labels)
-
- :param type: units type ('length' or 'area')
-
- :return: list of units labels
- """
- result = list()
- try:
- keys = self._units[type].keys()
- keys.sort()
- for idx in keys:
- result.append(self._units[type][idx]['label'])
- except KeyError:
- pass
-
- return result
- def GetUnitsKey(self, type, index):
- """Get units key based on index
-
- :param type: units type ('length' or 'area')
- :param index: units index
- """
- return self._units[type][index]['key']
- def GetUnitsIndex(self, type, key):
- """Get units index based on key
-
- :param type: units type ('length' or 'area')
- :param key: units key, e.g. 'me' for meters
- :return: index
- """
- for k, u in self._units[type].iteritems():
- if u['key'] == key:
- return k
- return 0
- Units = BaseUnits()
- def ConvertValue(value, type, units):
- """Convert value from map units to given units
- Inspired by vector/v.to.db/units.c
- :param value: value to be converted
- :param type: units type ('length', 'area')
- :param unit: destination units
- """
- # get map units
- # TODO
-
- f = 1
- if type == 'length':
- if units == 'me':
- f = 1.0
- elif units == 'km':
- f = 1.0e-3
- elif units == 'mi':
- f = 6.21371192237334e-4
- elif units == 'ft':
- f = 3.28083989501312
- else: # -> area
- if units == 'me':
- f = 1.0
- elif units == 'km':
- f = 1.0e-6
- elif units == 'mi':
- f = 3.86102158542446e-7
- elif units == 'ft':
- f = 10.7639104167097
- elif units == 'ar':
- f = 2.47105381467165e-4
- elif units == 'ht':
- f = 1.0e-4
- return f * value
- def formatDist(distance, mapunits):
- """Formats length numbers and units in a nice way.
- Formats length numbers and units as a function of length.
- >>> formatDist(20.56915, 'metres')
- (20.57, 'm')
- >>> formatDist(6983.4591, 'metres')
- (6.983, 'km')
- >>> formatDist(0.59, 'feet')
- (0.59, 'ft')
- >>> formatDist(8562, 'feet')
- (1.622, 'miles')
- >>> formatDist(0.48963, 'degrees')
- (29.38, 'min')
- >>> formatDist(20.2546, 'degrees')
- (20.25, 'deg')
- >>> formatDist(82.146, 'unknown')
- (82.15, 'units')
- Accepted map units are 'meters', 'metres', 'feet', 'degree'.
- Returns 'units' instead of unrecognized units.
- :param distance: map units
- :param mapunits: map units
- From code by Hamish Bowman Grass Development Team 2006.
- """
- if mapunits == 'metres':
- mapunits = 'meters'
- outunits = mapunits
- distance = float(distance)
- divisor = 1.0
- # figure out which units to use
- if mapunits == 'meters':
- if distance > 2500.0:
- outunits = 'km'
- divisor = 1000.0
- else:
- outunits = 'm'
- elif mapunits == 'feet':
- # nano-bug: we match any "feet", but US Survey feet is really
- # 5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
- # miles the tick markers are rounded to the nearest 10th of a
- # mile (528'), the difference in foot flavours is ignored.
- if distance > 5280.0:
- outunits = 'miles'
- divisor = 5280.0
- else:
- outunits = 'ft'
- elif 'degree' in mapunits:
- # was: 'degree' in mapunits and not haveCtypes (for unknown reason)
- if distance < 1:
- outunits = 'min'
- divisor = (1 / 60.0)
- else:
- outunits = 'deg'
- else:
- return (distance, 'units')
- # format numbers in a nice way
- if (distance / divisor) >= 2500.0:
- outdistance = round(distance / divisor)
- elif (distance / divisor) >= 1000.0:
- outdistance = round(distance / divisor, 1)
- elif (distance / divisor) > 0.0:
- outdistance = round(distance / divisor,
- int(math.ceil(3 - math.log10(distance / divisor))))
- else:
- outdistance = float(distance / divisor)
- return (outdistance, outunits)
- def doc_test():
- """Tests the module using doctest
- :return: a number of failed tests
- """
- import doctest
- from core.utils import do_doctest_gettext_workaround
- do_doctest_gettext_workaround()
- return doctest.testmod().failed
- if __name__ == '__main__':
- sys.exit(doc_test())
|