Skip to content

Commit

Permalink
adds measurements utils - WeightType, DistanceType (hacktoolkit#449)
Browse files Browse the repository at this point in the history
  • Loading branch information
jontsai committed Sep 10, 2024
1 parent 68205ca commit ff29e4b
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 0 deletions.
8 changes: 8 additions & 0 deletions utils/measurements/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .distance import DistanceType
from .weight import WeightType


__all__ = [
'DistanceType',
'WeightType',
]
73 changes: 73 additions & 0 deletions utils/measurements/distance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Python Standard Library Imports
from decimal import Decimal

# Local Imports
from .units import (
ConversionConstants,
convert_unit,
)


C = ConversionConstants.Distance


class DistanceType(Decimal):
"""Class that represents a distance (e.g. length, width, height).
Canonical unit is in meters.
"""

@classmethod
def from_meters(cls, value: Decimal) -> 'DistanceType':
return cls(value)

@classmethod
def from_kilometers(cls, value: Decimal) -> 'DistanceType':
return cls(convert_unit(value, C.KM_TO_M))

@classmethod
def from_feet(cls, value: Decimal) -> 'DistanceType':
return cls(convert_unit(value, C.FT_TO_M))

@classmethod
def from_yards(cls, value: Decimal) -> 'DistanceType':
return cls(convert_unit(value, C.YD_TO_M))

@classmethod
def from_miles(cls, value: Decimal) -> 'DistanceType':
return cls(convert_unit(value, C.MI_TO_M))

##
# NOTE: Lots of helper function follow, sorting rules:
#
# 1. Metric (SI), then Imperial
# 2. Increasing unit sizes
#

@property
def m(self) -> Decimal:
return self

@property
def km(self) -> Decimal:
return convert_unit(self, C.M_TO_KM)

@property
def in_(self) -> Decimal:
return self.inch

@property
def inch(self) -> Decimal:
return convert_unit(self, C.M_TO_IN)

@property
def ft(self) -> Decimal:
return convert_unit(self, C.M_TO_FT)

@property
def yd(self) -> Decimal:
return convert_unit(self, C.M_TO_YD)

@property
def mi(self) -> Decimal:
return convert_unit(self, C.M_TO_MI)
78 changes: 78 additions & 0 deletions utils/measurements/units.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Python Standard Library Imports
import typing as T
from decimal import Decimal


DecimalTypes = T.Union[str, int, float, Decimal]


class ConversionConstants:
"""Constants for converting between different units of measurement.
Reference: https://www.nist.gov/system/files/documents/2019/12/03/00-20-h133-apdxE_final-17.pdf # noqa: E501
"""

class Distance:
"""Constants for converting between different units of distance.
The canonical unit is meters.
"""

# Imperial to Imperial
MI_TO_FT = Decimal('5280')
YD_TO_FT = Decimal('3')
FT_TO_IN = Decimal('12')
IN_TO_FT = Decimal('1') / FT_TO_IN
YD_TO_MI = YD_TO_FT / MI_TO_FT

# Imperial to Metric
IN_TO_M = Decimal('0.0254')
FT_TO_M = Decimal('0.3048')
YD_TO_M = Decimal('0.9144')
MI_TO_M = Decimal('1609.347')

# Metric to Metric
M_TO_MM = Decimal('1000')
M_TO_CM = Decimal('100')
M_TO_M = Decimal('1')
M_TO_KM = Decimal('0.001')

MM_TO_M = Decimal('0.001')
CM_TO_M = Decimal('0.01')
KM_TO_M = Decimal('1000')

# Metric to Imperial
M_TO_FT = Decimal('1.0') / FT_TO_M
M_TO_IN = Decimal('1.0') / IN_TO_M
M_TO_YD = Decimal('1.0') / YD_TO_M
# M_TO_MI = Decimal('1.0') / MI_TO_M
M_TO_MI = Decimal('0.0006213712') # NIST value

class Weight:
"""Constants for converting between different units of weight.
The canonical unit is grams.
"""

# Imperial to Imperial
LB_TO_OZ = Decimal('16')
OZ_TO_LB = Decimal('0.0625')

# Metric to Imperial
G_TO_OZ = Decimal('0.03527396')
G_TO_LB = G_TO_OZ * OZ_TO_LB
KG_TO_OZ = Decimal('35.27396')
KG_TO_LB = Decimal('2.204623')

# Imperial to Metric
OZ_TO_G = Decimal('1.0') / G_TO_OZ
LB_TO_G = LB_TO_OZ * OZ_TO_G
OZ_TO_KG = Decimal('1.0') / KG_TO_OZ

# Metric to Metric
G_TO_KG = Decimal('0.001')
KG_TO_G = Decimal('1000')


def convert_unit(value: DecimalTypes, conversion_constant: DecimalTypes) -> Decimal:
return Decimal(value) * Decimal(conversion_constant)
53 changes: 53 additions & 0 deletions utils/measurements/weight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Python Standard Library Imports
from decimal import Decimal

# Local Imports
from .units import (
ConversionConstants,
convert_unit,
)


C = ConversionConstants.Weight


class WeightType(Decimal):
"""Class that represents weight.
Canonical unit is in grams.
"""

@classmethod
def from_grams(cls, value: Decimal) -> 'WeightType':
return cls(value)

@classmethod
def from_kilograms(cls, value: Decimal) -> 'WeightType':
return cls(convert_unit(value, C.KG_TO_G))

@classmethod
def from_pounds(cls, value: Decimal) -> 'WeightType':
return cls(convert_unit(value, C.LB_TO_G))

##
# NOTE: Lots of helper function follow, sorting rules:
#
# 1. Metric (SI), then Imperial
# 2. Increasing unit sizes
#

@property
def g(self) -> Decimal:
return self

@property
def kg(self) -> Decimal:
return convert_unit(self, C.G_TO_KG)

@property
def oz(self) -> Decimal:
return convert_unit(self, C.G_TO_OZ)

@property
def lb(self) -> Decimal:
return convert_unit(self, C.G_TO_LB)

0 comments on commit ff29e4b

Please sign in to comment.