Astro::Coords::Offset - Represent an offset from a base position


Astro-Coords documentation Contained in the Astro-Coords distribution.

Index


Code Index:

NAME

Top

Astro::Coords::Offset - Represent an offset from a base position

SYNOPSIS

Top

  use Astro::Coords::Offset;

  my $offset = new Astro::Coords::Offset( 10, 20, 
                                          system => 'J2000',
                                          projection => "TAN" );

  my $offset = new Astro::Coords::Offset( $ang1, $ang2, 
                                          system => 'J2000',
                                          projection => "TAN" );

  my ($a1, $a2) = $offset->offsets;
  my $arcsec = $a1->arcsec;

DESCRIPTION

Top

Sometimes, it is necessary for a position to be specified that is offset from the base tracking system. This class provides a means of specifying an offset in a particular coordinate system and using a specified projection.

METHODS

Top

Constructor

new

Create a new Offset object. The first two arguments must be the offsets in arcseconds or Astro::Coords::Angle objects. The projection and tracking system can be specified as optional hash arguments (defaulting to TAN and J2000 respectively).

  my $off = new Astro::Coords::Offset( 10, -20 );

  my $off = new Astro::Coords::Offset( @off, system => "AZEL", 
                                             projection => "SIN");

  my $off = new Astro::Coords::Offset( @off, system => "AZEL", 
                                             projection => "SIN",
                                             posang => $pa,
                                     );

Accessor Methods

offsets

Return the X and Y offsets.

  @offsets = $self->offsets;

as Astro::Coords::Angle objects.

xoffset

Returns just the X offset.

  $x = $off->xoffset;

yoffset

Returns just the Y offset.

  $x = $off->yoffset;

system

Coordinate system of this offset. Can be different to the coordinate system of the base position.

Allowed values are J2000, B1950, AZEL plus others specified by the JAC TCS XML (see "SEE ALSO" section at end). TRACKING is special since it can change, depending on which output coordinate frame is in use. See the tracking_system attribute for more details.

"Az/El" is treated as "AZEL" for backwards compatibility reasons.

posang

Position angle of this offset as an Astro::Coords::Angle object. Position angle follows the normal "East of North" convention.

  $off->posang( 45 );
  $pa = $off->posang;

If a number is supplied it is assumed to be in degrees (this matches the common usage in the JCMT TCS XML DTD).

By default returns a position angle of 0 deg.

projection

Return (or set) the projection that should be used for this offset. Defaults to tangent plane. Allowed options are TAN, SIN or ARC.

tracking_system

In some cases, the offset can be specified to be relative to the system that the telescope is currently using to track the source. This does not necessarily have to be the same as the coordinate frame that was originally used to specify the target. For example, it is perfectly acceptable to ask a telescope to go to a certain Az/El and then ask it to track in RA/Dec.

This method allows the tracking system to be specified independenttly of the offset coordinate system. It will only be used if the offset is specified to use "TRACKING" (but it allows the system to disambiguate an offset that was defined as "TRACKING B1950" from an offset that is simply "B1950".

The allowed types are the same as for system except that "TRACKING" is not permitted.

General Methods

invert

Return a new offset object with the sense of the offset inverted.

  $inv = $offset->invert;

clone

Create a cloned copy of this offset.

  $clone = $offset->clone;

SEE ALSO

Top

The allowed offset types are designed to match the specification used by the Portable Telescope Control System configuration XML. See http://www.jach.hawaii.edu/JACdocs/JCMT/OCS/ICD/006 for more on this.

AUTHOR

Top

Tim Jenness <tjenness@cpan.org>

COPYRIGHT

Top


Astro-Coords documentation Contained in the Astro-Coords distribution.
package Astro::Coords::Offset;

use 5.006;
use strict;
use warnings;
use Carp;

use Astro::Coords::Angle;

use constant PAZERO => new Astro::Coords::Angle( 0.0 );

use vars qw/ @PROJ  @SYSTEMS /;

our $VERSION = '0.01';

# Allowed projections
@PROJ = qw| SIN TAN ARC DIRECT |;

# Allowed coordinate systems  J\d+ and B\d+ are also allowed by the
# PTCS - these are pattern matches
@SYSTEMS = (qw|
	      TRACKING
	      GAL
	      ICRS
	      ICRF
              |,
	      qr|J\d+(\.\d)?|,
	      qr|B\d+(\.\d)?|,
            qw|
	      APP
	      HADEC
	      AZEL
	      MOUNT
	      OBS
	      FPLANE
	      |);

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;

  my $dc1 = shift;
  my $dc2 = shift;

  croak "Offsets must be supplied to constructor"
    if (!defined $dc1 || !defined $dc2);

  my %options = @_;

  # Aim for case-insensitive keys
  my %merged = (
		  system => "J2000",
		  projection => 'TAN',
		  tracking_system => undef,
		  posang => undef );

  for my $k (keys %options) {
    my $lk = lc($k);
    if (exists $merged{$lk}) {
      $merged{$lk} = $options{$k};
    }
  }

  # Store the offsets as Angle objects if they are not already
  $dc1 = new Astro::Coords::Angle( $dc1, units => 'arcsec' )
    unless UNIVERSAL::isa( $dc1, 'Astro::Coords::Angle');
  $dc2 = new Astro::Coords::Angle( $dc2, units => 'arcsec' )
    unless UNIVERSAL::isa( $dc2, 'Astro::Coords::Angle');


  # Create the object
  my $off = bless {
		   OFFSETS => [ $dc1, $dc2 ],
		   PROJECTION => undef,
		   POSANG   => PAZERO,
		   SYSTEM       => undef,
		   TRACKING_SYSTEM => undef,
		  }, $class;

  # Use accessor to set so that we get validation
  $off->projection( $merged{projection} );
  $off->system( $merged{system} );
  $off->tracking_system( $merged{tracking_system} )
    if defined $merged{tracking_system};
  $off->posang( $merged{posang} )
    if defined $merged{posang};

  return $off;
}

sub offsets {
  my $self = shift;
  return @{$self->{OFFSETS}};
}

sub xoffset {
  my $self = shift;
  my @xy = $self->offsets;
  return $xy[0];
}

sub yoffset {
  my $self = shift;
  my @xy = $self->offsets;
  return $xy[1];
}

sub system {
  my $self = shift;
  if (@_) { 
    my $p = shift;
    $p = uc($p);
    $p = "AZEL" if $p eq 'AZ/EL';

    # need to make sure that we convert the input system into
    # a TCS system
    my $match;
    for my $compare (@SYSTEMS) {
	if ($p =~ /^$compare/) {
	    if (!defined $match) {
                if (ref($compare)) {
                   # regex so we just take the input
                   $match = $p;
                } else {
                   # exact match to start of string so take the TCS value
   	 	   $match = $compare;
                }
	    } else {
		croak "Multiple matches for system '$p'";
	    }
	}
    }
    croak "Unknown system '$p'" unless defined $match;
    $self->{SYSTEM} = $match;
  }
  return $self->{SYSTEM};
}

sub posang {
  my $self = shift;
  if (@_) {
    my $pa = shift;
    if (!defined $pa) {
      $self->{POSANG} = PAZERO;
    } elsif (UNIVERSAL::isa($pa, "Astro::Coords::Angle")) {
      $self->{POSANG} = $pa;
    } elsif ($pa =~ /\d/) {
      $self->{POSANG} = new Astro::Coords::Angle( $pa, units => 'deg');
    } else {
      croak "Position angle for offset supplied in non-recognizable form ('$pa')";
    }
  }
  return $self->{POSANG};
}

sub projection {
  my $self = shift;
  if (@_) { 
    my $p = shift;
    $p = uc($p);
    my $match = join("|",@PROJ);
    croak "Unknown projection '$p'"
      unless $p =~ /^$match$/;
    $self->{PROJECTION} = $p; 
  }
  return $self->{PROJECTION};
}



#  From the TCS:
#   if (otype == direct)
#     {
#        *dc1 = t1 - b1;
#        *dc2 = t2 - b2;
#     }
#   else if (otype == tan_offset)
#     {
#        slaDs2tp(t1,t2,b1,b2,dc1,dc2,&jstat);
#     }
#   else if (otype == sin_offset)
#     {
#        da = t1 - b1;
#        cd = cos(t2);
#        *dc1 = cd * sin(da);
#        *dc2 = sin(t2)*cos(b2) - cd * sin(b2) * cos(da);
#     }
#   else if (otype == arc_offset)
#     {
#        da = t1 - b1;
#        cd = cos(t2);
#        sd = sin(t2);
#        cd0 = cos(b2);
#        sd0 = sin(b2);
#        cda = cos(da);
#        theta = acos(sd*sd0 + cd*cd0*cda);
#        to = theta/(sin(theta));
#        *dc1 = to*cd*sin(da);
#        *dc2 = to*(sd*cd0 - cd*sd0*cda);
#     }

sub tracking_system {
  my $self = shift;
  if (@_) { 
    my $p = shift;
    $p = uc($p);
    croak "Tracking System can not itself be 'TRACKING'"
      if $p eq 'TRACKING';
    my $match = join("|",@SYSTEMS);
    croak "Unknown system '$p'"
      unless $p =~ /^$match$/;
    $self->{TRACKING_SYSTEM} = $p;
  }
  return $self->{TRACKING_SYSTEM};
}

# We could do this by adding 180 deg to posang but people really
# expect the sign to change

sub invert {
  my $self = shift;

  my @xy = map { $_->negate } $self->offsets;
  my $pa = $self->posang->clone;
  $pa = undef if $pa->radians == 0;
  return $self->new( @xy, system => $self->system,
		     projection => $self->projection,
		     posang => $pa);
}

sub clone {
  my $self = shift;
  my @xy = map { $_->clone() } $self->offsets;
  my $pa = $self->posang->clone;
  $pa = undef if $pa->radians == 0;
  return $self->new( @xy, posang => $pa,
		     system => $self->system,
		     projection => $self->projection
		   );
}

1;