--- measure.py	2012-02-28 12:32:35.000000000 +0100
+++ /Dropbox/Development/dev/python/django/contrib/gis/measure.py	2012-02-23 17:46:25.000000000 +0100
@@ -35,134 +35,16 @@
 Inspired by GeoPy (http://exogen.case.edu/projects/geopy/)
 and Geoff Biggs' PhD work on dimensioned units for robotics.
 """
-__all__ = ['A', 'Area', 'D', 'Distance', 'V', 'Volume', 'W', 'Weight']
+__all__ = ['A', 'Area', 'D', 'Distance']
 from decimal import Decimal
 
-def is_number(obj):
-    return isinstance(obj, (int, float, long, Decimal))
-    
-def pretty_name(obj):
-    if obj.__class__ == type:
-        return obj.__name__
-    return obj.__class__.__name__
-
 class MeasureBase(object):
-    
-    STANDARD_UNIT  = None
-    ALIAS  = {}
-    UNITS  = {}
-    LALIAS = {}
-    
-    def __init__(self, default_unit=None, **kwargs):
-        # The base unit is in meters.
-        value, self._default_unit = self.default_units(kwargs)
-        setattr(self, self.STANDARD_UNIT, value)
-        if default_unit and isinstance(default_unit, str):
-            self._default_unit = default_unit
-            
-    def _get_standard(self):
-        return getattr(self, self.STANDARD_UNIT)
-        
-    def _set_standard(self, value):
-        setattr(self, self.STANDARD_UNIT, value)
-        
-    standard = property(_get_standard, _set_standard)
-    
-    def __len__(self):
-        return len(str(self))
-    
-    def __getattr__(self, name):
-        if name in self.UNITS:
-            return self.standard / self.UNITS[name]
-        else:
-            raise AttributeError('Unknown unit type: %s' % name)
-
-    def __repr__(self):
-        return '%s(%s=%s)' % (pretty_name(self), self._default_unit, getattr(self, self._default_unit))
-
-    def __str__(self):
-        val = getattr(self, self._default_unit)
-        if val == int(val):
-            val = int(val)
-        return '%s %s' % (val, self._default_unit)
-
-    def __cmp__(self, other):
-        if isinstance(other, self.__class__):
-            return cmp(self.standard, other.standard)
-        else:
-            return NotImplemented
-
-    def __add__(self, other):
-        if isinstance(other, self.__class__):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard + other.standard)})
-        else:
-            raise TypeError('%(class)s must be added with %(class)s' % {"class":pretty_name(self)})
-
-    def __iadd__(self, other):
-        if isinstance(other, self.__class__):
-            self.standard += other.standard
-            return self
-        else:
-            raise TypeError('%(class)s must be added with %(class)s' % {"class":pretty_name(self)})
-
-    def __sub__(self, other):
-        if isinstance(other, self.__class__):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard - other.standard)})
-        else:
-            raise TypeError('%(class)s must be subtracted from %(class)s' % {"class":pretty_name(self)})
-
-    def __isub__(self, other):
-        if isinstance(other, self.__class__):
-            self.standard -= other.standard
-            return self
-        else:
-            raise TypeError('%(class)s must be subtracted from %(class)s' % {"class":pretty_name(self)})
-
-    def __mul__(self, other):
-        if is_number(other):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard * other)})
-        else:
-            raise TypeError('%(class)s must be multiplied with number' % {"class":pretty_name(self)})
-
-    def __imul__(self, other):
-        if is_number(other):
-            self.standard *= float(other)
-            return self
-        else:
-            raise TypeError('%(class)s must be multiplied with number' % {"class":pretty_name(self)})
-
-    def __rmul__(self, other):
-        return self * other
-
-    def __div__(self, other):
-        if isinstance(other, self.__class__):
-            return self.standard / other.standard      
-        if is_number(other):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard / other)})
-        else:
-            raise TypeError('%(class)s must be divided with number or %(class)s' % {"class":pretty_name(self)})
-
-    def __idiv__(self, other):
-        if is_number(other):
-            self.standard /= float(other)
-            return self
-        else:
-            raise TypeError('%(class)s must be divided with number' % {"class":pretty_name(self)})
-
-    def __nonzero__(self):
-        return bool(self.standard)            
-    
     def default_units(self, kwargs):
         """
         Return the unit value and the default units specified
         from the given keyword arguments dictionary.
         """
         val = 0.0
-        default_unit = self.STANDARD_UNIT
         for unit, value in kwargs.iteritems():
             if not isinstance(value, float): value = float(value)
             if unit in self.UNITS:
@@ -203,7 +85,6 @@
             raise Exception('Could not find a unit keyword associated with "%s"' % unit_str)
 
 class Distance(MeasureBase):
-    STANDARD_UNIT = "m"
     UNITS = {
         'chain' : 20.1168,
         'chain_benoit' : 20.116782,
@@ -236,7 +117,6 @@
         'survey_ft' : 0.304800609601,
         'um' : 0.000001,
         'yd': 0.9144,
-        'pt': 0.0254 / 72,
         }
 
     # Unit aliases for `UNIT` terms encountered in Spatial Reference WKT.
@@ -276,155 +156,181 @@
         'US survey foot' : 'survey_ft',
         'U.S. Foot' : 'survey_ft',
         'Yard (Indian)' : 'indian_yd',
-        'Yard (Sears)' : 'sears_yd',
-        'Point': 'pt',
-        'Pixel': 'pt',
+        'Yard (Sears)' : 'sears_yd'
         }
     LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])
 
+    def __init__(self, default_unit=None, **kwargs):
+        # The base unit is in meters.
+        self.m, self._default_unit = self.default_units(kwargs)
+        if default_unit and isinstance(default_unit, str):
+            self._default_unit = default_unit
+
+    def __getattr__(self, name):
+        if name in self.UNITS:
+            return self.m / self.UNITS[name]
+        else:
+            raise AttributeError('Unknown unit type: %s' % name)
+
+    def __repr__(self):
+        return 'Distance(%s=%s)' % (self._default_unit, getattr(self, self._default_unit))
+
+    def __str__(self):
+        return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
+
+    def __cmp__(self, other):
+        if isinstance(other, Distance):
+            return cmp(self.m, other.m)
+        else:
+            return NotImplemented
+
+    def __add__(self, other):
+        if isinstance(other, Distance):
+            return Distance(default_unit=self._default_unit, m=(self.m + other.m))
+        else:
+            raise TypeError('Distance must be added with Distance')
+
+    def __iadd__(self, other):
+        if isinstance(other, Distance):
+            self.m += other.m
+            return self
+        else:
+            raise TypeError('Distance must be added with Distance')
+
+    def __sub__(self, other):
+        if isinstance(other, Distance):
+            return Distance(default_unit=self._default_unit, m=(self.m - other.m))
+        else:
+            raise TypeError('Distance must be subtracted from Distance')
+
+    def __isub__(self, other):
+        if isinstance(other, Distance):
+            self.m -= other.m
+            return self
+        else:
+            raise TypeError('Distance must be subtracted from Distance')
+
     def __mul__(self, other):
-        if isinstance(other, Area):
-            return Volume(default_unit=VOLUME_PREFIX + self._default_unit, 
-                **{VOLUME_PREFIX + self.STANDARD_UNIT: (self.standard * other.standard)})        
-        elif isinstance(other, self.__class__):
-            return Area(default_unit=AREA_PREFIX + self._default_unit, 
-                **{AREA_PREFIX + self.STANDARD_UNIT: (self.standard * other.standard)})
-        elif is_number(other):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard * other)})
-        else:
-            raise TypeError('%(distance)s must be multiplied with number, %(distance)s or %(area)s' % {
-                "distance" : pretty_name(self.__class__),
-                "area"     : pretty_name(Area),
-                })
-            
-AREA_PREFIX = "sq_"
+        if isinstance(other, (int, float, long, Decimal)):
+            return Distance(default_unit=self._default_unit, m=(self.m * float(other)))
+        elif isinstance(other, Distance):
+            return Area(default_unit='sq_' + self._default_unit, sq_m=(self.m * other.m))
+        else:
+            raise TypeError('Distance must be multiplied with number or Distance')
+
+    def __imul__(self, other):
+        if isinstance(other, (int, float, long, Decimal)):
+            self.m *= float(other)
+            return self
+        else:
+            raise TypeError('Distance must be multiplied with number')
+
+    def __rmul__(self, other):
+        return self * other
+
+    def __div__(self, other):
+        if isinstance(other, (int, float, long, Decimal)):
+            return Distance(default_unit=self._default_unit, m=(self.m / float(other)))
+        else:
+            raise TypeError('Distance must be divided with number')
+
+    def __idiv__(self, other):
+        if isinstance(other, (int, float, long, Decimal)):
+            self.m /= float(other)
+            return self
+        else:
+            raise TypeError('Distance must be divided with number')
+
+    def __nonzero__(self):
+        return bool(self.m)
 
 class Area(MeasureBase):
-    STANDARD_UNIT = AREA_PREFIX + Distance.STANDARD_UNIT
     # Getting the square units values and the alias dictionary.
-    UNITS = dict([(AREA_PREFIX + k, v ** 2) for k, v in Distance.UNITS.items()])
-    ALIAS = dict([(k, AREA_PREFIX + v) for k, v in Distance.ALIAS.items()])
+    UNITS = dict([('sq_%s' % k, v ** 2) for k, v in Distance.UNITS.items()])
+    ALIAS = dict([(k, 'sq_%s' % v) for k, v in Distance.ALIAS.items()])
     LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])
 
-    def __div__(self, other):
-        if isinstance(other, self.__class__):
-            return self.standard / other.standard          
-        if isinstance(other, Distance):
-            return Distance(default_unit=self._default_unit[len(AREA_PREFIX):], 
-                **{Distance.STANDARD_UNIT: (self.standard / other.standard)})
-        elif is_number(other):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard / other)})
-        else:
-            raise TypeError('%(area)s must be divided with number, %(distance)s or %(area)s' % {
-                "distance" : pretty_name(Distance),
-                "area"     : pretty_name(self.__class__),
-                }) 
-            
-    def __mul__(self, other):
-        if isinstance(other, Distance):
-            return Volume(default_unit=VOLUME_PREFIX+self._default_unit[len(AREA_PREFIX):], 
-                **{Volume.STANDARD_UNIT: (self.standard * other.standard)})        
-        elif is_number(other):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard * other)})
-        else:
-            raise TypeError('%(area)s must be multiplied with number or %(distance)s' % {
-                "distance" : pretty_name(Distance),
-                "area"     : pretty_name(self.__class__),
-                }) 
-            
-VOLUME_PREFIX = "vol_"
-
-class Volume(MeasureBase):
-    STANDARD_UNIT = VOLUME_PREFIX + Distance.STANDARD_UNIT
-    # Getting the cube units values and the alias dictionary.
-    UNITS = dict([(VOLUME_PREFIX + k, v ** 3) for k, v in Distance.UNITS.items()])
-    ALIAS = dict([(k, VOLUME_PREFIX + v) for k, v in Distance.ALIAS.items()])
-    LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])    
-    
-    def __div__(self, other):
-        if isinstance(other, self.__class__):
-            return self.standard / other.standard          
+    def __init__(self, default_unit=None, **kwargs):
+        self.sq_m, self._default_unit = self.default_units(kwargs)
+        if default_unit and isinstance(default_unit, str):
+            self._default_unit = default_unit
+
+    def __getattr__(self, name):
+        if name in self.UNITS:
+            return self.sq_m / self.UNITS[name]
+        else:
+            raise AttributeError('Unknown unit type: ' + name)
+
+    def __repr__(self):
+        return 'Area(%s=%s)' % (self._default_unit, getattr(self, self._default_unit))
+
+    def __str__(self):
+        return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
+
+    def __cmp__(self, other):
         if isinstance(other, Area):
-            return Distance(default_unit=self._default_unit[len(VOLUME_PREFIX):], 
-                **{Distance.STANDARD_UNIT: (self.standard / other.standard)})        
-        if isinstance(other, Distance):
-            return Area(default_unit=AREA_PREFIX+self._default_unit[len(VOLUME_PREFIX):], 
-                **{Area.STANDARD_UNIT: (self.standard / other.standard)})
-        elif is_number(other):
-            return self.__class__(default_unit=self._default_unit, 
-                **{self.STANDARD_UNIT: (self.standard / other)})
-        else:
-            raise TypeError('%(volume)s must be divided with number, %(distance)s, %(area)s or %(volume)s' % {
-                "distance" : pretty_name(Distance),
-                "area"     : pretty_name(Area),
-                "volume"   : pretty_name(self.__class__),
-                })     
-    
-class Weight(MeasureBase):
-    
-    STANDARD_UNIT = "gr"
-    
-    UNITS = {
-        'mg':  1.0 / 1000,
-        'gr':  1.0,
-        'kg':  1.0 * 1000,
-        'q' :  1.0 * 1000 * 100,
-        'ton': 1.0 * 1000 * 1000,
-        }
+            return cmp(self.sq_m, other.sq_m)
+        else:
+            return NotImplemented
 
-    # Unit aliases for `UNIT` terms encountered in Spatial Reference WKT.
-    ALIAS = {
-        'Milligram':  'mg',
-        'Gram':       'gr',
-        'Kilogram':   'kg',
-        'Quintal' :   'q',
-        'Ton' :       'ton',
-        }
-    LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])
+    def __add__(self, other):
+        if isinstance(other, Area):
+            return Area(default_unit=self._default_unit, sq_m=(self.sq_m + other.sq_m))
+        else:
+            raise TypeError('Area must be added with Area')
 
-# Shortcuts
-D = Distance
-A = Area
-V = Volume
-W = Weight
+    def __iadd__(self, other):
+        if isinstance(other, Area):
+            self.sq_m += other.sq_m
+            return self
+        else:
+            raise TypeError('Area must be added with Area')
+
+    def __sub__(self, other):
+        if isinstance(other, Area):
+            return Area(default_unit=self._default_unit, sq_m=(self.sq_m - other.sq_m))
+        else:
+            raise TypeError('Area must be subtracted from Area')
+
+    def __isub__(self, other):
+        if isinstance(other, Area):
+            self.sq_m -= other.sq_m
+            return self
+        else:
+            raise TypeError('Area must be subtracted from Area')
 
+    def __mul__(self, other):
+        if isinstance(other, (int, float, long, Decimal)):
+            return Area(default_unit=self._default_unit, sq_m=(self.sq_m * float(other)))
+        else:
+            raise TypeError('Area must be multiplied with number')
 
-if __name__ == '__main__':
+    def __imul__(self, other):
+        if isinstance(other, (int, float, long, Decimal)):
+            self.sq_m *= float(other)
+            return self
+        else:
+            raise TypeError('Area must be multiplied with number')
 
-    from itertools import product
-    
-    CONSTRUCTORS = {
-        float: lambda cls, val: cls(val),
-        A:     lambda cls, val: cls(**{cls.STANDARD_UNIT:val}),
-        D:     lambda cls, val: cls(**{cls.STANDARD_UNIT:val}),
-        V:     lambda cls, val: cls(**{cls.STANDARD_UNIT:val}),
-    }
-    
-    classes = [D, A, V, float]
-    
-    combs = product(classes, repeat = 2)
-    
-    a_val = 10
-    b_val = 5        
-    
-    for a_class, b_class in combs:
-        
-        print "-----------%s-vs-%s-----------" % (a_class.__name__.title(), b_class.__name__.title())
-        
-        a = CONSTRUCTORS[a_class](a_class, a_val)
-        b = CONSTRUCTORS[b_class](b_class, b_val)
-        
-        for verbose, operator in (("+", "__add__"), ("-", "__sub__"), ("*", "__mul__"), ("/", "__div__")):
-            
-            desc = "%s %s %s" % (a, verbose, b)
-            
-            print desc.ljust(25), ">    ", 
-            
-            try:
-                print getattr(a, operator)(b).__repr__()
-            except Exception, e:
-                print e    
+    def __rmul__(self, other):
+        return self * other
 
+    def __div__(self, other):
+        if isinstance(other, (int, float, long, Decimal)):
+            return Area(default_unit=self._default_unit, sq_m=(self.sq_m / float(other)))
+        else:
+            raise TypeError('Area must be divided with number')
+
+    def __idiv__(self, other):
+        if isinstance(other, (int, float, long, Decimal)):
+            self.sq_m /= float(other)
+            return self
+        else:
+            raise TypeError('Area must be divided with number')
+
+    def __nonzero__(self):
+        return bool(self.sq_m)
+
+# Shortcuts
+D = Distance
+A = Area
