package PDL::Graphics::TriD::Graph;
use base qw/PDL::Graphics::TriD::Object/;
use PDL::LiteF; # XXX F needed?
use fields qw(Data DataBind UnBound DefaultAxes Axis );
sub add_dataseries {
my($this,$data,$name) = @_;
if(!defined $name) {
$name = "Data0";
while(defined $this->{Data}{$name}) {$name++;}
}
$this->{Data}{$name} = $data;
$this->{DataBind}{$name} = [];
$this->{UnBound}{$name} = 1;
$this->add_object($data);
$this->changed();
return $name;
}
sub bind_data {
my($this,$dser,$axes,$axis) = @_;
push @{$this->{DataBind}{$dser}},[$axis,$axes];
delete $this->{UnBound}{$dser};
$this->changed();
}
sub bind_default {
my($this,$dser,$axes) = @_;
if(!defined $axes) {$axes = $this->{DefaultAxes}};
$this->{DataBind}{$dser} = [['Default',$axes]];
delete $this->{UnBound}{$dser};
}
sub set_axis {
my($this,$axis,$name) = @_;
$this->{Axis}{$name} = $axis;
$this->changed();
}
# Bind all unbound things here...
sub scalethings {
my($this) = @_;
for(keys %{$this->{UnBound}}) {
$this->bind_default($_);
}
for(values %{$this->{Axis}}) {
$_->init_scale() ;
}
my ($k,$v);
while(($k,$v) = each %{$this->{DataBind}}) {
for(@$v) {
$this->{Axis}{$_->[0]}->add_scale(
$this->{Data}{$k}->get_points(), $_->[1]);
}
}
for(values %{$this->{Axis}}) {
$_->finish_scale();
}
}
# use Data::Dumper;
sub get_points {
my($this,$name) = @_;
# print Dumper($this->{Axis});
my $d = $this->{Data}{$name}->get_points();
my @ddims = $d->dims; shift @ddims;
my $p = PDL->zeroes(&PDL::float(),3,@ddims);
my $pnew;
for(@{$this->{DataBind}{$name}}) {
defined($this->{Axis}{$_->[0]}) or die("Axis not defined: $_->[0]");
# Transform can return the same or a different piddle.
$pnew = $this->{Axis}{$_->[0]}->transform($p,$d,$_->[1]);
$p = $pnew;
}
return $pnew;
}
sub clear_data {
my($this) = @_;
$this->{Data} = {};
$this->{DataBind} = {};
$this->{UnBound} = {};
$this->changed();
}
sub delete_data {
my($this,$name) = @_;
delete $this->{Data}{$name};
delete $this->{DataBind}{$name};
delete $this->{UnBound}{$name};
$this->changed();
}
sub default_axes {
my($this) = @_;
$this->set_axis(PDL::Graphics::TriD::EuclidAxes->new(),"Euclid3");
$this->set_default_axis("Euclid3",[0,1,2]);
}
sub set_default_axis {
my($this,$name,$axes) = @_;
$this->{Axis}{Default} = $this->{Axis}{$name};
$this->{DefaultAxes} = $axes;
}
sub changed {}
package PDL::Graphics::TriD::EuclidAxes;
sub new {
my($type) = @_; bless {Names => [X,Y,Z]},$type;
}
sub init_scale {
my($this) = @_;
$this->{Scale} = [];
}
sub add_scale {
my($this,$data,$inds) = @_;
my $i = 0;
for(@$inds) {
my $d = $data->slice("($_)");
my $max = $d->max;
my $min = $d->min;
if(!defined $this->{Scale}[$i]) {
$this->{Scale}[$i] = [$min,$max];
} else {
if($min < $this->{Scale}[$i][0]) {
$this->{Scale}[$i][0] = $min;
}
if($max > $this->{Scale}[$i][1]) {
$this->{Scale}[$i][1] = $max;
}
}
$i++;
}
}
sub finish_scale {
my($this) = @_;
# Normalize the smallest differences away.
for(@{$this->{Scale}}) {
if(abs($_->[0] - $_->[1]) < 0.000001) {
$_->[1] = $_->[0] + 1;
} else {
my $shift = ($_->[1]-$_->[0])*0.05;
$_->[0] -= $shift;
$_->[1] += $shift;
}
}
}
# Add 0..1 to each axis.
sub transform {
my($this,$point,$data,$inds) = @_;
my $i = 0;
for(@$inds) {
(my $tmp = $point->slice("($i)")) +=
($data->slice("($_)") - $this->{Scale}[$i][0]) /
($this->{Scale}[$i][1] - $this->{Scale}[$i][0]) ;
$i++;
}
return $point;
}
#
# projects from the sphere to a cylinder
#
package PDL::Graphics::TriD::CylindricalEquidistantAxes;
use PDL::Core '';
sub new {
my($type) = @_;
bless {Names => [LON,LAT,Pressure]},$type;
}
sub init_scale {
my($this) = @_;
$this->{Scale} = [];
}
sub add_scale {
my($this,$data,$inds) = @_;
my $i = 0;
for(@$inds) {
my $d = $data->slice("($_)");
my $max = $d->max;
my $min = $d->min;
if($i==1){
if($max > 89.9999 or $min < -89.9999){
barf "Error in Latitude $max $min\n";
}
}
elsif($i==2){
$max = 1012.5 if($max<1012.5);
$min = 100 if($min>100);
}
if(!defined $this->{Scale}[$i]) {
$this->{Scale}[$i] = [$min,$max];
} else {
if($min < $this->{Scale}[$i][0]) {
$this->{Scale}[$i][0] = $min;
}
if($max > $this->{Scale}[$i][1]) {
$this->{Scale}[$i][1] = $max;
}
}
$i++;
}
# $this->{Center} = [$this->{Scale}[0][0]+($this->{Scale}[0][1]-$this->{Scale}[0][0])/2,
# $this->{Scale}[1][0]+($this->{Scale}[1][1]-$this->{Scale}[1][0])/2];
#
# Should make the projection center an option
#
$this->{Center} = [$this->{Scale}[0][0]+($this->{Scale}[0][1]-$this->{Scale}[0][0])/2,
0];
}
sub finish_scale {
my($this) = @_;
my @dist;
# Normalize the smallest differences away.
for(@{$this->{Scale}}) {
if(abs($_->[0] - $_->[1]) < 0.000001) {
$_->[1] = $_->[0] + 1;
}
push(@dist,$_->[1]-$_->[0]);
}
# for the z coordiniate reverse the min and max values
my $max = $this->{Scale}[2][0];
if($max < $this->{Scale}[2][1]){
$this->{Scale}[2][0] = $this->{Scale}[2][1];
$this->{Scale}[2][1] = $max;
}
# Normalize longitude and latitude scale
if($dist[1] > $dist[0]){
$this->{Scale}[0][0] -= ($dist[1]-$dist[0])/2;
$this->{Scale}[0][1] += ($dist[1]-$dist[0])/2;
}elsif($dist[0] > $dist[1] && $dist[0]<90){
$this->{Scale}[1][0] -= ($dist[0]-$dist[1])/2;
$this->{Scale}[1][1] += ($dist[0]-$dist[1])/2;
}elsif($dist[0] > $dist[1]){
$this->{Scale}[1][0] -= (90-$dist[1])/2;
$this->{Scale}[1][1] += (90-$dist[1])/2;
}
}
sub transform {
my($this,$point,$data,$inds) = @_;
my $i = 0;
if($#$inds!=2){
barf("Wrong number of arguments to transform $this\n");
exit;
}
my $pio180 = 0.017453292;
(my $tmp1 = $point->slice("(0)")) +=
0.5+($data->slice("($inds->[0])")-$this->{Center}[0]) /
($this->{Scale}[0][1] - $this->{Scale}[0][0])
*cos($data->slice("($inds->[1])")*$pio180);
(my $tmp2 = $point->slice("(1)")) +=
0.5+($data->slice("($inds->[1])")-$this->{Center}[1]) /
($this->{Scale}[1][1] - $this->{Scale}[1][0]);
(my $tmp3 = $point->slice("(2)")) .=
log($data->slice("($inds->[2])")/1012.5)/log($this->{Scale}[2][1]/1012.5);
return $point;
}
package PDL::Graphics::TriD::PolarStereoAxes;
use PDL::Core '';
sub new {
my($type) = @_;
bless {Names => [LONGITUDE,LATITUDE,HEIGHT]},$type;
}
sub init_scale {
my($this) = @_;
$this->{Scale} = [];
}
sub add_scale {
my($this,$data,$inds) = @_;
my $i = 0;
for(@$inds) {
my $d = $data->slice("($_)");
my $max = $d->max;
my $min = $d->min;
if($i==1){
if($max > 89.9999 or $min < -89.9999){
barf "Error in Latitude $max $min\n";
}
}
elsif($i==2){
$max = 1012.5 if($max<1012.5);
$min = 100 if($min>100);
}
if(!defined $this->{Scale}[$i]) {
$this->{Scale}[$i] = [$min,$max];
} else {
if($min < $this->{Scale}[$i][0]) {
$this->{Scale}[$i][0] = $min;
}
if($max > $this->{Scale}[$i][1]) {
$this->{Scale}[$i][1] = $max;
}
}
$i++;
}
$this->{Center} = [$this->{Scale}[0][0]+($this->{Scale}[0][1]-$this->{Scale}[0][0])/2,
$this->{Scale}[1][0]+($this->{Scale}[1][1]-$this->{Scale}[1][0])/2];
}
sub finish_scale {
my($this) = @_;
my @dist;
# Normalize the smallest differences away.
for(@{$this->{Scale}}) {
if(abs($_->[0] - $_->[1]) < 0.000001) {
$_->[1] = $_->[0] + 1;
}
push(@dist,$_->[1]-$_->[0]);
}
# for the z coordiniate reverse the min and max values
my $max = $this->{Scale}[2][0];
if($max < $this->{Scale}[2][1]){
$this->{Scale}[2][0] = $this->{Scale}[2][1];
$this->{Scale}[2][1] = $max;
}
# Normalize longitude and latitude scale
if($dist[1] > $dist[0]){
$this->{Scale}[0][0] -= ($dist[1]-$dist[0])/2;
$this->{Scale}[0][1] += ($dist[1]-$dist[0])/2;
}elsif($dist[0] > $dist[1] && $dist[0]<90){
$this->{Scale}[1][0] -= ($dist[0]-$dist[1])/2;
$this->{Scale}[1][1] += ($dist[0]-$dist[1])/2;
}elsif($dist[0] > $dist[1]){
$this->{Scale}[1][0] -= (90-$dist[1])/2;
$this->{Scale}[1][1] += (90-$dist[1])/2;
}
}
sub transform {
my($this,$point,$data,$inds) = @_;
my $i = 0;
if($#$inds!=2){
barf("Wrong number of arguments to transform $this\n");
exit;
}
my $pio180 = 0.017453292;
(my $tmp1 = $point->slice("(0)")) +=
0.5+($data->slice("($inds->[0])")-$this->{Center}[0]) /
($this->{Scale}[0][1] - $this->{Scale}[0][0])
*cos($data->slice("($inds->[1])")*$pio180);
(my $tmp2 = $point->slice("(1)")) +=
0.5+($data->slice("($inds->[1])")-$this->{Center}[1]) /
($this->{Scale}[1][1] - $this->{Scale}[1][0])
*cos($data->slice("($inds->[1])")*$pio180);
# Longitude transformation
# (my $tmp = $point->slice("(0)")) =
# ($this->{Center}[0]-$point->slice("(0)"))*cos($data->slice("(1)"));
# Latitude transformation
# (my $tmp = $point->slice("(1)")) =
# ($this->{Center}[1]-$data->slice("(1)"))*cos($data->slice("(1)"));
# Vertical transformation
# -7.2*log($data->slice("(2)")/1012.5
(my $tmp3 = $point->slice("(2)")) .=
log($data->slice("($inds->[2])")/1012.5)/log($this->{Scale}[2][1]/1012.5);
return $point;
}
1;