#!/usr/bin/perl

use strict;
use warnings;

use Panotools::Script;
use Getopt::Long;
use Pod::Usage;
my $help = 0;
my @image;
my $output = 'output';

GetOptions ('i=s' => \@image,
            'o=s' => \$output,
            'h|help' => \$help);

pod2usage (-verbose => 2) if $help;

my $path_pto = shift || pod2usage;
die "Can't find $path_pto" unless -e $path_pto;

my $pto = new Panotools::Script;
$pto->Read ($path_pto);

# input image paths can be overridden on command line
for my $id (0 .. scalar @ARGV -1)
{
    $pto->Image->[$id]->{n} = '"'. $ARGV[$id] .'"';
}

# do all images unless -i parameter is specified
unless (scalar @image)
{
    @image = (0 .. scalar @{$pto->Image} -1);
}

$pto->InitTrafo ($path_pto);

for my $id_image (@image)
{

    open SVG, '<'. $pto->Image->[$id_image]->Path ($pto);
    my @lines = (<SVG>);
    close SVG;

    my $xml = join '', @lines;
    $xml =~ s/(\r|\l|\n)//g;
    $xml =~ s/[[:space:]]+/ /g;
    $xml =~ s/> </></g;

    my ($width) = $xml =~ /<svg[^>]*[[:space:]]width="([0-9.]+)"/;
    my ($height) = $xml =~ /<svg[^>]*[[:space:]]height="([0-9.]+)"/;

    next unless $width;
    next unless $height;

    my $width_out = $pto->Panorama->{w};
    my $height_out = $pto->Panorama->{h};

    $xml =~ s/(<svg[^>]*[[:space:]]width=)"[0-9.]+"/$1"$width_out"/;
    $xml =~ s/(<svg[^>]*[[:space:]]height=)"[0-9.]+"/$1"$height_out"/;

    for my $path ($xml =~ /([[:space:]]d="[-0-9.,CLMQSTZclmqstz[:space:]]*")/g)
    {
        my @tokens = $path =~ /([[:space:]]d="|[-0-9.]+[,[:space:]][-0-9.]+|[[:space:]]|[CLMQSTZclmqstz]|")/g;

        my $relative = 0;
        my ($x_last, $y_last) = (0.0, 0.0);
        my ($x_curr, $y_curr) = (0.0, 0.0);
        my @tokens_out;

        for my $token (@tokens)
        {
            $relative = 0 if ($token =~ /^([CLMQST])$/);
            # lower case letters indicate relative coordinates follow
            $relative = 1 if ($token =~ /^([lm])$/);
            # these are relative to start of command
            if ($token =~ /^([cqst])$/)
            {
                $relative = 2;
                ($x_curr, $y_curr) = ($x_last, $y_last);
            }

            # coordinate pairs can be space or comma separated
            if ($token =~ /([-0-9.]+)[,[:space:]]([-0-9.]+)/)
            {
                my ($x, $y) = ($1, $2);
                if ($relative == 1)
                {
                    $x += $x_last;
                    $y += $y_last;
                }
                if ($relative == 2)
                {
                    $x += $x_curr;
                    $y += $y_curr;
                }
                $x_last = $x;
                $y_last = $y;

                ($x, $y) = $pto->Trafo ($id_image, $x, $y);
                $token = $x .','. $y;
            }
            push @tokens_out, $token;
        }
        my $path_new = join '', @tokens_out;
        # all coordinates are now absolute
        $path_new =~ tr/clmqst/CLMQST/;

        $xml =~ s/$path/$path_new/;
    }

    open SVG, '>'. $output . sprintf("%04d", $id_image) .'.svg';
    print SVG $xml;
    close SVG;
}

0;

__END__

=head1 NAME

nona-svg - stitch a vector panorama image 

=head1 SYNOPSIS

 nona-svg [options] -o output project_file (image files)

 Options:
  -o prefix    Prefix for output
  -i num       Images to render, can be specified multiple times
  -h | --help  Outputs help documentation.

=head1 DESCRIPTION

B<nona-svg> is a drop in replacement for nona that works with SVG vector files.

There are some snags:

The .pto project needs to prepared with the correct w and h (width and height
in pixels) parameters for the input SVG files in each i-line.  You can specify
the SVG filenames using the n parameter, or by appending the SVG filenames on
the command-line (similar to nona).

This tool uses regular expressions rather than an SVG parser, so expect it to
fail in all sorts of situations.  It seems to be ok with simple lines and
curves generated by Inkscape.

This tool uses pano_trafo from the Hugin project to do the projection math, the
way the connection is done makes it only likely to work on unixy systems.

Expect to see 'ContractViolation' errors from vigra, ignore them, this is a bug
in pano_trafo which unnecessarily tries to open image files.

Note that only homography transformations preserve splines, i.e. this only
works properly if the input and output projection is rectilinear.  Having said
that, the error with other projections isn't so noticeable if your lines are
short and/or they are converted to 'curves' in Inkscape before remapping.

=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 - August 2012

=cut