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');
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);
1512
1516
barf "map: Transformation had no inverse\n" unless defined($idx);
1514
1518
##############################
1515
1519
## Integrate ? (Jacobian, Gaussian, Hanning)
1516
my $integrate = ($method =~ m/^[jghJGH]/);
1520
my $integrate = ($method =~ m/^[jghJGH]/) if defined($method);
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) {
1524
1527
my $a = $in->interpND($idx,{method=>$method, bound=>$bound});
1525
1528
$out->(:) .= $a; # trivial slice prevents header overwrite...
2075
2083
my $lookup_func = sub {
2076
my($data,$p,$table_name) = @_;
2084
my($data,$p,$table,$scale,$offset) = @_;
2087
unless ((ref $data) && (UNIVERSAL::isa($data,'PDL')));
2078
2090
if($data->dim(0) > $me->{idim}) {
2079
2091
barf("Too many dims (".$data->dim(0).") for your table (".$me->{idim}.")\n");
2083
unless ((ref $data) && (UNIVERSAL::isa($data,'PDL')));
2087
->interpND(float($data) * $p->{scale} + $p->{offset},
2095
->interpND(float($data) * $scale + $offset,
2088
2096
$p->{interpND_opt}
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
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})};
2106
2114
## Lazy inverse -- find it if and only if we need it...
2107
2115
$me->{inv} = sub {
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)");
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;
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);
2132
$p->{iscale} = $scale;
2133
$p->{ioffset} = $offset;
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;
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)))->
2142
clump($itable->ndims-1); # oloop: (pixel, index)
2143
$oloop->mv(-1,0) -= $offset;
2144
$oloop->mv(-1,0) /= $scale;
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.
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,...)
2153
my $itable_flattened = zeroes($oloop);
2155
for $i(0..$oloop->dim(0)-1) {
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)
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)));
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;
2175
print " $i..." if( ($i%1000==0) && ( $PDL::verbose || $PDL::debug || $PDL::Transform::debug));
2177
$itable->clump($itable->ndims-1) .= $itable_flattened;
2178
$itable->mv(-1,0) -= $p->{offset};
2179
$itable->mv(-1,0) /= $p->{scale};
2181
$p->{itable} = $itable;
2112
&$lookup_func(@_[0..1], 'itable') ;
2183
&$lookup_func($data,$p, $p->{itable},$p->{iscale},$p->{ioffset}) ;
2646
2721
$cr = $hdr->{CROTA1} unless defined $cr;
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)] );
2655
2730
for my $i(1..$n) {
2656
2731
$cd->(($i-1)) .= $hdr->{"CDELT$i"};
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));
2659
2737
$matrix = $cdm x $cpm;