[ka-Map-users] Scalebar and javascript distance calculation errors

Daniel Ceregatti daniel at ceregatti.org
Mon Feb 6 03:23:46 EST 2006


Hi,

I'm using pg_sphere and some of my own javascript code in an application
I'm building which uses the ka-map "API". I keep the "API" files synced
with ka-map CVS, then I use my own startup.js and index.php to produce
my app, a stable version of which can be seen here:

http://map.sh.nu/release

My work-in-progress can be seen here:

http://map.sh.nu/prototype6

(Both developed in Firefox 1.5, not guaranteed to work in IE, or
safari...yet)

I've implemented it with the relatively new 100% javascript scalebar in
ka-map's scalebar subdirectory.

Anyhow, everything looked fine until I started adding points and radii
to the map. I'm using pg_sphere for radius searches, as it's easier to
use than postgis for the purposes of searching within a circle on a
spheroid (IMHO). The problem is that the scalebar and pg_sphere don't
agree in terms of distances.

Recently, while discussing my app with Paul Spencer on IRC, he was kind
enough to supply me with a javascript function to determine pixels per
mile from the myKaMap object's cellsize property:

function milesToPixels (miles) {
    var ddPerPixel = myKaMap.cellSize;
    var metersPerDD = 110570;
    //adjust for latitude
    kmPerDD = 110.570 * Math.cos (ddPerPixel * Math.PI / 180);
    var kmPerPixel = kmPerDD * ddPerPixel;
    var miPerPixel = kmPerPixel * 0.621371192;
    var pixelPerMi = 1 / miPerPixel;
    var pixels = Math.round (miles * pixelPerMi);
    debugLog ('Calculated pixels for ' + miles + ' mile(s): ' + pixels);
    return pixels;
}

I use this function to tell me the number of pixels per mile for the
current zoom level. I use its return value to overlay a pre-rendered
image of a circle whose radius in pixels matches the return value to
graphically illustrate the radius of a search. I found that the circles
I'm adding to my map match very closely with the scalebar by dragging
the circle, which is currently bisected horizontally and vertically for
the purposes of debugging, to the scalebar and eye-balling the radius
against the scalebar. They seem to match quite well.

The problem is, pg_sphere doesn't agree. I supply a query to pg_sphere
telling it to "get me all points for a particular crime code within an X
mile radius, within a specific time interval". This query returns not
only the points, but the distance from the center as well. Since
pg_sphere expects latitude, longitude, and radius in radians, I must
convert these before supplying them to the query:

$radians_per_mile = 0.00025; // Found on google.
$lon = $_GET["lon"] * pi () / 180.0; // Convert to radians
$lat = $_GET["lat"] * pi () / 180.0; // Convert to radians
$radius = (($_GET["radius"] + .05) * $radians_per_mile); // Add a little
padding so all my points are not less than the radius

A sample query:

select
    cd.dr as id,
    cd.lon,
    cd.lat,
    cd.crimeclass,
    cd.crimeloc as description,
    cc.description as desc,
    to_char (cd.begdate, 'DD/MM/YYYY') as thedate,
    cd.begtime as thetime,
    round ((cd.location <-> @@ scircle '<(-2.06427127801,
0.59322154771), 0.0002625>')::numeric / 0.00025, 2) as distance
from
    crimedata cd,
    crimecodes cc
where
    cd.crimeclass = cc.id
    and cd.location @ scircle '<(-2.06427127801, 0.59322154771), 0.0002625>'
    and cd.enddate >= to_timestamp ('11/09/2005', 'DD/MM/YYYY')
    and cd.enddate <= to_timestamp ('11/09/2005', 'DD/MM/YYYY') + '7
days'::interval
    and cd.crimeclass in (110, 113, 121, 122, 210, 220, 230, 231, 235,
236, 250, 251, 310, 320, 330, 331, 341, 343, 345, 350, 351, 352, 353,
410, 420, 421, 440, 441, 442, 443, 444, 445, 450, 451, 452, 453, 470,
471, 472, 473, 474, 475, 480, 485, 487, 491, 510, 520)
limit 100

This query is the one that's performed by default when the "search"
button is pressed with the pre-popullated form on
http://map.sh.nu/release. The request first perfoms a geocode search
using Geo::Coder::US (http://geocoder.us). This first search returns the
latitude and longitude (and more) of the search query, in this case the
corner of Main St. and Slauson Ave. in Los Angeles, California, USA. The
next part of the search is the pg_sphere query which uses the lat/lon
returned from the geocode search and adds the radius. I then use
ka-map's addObjectGeo function to add the search point, the circle, and
all queried crime points to my map.

As you can see, the search point as well as the circle center seem to be
placed perfectly. My crime data isn't actually very accurate, as some
precision was lost when the LAPD provided me a sample of their data, so
the points can be off by as much as 400 feet in some cases, but again,
that's attributable to the loss in precision. Anyhow, if you mouse over
the points, their metadata is shown in a popup, and one such datum is
the distance, which comes from the sql query. If you drag the map to the
left, you will expose a blue dot that's parallel to the circle's
horizontal bisector, on the corner of Central Ave. and Slauson Ave. I've
manually placed this point there, as denoted by the metadata. Using
google maps, I tried to find two points that seemed to be very close to
being 1 mile apart. I found that the corner of Main and Slauson seems to
be very close to 1 mile from the corner of Central and Slauson, and
Slauson runs East/West, parallel to lines on latitude. As you can see,
the circle doesn't encompass that point. If you zoom out twice, to the
point where 1 mile can be seen on the scalebar, you can also see that
the scalebar falls short of 1 mile, when comparing the distance between
the search point (the center of the circle) and this manually placed
point. But pg_sphere reports that these points are exactly 1 mile apart.

I must confess that I'm not a "cartographer" by trade. I'm a programmer,
and thus I do not understand what I'm doing some times with regards to
mapping applications. Terms like "re-projection" make my eyes glaze
over. All I can go with is what I know: All geocode searches which yield
a lat/lon fall on my map with a very high degree of accuracy, so it
seems that at least that part works properly. I also trust that
pg_sphere is not at fault here, as I've done some math on my points, and
they agree with the results provided by pg_sphere. My assumption is that
somehow the math in ka-map's new scalebar, as well as my milesToPixels
function, is faulty.

Thoughts?

Daniel Ceregatti (Primer in #mapserver on irc.freenode.net)


More information about the ka-Map-users mailing list