# Copyright (c) 2007, Роберт Коуп <[email protected]>
# Все права защищены.
#
# Распространение и использование в исходной и двоичной формах, с модификациями или без,
# разрешены при соблюдении следующих условий:
#
# 1. При повторном распространении исходного кода должно сохраняться указанное выше уведомление об авторских правах,
# этот список условий и следующие отказ от ответственности.
#
# 2. При повторном распространении в двоичной форме должно воспроизводиться
#
указанное выше уведомление об авторских правах, этот список условий и следующий отказ от ответственности в # документации и / или других материалах, поставляемых с распространением.
#
# 3. Запрещается использование ни названия Distance, ни имен участников.
# для поддержки или продвижения продуктов, созданных на основе этого программного обеспечения, без
# специального предварительного письменного разрешения.
#
# ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ ОБОБЩАЮЩИМИ АВТОРСКИМИ ПРАВАМИ И СОСТАВЛЯМИ «КАК ЕСТЬ» И
# ЛЮБЫМИ ЯВНЫМИ ИЛИ ПОДРАЗУМЕВАЕМЫМИ ГАРАНТИЯМИ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ПОДРАЗУМЕВАЕМЫЕ
# ГАРАНТИИ ТОВАРНОСТИ И ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ # ПРЕДОСТАВЛЕНИЯ
. НИ ПРИ
КАКИХ
ОБСТОЯТЕЛЬСТВАХ ВЛАДЕЛЕЦ АВТОРСКИХ ПРАВ ИЛИ СОСТАВНИКИ НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ, ПРИМЕРНЫЕ ИЛИ КОСВЕННЫЕ УБЫТКИ (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ЗАКУПКИ ТОВАРОВ ИЛИ УСЛУГ
ЗАМЕНЫ, ПОТЕРИ НАС ИЛИ ПРИБЫЛЬ; ИЛИ ПЕРЕРЫВ В ДЕЯТЕЛЬНОСТИ) ПО ПРИЧИНЕ
# ЛЮБАЯ ТЕОРИЯ ОТВЕТСТВЕННОСТИ, ЛИБО ПО КОНТРАКТУ, СТРОГОЙ ОТВЕТСТВЕННОСТИ ИЛИ ПЕРЕДАЧИ
# (ВКЛЮЧАЯ НЕБРЕЖНОСТЬ ИЛИ ИНОЕ), ВОЗНИКАЮЩАЯ ЛЮБОЙ СПОСОБОМ ИСПОЛЬЗОВАНИЯ ДАННОГО
# ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ДАЖЕ ЕСЛИ ПРЕДНАЗНАЧЕНА ВОЗМОЖНОСТЬ ТАКОГО УЩЕРБА.
#
"" "
Объекты Distance и Area для разумного и удобного расчета
и преобразования.
Авторы: Роберт Коуп, Джастин Бронн, Риккардо Ди Вирджилио
Вдохновленный GeoPy (https://github.com/geopy/geopy)
и доктором философии Джеффа Биггса, работает над размерными единицами для робототехники.
«»»
От десятичного импорта Decimal
из functools импортирует total_ordering
__all__ = [ 'A' , 'Площадь' , 'D' , 'Расстояние' ]
NUMERIC_TYPES = ( INT , поплавок , Decimal )
AREA_PREFIX = "sq_"
def pretty_name ( obj ):
вернуть объект . __name__ если объект . __class__ == type else obj . __class__ . __название__
@total_ordering
класс MeasureBase :
STANDARD_UNIT = None
ALIAS = {}
UNITS = {}
LALIAS = {}
def __init__ ( self , default_unit = None , ** kwargs ):
значение , self . _default_unit = self . default_units ( kwargs )
setattr ( self , self . STANDARD_UNIT , value ),
если default_unit и isinstance ( default_unit , str ):
self . _default_unit = default_unit
def _get_standard ( self ):
вернуть getattr ( self , self . STANDARD_UNIT )
def _set_standard ( self , значение ):
setattr ( self , self . STANDARD_UNIT , значение )
стандарт = свойство ( _get_standard , _set_standard )
def __getattr__ ( self , name ):
если имя в self . ЕДИНИЦЫ :
вернуть себе . стандарт / сам . UNITS [ имя ]
else :
поднять AttributeError ( 'Неизвестный тип устройства: % s ' % name )
def __repr__ ( self ):
return ' % s ( % s = % s )' % ( pretty_name ( self ), self . _default_unit , getattr ( self , self . _default_unit ))
def __str__ ( self ):
вернуть ' % s % s ' % ( getattr ( self , self . _default_unit ), self . _default_unit )
# **** Методы сравнения ****
def __eq__ ( self , other ):
if isinstance ( other , self . __class__ ):
вернуть self . стандарт == другое . стандарт
else :
return NotImplemented
Защиту __hash__ ( самостоятельно ):
возврат хэш ( самостоятельно . стандарт )
def __lt__ ( self , other ):
if isinstance ( other , self . __class__ ):
вернуть self . стандартный < другой . стандарт
else :
return NotImplemented
# **** Операторы методы ****
def __add__ ( self , other ):
if isinstance ( other , self . __class__ ):
вернуть self . __class__ (
default_unit = self . _default_unit ,
** { self . STANDARD_UNIT : ( self . standard + other . standard )}
)
else :
поднять TypeError ( ' % (class) sдолжен быть добавлен с помощью % (class) s ' % { "class" : pretty_name ( self )})
def __iadd__ ( self , other ):
if isinstance ( other , self . __class__ ):
self . стандарт + = другое . стандартный
возврат self
else :
raise TypeError ( ' % (class) s должен быть добавлен с % (class) s ' % { "class" : pretty_name ( self )})
def __sub__ ( self , other ):
if isinstance ( other , self . __class__ ):
вернуть self . __class__ (
default_unit = self . _default_unit ,
** { self . STANDARD_UNIT : ( self . standard - other . standard )}
)
else :
поднять TypeError ( ' % (class) sдолжно быть вычтено из % (class) s ' % { "class" : pretty_name ( self )})
def __isub__ ( self , other ):
if isinstance ( other , self . __class__ ):
self . стандарт - = другое . стандартный
возврат self
else :
raise TypeError ( ' % (class) s необходимо вычесть из % (class) s ' % { "class" : pretty_name ( self )})
def __mul__ ( self , other ):
if isinstance ( other , NUMERIC_TYPES ):
вернуть self . __class__ (
default_unit = self . _default_unit ,
** { self . STANDARD_UNIT : ( self . standard * other )}
)
else :
raise TypeError ( ' % (class) s необходимо умножить на число' % {"class" : pretty_name ( self )})
def __imul__ ( self , other ):
if isinstance ( other , NUMERIC_TYPES ):
self . standard * = float ( other )
return self
else :
raise TypeError ( ' % (class) s необходимо умножить на число' % { "class" : pretty_name ( self )})
def __rmul__ ( self , other ):
вернуть self * other
def __truediv__ ( self , other ):
if isinstance ( other , self . __class__ ):
вернуть self . стандартный / прочее . стандартный,
если isinstance ( другой , NUMERIC_TYPES ):
вернуть себя . __class__ (
default_unit = self . _default_unit ,
** { self . STANDARD_UNIT : ( self. стандартный / другой )}
)
else :
raise TypeError ( ' % (class) s должен быть разделен на число или % (class) s ' % { "class" : pretty_name ( self )})
def __itruediv__ ( self , other ):
if isinstance ( other , NUMERIC_TYPES ):
self . standard / = float ( other )
return self
else :
raise TypeError ( ' % (class) s должен быть разделен на число' % { "class" : pretty_name ( self )})
Защиту __bool__ ( самостоятельно ):
возврат BOOL ( самостоятельно . стандарт )
def default_units ( self , kwargs ):
"" "
Возвращает значение единицы измерения и единицы измерения по умолчанию, указанные
из заданного словаря аргументов ключевого слова.
" ""
val = 0.0
default_unit = self . STANDARD_UNIT
для единицы , значение в кваргах . items ():
if not isinstance ( value , float ):
value = float ( value )
if unit в себе . ЕДИНИЦЫ :
val + = self . UNITS [ unit ] * значение
default_unit = unit
elif unit in self . НИКНЕЙМЫ :
u = self . НИКНЕЙМЫ [ unit ]
val + = self . ЕДИНИЦЫ [ u ] * значение
default_unit = u
else :
lower = unit . нижний ()
если ниже в себе . ЕДИНИЦЫ :
val + = self . UNITS [ lower ] * value
default_unit = lower
elif lower in self . ЛАЛИАС :
u = я . ЛАЛИАС [ нижний ]
val + = self . UNITS [ u ] * значение
default_unit = u
else :
поднять AttributeError( 'Неизвестный тип устройства: % s ' % unit )
return val , default_unit
@classmethod
def unit_attname ( cls , unit_str ):
"" "
Получить имя атрибута единицы для заданной строки единицы измерения.
Например, если данная строка единицы измерения -" метр ", вернуть" m ".
Вызвать исключение, если атрибут не может быть найдено.
"" "
lower = unit_str . lower (),
если unit_str в cls . UNITS :
вернуть unit_str
elif ниже в cls . ЕДИНИЦЫ :
вернуть нижний
elif lower в cls . ЛАЛИАС :
вернуть cls . LALIAS [ lower ]
else :
raise Exception ( 'Не удалось найти ключевое слово юнита, связанное с " % s "' % unit_str )
[DOCS] класс Расстояние ( MeasureBase ):
STANDARD_UNIT = "м"
ЕДИНИЦЫ = {
'цепь' : 20,1168 ,
'chain_benoit' : 20,116782 ,
'chain_sears' : 20.1167645 ,
'british_chain_benoit' : 20.1167824944 ,
'british_chain_sears' : 20.1167651216 ,
'british_chain_sears_truncated' : 20,116756 ,
«см» : 0,01 ,
«британский_фт» : 0.304799471539 , г.
'british_yd' : 0,914398414616 ,
'clarke_ft' : 0,3047972654 ,
'clarke_link' : 0,201166195164 ,
'сажень' : 1,8288 ,
'фут' : 0,3048 ,
'Ферлонг' : 201.168 ,
'german_m' : 1.0000135965 ,
'gold_coast_ft' : 0.304799710181508 ,
«indian_yd ' : 0,914398530744 ,
' дюйм ' : 0,0254 ,
' км ' : 1000,0 ,
'ссылка ' : 0.201168 ,
'link_benoit' : 0.20116782 ,
'link_sears' : 0.20116765 ,
'm' : 1.0 ,
'mi' : 1609.344 ,
'mm' : 0.001 ,
'nm' : 1852.0 ,
'nm_uk' : 1853.184 ,
'rod' : 5.0292 ,
'sears_yd' : 0,91439841 ,
'Survey_ft' : 0,304800609601 ,
'um' : 0,000001 ,
'yd' : 0,9144 ,
}
# Псевдонимы единиц для терминов UNIT, встречающиеся в пространственной привязке WKT.
ALIAS = {
'сантиметр' : 'см' ,
'фут' : 'фут' ,
'дюймы' : 'дюйм' ,
'километр' : 'км' ,
'километр' : 'км' ,
'метр' : 'м' ,
«метр» : «м» ,
«микрометр» : «эм» ,
«микрометр» : «эм» ,
«миллиметр»
'мм' ,
'миля' : 'mi' ,
'ярд' : 'ярд' ,
'британская цепочка (Benoit 1895 B)' : 'british_chain_benoit' ,
'британская цепочка (Sears 1922)' : 'british_chain_sears' ,
'британская цепочка (Sears 1922 усечено ) ' : ' british_chain_sears_truncated ' ,
' British foot (Sears 1922) ' : ' british_ft ' ,
' British Foot ' : ' british_ft ' ,
' British Yard (Sears 1922) ' : ' british_yd ' ,
'Британский двор' : 'british_yd' ,
"Clarke's Foot" : 'clarke_ft' ,
"Clarke's link" : 'clarke_link' ,
'Chain (Benoit)' : 'chain_benoit' ,
'Chain (Sears)' : 'chain_sears' ,
'Foot (International)' : 'ft' ,
'Furrow Long' : 'furlong' ,
'German Legal meter' : 'german_m' ,
'Gold Coast foot' : 'gold_coast_ft' ,
'индийский двор' : 'indian_yd' ,
'Ссылка (Бенуа) ' : ' link_benoit ' ,
' Ссылка (Sears) ' : 'link_sears' ,
'Nautical Mile' : 'нм' ,
'Nautical Mile (Великобритания)' : 'nm_uk' ,
'США опрос лапка' : 'survey_ft' ,
'США Foot' : 'survey_ft' ,
'Yard (индийский)' : 'indian_yd' ,
'Yard (Sears)' : 'sears_yd'
}
LALIAS = { k . понизить (): V для к , V в АЛИАС . items ()}
def __mul__ ( self , other ):
if isinstance ( other , self . __class__ ):
return Area (
default_unit = AREA_PREFIX + self . _default_unit ,
** { AREA_PREFIX + self . STANDARD_UNIT : ( self . standard * other . standard )}
)
elif isinstance ( другое , NUMERIC_TYPES ):
вернуть себя . __class__ (
default_unit = self . _default_unit ,
** { self . STANDARD_UNIT : ( self . standard * other )}
)
else :
raise TypeError ( ' % (расстояние) s необходимо умножить на число или % (расстояние) s ' % {
" расстояние " : pretty_name ( self . __class__ ),
})
[документы] класс Area ( MeasureBase ):
STANDARD_UNIT = AREA_PREFIX + Distance . STANDARD_UNIT
# Получение значений квадратных единиц и словаря псевдонимов.
UNITS = { ' % s% s ' % ( AREA_PREFIX , k ): v ** 2 для k , v в расстоянии . ЕДИНИЦЫ . items ()}
АЛИАС = { k : ' % s% s ' % ( AREA_PREFIX , v ) для k , v в Distance . НИКНЕЙМЫ . items ()}
LALIAS = { k . понизить (): V для к , V в АЛИАС . items ()}
def __truediv__ ( self , other ):
if isinstance ( other , NUMERIC_TYPES ):
вернуть self . __class__ (
default_unit = self . _default_unit ,
** { self . STANDARD_UNIT : ( self . standard / other )}
)
else :
raise TypeError ( ' % (class) s должен быть разделен на число' % {"class" : pretty_name ( self )})
# Ярлыки
D = Расстояние
A = Площадь