Geo-Location-TimeZone

 view release on metacpan or  search on metacpan

INSTALL  view on Meta::CPAN


               perl Makefile.PL
               make
               make test
               make install

This should run on perl5 and later.  It might run on perl4.

Hard dependencies:

	Math::Polygon

b/build-data.pl  view on Meta::CPAN

#!/usr/bin/perl

$|=1;
use strict;
use Geo::ShapeFile;
use Math::Polygon;
use Data::Dumper;

use lib "../lib";
use lib "lib";
use Geo::Location::TimeZone;
# This is a hacky script to generate the data used by Geo::Location::TimeZone.
# It essentially uses brute force.  It is run by the package maintainer, and
# not as part of unpacking the package.
# The steps taken are:
#	1) Read in list of centroid points and matching names.

b/build-data.pl  view on Meta::CPAN

	# list.  Lets start looping.
	for ( my $s = 1 ; $s <= $lshape->num_parts ; $s++ ){
		my @points = ();

		# Store the points in a local array.
		foreach my $point( $lshape->get_part( $s ) ){
			push @points, [$point->X, $point->Y];
		}

		# Create the polygon.
		my $poly = Math::Polygon->new( @points );

		# What is the bounding box for this?
		my ($xmin, $ymin, $xmax, $ymax) = $poly->bbox;


		# Change those into 15 degree chunks.
		$xmin = &close15( $xmin );
		$ymin = &close15( $ymin );
		$xmax = &close15( $xmax );
		$ymax = &close15( $ymax );

b/build-data.pl  view on Meta::CPAN

						if( $trimX || $trimY ){
							$curoff--;
						}
					}

					if( $diddel ){
						print STDERR "Removed $diddel points leaving " . scalar @masspoints . " \n";
						# Recreate the poly using the
						# reduced set of points.
						# print STDERR "Recreating the polygon: " . join( ",", @masspoints ) . " X\n";
						$newpoly = Math::Polygon->new( @masspoints );

					}
				}

				# Save this zone if something different
				# is found, and the polygon has a bit of area.
				my $tarea = 0;
				if( $szone ne $usezone || $forceuse ){
					$tarea = $newpoly->area();
					if( $tarea > 0 ){

b/build-data.pl  view on Meta::CPAN

			}
		}elsif( $doneX ){
			print OUTPUT "\t\t# Grid $xc:$yc ; " . $recheck{"$xc"}{"$yc"} . " records\n";
			print OUTPUT "\t\t\"$yc\" => {\n";

			my $maxarea = -1;
			my $maxname = undef;
			foreach my $rkey( sort keys %{$data{"$xc"}{"$yc"}} ){
				next if( $rkey eq "o" );
				if( ! defined( $data{"$xc"}{"$yc"}{"$rkey"}{"a"} ) ){
					my $newpoly = Math::Polygon->new( @{$data{"$xc"}{"$yc"}{"$rkey"}{"p"}} );
					$data{"$xc"}{"$yc"}{"$rkey"}{"a"} = $newpoly->area();
				}
				if( $data{"$xc"}{"$yc"}{"$rkey"}{"a"} > $maxarea || $maxarea == -1 ){
					$maxarea = $data{"$xc"}{"$yc"}{"$rkey"}{"a"};
					$maxname = $rkey;
				}

			}

			# Decide what the default timezone is.
			if( defined( $maxname ) ){
				my @bbox = &expandbox( $xc, $yc );
				my @points = ();
				push @points, [$bbox[0],$bbox[1]];
				push @points, [$bbox[2],$bbox[3]];
				my $npoly = Math::Polygon->new( @points );

				# If there is only one polygon, and the area
				# is less than the bounding box, then we
				# need to retain it in the output.
				if( $maxarea < $npoly->area && $recheck{"$xc"}{"$yc"} > 1 ){
					# Need to output the timezones found
					# on the object that we're not putting
					# in as def_zs.
					foreach my $foundzs( keys %{$data{"$xc"}{"$yc"}{"$maxname"}} ){
						next unless( $foundzs =~ /^z/ );

lib/Geo/Location/TimeZone.pm  view on Meta::CPAN


The names of the timezones returned are according to the 'posix' directory
of the author's zoneinfo directory.  Some of these are usable with the
L<DateTime::TimeZone> library.

=cut

package Geo::Location::TimeZone;

use strict;
use Math::Polygon;

use vars qw/$VERSION/;
$VERSION = "0.1";

=head1 METHODS

=head2 new

This creates a new object.

lib/Geo/Location/TimeZone.pm  view on Meta::CPAN

					# Work through the 'f' string, taking
					# 12 bytes at a time until it is all
					# gone.

				}

				# new wants a list of [x,y],[x,y] .  how can I
				# get that from a list of [x,y,x,y,x,y] ?  Not
				# easily.  Better to incur the expense in 
				# build-data.
				my $poly = Math::Polygon->new( @{$dataref->{'data'}{"$lonoff"}{"$latoff"}{"$kkey"}{"p"}} );
				# print STDERR "Random number $kkey with data for " . $args{"lon"} . " and " . $args{"lat"} . " poly has " . $poly->nrPoints . " points X - " . $dataref->{'data'}{"$lonoff"}{"$latoff"}{"$kkey"}{"z"} . " X\n";

				if( $poly->contains( [ $args{"lon"}, $args{"lat"} ] ) ){
					my $curarea = $poly->area;
					if( $smallarea != - 1 ){
						if( $curarea < $smallarea ){
							$smallarea = $curarea;
							$smallname = $kkey;
						}
					}else{

lib/Geo/Location/TimeZone.pm  view on Meta::CPAN

	}

	return( $retval );
}

# 0.2 stuff
# =head2 do_pack
# 
# This is a helper routine used in the compression of GeoData so the overall
# size of the child libraries is kept low.  It takes a %hash of arguments,
# comprising either of a Math::Polygon object as 'poly', or a lat/lon pair
# as 'lat' and 'lon' (decimal degrees).  It returns a single binary string
# representing the data stored.
# 
# Each point supplied is converted to two shorts and two longs, in 'network'
# byte order, for a total of 12 bytes per point.  Clueful people will note
# that pack() does not support signed shorts and longs, and will read the
# comments in the library code next.
# 
# =cut
# 

lib/Geo/Location/TimeZone.pm  view on Meta::CPAN

# (increments of 180 for lat, 360 for lon).
sub do_pack {
	my $self = shift;
	my %args = ( @_ );

	my $retstr = undef;

	# If we have a polygon to deal with.
	if( defined( $args{"poly"} ) ){
		# Walk through the points that are returned, and call ourselves
		# again on each point.  Math::Polygon returns points in X,Y 
		# order, but since this is a Geo-related application, the
		# data is stored in lat,lon order.
		foreach my $point( $args{"poly"}->points ){
			$retstr .= $self->do_pack( lat => ${$point}[1], lon => ${$point}[0] );
		}

	}elsif( defined( $args{"lat"} ) && defined( $args{"lon"} ) ){

		# Push them into positive space so we can store them as 
		# unsigned numbers.

lib/Geo/Location/TimeZone.pm  view on Meta::CPAN

# =item string
# 
# The binary string to unpack.  This should be a multiple of 12 bytes.
# 
# =item return
# 
# How to return the data.  Possible return types are 'latlon', which will
# return a @list of the latitude and longitude, 'point', which will return
# a @list of X and Y values, 'listpoints', which will return a @list of
# points (each a sub-@list), and 'poly' which will return a prepared 
# Math::Polygon object.  Note that the 'latlon' and 'point' returns will only
# process the first 12 bytes.
# 
# =over
# 
# =cut

sub do_unpack {
	my $self = shift;

	my %args = ( @_ );

lib/Geo/Location/TimeZone.pm  view on Meta::CPAN

		}elsif( $latlon ){
			push @retlist, $latwhole, $lonwhole;
		}else{
			push @retlist, $lonwhole, $latwhole;
		}
	
	}

	# Decide what to return.
	if( $dopoly ){
		$retobj = Math::Polygon->new( @retlist );
		return( $retobj );
	}else{
		return( @retlist );
	}
}

=head1 AUTHOR

Bruce Campbell, 2007.  See http://cpan.zerlargal.org/Geo::Location::TimeZone

lib/Geo/Location/TimeZone.pm  view on Meta::CPAN


=cut

# The master data for this library lives in a hash called 'data' in 
# sub libraries.  The hash is 4-levels, 
# consisting of lonoff, latoff, random-key, and finally,
# 'p' (for poly),'z' (for zone), and 'c' (for copyright)
# lonoff and latoff are the result of putting the lat/lon into 15 degree 
# increments, from -12 to 12, and -6 to 6.
# random-key is just that; a random-key.
# The 'p'oly is a @list of X,Y values that Math::Polygon likes for input.
# The 'z'one is a text string that DateTime::TimeZone hopefully likes.
# The 'c'opyright is a text string by which people can lookup where the
#   data came from.
# The script which generates this data is in b/build-data.pl
1;



( run in 0.266 second using v1.01-cache-2.11-cpan-2b0bae70ee8 )