1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
"""
@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 sys
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 = sorted(self._units[type].keys())
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].items():
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())
|