Guest User

Untitled

a guest
Dec 22nd, 2010
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.45 KB | None | 0 0
  1. class EnvelopeError(Exception):
  2.     pass
  3.  
  4.  
  5. class Envelope(object):
  6.     """
  7.    A 2D envelope specifying the outer bounds of any spatial data
  8.    """
  9.  
  10.     def __init__(self, x_min, y_min, x_max, y_max):
  11.         self.x_min = x_min + 0.0
  12.         self.y_min = y_min + 0.0
  13.         self.x_max = x_max + 0.0
  14.         self.y_max = y_max + 0.0
  15.         try:
  16.             self._assert_valid_envelope()
  17.         except AssertionError:
  18.             err_str = 'Invalid envelope shape'
  19.             raise EnvelopeError(err_str)
  20.  
  21.     def __setattr__(self, attr, val):
  22.         try:
  23.             self._change_coordinate(attr, val)
  24.         except KeyError:
  25.             self.__dict__[attr] = val
  26.  
  27.     def _is_defined(self):
  28.         # Specify the minimum attributes needed to define the
  29.         # bounding box
  30.         attrs = ('x_min', 'y_min', 'x_max', 'y_max')
  31.         for attr in attrs:
  32.             if attr not in self.__dict__:
  33.                 return False
  34.         return True
  35.  
  36.     def _change_coordinate(self, attr, val):
  37.         # Get the existing value in case we need to roll it back
  38.         old_val = self.__dict__[attr]
  39.         self.__dict__[attr] = val
  40.  
  41.         # Test this envelope
  42.         try:
  43.             self._assert_valid_envelope()
  44.         except AssertionError:
  45.             # Roll back the change and then raise the error
  46.             self.__dict__[attr] = old_val
  47.             err_str = 'New value not valid for envelope'
  48.             raise EnvelopeError(err_str)
  49.  
  50.     def _assert_valid_envelope(self):
  51.         # Minimal bounds checking
  52.         assert self.x_min < self.x_max
  53.         assert self.y_min < self.y_max
  54.  
  55.  
  56. class RasterEnvelope(Envelope):
  57.     """
  58.    A 2D envelope specifying the outer bounds and cell size of
  59.    raster data
  60.    """
  61.  
  62.     def __init__(self, x_min, y_max, cell_size, **kwargs):
  63.         self.x_min = x_min + 0.0
  64.         self.y_max = y_max + 0.0
  65.         self.cell_size = cell_size + 0.0
  66.         try:
  67.             self.n_cols = kwargs['n_cols'] + 0
  68.             self.n_rows = kwargs['n_rows'] + 0
  69.             self.x_max = self.x_min + (self.n_cols * self.cell_size)
  70.             self.y_min = self.y_max - (self.n_rows * self.cell_size)
  71.         except KeyError:
  72.             try:
  73.                 self.x_max = kwargs['x_max'] + 0.0
  74.                 self.y_min = kwargs['y_min'] + 0.0
  75.                 self.n_cols = int((self.x_max - self.x_min) / self.cell_size)
  76.                 self.n_rows = int((self.y_max - self.y_min) / self.cell_size)
  77.             except KeyError:
  78.                 err_str = 'Either the number of rows and columns or '
  79.                 err_str += 'the lower-right coordinate was not specified'
  80.                 raise EnvelopeError(err_str)
  81.         try:
  82.             self._assert_valid_envelope()
  83.         except:
  84.             err_str = 'Invalid envelope shape'
  85.             raise EnvelopeError(err_str)
  86.  
  87.         # Ensure that the coordinates snap to window based on
  88.         # cell_size.  Change x_max and y_min if incorrect
  89.         self.x_max = self.x_min + (self.n_cols * self.cell_size)
  90.         self.y_min = self.y_max - (self.n_rows * self.cell_size)
  91.  
  92.     def __setattr__(self, attr, val):
  93.         if attr in ('x_min', 'y_min', 'x_max', 'y_max'):
  94.             try:
  95.                 self._change_coordinate(attr, val)
  96.             except KeyError:
  97.                 self.__dict__[attr] = val
  98.         elif attr in ('n_cols', 'n_rows'):
  99.             try:
  100.                 assert val + 0
  101.                 assert val > 0
  102.                 self.__dict__[attr] = int(val)
  103.             except TypeError:
  104.                 err_str = 'Number of rows or columns must be numeric'
  105.                 raise EnvelopeError(err_str)
  106.             except AssertionError:
  107.                 err_str = 'Number of rows or columns must be greater than 0'
  108.                 raise EnvelopeError(err_str)
  109.         else:
  110.             self.__dict__[attr] = val
  111.  
  112.         if self._is_defined():
  113.             if attr in ('x_min', 'y_min', 'x_max', 'y_max'):
  114.                 self.__dict__['n_cols'] = \
  115.                     int((self.x_max - self.x_min) / self.cell_size)
  116.                 self.__dict__['n_rows'] = \
  117.                     int((self.y_max - self.y_min) / self.cell_size)
  118.             self.__dict__['x_max'] = \
  119.                 self.x_min + (self.n_cols * self.cell_size)
  120.             self.__dict__['y_min'] = \
  121.                 self.y_max - (self.n_rows * self.cell_size)
  122.  
  123. if __name__ == '__main__':
  124.     import unittest
  125.  
  126.     class EnvelopeTest(unittest.TestCase):
  127.  
  128.         def test_default(self):
  129.             e = Envelope(0.0, 0.0, 10.0, 10.0)
  130.             self.assertEqual(e.x_min, 0.0)
  131.             self.assertEqual(e.y_min, 0.0)
  132.             self.assertEqual(e.x_max, 10.0)
  133.             self.assertEqual(e.y_max, 10.0)
  134.  
  135.         def test_incorrect_type(self):
  136.             self.assertRaises(TypeError, Envelope, 's', 'p', 'a', 'm')
  137.  
  138.         def test_insufficient_arguments(self):
  139.             self.assertRaises(TypeError, Envelope, 0.0, 0.0, 10.0)
  140.             self.assertRaises(TypeError, Envelope, 0.0, 0.0, 10.0, 10.0, 10.0)
  141.  
  142.         def test_incorrect_dimensions(self):
  143.             self.assertRaises(EnvelopeError, Envelope, 0.0, 0.0, 0.0, 0.0)
  144.             self.assertRaises(EnvelopeError, Envelope, 10.0, 10.0, 0.0, 0.0)
  145.  
  146.         def test_change_window_errors(self):
  147.             e = Envelope(0.0, 0.0, 10.0, 10.0)
  148.             self.assertRaises(EnvelopeError, setattr, e, 'x_min', 20.0)
  149.             self.assertRaises(EnvelopeError, setattr, e, 'x_max', -10.0)
  150.             self.assertRaises(EnvelopeError, setattr, e, 'y_min', 20.0)
  151.             self.assertRaises(EnvelopeError, setattr, e, 'y_max', -10.0)
  152.  
  153.         def test_additional_attributes(self):
  154.             e = Envelope(0.0, 0.0, 10.0, 10.0)
  155.             e.bob = 'silly_test'
  156.             self.assertEqual(e.x_min, 0.0)
  157.             e.bob = 'silly_test_2'
  158.             self.assertEqual(e.x_min, 0.0)
  159.             self.assertRaises(EnvelopeError, setattr, e, 'x_min', 20.0)
  160.  
  161.     class RasterEnvelopeTest(unittest.TestCase):
  162.  
  163.         def test_default(self):
  164.             re = RasterEnvelope(0.0, 10.0, 1.0, x_max=10.0, y_min=0.0)
  165.             self.assertEqual(re.x_min, 0.0)
  166.             self.assertEqual(re.y_min, 0.0)
  167.             self.assertEqual(re.x_max, 10.0)
  168.             self.assertEqual(re.y_max, 10.0)
  169.             self.assertEqual(re.cell_size, 1.0)
  170.  
  171.             re = RasterEnvelope(0.0, 10.0, 1.0, n_cols=10, n_rows=10)
  172.             self.assertEqual(re.x_min, 0.0)
  173.             self.assertEqual(re.y_min, 0.0)
  174.             self.assertEqual(re.x_max, 10.0)
  175.             self.assertEqual(re.y_max, 10.0)
  176.             self.assertEqual(re.cell_size, 1.0)
  177.  
  178.         def test_insufficient_arguments(self):
  179.             self.assertRaises(EnvelopeError, RasterEnvelope, 0.0, 10.0, 1.0)
  180.             self.assertRaises(EnvelopeError, RasterEnvelope, 0.0, 10.0, 1.0,
  181.                               x_max=10.0, n_rows=10)
  182.  
  183.         def test_incorrect_dimensions(self):
  184.             self.assertRaises(EnvelopeError, RasterEnvelope, 0.0, 10.0, 1.0,
  185.                               x_max=-10.0, y_min=20.0)
  186.             self.assertRaises(EnvelopeError, RasterEnvelope, 0.0, 10.0, 1.0,
  187.                               n_cols=0, n_rows=0)
  188.  
  189.         def test_change_window(self):
  190.             re = RasterEnvelope(0.0, 10.0, 1.0, x_max=10.0, y_min=0.0)
  191.             self.assertRaises(EnvelopeError, setattr, re, 'x_min', 20.0)
  192.             self.assertEqual(re.x_min, 0.0)
  193.  
  194.             self.assertRaises(EnvelopeError, setattr, re, 'n_cols', -1)
  195.             self.assertEqual(re.n_cols, 10)
  196.  
  197.             re.x_max = 8.0
  198.             self.assertEquals(re.n_cols, 8)
  199.  
  200.             re.n_cols = 9
  201.             self.assertEquals(re.x_max, 9.0)
  202.  
  203.         def test_snapping(self):
  204.             # Note that x_min, y_max stay constant for this class which
  205.             # is probably a limitation of its usefulness ...
  206.             #
  207.             # For now, check that changing a dimension less than the
  208.             # cell size resnaps it to the original
  209.             re = RasterEnvelope(0.0, 10.0, 1.0, x_max=10.0, y_min=0.0)
  210.             re.x_max = 10.1
  211.             self.assertEqual(re.x_max, 10.0)
  212.  
  213.             re.n_cols = 10.1
  214.             self.assertEqual(re.n_cols, 10)
  215.  
  216.         def test_nonsensical_changes(self):
  217.             re = RasterEnvelope(0.0, 10.0, 1.0, x_max=10.0, y_min=0.0)
  218.             self.assertRaises(EnvelopeError, setattr, re, 'x_min', 'spam')
  219.             self.assertRaises(EnvelopeError, setattr, re, 'n_cols', 'spam')
  220.  
  221.     unittest.main()
Advertisement
Add Comment
Please, Sign In to add comment