source: TI02-CSML/trunk/services/3rdParty/GeoTypes-0.6.0/GeoTypes/_Box.py @ 2194

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/services/3rdParty/GeoTypes-0.6.0/GeoTypes/_Box.py@2194
Revision 2194, 8.3 KB checked in by lawrence, 13 years ago (diff)

Adding various specs and 3rd party code of interest for the CSML
services development.

Line 
1
2################################################################################
3# Copyright (c) QinetiQ Plc 2003
4#
5# Licensed under the LGPL. For full license details see the LICENSE file.
6################################################################################
7
8"""
9Implementation of Box.
10
11ChangeLog:
12    14 jan 06: Added Box.fromWKT to parse relults from 'extent()' (fredericback@gmail.com)
13    17 jan 06: Change constructor to accept several argument types (fredericback@gmail.com)
14    13 jun 06: Added joinBoxes() (fredericback@gmail.com)
15"""
16
17from _Point import Point, pointFromSequence, pointFromValues
18
19class Box:
20    """
21    Box provides and implementation for a rectangular area in 2d space.
22
23    It has accessor functions for the upper right hand and lower left hand
24    corners of the box, which are Points. It supports equallity operations
25    with other Box objects.
26
27    The constructor accepts the following argument combinations:
28        - Box()                             like Box(Point(0,0), Point(0,0))
29        - Box( '((x.y),(x,y))' )            parse from string, x and y are floats
30        - Box( 'BOX(x y,x y)' )             parse from string, x and y are floats
31        - Box( Point(x,y), Point(x,y) )     set lower left and upper right points
32
33    NOTE: The accessor methods imply that they must recieve the
34    coords for the upper_right and lower_left corners. Passing the wrong
35    corners into the setXXX methods will result in a ValueError being raised.
36    """
37   
38    def __init__(self,*args):
39        """
40        The constructor accepts the following argument combinations:
41            - Box()                             initalise to ((0.0,0.0),(0.0,0.0))
42            - Box( '((x.y),(x,y))' )            parse from string, x and y are floats
43            - Box( 'BOX(x y,x y)' )             parse from string, x and y are floats
44            - Box( Point(x,y), Point(x,y) )     set lower left and upper right points
45        """
46        if len(args) == 0:
47            self._setUpperRight(Point())
48            self._setLowerLeft(Point())
49        elif len(args) == 1:
50
51            if args[0] == None: # avoid api breakage, args[0] may still be None
52                self._setUpperRight(Point())
53                self._setLowerLeft(Point())
54            elif args[0][0] == "B":
55                self.fromWKT(args[0]) # if starts with a "B"
56            else:
57                self.fromString(args[0])
58
59        elif len(args) == 2:
60            self._setUpperRight(args[0])
61            self._setLowerLeft(args[1])
62        else: raise ValueError, "wrong number of arguments"
63
64        self._normaliseCornerCoords()
65       
66    def _normaliseCornerCoords(self):
67        #print self._upper_right
68        xr = self._upper_right.getX()
69        xl = self._lower_left.getX()
70        yu = self._upper_right.getY()
71        yl = self._lower_left.getY()
72
73        if xl>xr and yl>yu:
74            self._upper_right = pointFromValues(xl,yl)
75            self._lower_left  = pointFromValues(xr,yu)                       
76        elif xl>xr:
77            self._upper_right = pointFromValues(xl,yu)
78            self._lower_left  = pointFromValues(xr,yl)           
79        elif yl>yu:
80            self._upper_right = pointFromValues(xr,yl)
81            self._lower_left  = pointFromValues(xl,yu)
82        #print self
83     
84    def fromWKT(self, s):
85        """ Initialise from a WKT string of the form 'BOX(x y,x y)'
86            This syntax is returned by the extent() command in postgis.
87        """
88   
89        try:
90            # skip 'BOX(' and ')'
91            s = s[4:] 
92            s = s[:-1]
93
94            # match
95            import re
96            f = "[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?"
97            e = r"(?P<x1>%s) (?P<y1>%s)\,(?P<x2>%s) (?P<y2>%s)" %(f,f,f,f)
98            points = re.match(e,s).groupdict()
99            # print points
100
101            # set matching results
102            ll = pointFromValues( float(points['x1']),float(points['y1']) )
103            ur = pointFromValues( float(points['x2']),float(points['y2']) )
104        except:
105            raise Exception("Could not parse '%s'" %s) # recast
106
107        self._setUpperRight(ur)
108        self._setLowerLeft(ll)
109        self._normaliseCornerCoords()
110
111    def fromString(self,s):
112        """
113        Initialise the Box from a string.       
114
115        (arg s) should be of the form '((x,y),(x,y))' where x and y are floating
116        point numbers.
117       
118        """       
119        seq = eval(s,{},{})
120        self._setUpperRight(pointFromSequence(seq[0]))
121        self._setLowerLeft(pointFromSequence(seq[1]))
122        self._normaliseCornerCoords()
123       
124    def setUpperRight(self,p):
125        """
126        Set the upper right corner of the Box.
127
128        (arg p) is a Point
129        """
130        if hasattr(self,'_lower_left'):
131            if p.getX() < self._lower_left.getX() \
132               or  p.getY() < self._lower_left .getY() :
133                raise ValueError, "coord is not upper right of box."
134        self._setUpperRight(p)
135           
136    def _setUpperRight(self,p):
137        "Unckecked, private version"
138        self._upper_right = p
139
140
141    def getUpperRight(self):
142        """
143        Return a Point that represents the uppoer right corner of the Box.
144        """
145        self._normaliseCornerCoords()
146        return self._upper_right
147
148    def setLowerLeft(self,p):
149        """
150        Set the lower left corner of the Box.
151
152        (arg p) is a Point
153        """
154        if  hasattr(self,'_upper_right'):
155            if p.getX() > self._upper_right.getX() \
156                   or  p.getY() > self._upper_right.getY() :
157                raise ValueError, "coord is not lower left of box."
158        self._setLowerLeft(p)
159           
160    def _setLowerLeft(self,p):
161        "Unckecked, private version"
162        self._lower_left = p
163             
164       
165    def getLowerLeft(self):
166
167        """
168        Return a Point that represents the lower left corner of the Box.
169        """
170        self._normaliseCornerCoords()
171        return self._lower_left
172
173    def __str__(self):
174        """
175        Generate a string representation of the Box that is
176        suitable to use in a Postgres query.
177        """
178        self._normaliseCornerCoords()
179        return "'(%s,%s)'" % (self.getUpperRight().__repr__(),
180                              self.getLowerLeft().__repr__())
181   
182    def __repr__(self):
183        """
184        Generate a represention of the Box as a string
185        suitable for 'evaling' as a tuple.
186        """
187        self._normaliseCornerCoords()
188        return "(%s,%s)" % (self.getUpperRight().__repr__(),
189                            self.getLowerLeft().__repr__())
190
191    def __eq__(self,other):
192        """
193        The is a simple equallity operator.
194        """
195        if (type(self) != type(other)):
196            return False
197        self._normaliseCornerCoords()
198        other._normaliseCornerCoords()
199        if self.getUpperRight() == other.getUpperRight() and \
200           self.getLowerLeft() == other.getLowerLeft():
201            return True
202        return False
203
204    def __ne__(self,other):
205        return not self.__eq__(other)
206
207
208# factory methods
209
210def boxFromPoints(upper_right,lower_left):
211    """
212    Return a Box.
213
214    (arg upper_right) is a Point object.
215    (arg lower_left) is a Point object.
216    """
217    b = Box()
218    b._setUpperRight(upper_right)
219    b._setLowerLeft(lower_left)
220    b._normaliseCornerCoords()
221    return b
222
223def boxFromSequence(seq):
224    """
225    Return a Box.
226
227    (arg seq) is a sequence of the form '((x,y),(x1,y1))' where (x,y) is
228    the upper right corner and (x1,y1) is the lower left corner.
229    """
230    b = Box()
231    b._setUpperRight(pointFromSequence(seq[0]))
232    b._setLowerLeft(pointFromSequence(seq[1]))
233    b._normaliseCornerCoords()
234    return b
235             
236               
237def joinBoxes(box_a, box_b):
238    """
239        Union of two boxes.
240        Useful to join geometry extents.
241       
242        box_a and box_b are instances of Box
243        returns a new Box
244    """
245    a_ll = box_a.getLowerLeft()
246    b_ll = box_b.getLowerLeft()
247    a_ur = box_a.getUpperRight()
248    b_ur = box_b.getUpperRight()
249    if a_ll.getX() < b_ll.getX(): mx = a_ll.getX()
250    else: mx = b_ll.getX()
251    if a_ll.getY() < b_ll.getY(): my = a_ll.getY()
252    else: my = b_ll.getY()
253    if a_ur.getX() > b_ur.getX(): Mx = a_ur.getX()
254    else: Mx = b_ur.getX()
255    if a_ur.getY() > b_ur.getY(): My = a_ur.getY()
256    else: My = b_ur.getY()
257    return Box( Point(mx,my), Point(Mx,My) )
258   
Note: See TracBrowser for help on using the repository browser.