1
/*=============================================================================
3
* WCSLIB - an implementation of the FITS WCS proposal.
4
* Copyright (C) 1995, Mark Calabretta
6
* This library is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU Library General Public License as published
8
* by the Free Software Foundation; either version 2 of the License, or (at
9
* your option) any later version.
11
* This library is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
14
* General Public License for more details.
16
* You should have received a copy of the GNU Library General Public License
17
* along with this library; if not, write to the Free Software Foundation,
18
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
* Correspondence concerning WCSLIB may be directed to:
21
* Internet email: mcalabre@atnf.csiro.au
22
* Postal address: Dr. Mark Calabretta,
23
* Australia Telescope National Facility,
28
*=============================================================================
30
* C routines which implement the FITS World Coordinate System (WCS)
35
* These utility routines apply the linear transformation defined by the WCS
36
* FITS header cards. There are separate routines for the image-to-pixel,
37
* linfwd(), and pixel-to-image, linrev(), transformations.
39
* An initialization routine, linset(), computes intermediate values from
40
* the transformation parameters but need not be called explicitly - see the
41
* explanation of lin.flag below.
43
* An auxiliary matrix inversion routine, matinv(), is included. It uses
44
* LU-triangular factorization with scaled partial pivoting.
47
* Initialization routine; linset()
48
* --------------------------------
49
* Initializes members of a linprm data structure which hold intermediate
50
* values. Note that this routine need not be called directly; it will be
51
* invoked by linfwd() and linrev() if the "flag" structure member is
52
* anything other than a predefined magic value.
54
* Given and/or returned:
55
* lin linprm* Linear transformation parameters (see below).
57
* Function return value:
60
* 1: Memory allocation error.
61
* 2: PC matrix is singular.
63
* Forward transformation; linfwd()
64
* --------------------------------
65
* Compute pixel coordinates from image coordinates. Note that where
66
* celestial coordinate systems are concerned the image coordinates
67
* correspond to (x,y) in the plane of projection, not celestial (lng,lat).
70
* imgcrd d[] Image (world) coordinate.
73
* lin linprm* Linear transformation parameters (see below).
76
* pixcrd d[] Pixel coordinate.
78
* Function return value:
81
* 1: The transformation is not invertible.
83
* Reverse transformation; linrev()
84
* --------------------------------
85
* Compute image coordinates from pixel coordinates. Note that where
86
* celestial coordinate systems are concerned the image coordinates
87
* correspond to (x,y) in the plane of projection, not celestial (lng,lat).
90
* pixcrd d[] Pixel coordinate.
92
* Given and/or returned:
93
* lin linprm* Linear transformation parameters (see below).
96
* imgcrd d[] Image (world) coordinate.
98
* Function return value:
103
* Linear transformation parameters
104
* --------------------------------
105
* The linprm struct consists of the following:
108
* This flag must be set to zero whenever any of the following members
109
* are set or modified. This signals the initialization routine,
110
* linset(), to recompute intermediaries.
112
* Number of image axes.
114
* Pointer to the first element of an array of double containing the
115
* coordinate reference pixel, CRPIXn.
117
* Pointer to the first element of the PC (pixel coordinate)
118
* transformation matrix.
120
* Pointer to the first element of an array of double containing the
121
* coordinate increments, CDELTn.
123
* The remaining members of the linprm struct are maintained by the
124
* initialization routine and should not be modified. Storage will be
125
* allocated for these arrays via malloc().
128
* Pointer to the first element of the matrix containing the product
129
* of the CDELTn diagonal matrix and the PC matrix.
131
* Pointer to the first element of the inverse of the piximg matrix.
133
* Author: Mark Calabretta, Australia Telescope National Facility
139
*===========================================================================*/
150
int i, ij, j, mem, n;
156
/* Allocate memory for internal arrays. */
157
mem = n * n * sizeof(double);
158
lin->piximg = (double*)malloc((size_t)mem);
159
if (lin->piximg == (double*)0) return 1;
161
lin->imgpix = (double*)malloc((size_t)mem);
162
if (lin->imgpix == (double*)0)
164
(void) free(lin->piximg);
168
/* Compute the pixel-to-image transformation matrix. */
169
for (i = 0, ij = 0; i < n; i++) {
170
for (j = 0; j < n; j++, ij++) {
171
lin->piximg[ij] = lin->cdelt[i] * lin->pc[ij];
175
/* Compute the image-to-pixel transformation matrix. */
176
if (matinv(n, lin->piximg, lin->imgpix))
178
(void) free(lin->piximg);
179
(void) free(lin->imgpix);
188
/*--------------------------------------------------------------------------*/
190
int linfwd(imgcrd, lin, pixcrd)
201
if (lin->flag != LINSET) {
202
if (linset(lin)) return 1;
205
for (i = 0, ij = 0; i < n; i++) {
207
for (j = 0; j < n; j++, ij++) {
208
pixcrd[i] += lin->imgpix[ij] * imgcrd[j];
212
for (j = 0; j < n; j++) {
213
pixcrd[j] += lin->crpix[j];
219
/*--------------------------------------------------------------------------*/
221
int linrev(pixcrd, lin, imgcrd)
233
if (lin->flag != LINSET) {
234
if (linset(lin)) return 1;
237
for (i = 0; i < n; i++) {
241
for (j = 0; j < n; j++) {
242
temp = pixcrd[j] - lin->crpix[j];
243
for (i = 0, ij = j; i < n; i++, ij+=n) {
244
imgcrd[i] += lin->piximg[ij] * temp;
251
/*--------------------------------------------------------------------------*/
253
int matinv(n, mat, inv)
259
register int i, ij, ik, j, k, kj, pj;
260
int status, itemp, mem, *mxl, *lxm, pivot;
262
double colmax, *lu, *rowmax, dtemp;
267
rowmax = (double *) 0;
269
/* Allocate memory for internal arrays. */
271
mem = n * sizeof(int);
272
if ((mxl = (int*)malloc((size_t)mem)) == (int*)0) return status;
273
if ((lxm = (int*)malloc((size_t)mem)) == (int*)0) goto end_of_it;
275
mem = n * sizeof(double);
276
if ((rowmax = (double*)malloc((size_t)mem)) == (double*)0) goto end_of_it;
279
if ((lu = (double*)malloc((size_t)mem)) == (double*)0) goto end_of_it;
282
/* Initialize arrays. */
283
for (i = 0, ij = 0; i < n; i++) {
284
/* Vector which records row interchanges. */
289
for (j = 0; j < n; j++, ij++) {
290
dtemp = fabs(mat[ij]);
291
if (dtemp > rowmax[i]) rowmax[i] = dtemp;
296
/* A row of zeroes indicates a singular matrix. */
297
if (rowmax[i] == 0.0)
305
/* Form the LU triangular factorization using scaled partial pivoting. */
306
for (k = 0; k < n; k++) {
307
/* Decide whether to pivot. */
308
colmax = fabs(lu[k*n+k]) / rowmax[k];
311
for (i = k+1; i < n; i++) {
313
dtemp = fabs(lu[ik]) / rowmax[i];
314
if (dtemp > colmax) {
321
/* We must pivot, interchange the rows of the design matrix. */
322
for (j = 0, pj = pivot*n, kj = k*n; j < n; j++, pj++, kj++) {
328
/* Amend the vector of row maxima. */
329
dtemp = rowmax[pivot];
330
rowmax[pivot] = rowmax[k];
333
/* Record the interchange for later use. */
339
/* Gaussian elimination. */
340
for (i = k+1; i < n; i++) {
343
/* Nothing to do if lu[ik] is zero. */
345
/* Save the scaling factor. */
349
for (j = k+1; j < n; j++) {
350
lu[i*n+j] -= lu[ik]*lu[k*n+j];
357
/* mxl[i] records which row of mat corresponds to row i of lu. */
358
/* lxm[i] records which row of lu corresponds to row i of mat. */
359
for (i = 0; i < n; i++) {
364
/* Determine the inverse matrix. */
365
for (i = 0, ij = 0; i < n; i++) {
366
for (j = 0; j < n; j++, ij++) {
371
for (k = 0; k < n; k++) {
372
inv[lxm[k]*n+k] = 1.0;
374
/* Forward substitution. */
375
for (i = lxm[k]+1; i < n; i++) {
376
for (j = lxm[k]; j < i; j++) {
377
inv[i*n+k] -= lu[i*n+j]*inv[j*n+k];
381
/* Backward substitution. */
382
for (i = n-1; i >= 0; i--) {
383
for (j = i+1; j < n; j++) {
384
inv[i*n+k] -= lu[i*n+j]*inv[j*n+k];
386
inv[i*n+k] /= lu[i*n+i];
389
status = 0; /* all o.k. */