#
# GENERATED WITH PDL::PP! Don't modify!
#
package PDL::Transform::Proj4;

our @EXPORT_OK = qw( t_proj );
our %EXPORT_TAGS = (Func=>\@EXPORT_OK);

use PDL::Core;
use PDL::Exporter;
use DynaLoader;


   
   our @ISA = ( 'PDL::Exporter','DynaLoader','PDL::Transform' );
   push @PDL::Core::PP, __PACKAGE__;
   bootstrap PDL::Transform::Proj4 ;



BEGIN {
use PDL::LiteF;
use PDL::NiceSlice;
use PDL::Transform;
use Alien::proj;
if ($^O =~ /MSWin32/ and $Alien::proj::VERSION le '1.25') {
  $ENV{PATH} = join ';', (Alien::proj->bin_dirs, $ENV{PATH});
}


}



#line 207 "proj4.pd"

# PDL::Transform::Proj4
#
# Judd Taylor, USF IMaRS
# 4 Apr 2006

=head1 NAME

PDL::Transform::Proj4 - PDL::Transform interface to the Proj4 projection library

=head1 SYNOPSIS

 # Using the generalized proj interface:
 # Make an orthographic map of Earth
 use PDL::Transform::Cartography;
 use PDL::Transform::Proj4;
 $x = earth_coast();
 $x = graticule(10,2)->glue(1,$x);
 $t = t_proj( proj_params => "+proj=ortho +ellps=WGS84 +lon_0=-90 +lat_0=40" );
 $w = pgwin(xs);
 $w->lines($t->apply($x)->clean_lines());

 # Using the aliased functions:
 # Make an orthographic map of Earth
 use PDL::Transform::Cartography;
 use PDL::Transform::Proj4;
 $x = earth_coast();
 $x = graticule(10,2)->glue(1,$x);
 $t = t_proj_ortho( ellps => 'WGS84', lon_0 => -90, lat_0 => 40 )
 $w = pgwin(xs);
 $w->lines($t->apply($x)->clean_lines());

=head1 DESCRIPTION

Works like PDL::Transform::Cartography, but using the proj library in the background.

Please see the proj library docs at L<http://www.remotesensing.org/proj> for more information
on proj, and how to use the library.

=head1 GENERALIZED INTERFACE

The main object here is the PDL::Transform::Proj4 object, aliased to the t_proj() function.

This object accepts all of the standard options described below, but mainly is there to be called
with just the B<proj_params> option defined.

When options are used, they must be used with a '+' before them when placed in the proj_params string,
but that is not required otherwise. See the SYNOPSIS above.

=head2 ALIASED INTERFACE

Other than t_proj(), all of the other transforms below have been autogenerated, and may not work
properly. The main problem is determining the parameters a projection requires from the proj
library itself.

Due to the difficulties in doing this, there may be times when the proj docs specify a parameter
for a projection that won't work using the anon-hash type specification. In that case, just throw
that parameter in the proj_params string, and everything should work fine.

=head1 PARAMETERS AVAILABLE IN ALL PROJECTIONS

=head2 General Parameters

=head3 proj_params

This is a string containing the proj "plus style" parameters. This would be similar to what you
would put on the command line for the 'proj' tool. Like "+proj=ortho +ellps=WGS84 +lon_0=-90 +lat_0=40".

This parameter overrides the others below when it contains parameters that are also specified
explicitly.

=head3 proj

The proj projection code to use (like ortho...)

=head3 x_0

Cartesian X offset for the output of the transformation

=head3 y_0

Cartesian Y offset for the output of the transformation

=head3 lat_0

Central latitude for the projection.
NOTE: This may mean other things depending on the projection selected, read the proj docs!

=head3 lon_0

Central longitude for the projection.
NOTE: This may mean other things depending on the projection selected, read the proj docs!

=head3 units

Cartesian units used for the output of the projection.
NOTE: Like most of the options here, this is likely useless in the current implementation
of this library.

=head3 init

Specify a file:unit for proj to use for its runtime defaults. See the proj docs.

=head3 no_defs

Don't load any defaults. See the proj docs.

=head3 over

Normally, the transformation limits the output to between -180 and 180 degrees (or the
cartesian equivalent), but with this option that behavior is turned off.

=head3 geoc

Input values are geocentric coordinates.

=head2 Earth Figure Parameters

=head3 ellps

Ellipsoid datum to use. Ex: WGS72, WGS74.
See the proj docs and command line tool for list of possibilities ('proj -le').

=head3 R

Radius of the Earth.

=head3 R_A

Radius of a sphere with equivalent surface area of specified ellipse.

=head3 R_V

Radius of a sphere with equivalent volume of specified ellipse.

=head3 R_a

Arithmetic mean of the major and minor axis, Ra = (a + b)/2.

=head3 R_g

Geometric mean of the major and minor axis, Rg = (ab)1/2.

=head3 R_h

Harmonic mean of the major and minor axis, Rh = 2ab/(a + b).

=head3 R_lat_a=phi

Arithmetic mean of the principle radii at latitude phi.

=head3 R_lat_g=phi

Geometric mean of the principle radii at latitude phi.

=head3 b

Semiminor axis or polar radius

=head3 f

Flattening

=head3 rf

Reciprocal flattening, +rf=1/f

=head3 e

Eccentricity +e=e

=head3 es

Eccentricity squared +es=e2

=cut

sub new
{
    my $proto = shift;
    my $sub = "PDL::Transform::Proj4::new()";
    #print STDERR "$sub: ARGS: [" . join(", ", @_ ) . "]\n";
    my $class = ref($proto) || $proto;
    my $self  = $class->SUPER::new( @_ );

    bless ($self, $class);

    my $o = $_[0];
    unless( (ref $o) )
        { $o = {@_}; }

    #use Data::Dumper;
    #my $dd2 = Data::Dumper->new( [$o], ["$sub: o"] );
    #$dd2->Indent(1);
    #print STDERR $dd2->Dump();

    $self->{name} = "Proj4";

    # Grab our options:

    # Used in the general sense:
    $self->{params}->{proj_params} = PDL::Transform::_opt( $o, ['proj_params','params'] );

    # Projection options available to all projections:
    $self->{general_params} = [ qw( proj x_0 y_0 lat_0 lon_0 units init ) ];
    foreach my $param ( @{ $self->{general_params} } )
        { $self->{params}->{$param} = PDL::Transform::_opt( $o, [ $param ] ); }

    # Options that have no value (like "+over"):
    $self->{bool_params} = [ qw( no_defs over geoc ) ];
    foreach my $param ( @{ $self->{bool_params} } )
        { $self->{params}->{$param} = ( PDL::Transform::_opt( $o, [ $param ] ) ) ? 'ON' : undef; }

    # Options for the Earth figure: (ellipsoid, etc):
    $self->{earth_params} = [ qw( ellps R R_A R_V R_a R_g R_h R_lat_a R_lat_g b f rf e es ) ];
    foreach my $param ( @{ $self->{earth_params} } )
        { $self->{params}->{$param} = PDL::Transform::_opt( $o, [ $param ] ); }

    # First process the old params that may already be in the string:
    # These override the specific params set above:
    if( defined( $self->{params}->{proj_params} ) )
    {
        $self->{orig_proj_params} = $self->{params}->{proj_params};

        my @params = split( /\s+/, $self->{orig_proj_params} );
        foreach my $param ( @params )
        {
            if( $param =~ /^\+(\S+)=(\S+)/ )
            {
                my ($name, $val) = ($1, $2);
                $self->{params}->{$name} = $val;
                #print STDERR "$sub: $name => $val\n";
            }
            elsif( $param =~ /^\+(\S+)/ )
            {   # Boolean option
                $self->{params}->{$1} = 'ON';
            }
        }
    }

    # Update the proj_string to current options:
    #
    $self->update_proj_string();

    #my $dd = Data::Dumper->new( [$self->{params}], ["$sub: params"] );
    #$dd->Indent(1);
    #print STDERR $dd->Dump();

    ##############################
    # The meat -- just copy and paste from Transform.pm :)
    #    (and do some proj stuff here as well)

    # Forward transformation:
    $self->{func} = sub
    {
        my $in = shift;
        my $opt = shift;
        my $out = $in->new_or_inplace();
        # Always set the badflag to 1 here, to handle possible bad projection values:
        $out->badflag(1);
        $out->inplace(1);
        PDL::Transform::Proj4::fwd_transform( $out, $opt->{proj_params} );
    };

    # Inverse transformation:
    $self->{inv} = sub
    {
        my $in = shift;
        my $opt = shift;
        my $out = $in->new_or_inplace();
        # Always set the badflag to 1 here, to handle possible bad projection values:
        $out->badflag(1);
        $out->inplace(1);
        PDL::Transform::Proj4::inv_transform( $out, $opt->{proj_params} );
    };

    return $self;
} # End of new()...

sub update_proj_string
{
    my $self = shift;
    my $sub = "PDL::Transform::Proj4::update_proj_string()";

    # (Re)Generate the proj_params string from the options passed:
    #
    delete( $self->{params}->{proj_params} );
    my $proj_string = "";

    foreach my $param ( sort keys %{ $self->{params} } )
#line 498 "proj4.pd"
    {
        next unless defined( $self->{params}->{$param} );

        $proj_string .= ( $self->{params}->{$param} eq 'ON' )
                        ? "+$param " : " +$param=" . $self->{params}->{$param} . " ";
        #print STDERR "$sub: Adding \'$proj_string\'...\n";
    }

    #print STDERR "$sub: Final proj_params: \'$proj_string\'\n";

    $self->{params}->{proj_params} = $proj_string;
} # End of update_proj_string()...

sub proj_params
{
    my $self = shift;
    $self->update_proj_string();
    return $self->{params}->{proj_params};
} # End of proj_params()...

# Returns a string with information about what parameters proj will
# actually use, this includes defaults, and +init=file stuff. It's
# the same as running 'proj -v'. It uses the proj command line, so
# it might not work with all shells. I've tested it with bash.
sub get_proj_info
{
    my $params = shift;
    my @a = split(/\n/, `echo | proj -v $params`);
    pop(@a);
    return join("\n", @a);
}

sub t_proj
{
    PDL::Transform::Proj4->new( @_ );
} # End of t_proj()...

1;
#line 366 "Proj4.pm"


=head1 FUNCTIONS

=cut






=head2 fwd_transform

=for sig

  Signature: (lonlat(n=2); [o] xy(n); char* params)

=for ref

PROJ forward transformation $params is a string of the projection
transformation parameters.

Returns a pdl with x, y values at positions 0, 1. The units are dependent
on PROJ behavior. They will be PDL->null if an error has occurred.

=for bad

Ignores bad elements of $lat and $lon, and sets the corresponding elements
of $x and $y to BAD

=for bad

fwd_transform processes bad values.
It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.

=cut




*fwd_transform = \&PDL::fwd_transform;






=head2 inv_transform

=for sig

  Signature: (xy(n=2); [o] lonlat(n); char* params)

=for ref

PROJ inverse transformation $params is a string of the projection
transformation parameters.

Returns a pdl with lon, lat values at positions 0, 1. The units are
dependent on PROJ behavior. They will be PDL->null if an error has
occurred.

=for bad

Ignores bad elements of $lat and $lon, and sets the corresponding elements
of $x and $y to BAD

=for bad

inv_transform processes bad values.
It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.

=cut




*inv_transform = \&PDL::inv_transform;





#line 196 "proj4.pd"

=head2 proj_version

Returns a 3-element list with PROJ major, minor, patch version-numbers.
Not exported.

=cut

my %SKIP = map +($_=>1), qw(
  and or Special for Madagascar
  fixed Earth For CH1903
);
sub load_projection_information {
    my $text = do { open my $fh, '-|', qw(proj -lP) or die "proj -lP: $!"; local $/; <$fh> };
    my @chunks = $text =~ /(.+?)(?=(?:^\S|\z))/gms;
    chomp for @chunks;
    my %descriptions = map {
      my ($id, $rest) = split /\s*:\s*/, $_, 2;
    } @chunks;
    my %info;
    foreach my $projection ( sort keys %descriptions ) {
        my $description = $descriptions{$projection};
        my %hash = (CODE => $projection);
        my @lines = split( /\n/, $description );
        chomp @lines;
        # Full name of this projection:
        ($hash{NAME}, my $temp) = splice @lines, 0, 2;
        if ($temp) {
          # The second line is usually a list of projection types this one is:
          $temp =~ s/no inv\.*,*//;
          $temp =~ s/or//;
          my @temp_types = split(/[,&\s]/, $temp );
          my @types = grep( /.+/, @temp_types );
          $hash{CATEGORIES} = \@types;
        }
        # If there's more than 2 lines, then it usually is a listing of parameters:
        # General parameters for all projections:
        $hash{PARAMS}{GENERAL} =
            [ qw( x_0 y_0 lon_0 units init no_defs geoc over ) ];
        # Earth Figure Parameters:
        $hash{PARAMS}{EARTH} =
            [ qw( ellps b f rf e es R R_A R_V R_a R_g R_h R_lat_g ) ];
        # Projection Specific Parameters:
        $hash{PARAMS}{PROJ} = [
          grep !$SKIP{$_}, map {s/=//; s/[,\[\]]//sg; $_}
            grep length, map split(/\s+/), @lines
        ];
        # Can this projection do inverse?
        $hash{INVERSE} = ( $description =~ /no inv/ ) ? 0 : 1;
        $info{$projection} = \%hash;
    }
    # A couple of overrides:
    #
    $info{ob_tran}{PARAMS}{PROJ} =
        [ 'o_proj', 'o_lat_p', 'o_lon_p', 'o_alpha', 'o_lon_c',
          'o_lat_c', 'o_lon_1', 'o_lat_1', 'o_lon_2', 'o_lat_2' ];
    $info{nzmg}{CATEGORIES} = [ 'fixed Earth' ];
    return \%info;
}

#line 542 "proj4.pd"

=head1 FUNCTIONS

=head2 t_proj

This is the main entry point for the generalized interface. See above on its usage.

=cut

#line 652 "proj4.pd"

=head1 AUTHOR

Judd Taylor, Orbital Systems, Ltd.
judd dot t at orbitalsystems dot com

=cut
#line 529 "Proj4.pm"

# Exit with OK status

1;
