#!/usr/bin/perl
use strict;
use warnings;
use Panotools::Script;
use Math::Trig;
use Image::Size;
use File::Spec;

die "Usage: $0 project.paf" unless (defined $ARGV[0] and -e $ARGV[0]);

my $path_paf = File::Spec->rel2abs ($ARGV[0]);
open (PAF, '<'. $path_paf);
my $paf = {};
for my $line (<PAF>)
{
    if ($line =~ /^(.+)=(.+)$/)
    {
        my ($key, $value) = ($1, $2);
        $key =~ s/\\ / /g;
        $paf->{$key} = $value;
    }
}

my ($v, $d, $f) = File::Spec->splitpath ($path_paf);
my $path_equirect = File::Spec->catpath ($v, $d, $paf->{'Panorama Image'});

my ($px_width_equirect, $px_height_equirect) = imgsize ($path_equirect);
die unless ($px_width_equirect * $px_height_equirect > 0);

my $deg_hfov_equirect = $paf->{'Image Maximum Pan'} - $paf->{'Image Minimum Pan'};
$deg_hfov_equirect = 360 if $deg_hfov_equirect < 1;

my $px_radius_equirect = ($deg_hfov_equirect / 360) * $px_width_equirect / (2 * atan2(0,-1));

my $rad_vfov = $paf->{'Initial FOV'} * atan2(0,-1) / 180;

my $px_height = int (tan ($rad_vfov/2) * $px_radius_equirect * 2);
my $px_width = int ($px_height * 4/3);

my $focal_length = $px_height / (2*tan($rad_vfov/2));
my $rad_hfov = 2 * atan( $px_width / (2.0 * $focal_length));

# create a .pto project to extract the rectilinear view stored in the .paf file
my $pto_extract = new Panotools::Script;
$pto_extract->Panorama->Set (w => $px_width, h => $px_height,
                             n => 'TIFF',
                             v => ($rad_hfov * 180 / atan2(0,-1)),
                             f => 0);

my $equirect = new Panotools::Script::Line::Image;
$equirect->Set (w => $px_width_equirect, h => $px_height_equirect, f => 4,
                v => $deg_hfov_equirect, r => 0, p => 0, y => 0,
                n => '"'. $path_equirect .'"');
push @{$pto_extract->Image}, $equirect;

$pto_extract->Transform (0, 0, 0 - $paf->{'Initial Pan'});
$pto_extract->Transform (0, $paf->{'Initial Tilt'}, 0);

my $path_temp_pto = $path_paf .'.'. $$ .'.temp.pto';

$pto_extract->Write ($path_temp_pto);

# render the rectilinear view, delete the .pto project
system ('nona', '-o', $path_paf .'.extract', $path_temp_pto);
unlink $path_temp_pto;

# create a .pto that reprojects the extracted rectilinear back into the original image
my $pto_insert = new Panotools::Script;
$pto_insert->Panorama->Set (w => $px_width_equirect, h => $px_height_equirect,
                            v => $deg_hfov_equirect, n => 'TIFF');

my $rectilinear = new Panotools::Script::Line::Image;
$rectilinear->Set (w => $px_width, h => $px_height,
                   f => 0, v => ($rad_hfov * 180 / atan2(0,-1)),
                   n => '"'. $path_paf .'.extract.tif"');
push @{$pto_insert->Image}, $rectilinear;

$pto_insert->Transform (0, 0 - $paf->{'Initial Tilt'}, 0);
$pto_insert->Transform (0, 0, $paf->{'Initial Pan'});

$pto_insert->Write ($path_paf .'.extract.pto');

__END__

=head1 NAME

pafextract - render panoglview .paf projects

=head1 SYNOPSIS

  panoglview equirectangular.tif
  pafextract project.paf
  gimp project.paf.extract.tif
  nona -o overlay project.paf.extract.pto
  composite overlay.tif equirectangular.tif merged.tif

=head1 DESCRIPTION

B<pafextract> takes a panoglview .paf file and renders the saved view as a
suitably sized .tif file.  This is useful for simply extracting a 'normal' view
from an equirectangular panorama.

A hugin .pto project is also created, containing all the information necessary
to reproject the extracted .tif image back into the same equirectangular space
as the original.  This is useful for merging edits back into the original with
a tool such as ImageMagick or the Gimp.

=head1 LICENSE

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

=head1 SEE ALSO

L<http://hugin.sourceforge.net/>

=head1 AUTHOR

Bruno Postle - September 2008.

=cut