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

Tim Schaub tim at commenspace.org
Mon Feb 6 11:20:30 EST 2006


Hey Daniel-

> I think the difference you are seeing in these two case below 
> is due to the fact the you are operating under the 
> misinformed concept that cellsize is rectangular when it is 
> not, despite that fact that it is being displayed as 
> rectangular on the image.

I agree with Steve that your problem is assuming a constant for
$radians_per_mile.

This also means that a circle (search radius) in geographic coordinates
will not be a circle in your projected coordinate system.

> One degree of longitude is approximately 69+ miles at the 
> equator. You can do the math to verify this. How many miles 
> are in one degree of longitude at the poles? But one degree 
> of latitude is always approx. 69+ miles regardless where you 
> are on the sphere.

In case you do want to do the math, here are the numbers you should use
(with units spelled out):

To convert north-south distances into radians: 
X mile * (1 nautical mile / 1.1508 mile) * (1 degree / 60 nautical mile)
* (pi radian / 180 degree) = Y radian

To convert east-west distances into radians (modify by latitude):
(X mile / cos(latitude)) * (1 nautical mile / 1.1508 mile) * (1 degree /
60 nautical mile) * (pi radian / 180 degree) = Y radian

This is assuming 1 nautical mile per minute of longitude at the equator
(definition of a nautical mile), 1.1508 for the number of statute miles
per nautical mile, and a spherical earth.  You can see that your
east-west distances approach infinite radians as you approach the poles.

Tim

P.S. - For the javascript scalebar, I have assumed that you're
interested in north-south distances if you're using a geographic
coordinate system.  This is the same assumption that the server side
scalebar uses.  You'll notice that it is somewhat misleading then to
place a scalebar horizontally (on screen) for a geographic coordinate
system.  If you're persnickety enough to care about this, you'll have to
make a vertical scalebar.  However, most other web maps make the same
assumption.

> 
> Ka-map assumes all calculation are done in the x-y plane 
> using cartessian coordinate math, hence cellsize represents 
> an approximation based on the value at the equator. As you 
> move off the equator you get more and more error.
> 
> I am not familiar with pg_sphere, but I assume (maybe 
> wrongly) that it is doing spherical math calculation which 
> take into account the issues above and hence you mismatch in 
> expectations.
> 
> -Steve W.
> 
> Daniel Ceregatti wrote:
> > 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) 
> > _______________________________________________
> > ka-Map-users mailing list
> > ka-Map-users at lists.maptools.org
> > http://lists.maptools.org/mailman/listinfo/ka-map-users
> > 
> 
> _______________________________________________
> ka-Map-users mailing list
> ka-Map-users at lists.maptools.org
> http://lists.maptools.org/mailman/listinfo/ka-map-users
> 



More information about the ka-Map-users mailing list