--- Geo-LatLon2Place/LatLon2Place.pm 2022/03/15 07:33:40 1.5 +++ Geo-LatLon2Place/LatLon2Place.pm 2022/03/17 00:32:54 1.6 @@ -74,7 +74,7 @@ use Carp (); BEGIN { - our $VERSION = 0.01; + our $VERSION = 0.9; require XSLoader; XSLoader::load (__PACKAGE__, $VERSION); @@ -130,55 +130,22 @@ If something is found, the associated data blob (always a binary string) is returned, otherwise you receive C. -Unless you specify a cusotrm format, the data blob is actually a UTF-8 -string, so you might want to call C on it to get a unicode -astring. - -At the moment, the implementation is in pure perl, but will eventually -move to C. +Unless you specify a custom format/extractor when building your database, +the data blob is actually a UTF-8 string, so you might want to call +C on it to get a unicode string: + + my $res = $db->lookup (47, 37); # near mariupol, UA + if (defined $res) { + utf8::decode $res; + # $res now contains the unicode result + } =cut -sub lookup_xs { - my ($self, $lat, $lon, $radius) = @_; - - lookup_ext_ $self->[1], $self->[2], $self->[3], $lat, $lon, 0, $radius, 0 -} - sub lookup { my ($self, $lat, $lon, $radius) = @_; - $radius ||= $self->[2]; - $radius = int +($radius + $self->[2] - 1) / $self->[2]; - - my $coslat = cos $lat * TORAD; - - my $blat = int $self->[3] * $coslat; - my $cx = int (($lon + 180) * $blat / 360); - my $cy = int (($lat + 90) * $self->[3] / 180); - - my ($min, $res) = (1e00); - - for my $y ($cy - $radius .. $cy + $radius) { - for my $x ($cx - $radius .. $cx + $radius) { - warn unpack "H*", pack "s< s<", $x, $y; - warn $blat; - for (unpack "(C/a*)*", cdb_get $self->[1], pack "s< s<", $x, $y) { - my ($plat, $plon, $w, $data) = unpack "s< s< C a*"; - $plat = $plat * ( 90 / 32767); - $plon = $plon * (180 / 32767); - - my $dx = ($lon - $plon) * TORAD * $coslat; - my $dy = ($lat - $plat) * TORAD; - my $d2 = ($dx * $dx + $dy * $dy) * $w; - - $d2 >= $min - or ($min, $res) = ($d2, $data); - } - } - } - - $res + lookup_ext_ $self->[1], $self->[2], $self->[3], $lat, $lon, 0, $radius, 0 } =back @@ -200,7 +167,7 @@ using an approximate euclidean distance on an equireactangular projection. The squared distance is multiplied with a weight (1..25 for the geonames database, based on population and adminstrative status, -always 1 for postcal codes), and the minimum distance wins. +always 1 for postal codes), and the minimum distance wins. Binning should not introduce errors, but bigger bins can slow down lookup times due to having to look at more places. The lookup assumes a spherical @@ -211,20 +178,25 @@ =head1 SPEED -The current implementation is written in pure perl, and on my machine, -typically does 10000-200000 lookups per second. The goal for version 1.0 -is to move the lookup to C. +On my machine, C typically does more than a million lookups per +second - performance varies depending on result density and number of +indexed points. =head1 TENTATIVE ROADMAP -The database writer should be accessible via a module, so you cna easily +The database writer should be accessible via a module, so you can easily generate your own databases without having to run an external command. -The api might be extended to allow for multiple returns, or nearest -neighbour search, or more return values (distance, coordinates). +The API might be extended to allow for multiple lookups, multiple +returns, or nearest neighbour search, or more return values (distance, +coordinates). + +Longer lookups will take advantage of perlmulticore. =head1 PERL MULTICORE SUPPORT +This is not yet implemented: + This module supports the perl multicore specification (L) when doing lookups.