#!/usr/bin/perl -w
# NAME: maptest.pl
# AIM: Convert a lat long zoom to a tile number
# 17/02/2014 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Math::Trig; # qw(great_circle_distance great_circle_direction deg2rad rad2deg);
##use POSIX;
use POSIX qw/floor/;

my $in_lat = 45;
my $in_lon = 123;
my $in_zoom = 9;

sub prt($) { print shift; }

sub mlog_10 {
  my $n = shift;
  return log($n)/log(10);
}


# from Theo HTML
#// The math
#// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
#	function lon2tile( lon, zoom ) {
#		return Math.floor( ( lon + 180 ) / 360 * pow( 2, zoom ) );
#	}
#	function lat2tile( lat, zoom ) {
#		return Math.floor(( 1 - Math.log( Math.tan( lat * pi / 180) + 1 / cos( lat * pi / 180)) / pi )/2 * pow(2, zoom) );
#	}
#	function tile2lon( x, z ) {
#		return ( x / pow( 2, z ) * 360 - 180 );
#	}
#	function tile2lat( y, z ) {
#		var n = pi - 2 * pi * y / pow( 2, z );
#		return 180 / pi * Math.atan( 0.5 * ( Math.exp( n ) - Math.exp( -n ) ));
#	}
sub lat2tilef($$) {
    my ($lat,$zoom) = @_;
    my $lat_rad = deg2rad($lat);
    my $n = 2 ** $zoom;
    my $ytile = floor((1.0 - mlog_10(tan($lat_rad) + (1 / cos($lat_rad))) / pi) / 2.0 * $n);
    return $ytile;
}

sub lon2tilef($$) {
    my ($lon,$zoom) = @_;
    my $n = 2 ** $zoom;
    my $xtile = floor($n * (($lon + 180) / 360));
    return $xtile;
}


# Python
# Lon./lat. to tile numbers
# import math
# def deg2num(lat_deg, lon_deg, zoom):
#  lat_rad = math.radians(lat_deg)
#  n = 2.0 ** zoom
#  xtile = int((lon_deg + 180.0) / 360.0 * n)
#  ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
#  return (xtile, ytile)
sub lat2tile($$) {
    my ($lat,$zoom) = @_;
    my $lat_rad = deg2rad($lat);
    my $n = 2 ** $zoom;
    my $ytile = int((1.0 - mlog_10(tan($lat_rad) + (1 / cos($lat_rad))) / pi) / 2.0 * $n);
    return $ytile;
}

sub lon2tile($$) {
    my ($lon,$zoom) = @_;
    my $n = 2 ** $zoom;
    my $xtile = int($n * (($lon + 180) / 360));
    return $xtile;
}


sub show_mappy() {
    prt("Converting lat $in_lat, lon $in_lon, zoom = $in_zoom to mappy\n");
    my $lat_rad = deg2rad($in_lat);
    my $n = 2 ** $in_zoom;
    my $xtile = int($n * (($in_lon + 180) / 360));
    my $ytile = int((1.0 - mlog_10(tan($lat_rad) + (1 / cos($lat_rad))) / pi) / 2.0 * $n);
    my $x = lon2tile($in_lon,$in_zoom);
    my $y = lat2tile($in_lat,$in_zoom);
    prt("xtile=$xtile, ytile=$ytile ($x/$y)\n");
}

sub test() {
    my $z = 19;
    my ($x,$y,$mx,$my,$tx,$ty,$cx,$cy);
    prt("Running test...\n");
    #for ($x = 0; $x < 180; $x += 0.1) {
    #    for ($y = 0; $y < 90; $y += 0.1) {
    #for ($x = -179; $x < 180; $x += 0.1) {
    #    for ($y = -89; $y < 90; $y += 0.1) {
    # from :
    for ($x = -179; $x < 180; $x += 0.1) {
        for ($y = -89; $y < 90; $y += 0.1) {
            $mx = lon2tile($x,$z);
            $my = lat2tile($y,$z);
            $tx = lon2tilef($x,$z);
            $ty = lat2tilef($y,$z);
            #if (($mx != $tx)||($my != $ty)) {
            #    prt("lon/lat/zoom $x/$y/$z mx=$mx my=$my tx=$tx ty=$ty\n");
            #}
            $cx = sprintf("%.2f",$x);
            $cy = sprintf("%.2f",$y);

            if ($mx != $tx) {
                prt("lon/lat/zoom $cx/$cy/$z DIFF mx/tx=$mx/$tx\n");
            }
            if ($my != $ty) {
                prt("lon/lat/zoom $cx/$cy/$z DIFF my/ty=$my/$ty\n");
            }
            ###prt("lon/lat/zoom $x/$y/$z mx=$mx my=$my\n");
        }
        # prt("Next longitude...\n");
    }
    exit(0);

}

show_mappy();
test();

# eof - maptest.pl


