root/trunk/MapFish/server/python/mapfish/lib/filters/spatial.py @ 1321

Revision 1321, 4.0 kB (checked in by aabt, 5 years ago)

update bbox spatial query and cleaner type conversion r=elemoine ( closes #191 )

Line 
1#
2# Copyright (C) 2007-2008  Camptocamp
3
4# This file is part of MapFish Server
5
6# MapFish Server is free software: you can redistribute it and/or modify
7# it under the terms of the GNU Lesser General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10
11# MapFish Server is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU Lesser General Public License for more details.
15
16# You should have received a copy of the GNU Lesser General Public License
17# along with MapFish Server.  If not, see <http://www.gnu.org/licenses/>.
18#
19
20from mapfish.lib.filters import Filter
21
22from sqlalchemy.sql import func
23
24from shapely.geometry.point import Point
25from shapely.geometry.polygon import Polygon
26
27class Spatial(Filter):
28    BOX = 'BOX'
29    WITHIN = 'WITHIN'
30
31    def __init__(self, type, geom_column, **kwargs):
32        """Create a spatial filter.
33
34          type
35              the type of filter to create. Possible values are
36              Spatial.BOX or Spatial.WITHIN.
37
38          geom_column
39              the Column object corresponding to the geometry
40              column.
41
42          \**kwargs
43              epsg
44                the EPSG code of the lon, lat or box values, see
45                below.
46
47              for Spatial.BOX filter:
48
49              box
50                a list of coordinates representing the bounding
51                box [xmin, ymin, xmax, ymax]
52           
53              for Spatial.WITHIN filter:
54
55              lon
56                the x coordinate of the center of the search
57                region, the projection system of that coordinate
58                can be specified with the epsg key.
59
60              lat
61                the y coordinate of the center of the search
62                region, the projection system of that coordinate
63                can be specified with the epsg key.
64
65              tolerance
66                the tolerance around the center of the search
67                region, is expressed in the units associated with
68                the projection system of the lon/lat coordinates.
69        """
70        self.type = type
71        self.geom_column = geom_column
72        self.values = kwargs
73        if 'epsg' in self.values:
74            self.epsg = self.values['epsg']
75        else:
76            self.epsg = None
77
78    def to_sql_expr(self):
79        if self.type == 'BOX':
80            return self.__to_sql_expr_box()
81
82        if self.type == 'WITHIN':
83            return self.__to_sql_expr_within()
84
85    def __to_sql_expr_box(self):
86        coords = self.values['box']
87
88        epsg = self.geom_column.type.srid
89        if self.epsg is not None:
90            epsg = self.epsg
91
92        coords = map(float, coords)
93
94        # define polygon from box
95        point_a = (coords[0], coords[1])
96        point_b = (coords[0], coords[3])
97        point_c = (coords[2], coords[3])
98        point_d = (coords[2], coords[1])
99        point_e = point_a
100        coords = (point_a, point_b, point_c, point_d, point_e)
101        poly = Polygon(coords)
102        pg_poly = func.geomfromtext(poly.wkt, epsg)
103
104        if epsg != self.geom_column.type.srid:
105            pg_poly = func.transform(pg_poly, epsg)
106
107        return func.st_intersects(self.geom_column, pg_poly)
108
109    def __to_sql_expr_within(self):
110        lon = self.values['lon']
111        lat = self.values['lat']
112        tolerance = self.values['tolerance']
113
114        epsg = self.geom_column.type.srid
115        if self.epsg is not None:
116            epsg = self.epsg
117
118        point = Point(lon, lat)
119        pg_point = func.pointfromtext(point.wkt, epsg)
120
121        geom = self.geom_column
122        if epsg != self.geom_column.type.srid:
123            geom = func.transform(geom, epsg)
124
125        if tolerance is not None and tolerance > 0:
126            e = func.distance(geom, pg_point) < tolerance
127        else:
128            e = func.within(pg_point, geom)
129
130        return e
Note: See TracBrowser for help on using the browser.