You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			181 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			181 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
"""UnitDbl module."""
 | 
						|
 | 
						|
import functools
 | 
						|
import operator
 | 
						|
 | 
						|
from matplotlib import _api
 | 
						|
 | 
						|
 | 
						|
class UnitDbl:
 | 
						|
    """Class UnitDbl in development."""
 | 
						|
 | 
						|
    # Unit conversion table.  Small subset of the full one but enough
 | 
						|
    # to test the required functions.  First field is a scale factor to
 | 
						|
    # convert the input units to the units of the second field.  Only
 | 
						|
    # units in this table are allowed.
 | 
						|
    allowed = {
 | 
						|
        "m": (0.001, "km"),
 | 
						|
        "km": (1, "km"),
 | 
						|
        "mile": (1.609344, "km"),
 | 
						|
 | 
						|
        "rad": (1, "rad"),
 | 
						|
        "deg": (1.745329251994330e-02, "rad"),
 | 
						|
 | 
						|
        "sec": (1, "sec"),
 | 
						|
        "min": (60.0, "sec"),
 | 
						|
        "hour": (3600, "sec"),
 | 
						|
        }
 | 
						|
 | 
						|
    _types = {
 | 
						|
        "km": "distance",
 | 
						|
        "rad": "angle",
 | 
						|
        "sec": "time",
 | 
						|
        }
 | 
						|
 | 
						|
    def __init__(self, value, units):
 | 
						|
        """
 | 
						|
        Create a new UnitDbl object.
 | 
						|
 | 
						|
        Units are internally converted to km, rad, and sec.  The only
 | 
						|
        valid inputs for units are [m, km, mile, rad, deg, sec, min, hour].
 | 
						|
 | 
						|
        The field UnitDbl.value will contain the converted value.  Use
 | 
						|
        the convert() method to get a specific type of units back.
 | 
						|
 | 
						|
        = ERROR CONDITIONS
 | 
						|
        - If the input units are not in the allowed list, an error is thrown.
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - value     The numeric value of the UnitDbl.
 | 
						|
        - units     The string name of the units the value is in.
 | 
						|
        """
 | 
						|
        data = _api.check_getitem(self.allowed, units=units)
 | 
						|
        self._value = float(value * data[0])
 | 
						|
        self._units = data[1]
 | 
						|
 | 
						|
    def convert(self, units):
 | 
						|
        """
 | 
						|
        Convert the UnitDbl to a specific set of units.
 | 
						|
 | 
						|
        = ERROR CONDITIONS
 | 
						|
        - If the input units are not in the allowed list, an error is thrown.
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - units     The string name of the units to convert to.
 | 
						|
 | 
						|
        = RETURN VALUE
 | 
						|
        - Returns the value of the UnitDbl in the requested units as a floating
 | 
						|
          point number.
 | 
						|
        """
 | 
						|
        if self._units == units:
 | 
						|
            return self._value
 | 
						|
        data = _api.check_getitem(self.allowed, units=units)
 | 
						|
        if self._units != data[1]:
 | 
						|
            raise ValueError(f"Error trying to convert to different units.\n"
 | 
						|
                             f"    Invalid conversion requested.\n"
 | 
						|
                             f"    UnitDbl: {self}\n"
 | 
						|
                             f"    Units:   {units}\n")
 | 
						|
        return self._value / data[0]
 | 
						|
 | 
						|
    def __abs__(self):
 | 
						|
        """Return the absolute value of this UnitDbl."""
 | 
						|
        return UnitDbl(abs(self._value), self._units)
 | 
						|
 | 
						|
    def __neg__(self):
 | 
						|
        """Return the negative value of this UnitDbl."""
 | 
						|
        return UnitDbl(-self._value, self._units)
 | 
						|
 | 
						|
    def __bool__(self):
 | 
						|
        """Return the truth value of a UnitDbl."""
 | 
						|
        return bool(self._value)
 | 
						|
 | 
						|
    def _cmp(self, op, rhs):
 | 
						|
        """Check that *self* and *rhs* share units; compare them using *op*."""
 | 
						|
        self.checkSameUnits(rhs, "compare")
 | 
						|
        return op(self._value, rhs._value)
 | 
						|
 | 
						|
    __eq__ = functools.partialmethod(_cmp, operator.eq)
 | 
						|
    __ne__ = functools.partialmethod(_cmp, operator.ne)
 | 
						|
    __lt__ = functools.partialmethod(_cmp, operator.lt)
 | 
						|
    __le__ = functools.partialmethod(_cmp, operator.le)
 | 
						|
    __gt__ = functools.partialmethod(_cmp, operator.gt)
 | 
						|
    __ge__ = functools.partialmethod(_cmp, operator.ge)
 | 
						|
 | 
						|
    def _binop_unit_unit(self, op, rhs):
 | 
						|
        """Check that *self* and *rhs* share units; combine them using *op*."""
 | 
						|
        self.checkSameUnits(rhs, op.__name__)
 | 
						|
        return UnitDbl(op(self._value, rhs._value), self._units)
 | 
						|
 | 
						|
    __add__ = functools.partialmethod(_binop_unit_unit, operator.add)
 | 
						|
    __sub__ = functools.partialmethod(_binop_unit_unit, operator.sub)
 | 
						|
 | 
						|
    def _binop_unit_scalar(self, op, scalar):
 | 
						|
        """Combine *self* and *scalar* using *op*."""
 | 
						|
        return UnitDbl(op(self._value, scalar), self._units)
 | 
						|
 | 
						|
    __mul__ = functools.partialmethod(_binop_unit_scalar, operator.mul)
 | 
						|
    __rmul__ = functools.partialmethod(_binop_unit_scalar, operator.mul)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        """Print the UnitDbl."""
 | 
						|
        return f"{self._value:g} *{self._units}"
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        """Print the UnitDbl."""
 | 
						|
        return f"UnitDbl({self._value:g}, '{self._units}')"
 | 
						|
 | 
						|
    def type(self):
 | 
						|
        """Return the type of UnitDbl data."""
 | 
						|
        return self._types[self._units]
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def range(start, stop, step=None):
 | 
						|
        """
 | 
						|
        Generate a range of UnitDbl objects.
 | 
						|
 | 
						|
        Similar to the Python range() method.  Returns the range [
 | 
						|
        start, stop) at the requested step.  Each element will be a
 | 
						|
        UnitDbl object.
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - start     The starting value of the range.
 | 
						|
        - stop      The stop value of the range.
 | 
						|
        - step      Optional step to use.  If set to None, then a UnitDbl of
 | 
						|
                      value 1 w/ the units of the start is used.
 | 
						|
 | 
						|
        = RETURN VALUE
 | 
						|
        - Returns a list containing the requested UnitDbl values.
 | 
						|
        """
 | 
						|
        if step is None:
 | 
						|
            step = UnitDbl(1, start._units)
 | 
						|
 | 
						|
        elems = []
 | 
						|
 | 
						|
        i = 0
 | 
						|
        while True:
 | 
						|
            d = start + i * step
 | 
						|
            if d >= stop:
 | 
						|
                break
 | 
						|
 | 
						|
            elems.append(d)
 | 
						|
            i += 1
 | 
						|
 | 
						|
        return elems
 | 
						|
 | 
						|
    def checkSameUnits(self, rhs, func):
 | 
						|
        """
 | 
						|
        Check to see if units are the same.
 | 
						|
 | 
						|
        = ERROR CONDITIONS
 | 
						|
        - If the units of the rhs UnitDbl are not the same as our units,
 | 
						|
          an error is thrown.
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - rhs     The UnitDbl to check for the same units
 | 
						|
        - func    The name of the function doing the check.
 | 
						|
        """
 | 
						|
        if self._units != rhs._units:
 | 
						|
            raise ValueError(f"Cannot {func} units of different types.\n"
 | 
						|
                             f"LHS: {self._units}\n"
 | 
						|
                             f"RHS: {rhs._units}")
 |