#!/usr/bin/perl -w 
# Лицензия "Делайте что хотите", а если очень нужно, то GPL :) 
# Сообщения на английском, чтобы не связываться с локалями и gettext :( .
# Кроме стандартных расширений perl необходим модуль perl::Magick.
#
# Эта программа предназначена для преобразования больших карт OziExplorer в формат, 
# который был бы пригоден для средств GPS-навигации на Sharp Zaurus: qpegps и gpsdrive.
# Файлы .ozf* нужно преобразовать в изображение (.png). Входные данные для запуска
# конвертера (координаты двух точек) можно получить из .map файла. 

use POSIX;

sub truncatecoord ($) { # для qpegps надо 4 цифры после десятичной точки
    $_[0] =~ m/.*\.\d\d\d\d/; 
    return $&;
}

sub testarg ($) { #FIXME
    if (not defined $_[0]) {die "Bad argument"};
}


if ( not $#ARGV + 1) { 
    print "Large raster maps cutting and resizing tool v.0.1 (recalc only)\n";
    print "\ngpsmapper FILENAME map_X map_Y fragment_X fragment_Y overlap_X overlap_Y scale \\\n          point1_X point1_Y point1_lon point1_lat point2_X point2_Y point2_lon \\\n	  point2_lat [-simulate]\n";
    print "\nThis script will create map.txt and map_koord.txt files\nfor Zaurus GPS moving map apps (qpegps and gpsdrive).\n";	
    print "It script was made for conversion of city maps,\nso the  Earth surface is considered to be flat.\n"; 
    print "\nRequired parameters are:\n";
    print "map_X, map_Y - map image dimensions If they differ from the real,\nsize of the map, it will be scaled to specified size.\n";
    print "frag_X, frag_Y - size of the fragments. Gpsdrive requires 1280x1024.\n";
    print "overlap_X, overlap_Y - amount of overlap between neighbour fragments.\n";
    print "scale - scale of the map (not used in calculations)\n";
    print "point1_X point1_Y point1_lon point1_lat\n";
    print " - XY position and GPS coordinates of a point on the map.\nlongitude and latitude must be given in decimal degrees.\nthe script needs two diagonally placed points to\ncalculate geolocation data for both qpegps and gpsdrive.\n";
} else { 

my $suffixes = "\.[G|g][I|i][F|f]|\.[J|j][P|p][G|g]|\.[P|p][N|n][G|g]|\.[B|b][M|m][P|p]";
my ($inmap_x, $inmap_y, $inmapclass);
my $inmapname = $ARGV[0];
my $basemapname;
($basemapname = $inmapname) =~ s/\....$//;
   $basemapname = "map_".$basemapname; # для gpsdrive
my $base_w = $ARGV[1]; testarg($ARGV[1]);
my $base_h = $ARGV[2]; testarg($ARGV[2]);
my $frag_w = $ARGV[3]; testarg($ARGV[3]);
my $frag_h = $ARGV[4]; testarg($ARGV[4]);
my $over_x = $ARGV[5]; testarg($ARGV[5]);
my $over_y = $ARGV[6]; testarg($ARGV[6]);
my $scale = $ARGV[7]; testarg($ARGV[7]);
my $first_lon = $ARGV[10]; testarg($ARGV[8]);
my $first_lat = $ARGV[11]; testarg($ARGV[9]);
my $first_x = $ARGV[8]; testarg($ARGV[10]);
my $first_y = $ARGV[9]; testarg($ARGV[11]);
my $secnd_lon = $ARGV[14]; testarg($ARGV[12]);
my $secnd_lat = $ARGV[15]; testarg($ARGV[13]);
my $secnd_x = $ARGV[12]; testarg($ARGV[14]);
my $secnd_y = $ARGV[13]; testarg($ARGV[15]);
my $simulate; if (defined $ARGV[16] and $ARGV[16] eq "-simulate") {$simulate = 1} else {$simulate = 0};
my ($baselon, $baselat);


    $lonperpix = ($secnd_lon - $first_lon)/($secnd_x - $first_x); # Шаг координат в 1 пикселе, две точки должны быть расположены диагонально, в углах картинки
    $latperpix = ($secnd_lat - $first_lat)/($secnd_y - $first_y); # это всегда отрицательное число

    $baselon = $first_lon - ($first_x * $lonperpix); # Поправка, если координаты точки1 не 0х0 
    $baselat = $first_lat - ($first_y * $latperpix);

    $fragnum_x = floor($base_w/($frag_w - $over_x)); # Максимальное количество целых фрагментов
    $fragnum_y = floor($base_h/($frag_h - $over_y));
    $cut_x = ($fragnum_x * ($frag_w - $over_x)) + $over_x;
    $cut_y = ($fragnum_y * ($frag_h - $over_y)) + $over_y;
    if ($cut_x > $base_w) {--($fragnum_x); $cut_x = ($fragnum_x * ($frag_w - $over_x)) + $over_x;}; # Если последний фрагмент выходит за рамки изображения
    if ($cut_y > $base_h) {--($fragnum_y); $cut_y = ($fragnum_y * ($frag_h - $over_y)) + $over_y;};
    $startcut_x = floor(($base_w - $cut_x)/2); # Координаты начала разрезаемого на фрагменты прямоугольника 
    $startcut_y = floor(($base_h - $cut_y)/2);

    print "$basemapname\n\n";
    # Показать координаты крайних угловых точек
    print "0 X 0 = ".$baselon." ".$baselat."\n".$base_w." X ".$base_h." = ".(($base_w * $lonperpix) + $baselon)." ".(($base_h * $latperpix) + $baselat)."\n\n";
    print "$fragnum_x Х $fragnum_y fragment(s)\nI shall crop an area of $cut_x X $cut_y pixels starting from $startcut_x X $startcut_y.\n";
    print "Recommended ".$fragnum_x." X ".$fragnum_y." fragment size is ".((($base_w - $over_x) / $fragnum_x) + $over_x)." X ".((($base_h - $over_y) / $fragnum_y) + $over_y)." pixels.\n\n";

    if (not $simulate) {
	print "Recalc only version!\n";
    };

    open (QGPS, "> maps.txt");
    open (GPSD, "> map_koord.txt");
    
    for($b=0; $b<$fragnum_y; ++$b) { # Перебор фрагментов по y 
	for($a=0; $a<$fragnum_x; ++$a) { # Перебор по x
	    $x=($startcut_x + ($a * ($frag_w - $over_x)));
	    $y=($startcut_y + ($b * ($frag_h - $over_y)));

	    $tlcoord_x = ($x * $lonperpix) + $baselon; # Расчет координат привязки для qpegps
	    $tlcoord_y = ($y * $latperpix) + $baselat;
	    $drcoord_x = (($x + $frag_w) * $lonperpix) + $baselon;
	    $drcoord_y = (($y + $frag_h) * $latperpix) + $baselat;
	    
	    print QGPS "LINEAR $basemapname-$a-$b.png $scale $frag_w $frag_h ".truncatecoord($tlcoord_x)." ".truncatecoord($tlcoord_y)." 0 0 ".truncatecoord($drcoord_x)." ".truncatecoord($drcoord_y)." $frag_w $frag_h\n"; # qpegps

	    $coord_x = ($tlcoord_x + $drcoord_x)/2; # Расчет координат центра для gpsdrive
	    $coord_y = ($tlcoord_y + $drcoord_y)/2;

	    print GPSD "$basemapname-$a-$b.png $coord_y $coord_x $scale\n"; # gpsdrive

	};
    }; 

    close (QGPS);
    close (GPSD);
    print "Finished.\n\n"; 
};