001    /* @(#)FitsWCS.java     $Revision: 1.3 $    $Date: 2003/04/08 14:54:31 $
002     *
003     * Copyright (C) 2003 European Southern Observatory 
004     * License:  GNU General Public License version 2 or later
005     */
006    package org.eso.fits;
007    
008    import java.io.*;
009    import java.text.*;
010    
011    /** FitsData class represents a FITS data unit
012     *
013     *  @version $Revision: 1.3 $ $Date: 2003/04/08 14:54:31 $
014     *  @author  P.Grosbol, DMD/ESO, <pgrosbol@eso.org>
015     */
016    public class FitsWCS {
017    
018        public final static int LIN = 0;
019        public final static int TAN = 1;
020        public final static int ARC = 2;
021    
022        private final static int MPS = 20;
023    
024        protected int        type;
025        protected int        nax = 0;
026        protected int[]      cproj;
027        protected double[]   crpix;
028        protected double[]   crval;
029        protected double[]   cdelt;
030        protected double[]   crota;
031        protected String[]   ctype;
032        protected double[][] cdMatrix;
033        protected double[][] pcMatrix;
034        protected boolean    hasPcMatrix = false;
035        protected boolean    hasCdMatrix = false;
036    
037        protected double[]   amdx = new double[MPS];
038        protected double[]   amdy = new double[MPS];
039    
040        /** Default constructor for FitsWCS class.
041         */
042        public FitsWCS() {
043            type = Fits.UNKNOWN;
044        }
045    
046        /** Constructor for FitsData class given a FITS header with 
047         *  associated data unit as a file.
048         *
049         *  @param header  FitsHeader object with the image header
050         */
051        public FitsWCS(FitsHeader header) {
052            this();
053            setHeader(header, ' ');
054        }
055    
056        /** Constructor for FitsData class given a FITS header with 
057         *  associated data unit as a file.
058         *
059         *  @param header  FitsHeader object with the image header
060         *  @param ver     version of WCS i.e. ' ' or 'A'..'Z'
061         */
062        public FitsWCS(FitsHeader header, char ver) {
063            this();
064            setHeader(header, ver);
065        }
066    
067        /** Constructor for FitsData class given a No. of axies of data array.
068         *
069         *  @param nax  No. of axies of data array
070         */
071        public FitsWCS(int nax) {
072            this();
073            init(nax);
074        }
075    
076        /** Define FITS header for FitsWCS object.
077         *
078         *  @param header  FitsHeader object with the image header
079         *  @param ver     version of WCS i.e. ' ' or 'A'..'Z'
080         */
081        public void setHeader(FitsHeader header, char ver) {
082            type = header.getType();
083    
084            FitsKeyword kw = header.getKeyword("NAXIS");
085            nax = (kw == null) ? 0 : kw.getInt();
086            init(nax);
087    
088            String sver = String.valueOf(ver).toUpperCase().trim();
089            for (int j=1; j<=nax; j++) {
090                kw = header.getKeyword("CRPIX"+j+sver);
091                crpix[j-1] = (kw == null) ? 0.0 : kw.getReal();
092    
093                kw = header.getKeyword("CRVAL"+j+sver);
094                crval[j-1] = (kw == null) ? 0.0 : kw.getReal();
095    
096                kw = header.getKeyword("CDELT"+j+sver);
097                cdelt[j-1] = (kw == null) ? 1.0 : kw.getReal();
098                cdMatrix[j-1][j-1] = cdelt[j-1];
099    
100                kw = header.getKeyword("CTYPE"+j+sver);
101                ctype[j-1] = (kw == null) ? "        " : kw.getString();
102                if (7<ctype[j-1].length()) {
103                    String wctype = ctype[j-1].substring(5, 7);
104                    if (wctype.equals("TAN")) {
105                        cproj[j-1] = TAN;
106                    } else if (wctype.equals("ARC")) {
107                        cproj[j-1] = ARC;
108                    } else {
109                        cproj[j-1] = LIN;
110                    }
111                } else {
112                    cproj[j-1] = LIN;
113                }
114    
115                for (int i=1; i<=nax; i++) {
116                    kw = header.getKeyword("CD"+j+"_"+j+sver);
117                    if (kw != null) {
118                        cdMatrix[j-1][i-1] = kw.getReal();
119                        hasCdMatrix = true;
120                    }
121                }
122    
123                for (int i=1; i<=nax; i++) {
124                    kw = header.getKeyword("PC"+j+"_"+i+sver);
125                    if (kw != null) {
126                        pcMatrix[j-1][i-1] = kw.getReal();
127                        hasPcMatrix = true;
128                    }
129                }
130            }
131    
132           for (int j=1; j<MPS; j++) {
133               kw = header.getKeyword("AMDX"+j);
134               amdx[j-1] = (kw == null) ? 0.0 : kw.getReal();
135               kw = header.getKeyword("AMDY"+j);
136               amdy[j-1] = (kw == null) ? 0.0 : kw.getReal();
137           }
138        }
139    
140        /** Initiate internal WCS data structures.
141         *
142         *  @param   nax  No. of axies of data array
143         */
144        private void init(int nax) {
145            cproj = new int[nax];
146            crpix = new double[nax];
147            crval = new double[nax];
148            cdelt = new double[nax];
149            ctype = new String[nax];
150            cdMatrix = new double[nax][nax];
151            pcMatrix = new double[nax][nax];
152            ctype = new String[nax];
153    
154            for (int n=0; n<nax; n++) {
155                cproj[n] = LIN;
156                crpix[n] = 0.0;
157                crval[n] = 0.0;
158                cdelt[n] = 1.0;
159                ctype[n] = "        ";
160                for (int i=0; i<nax; i++) {
161                    cdMatrix[n][i] = (i==n) ? 1.0 : 0.0;
162                    pcMatrix[n][i] = (i==n) ? 1.0 : 0.0;
163                }    
164            }
165        }
166    
167        /** Compute World Coordinates from pixel coordinates.
168         *
169         *  @param  p  Array with pixel coordinates
170         */
171        public double[] toWCS(double[] p) {
172            double[] w;
173            double[] q;
174    
175            for (int j=0; j<nax; j++) p[j] -= crpix[j];
176            if (hasPcMatrix) {
177                q = matrixMult(pcMatrix, p);
178                for (int j=0; j<nax; j++) q[j] *= cdelt[j];
179            } else if (hasCdMatrix) {
180                q = matrixMult(cdMatrix, p);
181            } else {
182                q = p;
183                for (int j=0; j<nax; j++) q[j] *= cdelt[j];
184            }
185    
186            switch (cproj[0]) {
187                case TAN:
188                case LIN:
189                    for (int j=0; j<nax; j++) q[j] += crval[j];
190            }
191    
192            return q;
193        }
194        /** Compute pixel coordinates from a set of World Coordinates.
195         *
196         *  @param  wcs  Array with World Coordinates
197         */
198        public double[] toPixel(double[] wcs) {
199            double[] pix = new double[nax];
200            double[] wc  = new double[nax];
201    
202            for (int n=0; n<nax; n++) {
203                pix[n] = (wcs[n]-crval[n])/cdelt[n] + crpix[n];
204            }
205            return pix;
206        }
207    
208        private double[] matrixMult(double[][] mtx, double[] vec) {
209            int nv = vec.length;
210            double[] res = new double[nv];
211    
212            for (int j=0; j<nv; j++) {
213                res[j] = 0;
214                for (int i=0; i<nv; i++) {
215                    res[j] += mtx[j][i] * vec[i];
216                }
217            }
218            return res;
219        }
220    }
221    
222    
223    
224    
225