~ubuntu-branches/ubuntu/maverick/pdl/maverick

« back to all changes in this revision

Viewing changes to Lib/Transform/transform.pd

  • Committer: Bazaar Package Importer
  • Author(s): Andres Rodriguez
  • Date: 2009-12-05 12:37:41 UTC
  • mfrom: (2.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091205123741-ilqkc9s4zlk71z13
Tags: 1:2.4.5+dfsg-2ubuntu1
* Merge from debian testing (LP: #492898), remaining changes:
  - debian/perldl.conf: Enabled NAN support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
1
2
pp_addpm({At=>'Top'},<<'======EOD======');
2
3
 
3
4
=head1 NAME
858
859
         i_off += in->dimincs[i] * j;
859
860
       }
860
861
  
861
 
        if(bound_ok) {
 
862
       {  /* convenience block for bounds handling and data weighting */
862
863
         PDL_Double alpha = 1.0;
863
864
         PDL_Double *ap = tvec;
864
865
         PDL_Double *bp = dvec;
901
902
                     dd += *(ap++) * *(cp++);
902
903
                  dd /= blur;
903
904
                  sum += dd * dd;
904
 
                  if(sum > 4)  /* 2 pixels -- four half-widths */
905
 
                    i = ndims;
 
905
                  if(sum > 4) /* 2 pixels -- four half-widths */
 
906
                    i = ndims; /* exit early if this pixel is too far outside the footprint of the ideal point */
906
907
               }
907
908
               
908
909
               if(sum > 4)      
923
924
        /* We've got the weighting, now accumulate the values as needed... */
924
925
         wgt += alpha;
925
926
       
 
927
       if(bound_ok)
926
928
         { 
927
929
          PDL_Double *ac = acc;
928
930
          $GENERIC() *dat = (($GENERIC() *)(in->data)) + i_off;
930
932
               *(ac++) += *dat * alpha;
931
933
               dat += in->dimincs[ndims];
932
934
          }
933
 
         }
934
 
       } /* end of bound_ok check */
 
935
         }/* end of bound_ok check */
 
936
 
 
937
       }  /* end of data collection convenience block */
935
938
       
936
939
       /* Advance input accumulation loop */
937
940
       for(i=0; 
940
943
           i++) {
941
944
          ivec[i] = -psize;
942
945
       }
943
 
     } while(i<ndims);
 
946
     } while(i<ndims);  /* end of total data accumulation loop */
944
947
     
945
948
     {
946
949
       PDL_Double *ac = acc;
1454
1457
        $omax = $oc2->maximum;
1455
1458
 
1456
1459
        $osize = $omax - $omin;
1457
 
        $osize->where($osize == 0) .= 1.0;
 
1460
        my $tosize;
 
1461
        ($tosize = $osize->where($osize == 0)) .= 1.0;
1458
1462
      }
1459
1463
 
1460
1464
      my ($scale) = $osize / pdl(($out->dims)[0..$nd-1]);
1468
1472
 
1469
1473
      my $d;
1470
1474
      for $d(1..$nd) {
1471
 
          $out->hdr->{"CRPIX$d"} = 1 + ($out->dim($d-1))/2 ;
 
1475
          $out->hdr->{"CRPIX$d"} = 1 + ($out->dim($d-1)-1)/2 ;
1472
1476
          $out->hdr->{"CDELT$d"} = $scale->at($d-1);
1473
1477
          $out->hdr->{"CRVAL$d"} = ( $omin->at($d-1) + $omax->at($d-1) ) /2 ;
1474
1478
          $out->hdr->{"NAXIS$d"} = $out->dim($d-1);
1500
1504
 
1501
1505
  ##############################
1502
1506
  ## Figure out the interpND options
1503
 
  my $method = _opt($opt,['m','method','Method']);
 
1507
  my $method = _opt($opt,['m','method','Method'],undef);
1504
1508
  my $bound = _opt($opt,['b','bound','boundary','Boundary'],'t');
1505
1509
 
1506
1510
 
1507
1511
  ##############################
1508
1512
  ## Rubber meets the road: calculate the inverse transformed points.
1509
1513
  my $ndc = PDL::Basic::ndcoords(@dd);
1510
 
  my $idx = $me->invert($ndc->double + 0.5);
 
1514
  my $idx = $me->invert($ndc->double);
1511
1515
 
1512
1516
  barf "map: Transformation had no inverse\n" unless defined($idx);
1513
1517
        
1514
1518
  ##############################
1515
1519
  ## Integrate ?  (Jacobian, Gaussian, Hanning)  
1516
 
  my $integrate = ($method =~ m/^[jghJGH]/);
 
1520
  my $integrate = ($method =~ m/^[jghJGH]/) if defined($method);
1517
1521
 
1518
1522
  ##############################
1519
1523
  ## Sampling code:
1520
1524
  ## just transform and interpolate. 
1521
1525
  ##  ( Kind of an anticlimax after all that, eh? )
1522
1526
  if(!$integrate) {
1523
 
 
1524
1527
    my $a = $in->interpND($idx,{method=>$method, bound=>$bound});
1525
1528
    $out->(:) .= $a; # trivial slice prevents header overwrite...
1526
1529
    return $out;
1981
1984
 
1982
1985
The lookup index scaling is: out = lookup[ (scale * data) + offset ].
1983
1986
 
1984
 
The inverse transform is calculated. 
 
1987
A simplistic table inversion routine is included.  This means that
 
1988
you can (for example) use the C<map> method with C<t_lookup> transformations.
 
1989
But the table inversion is exceedingly slow, and not practical for tables
 
1990
larger than about 100x100.  The inversion table is calculated in its
 
1991
entirety the first time it is needed, and then cached until the object is
 
1992
destroyed.
1985
1993
 
1986
1994
Options are listed below; there are several synonyms for each.
1987
1995
 
2014
2022
 
2015
2023
To scale logarithmically the Y axis of m51, try:
2016
2024
 
2017
 
  $a = rfits('m51.fits');
2018
 
  $lookup = xvals(256,256) -> cat( 10**(yvals(256,256)/100) * 256/10**2.55 );
 
2025
  $a = float rfits('m51.fits');
 
2026
  $lookup = xvals(128,128) -> cat( 10**(yvals(128,128)/50) * 256/10**2.55 );
2019
2027
  $t = t_lookup($lookup);
2020
2028
  $b = $t->map($a);
2021
2029
 
2058
2066
  my($method)= _opt($o,['m','meth','method','Method']);
2059
2067
 
2060
2068
  $me->{idim} = $source->ndims - 1;
2061
 
  $me->{odim} = $source->dims($source->ndims-1);
 
2069
  $me->{odim} = $source->dim($source->ndims-1);
2062
2070
 
2063
2071
  $me->{params} = {
2064
2072
      table => $source,
2073
2081
 
2074
2082
  
2075
2083
   my $lookup_func = sub {
2076
 
     my($data,$p,$table_name) = @_;
 
2084
     my($data,$p,$table,$scale,$offset) = @_;
 
2085
 
 
2086
    $data = pdl($data) 
 
2087
      unless ((ref $data) && (UNIVERSAL::isa($data,'PDL')));
 
2088
      $main::foo = $data;
2077
2089
 
2078
2090
    if($data->dim(0) > $me->{idim}) {
2079
2091
      barf("Too many dims (".$data->dim(0).") for your table (".$me->{idim}.")\n");
2080
2092
    };
2081
2093
 
2082
 
    $data = pdl($data) 
2083
 
      unless ((ref $data) && (UNIVERSAL::isa($data,'PDL')));
2084
 
 
2085
 
    my($a)= ($p
2086
 
             ->{$table_name}
2087
 
             ->interpND(float($data) * $p->{scale} + $p->{offset},
 
2094
    my($a)= ($table
 
2095
             ->interpND(float($data) * $scale + $offset,
2088
2096
                        $p->{interpND_opt}
2089
2097
                        )
2090
2098
             );
2094
2102
    # the dimension list.
2095
2103
    my($dnd) = $data->ndims - 1;
2096
2104
    return ($a -> ndims > $data->ndims - 1) ? 
2097
 
      ($a->reorder( $dnd..($dnd + $p->{$table_name}->ndims - $data->dim(0)-1)
 
2105
      ($a->reorder( $dnd..($dnd + $table->ndims - $data->dim(0)-1)
2098
2106
                    , 0..$data->ndims-2
2099
2107
                    )
2100
2108
       ) : $a;
2101
2109
  };
2102
2110
 
2103
 
  $me->{func} = sub {my($data,$p) = @_;  &$lookup_func($data,$p,'table')};
 
2111
  $me->{func} = sub {my($data,$p) = @_;  &$lookup_func($data,$p,$p->{table},$p->{scale},$p->{offset})};
2104
2112
 
2105
2113
  #######
2106
2114
  ## Lazy inverse -- find it if and only if we need it...
2107
2115
  $me->{inv} = sub {
 
2116
      my $data = shift;
2108
2117
      my $p = shift;
2109
2118
      if(!defined($p->{'itable'})) {
2110
 
        barf "Inversion of lookup transforms is not yet implemented\n";
 
2119
        if($me->{idim} != $me->{odim}) {
 
2120
         barf("t_lookup: can't calculate an inverse of a projection operation! (idim != odim)");
 
2121
        }
 
2122
       print "t_lookup: Warning, table inversion is only weakly supported.  \n   I'll try to invert it using a pretty boneheaded algorithm...\n  (If it takes too long, consider writing a faster algorithm!)\n   Calculating inverse table (will be cached)...\n" if($PDL::verbose || $PDL::debug || $PDL::Transform::debug);
 
2123
        my $itable = zeroes($p->{table});
 
2124
        my $minvals = $p->{table}->clump($me->{idim})->minimum;
 
2125
        my $maxvals = $p->{table}->clump($me->{idim})->maximum;
 
2126
        
 
2127
        # Scale so that the range runs from 0 through the top pixel in the table
 
2128
        my $scale = (  pdl(  $itable->dims  )->(0:-2)-1  ) / 
 
2129
                    (($maxvals - $minvals)+ (($maxvals-$minvals) == 0));
 
2130
        my $offset = - ($minvals/$scale);
 
2131
 
 
2132
        $p->{iscale} = $scale;
 
2133
        $p->{ioffset} = $offset;
 
2134
                      
 
2135
        my $enl_scale = $p->{'enl_scale'} || 10;
 
2136
        my $smallcoords = ndcoords((pdl($enl_scale * 2 + 1)->at(0)) x $me->{idim})/ $enl_scale - 1;
 
2137
 
 
2138
        # $oloop runs over (point, index) for all points in the output table, in 
 
2139
        # $p->{table} output space
 
2140
        $oloop = ndcoords($itable->mv(-1,0)->((0)))->
 
2141
                        mv(0,-1)->
 
2142
                        clump($itable->ndims-1);  # oloop: (pixel, index)
 
2143
        $oloop->mv(-1,0) -= $offset;
 
2144
        $oloop->mv(-1,0) /= $scale;
 
2145
 
 
2146
        # The Right Thing to do here is to take the outer product of $itable and $otable, then collapse 
 
2147
        # to find minimum distance.  But memory demands for that would be HUGE.  Instead we do an 
 
2148
        # elementwise calculation.
 
2149
 
 
2150
        print "t_lookup: inverting ".$oloop->dim(0)." points...\n" if($PDL::verbose || $PDL::debug || $PDL::Transform::debug);
 
2151
        my $pt = $p->{table}->mv(-1,0); # pt runs (index, x,y,...)
 
2152
 
 
2153
        my $itable_flattened = zeroes($oloop);
 
2154
 
 
2155
        for $i(0..$oloop->dim(0)-1) {
 
2156
 
 
2157
            my $olp = $oloop->(($i));                # olp runs (index)
 
2158
            my $diff = ($pt - $olp);                 # diff runs (index, x, y, ...)
 
2159
            my $r2 = ($diff * $diff)->sumover;       # r2 runs (x,y,...)
 
2160
            my $c = whichND($r2==$r2->min)->(:,(0)); # c runs (index)
 
2161
 
 
2162
            # Now zero in on the neighborhood around the point of closest approach.
 
2163
            my $neighborhood = $p->{table}->interpND($c + $smallcoords,{method=>'linear',bound=>'t'})->
 
2164
                     mv(-1,0); # neighborhood runs (index, dx, dy,...)
 
2165
            $diff = $neighborhood - $olp;        # diff runs (index, dx, dy, ...)
 
2166
            $r2 = ($diff * $diff)->sumover;      # r2 runs (dx,dy,...)
 
2167
            my $dc = $smallcoords->mv(0,-1)->indexND(0+whichND($r2==$r2->min)->(:,(0)));
 
2168
            
 
2169
 
 
2170
            my $coord = $c + $dc;
 
2171
            # At last, we've found the best-fit to an enl_scale'th of an input-table pixel.
 
2172
            # Back it out to input-science coordinates, and stuff it in the inverse table.
 
2173
            $itable_flattened->(($i)) .= $coord;
 
2174
            
 
2175
            print " $i..." if( ($i%1000==0) && ( $PDL::verbose || $PDL::debug || $PDL::Transform::debug));
 
2176
        }
 
2177
        $itable->clump($itable->ndims-1) .= $itable_flattened;
 
2178
        $itable->mv(-1,0) -= $p->{offset};
 
2179
        $itable->mv(-1,0) /= $p->{scale};
 
2180
 
 
2181
        $p->{itable} = $itable;
2111
2182
      }
2112
 
      &$lookup_func(@_[0..1], 'itable') ;
 
2183
      &$lookup_func($data,$p, $p->{itable},$p->{iscale},$p->{ioffset}) ;
2113
2184
    };
2114
2185
 
2115
2186
 
2230
2301
sub PDL::Transform::Linear::new {
2231
2302
  my($class) = shift;
2232
2303
  my($o) = $_[0];
 
2304
  pop @_ if (($#_ % 2 ==0) && !defined($_[-1]));
 
2305
  #suppresses a warning if @_ has an odd number of elements and the
 
2306
  #last is undef
 
2307
 
2233
2308
  if(!(ref $o)) {
2234
2309
    $o = {@_};
2235
2310
  }
2615
2690
    
2616
2691
    #
2617
2692
    # CPi_j + CDELTi formalism
2618
 
    # If CPi_j arent present, and N=2, then try using CROTA or
 
2693
    # If CPi_j aren't present, and N=2, then try using CROTA or
2619
2694
    # CROTA2 to generate a rotation matrix instea.  
2620
2695
    #
2621
2696
  
2646
2721
      $cr = $hdr->{CROTA1} unless defined $cr;
2647
2722
 
2648
2723
      $cr *= $DEG2RAD;
2649
 
        # Rotation matrix rotates clockwise to get from sci to pixel coords
2650
 
        # (image has been rotated ccw, according to FITS standard)
2651
 
      $cpm .= pdl( [cos($cr), -sin($cr)],[sin($cr),cos($cr)] );
 
2724
        # Rotation matrix rotates counterclockwise to get from sci to pixel coords
 
2725
        # (detector has been rotated ccw, according to FITS standard)
 
2726
      $cpm .= pdl( [cos($cr), sin($cr)],[-sin($cr),cos($cr)] );
2652
2727
 
2653
2728
    }
2654
2729
      
2655
2730
    for my $i(1..$n) {
2656
2731
      $cd->(($i-1)) .= $hdr->{"CDELT$i"};
2657
2732
    }
2658
 
    
 
2733
#If there are no CDELTs, then we assume they are all 1.0,
 
2734
#as in PDL::Graphics::PGPLOT::Window::_FITS_tr.
 
2735
    $cd+=1 if (all($cd==0));
 
2736
 
2659
2737
    $matrix = $cdm x $cpm;
2660
2738
  }
2661
2739