First, because cos is single valued over the range of possible angles

(as measured

from the center of the earth, 0 <= d <= PI) distance is monotonic with

cos distance.

So you can pre-calculate the cos of the distance, and compare the

innder expression

to that:

th = cos(near_value_in_km / 6378.137)

Also, pre-calculate lat as radians, sin of long, and cos of long, so

that there's no

chance that the database will perform these calculations once per row

as opposed to

once per query. Then:

(cos_long * cos(radians(lattitude)) * cos(radians(longitude) -

rad_lat) + sin_long * sin(radians(latitude) > th

(Yes, greater than. Cos is max, +1, at minimum distance.)

Far fewer trig functions per row.

And if you're willing to denormalize, storing latitude as both its sin

and cos, and longitude

as its cos (possibly, further denormalization, also storing the

original degree values to

avoid dancing low order decimals in the UI), then you only need one

trig functionper row.

If you arrange to return the expression, you don't even have to

recalculate it on the python

side to get actual distance, if desired, for the items that are close

enough (take acos and

multiply by earth radius).

Note that you can still sort on cos(distance) in the DB if you're

interested in, for example,

a closest first presentation.

Applying the bounding box first means that you can avoid even that one

cos for items that

are outside the bounding box.

On Fri, Jul 30, 2010 at 4:06 AM, Henrik Genssen

<henrik.genssen@miadi.net> wrote:

> I use .extra(where=[where])

>

> and something like this (measures km, not miles):

> ( 6378.137 * acos( cos( radians(long) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(lat) ) + sin( radians(long) ) * sin( radians( latitude ) ) ) ) < 10

>

> latitude and logitude are db-fields, 6378.137 the radius of the earth, long/lat my current position, searches for objects in a 10 km circle

>

> regards

>

> Henrik

>

>

>>reply to message:

>>date: 30.07.2010 07:30:30

>>from: "Jani Tiainen" <redetin@gmail.com>

>>to: django-users@googlegroups.com

>>subject: Re: Best way to find near people

>>

>>> On Jul 29, 2010, at 2:58 PM, Alexandre González wrote:

>>> > Hi!

>>> >

>>> > I'm searching near people in my app. I'm doing it a this way:

>>> >

>>> > 37 people = Person.objects.all().exclude(user=request.user)

>>> > 38

>>> > 39 near_people = list()

>>> > 40 for person in people:

>>> > 41 if self.is_near(me.coordinates, person.coordinates):

>>> > near_people.append(person)

>>> >

>>> > Now, I'm getting all the the Person objects. This is a inefficient way.

>>> >

>>> > The coordinates are latitude/longitude coordinates, so I think in test

>>> > the variation and get only latitude +/- 1 and longitude +/- 1 and after

>>> > this, do the test exactly (the funcion is_near).

>>> >

>>> > But instead this, can I "draw" a circle and search only Person objects

>>> > inside it?

>>>

>>> I'm not sure what database you are using, but if you are using PostgreSQL,

>>> it has built-in geometric operators specifically for this kind of thing.

>>> You might have to drop down into SQL, but in 1.2, that's nice and easy.

>>>

>>> The PostgreSQL documentation on this is at:

>>>

>>> http://www.postgresql.org/docs/8.4/interactive/datatype-geometric.html

>>> --

>>> -- Christophe Pettus

>>> xof@thebuild.com

>>

>>Or if spatial operations are really needed, why not to use real spatial

>>database and GeoDjango (django.contrib.gis). Spatialite, Postgis, Mysql or

>>oracle. All supports at spatial to some extent. And there you can do easily

>>simple filtering:

>>

>>Person.objects.filter(person_coordinates__dwithin(me.coordinates, distance))

>>

>>..and geodjango + spatial engine behind it will take care of all that complex

>>stuff.

>>

>>Note: you can still use GEOS parts from geodjango to do calculations so you

>>don't have to reinvent wheel if you want to keep coordinates as you already

>>have.

>>

>>--

>>

>>Jani Tiainen

>>

>>--

>>You received this message because you are subscribed to the Google Groups "Django users" group.

>>To post to this group, send email to django-users@googlegroups.com.

>>To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.

>>For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

>>

>

> --

> You received this message because you are subscribed to the Google Groups "Django users" group.

> To post to this group, send email to django-users@googlegroups.com.

> To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.

> For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

>

>

--

You received this message because you are subscribed to the Google Groups "Django users" group.

To post to this group, send email to django-users@googlegroups.com.

To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

## No comments:

## Post a Comment