PostGIS "nearest" including range limiting

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    def nearest_to(self, point, number=5, geom_column='latlon',
                   from_srid=2163, to_srid=2163,
                   within_range=None):
        """finds the model objects nearest to a given point
        
        `point` is a tuple of (x, y) in the spatial ref sys given by `from_srid`
        
        returns a list of tuples, sorted by increasing distance from the given `point`. 
        each tuple being (model_object, dist), where distance is in the units of the 
        spatial ref sys given by `to_srid`"""
        if not isinstance(point, tuple):
            raise TypeError
        from string import Template
        cursor = connection.cursor()
        x, y = point
        table = self.model._meta.db_table
        distance_clause = ''
        if within_range:
            distance_clause = "AND (Distance(GeomFromText('POINT($x $y)', $from_srid), $geom_column) <= %f)" % within_range
        sql = Template("""
            SELECT id,
                Length(Transform(SetSRID(MakeLine($geom_column, GeomFromText('POINT(' || $x || ' ' || $y || ')', $from_srid)), $from_srid), $to_srid))
            

            FROM $table
            WHERE $geom_column IS NOT NULL %s
            ORDER BY Distance(GeomFromText('POINT($x $y)', $from_srid), $geom_column) ASC
            LIMIT $number;
        """ % distance_clause)
        cursor.execute(sql.substitute(locals()))
        nearbys = cursor.fetchall()
        # get a list of primary keys of the nearby model objects
        ids = [p[0] for p in nearbys]
        # get a list of distances from the model objects
        dists = [p[1] for p in nearbys]
        places = self.filter(id__in=ids)
        # the QuerySet comes back in an undefined order; let's
        # order it by distance from the given point
        def order_by(objects, listing, name):
            """a convenience method that takes a list of objects,
            and orders them by comparing an attribute given by `name`
            to a sorted listing of values of the same length."""
            sorted = []
            for i in listing:
                for obj in objects:
                    if getattr(obj, name) == i:
                        sorted.append(obj)
            return sorted
        return zip(order_by(places, ids, 'id'), dists)

More like this

  1. SearchableManager by stephen_mcd 4 years, 1 month ago
  2. oracle 10g fulltext search & patch nclob field limitations by ageldama 6 years ago
  3. Simple "html email with images" sender by andres_torres_marroquin 3 years, 1 month ago
  4. Generic CSV Export by zbyte64 5 years, 10 months ago
  5. Convert Microsoft "smart quotes" to standard quotes by nomadjourney 3 years, 6 months ago

Comments

(Forgotten your password?)