# 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
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 ] * value
default_unit = unit
elif unit in self . НИКНЕЙМЫ :
u = self . НИКНЕЙМЫ [ unit ]
val + = self . UNITS [ u ] * значение
default_unit = u
else :
lower = unit . нижний ()
если ниже в себе . ЕДИНИЦЫ :
val + = self . UNITS [ lower ] * значение
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 . ЕДИНИЦЫ :
вернуть нижний
элиф нижний в 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 = Площадь