Next: Metadata Lexicons Up: Putting It All Together: Previous: Updating the coordinate display

## The Viewable: Loading the Proper Metadata

You might wonder how the coordinate system was created in first place for it to be used by our viewer. Creating a `CoordinateSystem` object is usually the job of a `Viewable` implementation whose job is to be a format-independent interface between the application and a format-specific reader. It needs to read the relevent data from the formatted data source, load them into a `Metadata` list, and then turn them into the proper `CoordinateSystem`. Because of the relationship between a `Viewable` implementation and the specific data format it sits on top of, one normally would only need to mess with the details of creating new `CoordinateSystem` objects when integrating a new data format with the Horizon package.

Our demonstration applet, `CoordDemoApplet` illustrates how to create `CoordinateSystem`
[0] objects. As mentioned in §3.2.1, GIF and JPEG images are usually given the simplest
[3] `CoordinateSystem`s which are simply pixel based; this is because these data formats do not include anymore complex information about the coordinate system the pixels reside in. In principle, however the coordinate system information could exist somewhere other than in the file containing such an image. In our example, we show how we might use externally obtained coordinate metadata to apply complex coordinate systems to a selection of predefined GIF and JPEG images. This is done by wrapping the images in a special implementation of the `Viewable` interface (whose definition is given within the `CoordDemoApplet.java` file).

In this section, we will look at one of those images, an image of the center of the Milky Way taken at radio frequencies. The implementation of the `Viewable`'s `getCoordSys` first checks to see there is coordinate metadata available for the image. If not, it returns a simple `CoordinateSystem` object just like we saw in §3.2.1. If the image is one it recognizes, it declares its coordinate metadata:

        // GalacticCenter.gif
        if (id.equals("GalacticCenter.gif")) {

            // here's the basic data that applies to this image; this
            // information would usually be obtained from the input
            // data itself using a reader that understands the data's
            // format
            //
            // Number of axes
            int naxes = 2;

            // Reference position in degrees
            double[] refval = { 265.604165196, -28.9583335072 };

            // Reference voxel: the voxel whose position is the reference
            // position
            double[] refpos = { 265.0, 182.0 };

            // Voxel size in absolute degrees
            double[] voxelsize = { -2.777777845E-04, -2.777777845E-04 };

            // Names for the axes:
            String[] axisnames = { "R.A.", "Dec." };

            // Projection code: type of projection used
            String projcode = "SIN";

For typical scientific formats, this data would come from the format-specific reader which would have extracted the data from the file itself.

Next we load the data into a `Metadata` list:

            // Before we create the CoordinateSystem object, we need to
            // load the parameters into a Metadata object.  This is best
            // done using a CoordMetadata object.
            CoordMetadata cmdata = new CoordMetadata(2);

            // The CoordMetadata class is aware of the metadata that
            // CoordinateSystems look for and helps ensure that the data
            // is loaded with the correct metadata name and type.  It
            // does this by providing special set methods for the
            // Coordinate related metadata.  See the API documentation for
            // CoordMetadata for more information.
            //
            cmdata.setAxisRefposition(0, refpos[0]);
            cmdata.setAxisRefposition(1, refpos[1]);
            cmdata.setAxisRefvalue(0, refval[0]);
            cmdata.setAxisRefvalue(1, refval[1]);
            cmdata.setAxisStepsize(0, voxelsize[0]);
            cmdata.setAxisStepsize(1, voxelsize[1]);

            cmdata.setAxisType(0, "longitude");
            cmdata.setAxisType(1, "latitude");

            // If we know what the correct data Metadata key name and type
            // for the data we are setting, we could alternatively use a
            // method of the super-class Metadata (see API documentation
            // for CoordMetadata for details):
            //
            cmdata.setAxisName(axisnames);

            // We should choose formatter objects of type CoordAxisPos.
            // This object converts a double into a formatted String.
            // If we do not set this, a default formatter will be set
            // that prints the position as normal double values.
            //
            // For this dataset, we want the positions printed with a
            // special format.  RA should be printed in
            // hours:minutes:seconds format and Dec should be printed
            // in degrees:minutes:seconds format.
            cmdata.setAxisFormatter(0, new HHMMSSAxisPosFormatter());
            cmdata.setAxisFormatter(1, new DDMMSSAxisPosFormatter());

            // Now we create the desired CoordinateSystem.  Our reader tells
            // us (or assumes) that the coordinate system is a sphere
            // projected on a plane; thus we will use the
            // ProjectedSphericalCoordinateSystem.
            //
            // This CoordinateSystem requires a metadatum called "projection",
            // the code that identifies the projection type. (See
            // ProjectedSphericalCoordinateSystem API documentation.)
            //
            cmdata.put("projection", projcode);

We used the `CoordMetadata` class to help us load the data in accordance with the horizon schema so that the data can be used by the coordinate classes. Note, however, that this GIF image was originally created from a FITS file. If we were reading the FITS file directly, we could use the `FITSCoordMetadata` class to load the data. This class takes the FITS metadata in its native form and automatically converts it to the horizon schema before saving them in the metadata list.

Finally, we can create the `CoordinateSystem`:

            // We tell the constructor that axis 0 is the longitude axis and
            // axis 1 is the latitude axis.
            //
            try {
                coord = new SphLinCoordinateSystem(cmdata);
            } catch (IllegalTransformException ex) {
                System.err.println("Warning: " + ex.getMessage() + "\n" +
                                   "Using a default coordinate system.");
                coord = new CoordinateSystem(new CoordMetadata(2));
            }
        }

We chose the `ncsa.horizon.coordinates.systems.SphLinCoordinateSystem` implementation because our image has two spherical axes in it, right ascension and declination, which represent longitude and latitude on the sky. The `try` block is used to catch an exception that might be thrown if the collection of metadata do not describe any definable coordinate system. This might happen if some of the metadata have erroneous or inconsistent values or if needed metadata do not exist in the metadata list. In this case, we resort to a simple pixel-based coordinate system.

As a summary, we can trace the procedure of coordinate tracking from the initial metadata to the display of coordinate systems by a viewer. First the coordinate-related metadata are read in from a format-specific file and loaded into a `Metadata` list using the horizon schema. These metadata are then used to create a `CoordinateSystem` object which is handed to the `Viewer` via the `Viewable`'s `getCoordSys` method. The `Viewer` keeps track of how the data is displayed in its display region using an `ImageDisplayMap` object. When the user requests the coordinate position from a displayed pixel (say, by moving the mouse over the pixel), the display pixel is first converted to a data voxel by passing it through the `ImageDisplayMap`; that voxel is then sent through the `CoordinateSystem` to get the coordinate position. When it is displayed for the user, it is automatically printed in a coordinate system-specific format.

Next: Metadata Lexicons Up: Putting It All Together: Previous: Updating the coordinate display