Source code for shapeit.measure
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Created on 5/8/19 by Pat Daburu
"""
.. currentmodule:: shapeit.distance
.. moduleauthor:: Pat Daburu <pat@daburu.net>
This module deals with linear distance measurements.
"""
from enum import Enum
import math
from typing import Dict
[docs]class Units(Enum):
"""
These are common distance units.
"""
METERS = 'meters' #: meters
KILOMETERS = 'kilometers' #: kilometers
_meter_conversions: Dict[Units, float] = {
Units.METERS: 1.0, # 1 meter = 1 meter
Units.KILOMETERS: 1000.0 # 1 kilometer = 1000 meters
} #: conversion factors from meters to other linear distance units
[docs]def meters(n: float, units: Units, dimension: int = 1) -> float:
"""
Convert a linear distance to its equivalent in meters.
:param n: the quantity
:param units: the units in which the distance is expressed
:param dimension: the dimensions of the measurement
:return: the equivalent quantity in meters
.. seealso::
:py:class:`Units`
"""
if dimension < 1 or dimension > 3:
raise ValueError("'dimension' must be between 1 and 3.")
return n * (math.pow(_meter_conversions[units], dimension))
[docs]def convert(
n: float,
units: Units,
to: Units,
dimension: int = 1
) -> float:
"""
Convert a quantity defined in one unit to its equivalent quantity in another
unit.
:param n: the quantity
:param units: the units
:param to: the conversion units
:param dimension: the dimensionality of `n`
:return: the equivalent units
:raises ValueError: if the ``dimension`` parameter is not ``1``, ``2``, or
``3``
.. note::
If the units represent a square (*e.g.* "square meters"), the
``dimension`` parameter should be ``2``. If it's cubic
(*e.g.* "cubic meters"), ``dimension`` should be ``3``. For linear
distances, use the default (``1``).
"""
# Sanity Check: If the original units and the target units are the same...
if units == to:
# ...just return the original quantity.
return n
if dimension < 1 or dimension > 3:
raise ValueError("'dimension' must be between 1 and 3.")
# Get the quantity in meters. Notice that if we're working with 2
# dimensions (squares) or 3 dimensions (cubes) we only want the length
# of one "side".
m1d = meters(
n=(
n if dimension == 1
else math.pow(n, (1.0/float(dimension))) # nth root
),
units=units,
dimension=1 # We've already reduced `n` to one dimension.
)
# Convert the 1-dimensional length in meters to its equivalent in the
# target units.
to1d = m1d/_meter_conversions[to]
# Now restore the original dimensionality and return the value.
return (
to1d if dimension == 1
else math.pow(to1d, dimension)
)