[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