/*============================================================================
WCSLIB 4.3 - an implementation of the FITS WCS standard.
Copyright (C) 1995-2007, Mark Calabretta
This file is part of WCSLIB.
WCSLIB is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with WCSLIB. If not, see .
Correspondence concerning WCSLIB may be directed to:
Internet email: mcalabre@atnf.csiro.au
Postal address: Dr. Mark Calabretta
Australia Telescope National Facility, CSIRO
PO Box 76
Epping NSW 1710
AUSTRALIA
Author: Mark Calabretta, Australia Telescope National Facility
http://www.atnf.csiro.au/~mcalabre/index.html
$Id: lin.c,v 4.3 2007/12/27 05:41:36 cal103 Exp $
*===========================================================================*/
#include
#include
#include
#include "lin.h"
const int LINSET = 137;
/* Map status return value to message. */
const char *lin_errmsg[] = {
"Success",
"Null linprm pointer passed",
"Memory allocation failed",
"PCi_ja matrix is singular"};
/*--------------------------------------------------------------------------*/
int linini(alloc, naxis, lin)
int alloc, naxis;
struct linprm *lin;
{
int i, j;
double *pc;
if (lin == 0x0) return 1;
if (naxis <= 0) {
return 2;
}
if (lin->flag == -1 || lin->m_flag != LINSET) {
lin->m_flag = 0;
lin->m_naxis = 0x0;
lin->m_crpix = 0x0;
lin->m_pc = 0x0;
lin->m_cdelt = 0x0;
}
/* Allocate memory for arrays if required. */
if (alloc ||
lin->crpix == 0x0 ||
lin->pc == 0x0 ||
lin->cdelt == 0x0) {
/* Was sufficient allocated previously? */
if (lin->m_flag == LINSET && lin->m_naxis < naxis) {
/* No, free it. */
linfree(lin);
}
if (alloc || lin->crpix == 0x0) {
if (lin->m_crpix) {
/* In case the caller fiddled with it. */
lin->crpix = lin->m_crpix;
} else {
if (!(lin->crpix = calloc(naxis, sizeof(double)))) {
return 2;
}
lin->m_flag = LINSET;
lin->m_naxis = naxis;
lin->m_crpix = lin->crpix;
}
}
if (alloc || lin->pc == 0x0) {
if (lin->m_pc) {
/* In case the caller fiddled with it. */
lin->pc = lin->m_pc;
} else {
if (!(lin->pc = calloc(naxis*naxis, sizeof(double)))) {
linfree(lin);
return 2;
}
lin->m_flag = LINSET;
lin->m_naxis = naxis;
lin->m_pc = lin->pc;
}
}
if (alloc || lin->cdelt == 0x0) {
if (lin->m_cdelt) {
/* In case the caller fiddled with it. */
lin->cdelt = lin->m_cdelt;
} else {
if (!(lin->cdelt = calloc(naxis, sizeof(double)))) {
linfree(lin);
return 2;
}
lin->m_flag = LINSET;
lin->m_naxis = naxis;
lin->m_cdelt = lin->cdelt;
}
}
}
/* Free memory allocated by linset(). */
if (lin->flag == LINSET) {
if (lin->piximg) free(lin->piximg);
if (lin->imgpix) free(lin->imgpix);
}
lin->piximg = 0x0;
lin->imgpix = 0x0;
lin->i_naxis = 0x0;
lin->flag = 0;
lin->naxis = naxis;
/* CRPIXja defaults to 0.0. */
for (j = 0; j < naxis; j++) {
lin->crpix[j] = 0.0;
}
/* PCi_ja defaults to the unit matrix. */
pc = lin->pc;
for (i = 0; i < naxis; i++) {
for (j = 0; j < naxis; j++) {
if (j == i) {
*pc = 1.0;
} else {
*pc = 0.0;
}
pc++;
}
}
/* CDELTia defaults to 1.0. */
for (i = 0; i < naxis; i++) {
lin->cdelt[i] = 1.0;
}
return 0;
}
/*--------------------------------------------------------------------------*/
int lincpy(alloc, linsrc, lindst)
int alloc;
const struct linprm *linsrc;
struct linprm *lindst;
{
int i, j, naxis, status;
const double *srcp;
double *dstp;
if (linsrc == 0x0) return 1;
naxis = linsrc->naxis;
if (naxis <= 0) {
return 2;
}
if ((status = linini(alloc, naxis, lindst))) {
return status;
}
srcp = linsrc->crpix;
dstp = lindst->crpix;
for (j = 0; j < naxis; j++) {
*(dstp++) = *(srcp++);
}
srcp = linsrc->pc;
dstp = lindst->pc;
for (i = 0; i < naxis; i++) {
for (j = 0; j < naxis; j++) {
*(dstp++) = *(srcp++);
}
}
srcp = linsrc->cdelt;
dstp = lindst->cdelt;
for (i = 0; i < naxis; i++) {
*(dstp++) = *(srcp++);
}
return 0;
}
/*--------------------------------------------------------------------------*/
int linfree(lin)
struct linprm *lin;
{
if (lin == 0x0) return 1;
if (lin->flag != -1) {
/* Free memory allocated by linini(). */
if (lin->m_flag == LINSET) {
if (lin->crpix == lin->m_crpix) lin->crpix = 0x0;
if (lin->pc == lin->m_pc) lin->pc = 0x0;
if (lin->cdelt == lin->m_cdelt) lin->cdelt = 0x0;
if (lin->m_crpix) free(lin->m_crpix);
if (lin->m_pc) free(lin->m_pc);
if (lin->m_cdelt) free(lin->m_cdelt);
}
}
lin->m_flag = 0;
lin->m_naxis = 0;
lin->m_crpix = 0x0;
lin->m_pc = 0x0;
lin->m_cdelt = 0x0;
/* Free memory allocated by linset(). */
if (lin->flag == LINSET) {
if (lin->piximg) free(lin->piximg);
if (lin->imgpix) free(lin->imgpix);
}
lin->piximg = 0x0;
lin->imgpix = 0x0;
lin->i_naxis = 0;
lin->flag = 0;
return 0;
}
/*--------------------------------------------------------------------------*/
int linprt(lin)
const struct linprm *lin;
{
int i, j, k;
if (lin == 0x0) return 1;
if (lin->flag != LINSET) {
printf("The linprm struct is UNINITIALIZED.\n");
return 0;
}
printf(" flag: %d\n", lin->flag);
printf(" naxis: %d\n", lin->naxis);
printf(" crpix: %p\n", (void *)lin->crpix);
printf(" ");
for (i = 0; i < lin->naxis; i++) {
printf(" %- 11.5g", lin->crpix[i]);
}
printf("\n");
k = 0;
printf(" pc: %p\n", (void *)lin->pc);
for (i = 0; i < lin->naxis; i++) {
printf(" pc[%d][]:", i);
for (j = 0; j < lin->naxis; j++) {
printf(" %- 11.5g", lin->pc[k++]);
}
printf("\n");
}
printf(" cdelt: %p\n", (void *)lin->cdelt);
printf(" ");
for (i = 0; i < lin->naxis; i++) {
printf(" %- 11.5g", lin->cdelt[i]);
}
printf("\n");
printf(" unity: %d\n", lin->unity);
if (lin->piximg == 0x0) {
printf(" piximg: (nil)\n");
} else {
k = 0;
for (i = 0; i < lin->naxis; i++) {
printf("piximg[%d][]:", i);
for (j = 0; j < lin->naxis; j++) {
printf(" %- 11.5g", lin->piximg[k++]);
}
printf("\n");
}
}
if (lin->imgpix == 0x0) {
printf(" imgpix: (nil)\n");
} else {
k = 0;
for (i = 0; i < lin->naxis; i++) {
printf("imgpix[%d][]:", i);
for (j = 0; j < lin->naxis; j++) {
printf(" %- 11.5g", lin->imgpix[k++]);
}
printf("\n");
}
}
printf(" m_flag: %d\n", lin->m_flag);
printf(" m_naxis: %d\n", lin->m_naxis);
printf(" m_crpix: %p", (void *)lin->m_crpix);
if (lin->m_crpix == lin->crpix) printf(" (= crpix)");
printf("\n");
printf(" m_pc: %p", (void *)lin->m_pc);
if (lin->m_pc == lin->pc) printf(" (= pc)");
printf("\n");
printf(" m_cdelt: %p", (void *)lin->m_cdelt);
if (lin->m_cdelt == lin->cdelt) printf(" (= cdelt)");
printf("\n");
return 0;
}
/*--------------------------------------------------------------------------*/
int linset(lin)
struct linprm *lin;
{
int i, j, n, status;
double *pc, *piximg;
if (lin == 0x0) return 1;
n = lin->naxis;
/* Check for a unit matrix. */
lin->unity = 1;
pc = lin->pc;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (j == i) {
if (*(pc++) != 1.0) {
lin->unity = 0;
break;
}
} else {
if (*(pc++) != 0.0) {
lin->unity = 0;
break;
}
}
}
}
if (lin->unity) {
if (lin->flag == LINSET) {
/* Free memory that may have been allocated previously. */
if (lin->piximg) free(lin->piximg);
if (lin->imgpix) free(lin->imgpix);
}
lin->piximg = 0x0;
lin->imgpix = 0x0;
lin->i_naxis = 0;
} else {
if (lin->flag != LINSET || lin->i_naxis < n) {
if (lin->flag == LINSET) {
/* Free memory that may have been allocated previously. */
if (lin->piximg) free(lin->piximg);
if (lin->imgpix) free(lin->imgpix);
}
/* Allocate memory for internal arrays. */
if (!(lin->piximg = calloc(n*n, sizeof(double)))) {
return 2;
}
if (!(lin->imgpix = calloc(n*n, sizeof(double)))) {
free(lin->piximg);
return 2;
}
lin->i_naxis = n;
}
/* Compute the pixel-to-image transformation matrix. */
pc = lin->pc;
piximg = lin->piximg;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
*(piximg++) = lin->cdelt[i] * (*(pc++));
}
}
/* Compute the image-to-pixel transformation matrix. */
if ((status = matinv(n, lin->piximg, lin->imgpix))) {
return status;
}
}
lin->flag = LINSET;
return 0;
}
/*--------------------------------------------------------------------------*/
int linp2x(lin, ncoord, nelem, pixcrd, imgcrd)
struct linprm *lin;
int ncoord, nelem;
const double pixcrd[];
double imgcrd[];
{
int i, j, k, n, status;
double temp;
register const double *pix;
register double *img, *piximg;
/* Initialize. */
if (lin == 0x0) return 1;
if (lin->flag != LINSET) {
if ((status = linset(lin))) return status;
}
n = lin->naxis;
/* Convert pixel coordinates to intermediate world coordinates. */
pix = pixcrd;
img = imgcrd;
if (lin->unity) {
for (k = 0; k < ncoord; k++) {
for (i = 0; i < n; i++) {
*(img++) = lin->cdelt[i] * (*(pix++) - lin->crpix[i]);
}
pix += (nelem - n);
img += (nelem - n);
}
} else {
for (k = 0; k < ncoord; k++) {
for (i = 0; i < n; i++) {
img[i] = 0.0;
}
for (j = 0; j < n; j++) {
/* Column-wise multiplication allows this to be cached. */
temp = *(pix++) - lin->crpix[j];
piximg = lin->piximg + j;
for (i = 0; i < n; i++, piximg += n) {
img[i] += *piximg * temp;
}
}
pix += (nelem - n);
img += nelem;
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
int linx2p(lin, ncoord, nelem, imgcrd, pixcrd)
struct linprm *lin;
int ncoord, nelem;
const double imgcrd[];
double pixcrd[];
{
int i, j, k, n, status;
register const double *img;
register double *imgpix, *pix;
/* Initialize. */
if (lin == 0x0) return 1;
if (lin->flag != LINSET) {
if ((status = linset(lin))) return status;
}
n = lin->naxis;
/* Convert intermediate world coordinates to pixel coordinates. */
img = imgcrd;
pix = pixcrd;
if (lin->unity) {
for (k = 0; k < ncoord; k++) {
for (j = 0; j < n; j++) {
*(pix++) = (*(img++) / lin->cdelt[j]) + lin->crpix[j];
}
pix += (nelem - n);
img += (nelem - n);
}
} else {
for (k = 0; k < ncoord; k++) {
imgpix = lin->imgpix;
for (j = 0; j < n; j++) {
*pix = 0.0;
for (i = 0; i < n; i++) {
*pix += *imgpix * img[i];
imgpix++;
}
*(pix++) += lin->crpix[j];
}
pix += (nelem - n);
img += nelem;
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
int matinv(n, mat, inv)
int n;
const double mat[];
double inv[];
{
register int i, ij, ik, j, k, kj, pj;
int itemp, *mxl, *lxm, pivot;
double colmax, *lu, *rowmax, dtemp;
/* Allocate memory for internal arrays. */
if (!(mxl = calloc(n, sizeof(int)))) return 2;
if (!(lxm = calloc(n, sizeof(int)))) {
free(mxl);
return 2;
}
if (!(rowmax = calloc(n, sizeof(double)))) {
free(mxl);
free(lxm);
return 2;
}
if (!(lu = calloc(n*n, sizeof(double)))) {
free(mxl);
free(lxm);
free(rowmax);
return 2;
}
/* Initialize arrays. */
for (i = 0, ij = 0; i < n; i++) {
/* Vector that records row interchanges. */
mxl[i] = i;
rowmax[i] = 0.0;
for (j = 0; j < n; j++, ij++) {
dtemp = fabs(mat[ij]);
if (dtemp > rowmax[i]) rowmax[i] = dtemp;
lu[ij] = mat[ij];
}
/* A row of zeroes indicates a singular matrix. */
if (rowmax[i] == 0.0) {
free(mxl);
free(lxm);
free(rowmax);
free(lu);
return 3;
}
}
/* Form the LU triangular factorization using scaled partial pivoting. */
for (k = 0; k < n; k++) {
/* Decide whether to pivot. */
colmax = fabs(lu[k*n+k]) / rowmax[k];
pivot = k;
for (i = k+1; i < n; i++) {
ik = i*n + k;
dtemp = fabs(lu[ik]) / rowmax[i];
if (dtemp > colmax) {
colmax = dtemp;
pivot = i;
}
}
if (pivot > k) {
/* We must pivot, interchange the rows of the design matrix. */
for (j = 0, pj = pivot*n, kj = k*n; j < n; j++, pj++, kj++) {
dtemp = lu[pj];
lu[pj] = lu[kj];
lu[kj] = dtemp;
}
/* Amend the vector of row maxima. */
dtemp = rowmax[pivot];
rowmax[pivot] = rowmax[k];
rowmax[k] = dtemp;
/* Record the interchange for later use. */
itemp = mxl[pivot];
mxl[pivot] = mxl[k];
mxl[k] = itemp;
}
/* Gaussian elimination. */
for (i = k+1; i < n; i++) {
ik = i*n + k;
/* Nothing to do if lu[ik] is zero. */
if (lu[ik] != 0.0) {
/* Save the scaling factor. */
lu[ik] /= lu[k*n+k];
/* Subtract rows. */
for (j = k+1; j < n; j++) {
lu[i*n+j] -= lu[ik]*lu[k*n+j];
}
}
}
}
/* mxl[i] records which row of mat corresponds to row i of lu. */
/* lxm[i] records which row of lu corresponds to row i of mat. */
for (i = 0; i < n; i++) {
lxm[mxl[i]] = i;
}
/* Determine the inverse matrix. */
for (i = 0, ij = 0; i < n; i++) {
for (j = 0; j < n; j++, ij++) {
inv[ij] = 0.0;
}
}
for (k = 0; k < n; k++) {
inv[lxm[k]*n+k] = 1.0;
/* Forward substitution. */
for (i = lxm[k]+1; i < n; i++) {
for (j = lxm[k]; j < i; j++) {
inv[i*n+k] -= lu[i*n+j]*inv[j*n+k];
}
}
/* Backward substitution. */
for (i = n-1; i >= 0; i--) {
for (j = i+1; j < n; j++) {
inv[i*n+k] -= lu[i*n+j]*inv[j*n+k];
}
inv[i*n+k] /= lu[i*n+i];
}
}
free(mxl);
free(lxm);
free(rowmax);
free(lu);
return 0;
}